From e48d2d58e0ccca688e85a6897214df378b3610e7 Mon Sep 17 00:00:00 2001 From: Pavel Stupnikov Date: Mon, 16 Mar 2015 03:20:50 +0300 Subject: [PATCH] latest novapolis client for 1.5 --HG-- branch : novattd150 --- projects/openttd_vs90.vcproj | 376 +++++++++++--------- source.list | 9 + src/bridge_gui.cpp | 3 + src/build_vehicle_gui.cpp | 19 +- src/command.cpp | 42 ++- src/company_base.h | 8 + src/company_cmd.cpp | 20 ++ src/company_func.h | 1 + src/company_gui.cpp | 68 ++++ src/crashlog.cpp | 4 +- src/depot_gui.cpp | 91 +++-- src/economy.cpp | 25 ++ src/gfx.cpp | 1 + src/gfx_func.h | 1 + src/gfx_type.h | 10 + src/gfxinit.cpp | 1 + src/goal_gui.cpp | 10 +- src/graph_gui.cpp | 224 ++++++++++-- src/gui.h | 4 + src/hotkeys.cpp | 16 + src/industry_gui.cpp | 102 +++++- src/lang/english.txt | 288 ++++++++++++++- src/main_gui.cpp | 13 +- src/misc.cpp | 1 + src/misc_gui.cpp | 242 +++++++++++++ src/network/network.cpp | 3 +- src/network/network_client.cpp | 74 +++- src/network/network_func.h | 3 +- src/network/network_gui.cpp | 49 ++- src/order_gui.cpp | 146 +++++++- src/rail_cmd.cpp | 3 + src/rail_gui.cpp | 126 ++++++- src/rev.cpp | 10 +- src/rev.cpp.in | 4 +- src/road_gui.cpp | 195 ++++++++++- src/saveload/town_sl.cpp | 9 + src/settings_gui.cpp | 24 ++ src/settings_type.h | 14 + src/smallmap_gui.cpp | 2 +- src/station_gui.cpp | 5 +- src/table/settings.ini | 133 +++++++ src/table/sprites.h | 16 +- src/tile_cmd.h | 1 + src/tilehighlight_func.h | 4 + src/tilehighlight_type.h | 5 + src/toolbar_gui.cpp | 147 +++++++- src/town.h | 78 +++++ src/town_cmd.cpp | 237 ++++++++++++- src/town_gui.cpp | 448 +++++++++++++++++++++++- src/vehicle_gui.cpp | 55 ++- src/video/sdl_v.cpp | 12 +- src/video/win32_v.cpp | 2 + src/viewport.cpp | 616 ++++++++++++++++++++++++++------- src/viewport_func.h | 2 +- src/viewport_gui.cpp | 5 + src/viewport_type.h | 1 + src/widgets/company_widget.h | 4 + src/widgets/dropdown.cpp | 7 +- src/widgets/dropdown_type.h | 39 +++ src/widgets/graph_widget.h | 4 + src/widgets/industry_widget.h | 1 + src/widgets/network_widget.h | 5 + src/widgets/rail_widget.h | 10 +- src/widgets/road_widget.h | 38 +- src/widgets/toolbar_widget.h | 2 + src/widgets/town_widget.h | 26 ++ src/window.cpp | 57 ++- src/window_gui.h | 28 ++ src/window_type.h | 13 + 69 files changed, 3756 insertions(+), 486 deletions(-) diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 666760ce78..38bf0cccbd 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -1,7 +1,7 @@ + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - @@ -447,6 +445,10 @@ RelativePath=".\..\src\autoreplace.cpp" > + + @@ -507,6 +509,10 @@ RelativePath=".\..\src\dedicated.cpp" > + + @@ -543,6 +549,10 @@ RelativePath=".\..\src\fios.cpp" > + + @@ -551,10 +561,6 @@ RelativePath=".\..\src\fontdetection.cpp" > - - @@ -568,11 +574,11 @@ > - - - - @@ -627,18 +625,14 @@ RelativePath=".\..\src\linkgraph\linkgraphschedule.cpp" > - - - - + + @@ -703,6 +697,10 @@ RelativePath=".\..\src\rail.cpp" > + + @@ -751,6 +749,10 @@ RelativePath=".\..\src\station.cpp" > + + @@ -767,10 +769,6 @@ RelativePath=".\..\src\strings.cpp" > - - @@ -867,6 +865,10 @@ RelativePath=".\..\src\autoslope.h" > + + @@ -887,6 +889,10 @@ RelativePath=".\..\src\bridge.h" > + + @@ -999,6 +1005,10 @@ RelativePath=".\..\src\video\dedicated_v.h" > + + @@ -1091,6 +1101,10 @@ RelativePath=".\..\src\fios.h" > + + @@ -1099,10 +1113,6 @@ RelativePath=".\..\src\fontdetection.h" > - - @@ -1199,6 +1209,10 @@ RelativePath=".\..\src\ini_type.h" > + + @@ -1211,18 +1225,6 @@ RelativePath=".\..\src\language.h" > - - - - - - @@ -1251,14 +1253,6 @@ RelativePath=".\..\src\linkgraph\linkgraphschedule.h" > - - - - @@ -1271,6 +1265,10 @@ RelativePath=".\..\src\map_type.h" > + + @@ -1519,6 +1517,10 @@ RelativePath=".\..\src\rail_type.h" > + + @@ -1859,6 +1861,10 @@ RelativePath=".\..\src\viewport_type.h" > + + @@ -1903,6 +1909,10 @@ RelativePath=".\..\src\window_type.h" > + + @@ -2055,10 +2065,18 @@ RelativePath=".\..\src\build_vehicle_gui.cpp" > + + + + @@ -2255,20 +2273,28 @@ RelativePath=".\..\src\viewport_gui.cpp" > + + + + + + @@ -2599,6 +2629,10 @@ RelativePath=".\..\src\waypoint_cmd.cpp" > + + - - - - @@ -3863,6 +3889,14 @@ RelativePath=".\..\src\blitter\32bpp_sse4.hpp" > + + + + diff --git a/source.list b/source.list index 3b66ab9fca..e062c1b22c 100644 --- a/source.list +++ b/source.list @@ -143,6 +143,7 @@ base_media_func.h base_station_base.h bmp.h bridge.h +cargo_table_gui.h cargo_type.h cargoaction.h cargomonitor.h @@ -386,6 +387,7 @@ vehiclelist.h viewport_func.h viewport_sprite_sorter.h viewport_type.h +watch_gui.h water.h waypoint_base.h waypoint_func.h @@ -397,6 +399,7 @@ video/win32_v.h window_func.h window_gui.h window_type.h +zoning.h zoom_func.h zoom_type.h #if WIN32 @@ -452,7 +455,9 @@ autoreplace_gui.cpp bootstrap_gui.cpp bridge_gui.cpp build_vehicle_gui.cpp +cargo_table_gui.cpp cheat_gui.cpp +commands_gui.cpp company_gui.cpp console_gui.cpp date_gui.cpp @@ -501,8 +506,10 @@ train_gui.cpp transparency_gui.cpp tree_gui.cpp vehicle_gui.cpp +watch_gui.cpp viewport_gui.cpp waypoint_gui.cpp +zoning_gui.cpp # Widgets widgets/airport_widget.h @@ -511,6 +518,7 @@ widgets/autoreplace_widget.h widgets/bootstrap_widget.h widgets/bridge_widget.h widgets/build_vehicle_widget.h +widgets/cargo_table_widget.h widgets/cheat_widget.h widgets/company_widget.h widgets/console_widget.h @@ -590,6 +598,7 @@ vehicle_cmd.cpp void_cmd.cpp water_cmd.cpp waypoint_cmd.cpp +zoning_cmd.cpp # Save/Load handlers saveload/afterload.cpp diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index 2e9657e322..019768d23c 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -24,6 +24,7 @@ #include "cmd_helper.h" #include "tunnelbridge_map.h" #include "road_gui.h" +#include "tilehighlight_func.h" #include "widgets/bridge_widget.h" @@ -72,6 +73,8 @@ void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uin DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(p1)); ConnectRoadToStructure(p1, start_direction); } + + StoreRailPlacementEndpoints(p1, end_tile, (TileX(p1) == TileX(end_tile)) ? TRACK_Y : TRACK_X, false); } /** Window class for handling the bridge-build GUI. */ diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 715c87e99e..49d16f8750 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -34,7 +34,7 @@ #include "autoreplace_func.h" #include "widgets/build_vehicle_widget.h" - +#include "hotkeys.h" #include "table/strings.h" #include "safeguards.h" @@ -1481,13 +1481,28 @@ struct BuildVehicleWindow : Window { { this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); } + + virtual EventState OnHotkey(int hotkey) + { + if (this->owner != _local_company) return ES_NOT_HANDLED; + return Window::OnHotkey(hotkey); + } + + static HotkeyList hotkeys; }; +static Hotkey build_vehicle_hotkeys[] = { + Hotkey('R', "build_vehicle", WID_BV_BUILD), + HOTKEY_LIST_END +}; +HotkeyList BuildVehicleWindow::hotkeys("build_vehicle", build_vehicle_hotkeys); + static WindowDesc _build_vehicle_desc( WDP_AUTO, "build_vehicle", 240, 268, WC_BUILD_VEHICLE, WC_NONE, WDF_CONSTRUCTION, - _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets), + &BuildVehicleWindow::hotkeys ); void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) diff --git a/src/command.cpp b/src/command.cpp index 2830144f89..8d5e1e9a41 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -26,6 +26,10 @@ #include "signal_func.h" #include "core/backup_type.hpp" #include "object_base.h" +#include "window_func.h" +#include "watch_gui.h" +#include "network/network_base.h" +#include "window_func.h" #include "table/strings.h" @@ -547,14 +551,19 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd) bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd) { /* Cost estimation is generally only done when the - * local user presses shift while doing somthing. - * However, in case of incoming network commands, - * map generation or the pause button we do want - * to execute. */ - bool estimate_only = _shift_pressed && IsLocalCompany() && - !_generating_world && - !(cmd & CMD_NETWORK_COMMAND) && - (cmd & CMD_ID_MASK) != CMD_PAUSE; + * local user presses shift while constructing somthing. + * However, in case of incoming network commands or + * map generation we do want to execute. */ + bool estimate_only = false; + switch (_command_proc_table[cmd & CMD_ID_MASK].type) { + case CMDT_LANDSCAPE_CONSTRUCTION: + case CMDT_VEHICLE_CONSTRUCTION: + estimate_only = _shift_pressed && IsLocalCompany() && + !_generating_world && !(cmd & CMD_NETWORK_COMMAND); + break; + default: + break; // just to silence warnings + } /* We're only sending the command, so don't do * fancy things for 'success'. */ @@ -756,6 +765,23 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, if (c != NULL) c->last_build_coordinate = tile; } + /* Send Tile Number to Watching Company Windows */ + WatchCompany *wc; + for(int watching_window = 0; ; watching_window++){ + wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANY, watching_window)); + if(wc != NULL) wc->OnDoCommand(_current_company, tile); + else break; + } + + NetworkClientInfo *ci; + FOR_ALL_CLIENT_INFOS(ci) { + if (ci->client_playas == _current_company) { + wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANYA, ci->client_id)); + if (wc != NULL) wc->OnDoCommand(_current_company, tile); + break; + } + } + SubtractMoneyFromCompany(res2); /* update signals if needed */ diff --git a/src/company_base.h b/src/company_base.h index b220669c8c..9835f5f50e 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -17,6 +17,7 @@ #include "autoreplace_type.h" #include "tile_type.h" #include "settings_type.h" +#include "cargo_type.h" #include "group.h" /** Statistics about the economy. */ @@ -26,6 +27,7 @@ struct CompanyEconomyEntry { CargoArray delivered_cargo; ///< The amount of delivered cargo. int32 performance_history; ///< Company score (scale 0-1000) Money company_value; ///< The value of the company. + Money cargo_income[NUM_CARGO]; ///< Cargo income from each cargo type }; struct CompanyInfrastructure { @@ -124,6 +126,12 @@ struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure. + uint32 cargo_units[NUM_CARGO]; ///< Total amount of transported cargo for each cargo ID + Money cargo_income[NUM_CARGO]; ///< Total income from transported cargo for each cargo ID + + uint32 cargo_units_period[2][NUM_CARGO]; ///< Monthly amount of transported cargo for each cargo ID + Money cargo_income_period[2][NUM_CARGO]; ///< Monthly income from transported cargo for each cargo ID + /** * Is this company a valid company, controlled by the computer (a NoAI program)? * @param index Index in the pool. diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 3a94078582..538c11c22f 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -38,6 +38,7 @@ #include "story_base.h" #include "table/strings.h" +#include "cargo_type.h" #include "safeguards.h" @@ -69,6 +70,8 @@ Company::Company(uint16 name_1, bool is_ai) for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR; InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1); } /** Destructor. */ @@ -91,6 +94,8 @@ void Company::PostDestructor(size_t index) InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); /* If the currently shown error message has this company in it, then close it. */ InvalidateWindowData(WC_ERRMSG, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1); } /** @@ -576,9 +581,23 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index); Game::NewEvent(new ScriptEventCompanyNew(c->index)); + if (!is_ai) UpdateAllTownVirtCoords(); //coloured rating + + for (uint j = 0; j < NUM_CARGO; j++) { + c->cargo_income[j] = 0; + c->cargo_units[j] = 0; + } + CargoResetPeriods(c); + return c; } +void CargoResetPeriods(Company *c){ + memmove(&c->cargo_income_period[1], &c->cargo_income_period[0], sizeof(c->cargo_income_period[0])); + memset(&c->cargo_income_period, 0, sizeof(c->cargo_income_period[0])); + memmove(&c->cargo_units_period[1], &c->cargo_units_period[0], sizeof(c->cargo_units_period[0])); + memset(&c->cargo_units_period, 0, sizeof(c->cargo_units_period[0])); +} /** Start the next competitor now. */ void StartupCompanies() { @@ -1081,6 +1100,7 @@ CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uin free(c->name); c->name = reset ? NULL : stredup(text); MarkWholeScreenDirty(); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); CompanyAdminUpdate(c); } diff --git a/src/company_func.h b/src/company_func.h index b5d9361673..2af836a4fd 100644 --- a/src/company_func.h +++ b/src/company_func.h @@ -31,6 +31,7 @@ void SubtractMoneyFromCompany(CommandCost cost); void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cost); CommandCost CheckOwnership(Owner owner, TileIndex tile = 0); CommandCost CheckTileOwnership(TileIndex tile); +void CargoResetPeriods(Company *c); extern CompanyByte _local_company; extern CompanyByte _current_company; diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 1f3b06355d..cba418f128 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -1917,6 +1917,9 @@ static const NWidgetPart _nested_company_widgets[] = { NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS), NWidget(NWID_SPACER), SetMinimalSize(90, 0), EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_RESET), SetFill(1, 0), SetDataTip(STR_XI_RESET2, STR_XI_RESET), + NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_SUSPEND), SetFill(1, 0), SetDataTip(STR_XI_SUSPEND2, STR_XI_SUSPEND), + NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_RESUME), SetFill(1, 0), SetDataTip(STR_XI_RESUME2, STR_XI_RESUME), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), EndContainer(), @@ -1950,6 +1953,7 @@ static const NWidgetPart _nested_company_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_JOIN2), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), @@ -1987,6 +1991,16 @@ static const StringID _company_view_vehicle_count_strings[] = { /** * Window with general information about a company */ +static void ResetCallback(Window *w, bool confirmed) +{ + if (confirmed) { + CompanyID company2 = (CompanyID)w->window_number; + char msg[128]; + seprintf(msg, lastof(msg), "!reset %i", company2 + 1); + NetworkClientSendChatToServer(msg); + } +} + struct CompanyWindow : Window { CompanyWidgets query_widget; @@ -2083,6 +2097,13 @@ struct CompanyWindow : Window } } + if(!_networking){ + this->SetWidgetDisabledState(CW_WIDGET_COMPANY_RESUME, true); + this->SetWidgetDisabledState(CW_WIDGET_COMPANY_SUSPEND, true); + this->SetWidgetDisabledState(CW_WIDGET_COMPANY_RESET, true); + this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN2, true); + } + this->DrawWidgets(); } @@ -2139,6 +2160,15 @@ struct CompanyWindow : Window break; } + case CW_WIDGET_COMPANY_RESUME: + case CW_WIDGET_COMPANY_SUSPEND: + case CW_WIDGET_COMPANY_RESET: + case CW_WIDGET_COMPANY_JOIN2: + if(!_networking || !_novarole){ + size->width = 0; + size->height = 0; + } + break; #ifdef ENABLE_NETWORK case WID_C_HAS_PASSWORD: *size = maxdim(*size, GetSpriteSize(SPR_LOCK)); @@ -2365,6 +2395,44 @@ struct CompanyWindow : Window /* just send the join command */ NetworkClientRequestMove(company); } + MarkWholeScreenDirty(); + break; + } + + case CW_WIDGET_COMPANY_JOIN2:{ + CompanyID company2 = (CompanyID)this->window_number; + this->query_widget = CW_WIDGET_COMPANY_JOIN2; + char msg[128]; + seprintf(msg, lastof(msg), "!move %i", company2 + 1); + NetworkClientSendChatToServer(msg); + MarkWholeScreenDirty(); + break; + } + case CW_WIDGET_COMPANY_RESET:{ + if (!_networking) return; + this->query_widget = CW_WIDGET_COMPANY_RESET; + ShowQuery(STR_XI_RESET_CAPTION, STR_XI_REALY_RESET, this, ResetCallback); + MarkWholeScreenDirty(); + break; + } + case CW_WIDGET_COMPANY_SUSPEND:{ + if (!_networking) return; + this->query_widget = CW_WIDGET_COMPANY_SUSPEND; + CompanyID company2 = (CompanyID)this->window_number; + char msg[128]; + seprintf(msg, lastof(msg), "!lockp %i", company2 + 1); + NetworkClientSendChatToServer(msg); + MarkWholeScreenDirty(); + break; + } + case CW_WIDGET_COMPANY_RESUME:{ + if (!_networking) return; + this->query_widget = CW_WIDGET_COMPANY_RESUME; + CompanyID company2 = (CompanyID)this->window_number; + char msg[128]; + seprintf(msg, lastof(msg), "!lockp %i", company2 + 1); + NetworkClientSendChatToServer(msg); + MarkWholeScreenDirty(); break; } #endif /* ENABLE_NETWORK */ diff --git a/src/crashlog.cpp b/src/crashlog.cpp index cecbb63120..009405882d 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -87,7 +87,7 @@ char *CrashLog::LogCompiler(char *buffer, const char *last) const char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const { return buffer + seprintf(buffer, last, - "OpenTTD version:\n" + "OpenTTD version: Novapolis patched client http://www.novapolis.net\n\n\n" " Version: %s (%d)\n" " NewGRF ver: %08x\n" " Bits: %d\n" @@ -313,7 +313,7 @@ char *CrashLog::LogGamelog(char *buffer, const char *last) const char *CrashLog::FillCrashLog(char *buffer, const char *last) const { time_t cur_time = time(NULL); - buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n"); + buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\nNovapolis patched client http://www.novapolis.net\nPlease, unless you encounter this bug with unpatched OpenTTD version, report bug to Novapolis team\n\n"); buffer += seprintf(buffer, last, "Crash at: %s", asctime(gmtime(&cur_time))); YearMonthDay ymd; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index bddfc7c2d7..cad8eed13f 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -28,7 +28,7 @@ #include "vehiclelist.h" #include "order_backup.h" #include "zoom_func.h" - +#include "hotkeys.h" #include "widgets/depot_widget.h" #include "table/strings.h" @@ -81,34 +81,6 @@ static const NWidgetPart _nested_train_depot_widgets[] = { EndContainer(), }; -static WindowDesc _train_depot_desc( - WDP_AUTO, "depot_train", 362, 123, - WC_VEHICLE_DEPOT, WC_NONE, - 0, - _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) -); - -static WindowDesc _road_depot_desc( - WDP_AUTO, "depot_roadveh", 316, 97, - WC_VEHICLE_DEPOT, WC_NONE, - 0, - _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) -); - -static WindowDesc _ship_depot_desc( - WDP_AUTO, "depot_ship", 306, 99, - WC_VEHICLE_DEPOT, WC_NONE, - 0, - _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) -); - -static WindowDesc _aircraft_depot_desc( - WDP_AUTO, "depot_aircraft", 332, 99, - WC_VEHICLE_DEPOT, WC_NONE, - 0, - _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) -); - extern void DepotSortList(VehicleList *list); /** @@ -295,9 +267,16 @@ struct DepotWindow : Window { this->sel, EIT_IN_DEPOT, free_wagon ? 0 : this->hscroll->GetPosition(), this->vehicle_over); /* Length of consist in tiles with 1 fractional digit (rounded up) */ - SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE)); - SetDParam(1, 1); - DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter + if (_settings_client.gui.old_depot_train_length_calc) { + SetDParam(0, CeilDiv(u->gcache.cached_total_length, 8)); + SetDParam(1, 1); + DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT); // Draw the counter + } + else { + SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE)); + SetDParam(1, 1); + DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter + } break; } @@ -995,8 +974,24 @@ struct DepotWindow : Window { return ES_NOT_HANDLED; } + + virtual EventState OnHotkey(int hotkey) + { + if (this->owner != _local_company) return ES_NOT_HANDLED; + return Window::OnHotkey(hotkey); + } + + static HotkeyList hotkeys; }; +static Hotkey depot_hotkeys[] = { + Hotkey(WKC_CTRL | 'F', "depot_go_all", WID_D_START_ALL), + Hotkey('R', "depot_build_vehicle", WID_D_BUILD), + Hotkey(WKC_NONE, "depot_clone_vehicle", WID_D_CLONE), + HOTKEY_LIST_END +}; +HotkeyList DepotWindow::hotkeys("depot_gui", depot_hotkeys); + static void DepotSellAllConfirmationCallback(Window *win, bool confirmed) { if (confirmed) { @@ -1007,6 +1002,38 @@ static void DepotSellAllConfirmationCallback(Window *win, bool confirmed) } } +static WindowDesc _train_depot_desc( + WDP_AUTO, "depot_train", 362, 123, + WC_VEHICLE_DEPOT, WC_NONE, + 0, + _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets), + &DepotWindow::hotkeys +); + +static WindowDesc _road_depot_desc( + WDP_AUTO, "depot_roadveh", 316, 97, + WC_VEHICLE_DEPOT, WC_NONE, + 0, + _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets), + &DepotWindow::hotkeys +); + +static WindowDesc _ship_depot_desc( + WDP_AUTO, "depot_ship", 306, 99, + WC_VEHICLE_DEPOT, WC_NONE, + 0, + _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets), + &DepotWindow::hotkeys +); + +static WindowDesc _aircraft_depot_desc( + WDP_AUTO, "depot_aircraft", 332, 99, + WC_VEHICLE_DEPOT, WC_NONE, + 0, + _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets), + &DepotWindow::hotkeys +); + /** * Opens a depot window * @param tile The tile where the depot/hangar is located diff --git a/src/economy.cpp b/src/economy.cpp index ea9d610226..c4d1f3ed9e 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -53,6 +53,7 @@ #include "table/strings.h" #include "table/pricebase.h" +#include "cargo_table_gui.h" #include "safeguards.h" @@ -386,6 +387,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) /* Reset the ratings for the old owner */ t->ratings[old_owner] = RATING_INITIAL; ClrBit(t->have_ratings, old_owner); + ClrBit(t->fund_regularly, old_owner); /* Transfer exclusive rights */ if (t->exclusive_counter > 0 && t->exclusivity == old_owner) { @@ -1081,6 +1083,14 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti const CargoSpec *cs = CargoSpec::Get(cargo_type); st->town->received[cs->town_effect].new_act += accepted; + /* Increase town's counter for all goods types only if delivered near town*/ + if(CB_Enabled()){ + if (_settings_client.gui.cb_distance_check == 0 || (DistanceManhattan(st->town->xy, st->xy) <= _settings_client.gui.cb_distance_check)) { + st->town->new_act_cargo[cargo_type] += accepted; + InvalidateWindowData(WC_CB_TOWN, st->town->index); + } + } + /* Determine profit */ Money profit = GetTransportedGoodsIncome(accepted, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type); @@ -1097,6 +1107,16 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti } } + company->cargo_income[cargo_type] += profit; + company->cargo_units[cargo_type] += num_pieces; + + company->cargo_income_period[0][cargo_type] += profit; + company->cargo_units_period[0][cargo_type] += num_pieces; + + company->cur_economy.cargo_income[cargo_type] += profit; + + InvalidateCargosWindows(company->index); + return profit; } @@ -1923,6 +1943,11 @@ void CompaniesMonthlyLoop() } CompaniesPayInterest(); HandleEconomyFluctuations(); + + Company *c; + FOR_ALL_COMPANIES(c){ + CargoResetPeriods(c); + } } static void DoAcquireCompany(Company *c) diff --git a/src/gfx.cpp b/src/gfx.cpp index a8079d839d..4491e60705 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -33,6 +33,7 @@ bool _fullscreen; byte _support8bpp; CursorVars _cursor; bool _ctrl_pressed; ///< Is Ctrl pressed? +bool _alt_pressed; ///< Is Alt pressed? bool _shift_pressed; ///< Is Shift pressed? byte _fast_forward; bool _left_button_down; ///< Is left mouse button pressed? diff --git a/src/gfx_func.h b/src/gfx_func.h index 155da59924..13f469c02c 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -55,6 +55,7 @@ extern bool _fullscreen; extern byte _support8bpp; extern CursorVars _cursor; extern bool _ctrl_pressed; ///< Is Ctrl pressed? +extern bool _alt_pressed; ///< Is Alt pressed? extern bool _shift_pressed; ///< Is Shift pressed? extern byte _fast_forward; diff --git a/src/gfx_type.h b/src/gfx_type.h index b209d6e2db..c5ffa80f3b 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -104,6 +104,16 @@ enum WindowKeyCodes { WKC_COMMA = 151, ///< , Comma WKC_PERIOD = 152, ///< . Period WKC_MINUS = 153, ///< - Minus + + WKC_L_BRACE = 154, ///< { Left brace + WKC_R_BRACE = 155, ///< } Right brace + + WKC_L_PAREN = 157, ///< ( Left parentheses + WKC_R_PAREN = 158, ///< ) Right parentheses + WKC_PLUS = 159, ///< + Plus + WKC_EXCLAIM = 160, ///< ! Exclamation mark + WKC_ASTERISK = 161, ///< * Asterisk + WKC_DOLLAR = 162, ///< $ Dollar sign }; /** A single sprite of a list of animated cursors */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index e50327c5e4..88d4b03f6d 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -192,6 +192,7 @@ static void LoadSpriteTables() i++ ); } + LoadGrfFile("innerhighlight.grf", SPR_INNER_HIGHLIGHT_BASE, i++); /* Initialize the unicode to sprite mapping table */ InitializeUnicodeGlyphMap(); diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp index 5ec929e72d..3bd408f48a 100644 --- a/src/goal_gui.cpp +++ b/src/goal_gui.cpp @@ -184,7 +184,15 @@ struct GoalListWindow : public Window { resize->height = d.height; - d.height *= 5; + uint num = 0; + const Goal *s; + FOR_ALL_GOALS(s) { + if (s->company == INVALID_COMPANY || s->company == this->window_number) { + num++; + } + } + + d.height *= (5 + num); d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index c8b2298e16..e9e0f7549f 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -103,6 +103,23 @@ struct GraphLegendWindow : Window { } }; + +/** Construct the row containing the digit keys. */ +static NWidgetBase *MakeCargoButtons(int *biggest_index) +{ + NWidgetVertical *ver = new NWidgetVertical; + + for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { + NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, WID_CPR_CARGO_FIRST + i, NULL); + leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO; + leaf->SetFill(1, 0); + leaf->SetLowered(true); + ver->Add(leaf); + } + *biggest_index = WID_CPR_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1; + return ver; +} + /** * Construct a vertical list of buttons, one for each company. * @param biggest_index Storage for collecting the biggest index used in the returned tree. @@ -533,10 +550,64 @@ public: return INVALID_DATAPOINT; } + void UpdateExcludedData() + { + this->excluded_data = 0; + + int i = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (HasBit(_legend_excluded_cargo, cs->Index())) SetBit(this->excluded_data, i); + i++; + } + } + + void UpdateLoweredWidgets() + { + for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { + this->SetWidgetLoweredState(WID_CPR_CARGO_FIRST + i, !HasBit(this->excluded_data, i)); + } + } + virtual void OnClick(Point pt, int widget, int click_count) { + switch (widget) { /* Clicked on legend? */ - if (widget == WID_CV_KEY_BUTTON) ShowGraphLegend(); + case WID_CV_KEY_BUTTON: + ShowGraphLegend(); + break; + case WID_CPR_ENABLE_CARGOES: + /* Remove all cargoes from the excluded lists. */ + _legend_excluded_cargo = 0; + this->excluded_data = 0; + this->UpdateLoweredWidgets(); + this->SetDirty(); + break; + + case WID_CPR_DISABLE_CARGOES: { + /* Add all cargoes to the excluded lists. */ + int i = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + SetBit(_legend_excluded_cargo, cs->Index()); + SetBit(this->excluded_data, i); + i++; + } + this->UpdateLoweredWidgets(); + this->SetDirty(); + break; + } + + default: + if (widget >= WID_CPR_CARGO_FIRST) { + int i = widget - WID_CPR_CARGO_FIRST; + ToggleBit(_legend_excluded_cargo, _sorted_cargo_specs[i]->Index()); + this->ToggleWidgetLoweredState(widget); + this->UpdateExcludedData(); + this->SetDirty(); + } + break; + } } virtual void OnTick() @@ -674,8 +745,60 @@ struct IncomeGraphWindow : BaseGraphWindow { virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { + if(_legend_excluded_cargo == 0){ return c->old_economy[j].income; } + uint total_income = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(_legend_excluded_cargo, cs->Index())){ + total_income += c->old_economy[j].cargo_income[cs->Index()]; + } + } + return total_income; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget < WID_CPR_CARGO_FIRST) { + BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize); + return; + } + + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; + SetDParam(0, cs->name); + Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO); + d.width += 14; // colour field + d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(d, *size); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget < WID_CPR_CARGO_FIRST) { + BaseGraphWindow::DrawWidget(r, widget); + return; + } + + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; + bool rtl = _current_text_dir == TD_RTL; + + /* Since the buttons have no text, no images, + * both the text and the coloured box have to be manually painted. + * clk_dif will move one pixel down and one pixel to the right + * when the button is clicked */ + byte clk_dif = this->IsWidgetLowered(widget) ? 1 : 0; + int x = r.left + WD_FRAMERECT_LEFT; + int y = r.top; + + int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT); + + GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK); + GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour); + SetDParam(0, cs->name); + DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); + } }; static const NWidgetPart _nested_income_graph_widgets[] = { @@ -690,6 +813,14 @@ static const NWidgetPart _nested_income_graph_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1), + NWidget(NWID_VERTICAL),//add + NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0), SetResize(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidgetFunction(MakeCargoButtons), + NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), SetResize(0, 1), + EndContainer(),//add NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), @@ -723,8 +854,60 @@ struct DeliveredCargoGraphWindow : BaseGraphWindow { virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { + if(_legend_excluded_cargo == 0){ return c->old_economy[j].delivered_cargo.GetSum(); } + uint total_delivered = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(_legend_excluded_cargo, cs->Index())){ + total_delivered += c->old_economy[j].delivered_cargo[cs->Index()]; + } + } + return total_delivered; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget < WID_CPR_CARGO_FIRST) { + BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize); + return; + } + + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; + SetDParam(0, cs->name); + Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO); + d.width += 14; // colour field + d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(d, *size); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget < WID_CPR_CARGO_FIRST) { + BaseGraphWindow::DrawWidget(r, widget); + return; + } + + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; + bool rtl = _current_text_dir == TD_RTL; + + /* Since the buttons have no text, no images, + * both the text and the coloured box have to be manually painted. + * clk_dif will move one pixel down and one pixel to the right + * when the button is clicked */ + byte clk_dif = this->IsWidgetLowered(widget) ? 1 : 0; + int x = r.left + WD_FRAMERECT_LEFT; + int y = r.top; + + int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT); + + GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK); + GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour); + SetDParam(0, cs->name); + DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); + } }; static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = { @@ -739,6 +922,15 @@ static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1), + NWidget(NWID_VERTICAL),//add + NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0), SetResize(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidgetFunction(MakeCargoButtons), + NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), SetResize(0, 1), + EndContainer(),//add + NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), @@ -899,7 +1091,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { } this->first_init = false; } - +/* void UpdateExcludedData() { this->excluded_data = 0; @@ -918,7 +1110,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { this->SetWidgetLoweredState(WID_CPR_CARGO_FIRST + i, !HasBit(this->excluded_data, i)); } } - +*/ virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget < WID_CPR_CARGO_FIRST) { @@ -960,12 +1152,12 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { SetDParam(0, cs->name); DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); } - +/* virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_CPR_ENABLE_CARGOES: - /* Remove all cargoes from the excluded lists. */ + /* Remove all cargoes from the excluded lists. * / _legend_excluded_cargo = 0; this->excluded_data = 0; this->UpdateLoweredWidgets(); @@ -973,7 +1165,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { break; case WID_CPR_DISABLE_CARGOES: { - /* Add all cargoes to the excluded lists. */ + /* Add all cargoes to the excluded lists. * / int i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { @@ -997,7 +1189,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { break; } } - +*/ virtual void OnTick() { /* Override default OnTick */ @@ -1031,23 +1223,6 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { } }; -/** Construct the row containing the digit keys. */ -static NWidgetBase *MakeCargoButtons(int *biggest_index) -{ - NWidgetVertical *ver = new NWidgetVertical; - - for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { - NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, WID_CPR_CARGO_FIRST + i, NULL); - leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO; - leaf->SetFill(1, 0); - leaf->SetLowered(true); - ver->Add(leaf); - } - *biggest_index = WID_CPR_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1; - return ver; -} - - static const NWidgetPart _nested_cargo_payment_rates_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), @@ -1582,3 +1757,4 @@ void ShowPerformanceRatingDetail() { AllocateWindowDescFront(&_performance_rating_detail_desc, 0); } + diff --git a/src/gui.h b/src/gui.h index 61f2e01307..fc0381c9b7 100644 --- a/src/gui.h +++ b/src/gui.h @@ -39,6 +39,10 @@ Window *ShowBuildDocksScenToolbar(); /* airport_gui.cpp */ Window *ShowBuildAirToolbar(); +/* commands_gui.cpp */ +void ShowCommandsToolbar(); +void ShowLoginWindow(); + /* tgp_gui.cpp */ void ShowGenerateLandscape(); void ShowHeightmapLoad(); diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 8933acb840..e21059ad1a 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -61,6 +61,22 @@ static const KeycodeNames _keycode_to_name[] = { {"NUM_MINUS", WKC_NUM_MINUS}, {"=", WKC_EQUALS}, {"-", WKC_MINUS}, + + {"BACKSPACE", WKC_BACKSPACE}, + {"SLASH", WKC_SLASH}, + {"SEMICOLON", WKC_SEMICOLON}, + {"L_BRACKET", WKC_L_BRACKET}, + {"BACKSLASH", WKC_BACKSLASH}, + {"R_BRACKET", WKC_R_BRACKET}, + {"SINGLEQUOTE", WKC_SINGLEQUOTE}, + {"PERIOD", WKC_PERIOD}, + + {"L_BRACE", WKC_L_BRACE}, + {"R_BRACE", WKC_R_BRACE}, + {"L_PAREN", WKC_L_PAREN}, + {"R_PAREN", WKC_R_PAREN}, + {"EXCLAIM", WKC_EXCLAIM}, + {"ASTERISK", WKC_ASTERISK}, }; /** diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index e287fbd98d..6b83715672 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -30,6 +30,7 @@ #include "tilehighlight_func.h" #include "string_func.h" #include "sortlist_type.h" +#include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "company_base.h" #include "core/geometry_func.hpp" @@ -41,6 +42,7 @@ #include "widgets/industry_widget.h" #include "table/strings.h" +#include "hotkeys.h" #include "safeguards.h" @@ -188,14 +190,6 @@ static const NWidgetPart _nested_build_industry_widgets[] = { EndContainer(), }; -/** Window definition of the dynamic place industries gui */ -static WindowDesc _build_industry_desc( - WDP_AUTO, "build_industry", 170, 212, - WC_BUILD_INDUSTRY, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets) -); - /** Build (fund or prospect) a new industry, */ class BuildIndustryWindow : public Window { int selected_index; ///< index of the element in the matrix @@ -267,7 +261,7 @@ class BuildIndustryWindow : public Window { } public: - BuildIndustryWindow() : Window(&_build_industry_desc) + BuildIndustryWindow(WindowDesc *desc) : Window(desc) { this->timer_enabled = _loaded_newgrf_features.has_newindustries; @@ -625,13 +619,38 @@ public: if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; this->SetButtons(); } + + virtual EventState OnHotkey(int hotkey) + { + return Window::OnHotkey(hotkey); + } + + static HotkeyList hotkeys; }; +static Hotkey build_industry_hotkeys[] = { + Hotkey((uint16)0, "display_chain", WID_DPI_DISPLAY_WIDGET), + Hotkey((uint16)0, "build_button", WID_DPI_FUND_WIDGET), + HOTKEY_LIST_END +}; + +HotkeyList BuildIndustryWindow::hotkeys("industry_fund_gui", build_industry_hotkeys); + +/** Window definition of the dynamic place industries gui */ +static WindowDesc _build_industry_desc( + WDP_AUTO, "build_industry", 170, 212, + WC_BUILD_INDUSTRY, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets), + &BuildIndustryWindow::hotkeys +); + + void ShowBuildIndustryWindow() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; - new BuildIndustryWindow(); + new BuildIndustryWindow(&_build_industry_desc); } static void UpdateIndustryProduction(Industry *i); @@ -1059,6 +1078,7 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_FILTER), SetDataTip(STR_BUTTON_FILTER, STR_TOOLTIP_FILTER_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), @@ -1086,6 +1106,10 @@ protected: static const StringID sorter_names[]; static GUIIndustryList::SortFunction * const sorter_funcs[]; + /* type_filter[industry_type] is set to true if player wishes that type to by displayed */ + static bool type_filter[NUM_INDUSTRYTYPES]; + static bool initialized; + GUIIndustryList industries; Scrollbar *vscroll; @@ -1097,7 +1121,9 @@ protected: const Industry *i; FOR_ALL_INDUSTRIES(i) { - *this->industries.Append() = i; + if (this->type_filter[i->type]){ + *this->industries.Append() = i; + } } this->industries.Compact(); @@ -1229,9 +1255,17 @@ protected: } } + void initIndustryTypeFilter() + { + for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) + this->type_filter[indt] = true; + IndustryDirectoryWindow::initialized = true; + } + public: IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { + if (IndustryDirectoryWindow::initialized == false) this->initIndustryTypeFilter(); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); @@ -1300,6 +1334,11 @@ public: break; } + case WID_ID_DROPDOWN_FILTER: { + size->width = 65; + break; + } + case WID_ID_INDUSTRY_LIST: { Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); for (uint i = 0; i < this->industries.Length(); i++) { @@ -1328,6 +1367,22 @@ public: ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0); break; + case WID_ID_DROPDOWN_FILTER: { + DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_ALL, -2, false); + *list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_NONE, -1, false); + *list->Append() = new DropDownListItem(-3, false); + + for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) { + const IndustrySpec *inds = GetIndustrySpec(indt); + if (inds->enabled) + *list->Append() = new DropDownListCheckedItem(inds->name, indt, false, IndustryDirectoryWindow::type_filter[indt]); + } + + ShowDropDownList(this, list, -2, WID_ID_DROPDOWN_FILTER, 0, true, false); + break; + } + case WID_ID_INDUSTRY_LIST: { uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP); if (p < this->industries.Length()) { @@ -1344,10 +1399,27 @@ public: virtual void OnDropdownSelect(int widget, int index) { - if (this->industries.SortType() != index) { - this->industries.SetSortType(index); - this->BuildSortIndustriesList(); + if (widget == WID_ID_DROPDOWN_CRITERIA) { + if (this->industries.SortType() != index) { + this->industries.SetSortType(index); + } } + else if (widget == WID_ID_DROPDOWN_FILTER) { + if ( index == -1 ) { // aka SELECT NONE + for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) + IndustryDirectoryWindow::type_filter[indt] = false; + // must SetDurty to force redraw of the listing widget + this->SetDirty(); + } + else if ( index == -2 ) { // aka SELECT ALL + for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) + IndustryDirectoryWindow::type_filter[indt] = true; + } + else + IndustryDirectoryWindow::type_filter[index] = IndustryDirectoryWindow::type_filter[index] ? false: true; + this->industries.ForceRebuild(); + } + this->BuildSortIndustriesList(); } virtual void OnResize() @@ -1385,6 +1457,8 @@ public: Listing IndustryDirectoryWindow::last_sorting = {false, 0}; const Industry *IndustryDirectoryWindow::last_industry = NULL; +bool IndustryDirectoryWindow::initialized = false; +bool IndustryDirectoryWindow::type_filter[NUM_INDUSTRYTYPES]; /* Available station sorting functions. */ GUIIndustryList::SortFunction * const IndustryDirectoryWindow::sorter_funcs[] = { diff --git a/src/lang/english.txt b/src/lang/english.txt index db4f8844b8..b4727e9781 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -232,6 +232,9 @@ STR_TOOLTIP_GROUP_ORDER :{BLACK}Select g STR_TOOLTIP_SORT_ORDER :{BLACK}Select sorting order (descending/ascending) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Select sorting criteria STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select filtering criteria +STR_BUTTON_FILTER :{BLACK}Filter +STR_BUTTON_FILTER_SELECT_ALL :Select All +STR_BUTTON_FILTER_SELECT_NONE :Select None STR_BUTTON_SORT_BY :{BLACK}Sort by STR_BUTTON_LOCATION :{BLACK}Location STR_BUTTON_RENAME :{BLACK}Rename @@ -322,9 +325,11 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Display STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Display subsidies STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Display list of company's stations STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Display company finances information +STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_CARGOS :{BLACK}Display company cargos information STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Display general company information STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Display story book STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Display goal list +STR_TOOLBAR_TOOLTIP_DISPLAY_WATCH :{BLACK}Watch company's actions STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Display graphs STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Display company league table STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Fund construction of new industry or list all industries @@ -376,6 +381,7 @@ STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Settings STR_SETTINGS_MENU_SCRIPT_SETTINGS :AI/Game script settings STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF settings STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency options +STR_SETTINGS_MENU_ZONING :Zoning STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Town names displayed STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Station names displayed STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Waypoint names displayed @@ -400,6 +406,7 @@ STR_MAP_MENU_MAP_OF_WORLD :Map of world STR_MAP_MENU_EXTRA_VIEW_PORT :Extra viewport STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend STR_MAP_MENU_SIGN_LIST :Sign list +STR_MAP_MENU_WATCH_COMPANY :Watch Company ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Town directory @@ -468,7 +475,7 @@ STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information -STR_ABOUT_MENU_SEPARATOR : +STR_ABOUT_MENU_SEPARATOR :Novapolis STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug STR_ABOUT_MENU_SCREENSHOT :Screenshot @@ -479,6 +486,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks +STR_ABOUT_MENU_LOGIN_WINDOW :Login Window ############ range ends here ############ range for ordinal numbers used for the place in the highscore window @@ -1707,6 +1715,26 @@ STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value +STR_CONFIG_SETTING_VEHICLES_CTRL :{ORANGE}Controls & Orders +STR_CONFIG_SETTING_ORDER_SHORTCUTS :{ORANGE}Order's Shortcuts +STR_CONFIG_SETTING_CTRL_ENABLE_CTRLCLICK_STARTSTOP :Allow ctrl+left-click vehicles to start or stop them: {STRING2} +STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_TRANSFER :"Transfer" orders are "No Loading" by default: {STRING2} +STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_UNLOAD :"Unload all" orders are "No Loading" by default: {STRING2} + +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLLCLICK :ctrl+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLSHIFTLCLICK :ctrl+shift+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_SHIFTLCLICK :shift+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTLCLICK :alt+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTSHIFTCLICK :alt+shift+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLALTLCLICK :ctrl+alt+left-click: {STRING2} +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE :do nothing +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FULL_LOAD_ANY :Full load any cargo +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_TRANSFER_CARGO :Transfer cargo +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_UNLOAD_ALL :Force unload of all cargo +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FEEDERLOAD :Feeder Load (replace first order) +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FEEDERDROP :Feeder Unload (replace last order) +STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NO_LOAD :Do not load any cargo + # Config errors STR_CONFIG_ERROR :{WHITE}Error with the configuration file... STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}' @@ -2316,6 +2344,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Maglev Construc STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Build railway track using the Autorail mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_POLYRAIL :{BLACK}Build railway track using the Polyline mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Build train depot (for buying and servicing trains). Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Convert rail to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Build railway station. Ctrl enables joining stations. Shift toggles building/showing cost estimate @@ -2333,6 +2362,7 @@ STR_RAIL_NAME_MAGLEV :Maglev # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Train Depot Orientation STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Select railway depot orientation +STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP :{BLACK}Automatically select railway depot orientation based on environment # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Waypoint @@ -2341,6 +2371,8 @@ STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Select w # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Rail Station Selection STR_STATION_BUILD_ORIENTATION :{BLACK}Orientation +STR_STATION_BUILD_ORIENTATION_AUTO :{BLACK}Auto +STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP :{BLACK}Automatically select station orientation based on environment STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Select railway station orientation STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Number of tracks STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Select number of platforms for railway station @@ -2396,6 +2428,7 @@ STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramway STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD :{BLACK}Build road section using the Autoroad mode with only full tile roads. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate @@ -2416,6 +2449,7 @@ STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Dep STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select road vehicle depot orientation STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Tram Depot Orientation STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select tram vehicle depot orientation +STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP :{BLACK}Automatically select road depot orientation based on environment # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Bus Station Orientation @@ -4879,10 +4913,18 @@ STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STR STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING1} # Viewport strings +STR_VIEWPORT_TOWN_POP_VERY_POOR_RATING :{WHITE}{TOWN} {RED}({COMMA}) +STR_VIEWPORT_TOWN_POP_MEDIOCRE_RATING :{WHITE}{TOWN} {ORANGE}({COMMA}) +STR_VIEWPORT_TOWN_POP_GOOD_RATING :{WHITE}{TOWN} {YELLOW}({COMMA}) STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) +STR_VIEWPORT_TOWN_POP_EXCELLENT_RATING :{WHITE}{TOWN} {GREEN}({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} +STR_VIEWPORT_TOWN_TINY_VERY_POOR_RATING :{TINY_FONT}{RED}{TOWN} +STR_VIEWPORT_TOWN_TINY_MEDIOCRE_RATING :{TINY_FONT}{ORANGE}{TOWN} +STR_VIEWPORT_TOWN_TINY_GOOD_RATING :{TINY_FONT}{YELLOW}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} +STR_VIEWPORT_TOWN_TINY_EXCELLENT_RATING :{TINY_FONT}{GREEN}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} @@ -4968,3 +5010,247 @@ STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) + +### PATCH +STR_TOWN_DIRECTORY_CAPTION_EXTRA :{WHITE}Towns ({YELLOW}{COMMA}{WHITE} / {ORANGE}{COMMA}{WHITE}) +STR_LOCAL_AUTHORITY_COMPANY_RATING_NUM :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} {BLACK}({COMMA}) +STR_TOWN_VIEW_GROWTH :{BLACK}GR: {ORANGE}{COMMA} {BLACK}Next: {ORANGE}{COMMA} {BLACK}RH: {ORANGE}{COMMA} {BLACK}Flag {ORANGE}{NUM} {BLACK}FB: {ORANGE}{NUM} {BLACK}month{P "" s} +STR_TOWN_VIEW_GROWTH_TILES :{BLACK}HS: {ORANGE}{COMMA}(+{COMMA}) {BLACK}CS: {ORANGE}{COMMA}(+{COMMA}) {BLACK}HR: {ORANGE}{COMMA}(+{COMMA}) +STR_TOWN_VIEW_REALPOP_RATE :{BLACK}Real Population: {YELLOW}{COMMA} {BLACK}Rating: {YELLOW}{COMMA} +STR_TOWN_VIEW_HOUSE_STATE :{BLACK}Houses: UC {ORANGE}{COMMA} {BLACK}UR: {ORANGE}{COMMA} {BLACK}DTM: {ORANGE}{COMMA} +STR_CB_DISTANCE_CHECK :CB town acceptance: {STRING2} + +###ADMIN +STR_WATCH_WINDOW_TITLE :{WHITE}Watching {RAW_STRING}. +STR_WATCH_CLICK_TO_WATCH_COMPANY :{BLACK}Click here to watch company building +STR_WATCH_CLICK_NEW_WINDOW :{BLACK}Click here to open new watching window + +STR_WATCH_WINDOW_TITLE_CLIENT :{WHITE}{RAW_STRING} in {RAW_STRING}({NUM}). +STR_XI_KICK :{BLACK}Kick +STR_XI_KICKC :{BLACK}Kick from cp +STR_XI_BAN :{BLACK}Ban +STR_XI_BAN1 :{BLACK}Ban (1 day) +STR_XI_LOCK :{BLACK}Lock +STR_XI_UNLOCK :{BLACK}UNLock +STR_XI_JOIN :{BLACK}Join company +STR_XI_RESET :{BLACK}Reset company +STR_XI_RESET2 :{BLACK}Reset +STR_XI_WATCH :Watch +STR_XI_SUSPEND :{BLACK}Suspend +STR_XI_SUSPEND2 :{BLACK}Suspend +STR_XI_RESUME :{BLACK}Resume +STR_XI_RESUME2 :{BLACK}Resume +STR_XI_ENABLE :{BLACK}En/Dis +STR_XI_SIGN_TOOLTIP :{BLACK}Put a sign to attract player +STR_XI_PLAYERS_TOOLTIP :{BLACK}Show clients +STR_XI_COMPANYW_TOOLTIP :{BLACK}Open Company window +STR_XI_COMPANYHQ :{BLACK}HQ +STR_XI_COMPANYHQ_TOOLTIP :{BLACK}Go to company's HQ +STR_XI_PRIVATE_PLAYER_MESSAGE :{BLACK}.{GREEN}P{BLACK}. +STR_XI_PRIVATE_PLAYER_MESSAGE_TOOLTIP :{BLACK}Send a Custom private message to this player +STR_XI_PRIVATE_COMPANY_MESSAGE :{BLACK}.{GREEN}C{BLACK}. +STR_XI_PRIVATE_COMPANY_MESSAGE_TOOLTIP :{BLACK}Send a Custom private message to this company + +STR_XI_BAN_QUERY :{WHITE} +STR_XI_BAN_DAYSDEFAULT :1 +STR_XI_REALY_RESET :{WHITE}Are you sure?. +STR_XI_RESET_CAPTION :{WHITE}Reset + +STR_NETWORK_CLIENT_EXTRA :{WHITE} (#{NUM} in c#{NUM}) + +######## Zoning toolbar + +STR_ZONING_TOOLBAR :{WHITE}Zoning toolbar +STR_ZONING_OUTER :{BLACK}Outer tile borders: +STR_ZONING_INNER :{BLACK}Inner tile borders: +STR_ZONING_OUTER_INFO :{BLACK}Select which type of zoning you want on the outer border of a tile. +STR_ZONING_INNER_INFO :{BLACK}Select which type of zoning you want on the inner border of a tile. + +STR_ZONING_NO_ZONING :{BLACK}Nothing +STR_ZONING_AUTHORITY :{BLACK}Authority +STR_ZONING_CAN_BUILD :{BLACK}Where I can't build +STR_ZONING_STA_CATCH :{BLACK}Station catchment +STR_ZONING_IND_CATCH :{BLACK}Industry catchment +STR_ZONING_BUL_CATCH :{BLACK}City catchment +STR_ZONING_BUL_UNSER :{BLACK}Unserved buildings +STR_ZONING_IND_UNSER :{BLACK}Unserved industries +STR_ZONING_TOWN_ZONES :{BLACK}Town zones +STR_ZONING_CB_TOWN_BORDERS :{BLACK}CB town borders +STR_ZONING_CB_BORDERS :{BLACK}CB borders +STR_ZONING_ADVERTISEMENT_ZONES :{BLACK}Advertisement +STR_ZONING_TOWN_GROWTH_TILES :{BLACK}Town growth tiles + +# Commands toolbar +STR_TOOLBAR_COMMANDS_CAPTION :{WHITE}Commands +STR_TOOLBAR_COMMANDS_GOAL_CAPTION :{BLACK}Goal +STR_TOOLBAR_COMMANDS_GOAL_TOOLTIP :{BLACK}Send !goal command to server. +STR_TOOLBAR_COMMANDS_QUEST_CAPTION :{BLACK}Quest list +STR_TOOLBAR_COMMANDS_QUEST_TOOLTIP :{BLACK}Send !quest command to server. +STR_TOOLBAR_COMMANDS_SCORE_CAPTION :{BLACK}Score +STR_TOOLBAR_COMMANDS_SCORE_TOOLTIP :{BLACK}Send !score command to server. +STR_TOOLBAR_COMMANDS_TOWN_CAPTION :{BLACK}Town +STR_TOOLBAR_COMMANDS_TOWN_TOOLTIP :{BLACK}Send !town command to server. +STR_TOOLBAR_COMMANDS_TOWN_ID_CAPTION :{BLACK}Town ID +STR_TOOLBAR_COMMANDS_TOWN_ID_TOOLTIP :{BLACK}Send !town c-id command to server. +STR_TOOLBAR_COMMANDS_HINT_CAPTION :{BLACK}CB Hint +STR_TOOLBAR_COMMANDS_HINT_TOOLTIP :{BLACK}Send !hint command to server(Shows town demand in CB mode). +STR_TOOLBAR_COMMANDS_LOGIN_CAPTION :{BLACK}Login +STR_TOOLBAR_COMMANDS_LOGIN_TOOLTIP :{BLACK}Send !login command to server. +STR_TOOLBAR_COMMANDS_TIMELEFT_CAPTION :{BLACK}Timeleft +STR_TOOLBAR_COMMANDS_TIMELEFT_TOOLTIP :{BLACK}Send !timeleft command to server. +STR_TOOLBAR_COMMANDS_NS_CAPTION :{BLACK}NS{NUM} +STR_TOOLBAR_COMMANDS_NS_TOOLTIP :{BLACK}Join NS{NUM} +STR_TOOLBAR_COMMANDS_RESETME_CAPTION :{BLACK}ResetMe +STR_TOOLBAR_COMMANDS_RESETME_TOOLTIP :{BLACK}Send !resetme command to server. +STR_TOOLBAR_COMMANDS_SAVEME_CAPTION :{BLACK}SaveMe +STR_TOOLBAR_COMMANDS_SAVEME_TOOLTIP :{BLACK}Send !saveme command to server. +STR_TOOLBAR_COMMANDS_NAME_CAPTION :{BLACK}New name +STR_TOOLBAR_COMMANDS_NAME_TOOLTIP :{BLACK}Send !name command to server. +STR_TOOLBAR_COMMANDS_INFO_CAPTION :{BLACK}Info +STR_TOOLBAR_COMMANDS_INFO_TOOLTIP :{BLACK}Send !info command to server. + +STR_TOOLBAR_COMMANDS_OPTION_CARGO_CAPTION :{BLACK}Both +STR_TOOLBAR_COMMANDS_OPTION_CARGO_TOOLTIP :{BLACK}Switch cargo buttons to both amount and income +STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_CAPTION :{BLACK}Income +STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_CAPTION :{BLACK}Amount +STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_TOOLTIP :{BLACK}Switch cargo buttons to amount +STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_TOOLTIP :{BLACK}Switch cargo buttons to income + + +STR_TOOLBAR_COMMANDS_TOWN_QUERY :{WHITE}Company ID: +STR_TOOLBAR_COMMANDS_LOGIN_NAME_QUERY :{WHITE} +STR_TOOLBAR_COMMANDS_LOGIN_PASSWORD_QUERY :{WHITE}Password: +STR_TOOLBAR_COMMANDS_NAME_NEWNAME_QUERY :{WHITE}New name: + +STR_TOOLBAR_COMMANDS_TOPICS_CAPTION :{BLACK}Topics +STR_TOOLBAR_COMMANDS_TOPICS_TOOLTIP :{BLACK}Display help topics +STR_TOOLBAR_COMMANDS_TOPIC1_CAPTION :{BLACK}HELP Login +STR_TOOLBAR_COMMANDS_TOPIC1_TOOLTIP :{BLACK}How to use login +STR_TOOLBAR_COMMANDS_TOPIC2_CAPTION :{BLACK}HELP Coal Accept +STR_TOOLBAR_COMMANDS_TOPIC2_TOOLTIP :{BLACK}What to do when town does not accept Coal +STR_TOOLBAR_COMMANDS_TOPIC3_CAPTION :{BLACK}HELP Food accept +STR_TOOLBAR_COMMANDS_TOPIC3_TOOLTIP :{BLACK}What to do when town does not accept Food +STR_TOOLBAR_COMMANDS_TOPIC4_CAPTION :{BLACK}HELP energy +STR_TOOLBAR_COMMANDS_TOPIC4_TOOLTIP :{BLACK}What are tourists, business mail or energy? +STR_TOOLBAR_COMMANDS_TOPIC5_CAPTION :{BLACK}HELP admin +STR_TOOLBAR_COMMANDS_TOPIC5_TOOLTIP :{BLACK}How to use admin command? +STR_TOOLBAR_COMMANDS_TOPIC6_CAPTION :{BLACK}HELP New Comp. +STR_TOOLBAR_COMMANDS_TOPIC6_TOOLTIP :{BLACK}Why new company can not be starter? + +STR_TOOLBAR_COMMANDS_HELP_CAPTION :{BLACK}Help +STR_TOOLBAR_COMMANDS_HELP_TOOLTIP :{BLACK}Display Help +STR_TOOLBAR_COMMANDS_RULES_CAPTION :{BLACK}RULES +STR_TOOLBAR_COMMANDS_RULES_TOOLTIP :{BLACK}Show Rules +STR_TOOLBAR_COMMANDS_CBHINT_CAPTION :{BLACK}CB Hint +STR_TOOLBAR_COMMANDS_CBHINT_TOOLTIP :{BLACK}Display help for City builder +STR_TOOLBAR_COMMANDS_BEST_CAPTION :{BLACK}Best +STR_TOOLBAR_COMMANDS_BEST_TOOLTIP :{BLACK}Show 5 best games +STR_TOOLBAR_COMMANDS_RANK_CAPTION :{BLACK}Rank +STR_TOOLBAR_COMMANDS_RANK_TOOLTIP :{BLACK}Show top 10 players +STR_TOOLBAR_COMMANDS_ME_CAPTION :{BLACK}My Rank +STR_TOOLBAR_COMMANDS_ME_TOOLTIP :{BLACK}Show your ranking position + +#login window +STR_LOGINWINDOW_CAPTION :{WHITE}Login Window +STR_LOGINWINDOW_NOVAPOLIS :{BLACK}Novapolis +STR_LOGINWINDOW_NICE :{BLACK}N-ice +STR_LOGINWINDOW_BTPRO :{BLACK}BTPro +STR_LOGINERROR_NOCONNECT :{WHITE}Failed to connect +STR_LOGINERROR_BADINPUT :{WHITE}Bad username or password +STR_LOGIN_USERNAME :{WHITE}Username +STR_LOGIN_PASSWORD :{WHITE}Password +STR_LOGIN_SET :{WHITE}Set +STR_LOGIN_NOTSET :{WHITE}Not Set +STR_LOGIN_CHANGE_USERNAME :{WHITE}Change username +STR_LOGIN_CHANGE_PASSWORD :{WHITE}Change password +STR_LOGIN_SEND_LOGIN_TT :{WHITE}Send Login - you must but on the correct community server +STR_LOGIN_USERNAME_DISPLAY :{WHITE}{RAW_STRING} +STR_LOGIN_PASSWORD_DISPLAY :{WHITE}{STRING} + +#cargo table +STR_TOOLBAR_CARGOS_HEADER_CARGO :{BLACK}Cargo Name +STR_TOOLBAR_CARGOS_HEADER_AMOUNT :{BLACK}Amount +STR_TOOLBAR_CARGOS_HEADER_INCOME :{BLACK}Income +STR_TOOLBAR_CARGOS_HEADER_TOTAL :{BLACK}Total +STR_TOOLBAR_CARGOS_HEADER_TOTAL_MONTH :{BLACK}Total this Month + +STR_TOOLBAR_CARGOS_UNITS :{BLACK}{COMMA} +STR_TOOLBAR_CARGOS_UNITS_TOTAL :{BLACK}{COMMA} +STR_TOOLBAR_CARGOS_CAPTION :{WHITE}{COMPANY} Cargo Transported {BLACK}{COMPANY_NUM} +STR_TOOLBAR_CARGOS_NAME :{BLACK}{STRING} + +#towns +STR_TOWN_DIRECTORY_TOWN_COLOUR :{ORANGE}{TOWN}{BLACK} ({COMMA}) +STR_TOWN_DIRECTORY_CITY_COLOUR :{YELLOW}{TOWN}{BLACK} ({COMMA}) +STR_OLD_DEPOT_TRAINT_LENGTH :Old depot length format: {STRING2} +STR_SMALLMAP_TOWN_LARGE :{TINY_FONT}{YELLOW}{TOWN} + +STR_ORDER_DIST :{NUM}, {NUM} + +#server list +STR_NETWORK_SELECT_NOVA :{BLACK}Novapolis +STR_NETWORK_SELECT_NICE :{BLACK}N-ice +STR_NETWORK_SELECT_BTPRO :{BLACK}BTPro +STR_NETWORK_SELECT_REDDIT :{BLACK}reddit +STR_NETWORK_SELECT_SERVER_TOOLTIP :{BLACK}Filter this one + +### Town CB gui +STR_BUTTON_CB :{STRING} +STR_BUTTON_CB_YES :{BLACK}CB +STR_TOWN_VIEW_CB_CAPTION :{WHITE}{TOWN} + +STR_CB_LARGE_ADVERTISING_CAMPAIGN :{BLACK}Large Advertising +STR_CB_NEW_BUILDINGS :{BLACK}Fund Buildings +STR_CB_FUND_REGULAR :{BLACK}Fund Regularly +STR_CB_FUND_REGULAR_TT :{BLACK}Every time fund buildings is zero and company has enough money, buildings will be funded automatically +STR_CB_FUNDED_REGULARLY :{GREEN}Town is funded regularly + +STR_TOWN_CB_FUNDING :{ORANGE}Funded for {YELLOW}{COMMA}{ORANGE} month{P "" s} +STR_TOWN_CB_GROWING :{GREEN}Town is growing! +STR_TOWN_CB_NOT_GROWING :{WHITE}Town is not growing +STR_TOWN_CB_GROWING_DETAIL :{ORANGE}1 house in {YELLOW}{COMMA} {ORANGE}days ({YELLOW}{COMMA}%{ORANGE}). Next House in {YELLOW}{COMMA} {ORANGE}days + +STR_TOWN_GROWTH_HEADER_CARGO :{BLACK}Cargo +STR_TOWN_GROWTH_HEADER_AMOUNT :{BLACK}Delivered +STR_TOWN_GROWTH_HEADER_REQ :{BLACK}Required +STR_TOWN_GROWTH_HEADER_LAST :{BLACK}Last Month +STR_TOWN_GROWTH_HEADER_STORE :{BLACK}Stored +STR_TOWN_GROWTH_HEADER_STORE_PCT :{BLACK}Use% +STR_TOWN_GROWTH_HEADER_FROM :{BLACK}From + +STR_TOWN_CB_CARGO_NAME :{BLACK}{STRING}: + +STR_TOWN_CB_CARGO_AMOUNT_GOOD :{GREEN}{COMMA} +STR_TOWN_CB_CARGO_AMOUNT_BAD :{YELLOW}{COMMA} +STR_TOWN_CB_CARGO_AMOUNT_NOT :{SILVER}{COMMA} + +STR_TOWN_CB_CARGO_REQ_YES :{ORANGE}{COMMA} +STR_TOWN_CB_CARGO_REQ_NOT :{SILVER}{COMMA} + +STR_TOWN_CB_CARGO_STORE_YES :{LTBLUE}{COMMA} +STR_TOWN_CB_CARGO_STORE_NOT :{SILVER}{COMMA} +STR_TOWN_CB_CARGO_STORE_DECAY :{BLACK}- + +STR_TOWN_CB_CARGO_STORE_PCT_YES :{LTBLUE}{COMMA}% +STR_TOWN_CB_CARGO_STORE_PCT_NOT :{SILVER}{COMMA}% + +STR_TOWN_CB_CARGO_PREVIOUS_YES :{GREEN}{COMMA} +STR_TOWN_CB_CARGO_PREVIOUS_EDGE :{YELLOW}{COMMA} +STR_TOWN_CB_CARGO_PREVIOUS_BAD :{RED}{COMMA} +STR_TOWN_CB_CARGO_PREVIOUS_NOT :{SILVER}{COMMA} + +STR_TOWN_CB_CARGO_FROM_YES :{YELLOW}{COMMA} +STR_TOWN_CB_CARGO_FROM_NOT :{SILVER}{COMMA} + +#polyrail double click option +STR_CONFIG_SETTING_POLYRAIL_DOUBLECLICK_TOOLTIPS :Enable finishing polyrail with mouse double click{STRING2} + +#tooltips extra +STR_CONFIG_SETTING_ENABLE_EXTRA_TOOLTIPS :Enable extra tooltips{STRING2} +STR_TTE_HOUSE_NAME :{LTBLUE}{STRING} +STR_TTE_HOUSE :{BLACK}Population: {NUM} +STR_TTE_INDUSTRY_NAME :{LTBLUE}{INDUSTRY} +STR_TTE_INDUSTRY :{WHITE}{STRING} {BLACK}{CARGO_SHORT} {YELLOW}{NUM} % +STR_TTE_STATION_NAME :{LTBLUE}{STATION} +STR_TTE_STATION :{WHITE}{STRING} {BLACK}{CARGO_SHORT} {YELLOW}{NUM} % +STR_LAND_AREA_INFORMATION_POP :{BLACK}Population: {LTBLUE}{NUM} diff --git a/src/main_gui.cpp b/src/main_gui.cpp index fe26335e94..ce8acfc338 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -107,7 +107,7 @@ bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyl if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); w->SetDirty(); - if (w->IsWidgetLowered(widget)) { + if (w->IsWidgetLowered(widget) && mode == _thd.place_mode) { ResetObjectToPlace(); return false; } @@ -227,6 +227,7 @@ enum { GHK_TOGGLE_INVISIBILITY = GHK_TOGGLE_TRANSPARENCY + 9, GHK_TRANSPARENCY_TOOLBAR = GHK_TOGGLE_INVISIBILITY + 8, GHK_TRANSPARANCY, + GHK_BORROW_ALL, GHK_CHAT, GHK_CHAT_ALL, GHK_CHAT_COMPANY, @@ -393,6 +394,10 @@ struct MainWindow : Window ResetRestoreAllTransparency(); break; + case GHK_BORROW_ALL: + DoCommandP(0, 0, 1, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY)); + break; + #ifdef ENABLE_NETWORK case GHK_CHAT: // smart chat; send to team if any, otherwise to all if (_networking) { @@ -465,6 +470,11 @@ struct MainWindow : Window InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true); } + virtual void OnMouseOver(Point pt, int widget) + { + if (_game_mode != GM_MENU && _settings_client.gui.enable_extra_tooltips && pt.x != -1) GuiPrepareTooltipsExtra(this); + } + static HotkeyList hotkeys; }; @@ -511,6 +521,7 @@ static Hotkey global_hotkeys[] = { Hotkey('8' | WKC_CTRL | WKC_SHIFT, "invisibility_catenary", GHK_TOGGLE_INVISIBILITY + 7), Hotkey('X' | WKC_CTRL, "transparency_toolbar", GHK_TRANSPARENCY_TOOLBAR), Hotkey('X', "toggle_transparency", GHK_TRANSPARANCY), + Hotkey(WKC_NONE, "borrow_all", GHK_BORROW_ALL), #ifdef ENABLE_NETWORK Hotkey(_ghk_chat_keys, "chat", GHK_CHAT), Hotkey(_ghk_chat_all_keys, "chat_all", GHK_CHAT_ALL), diff --git a/src/misc.cpp b/src/misc.cpp index f32cd7ad5e..871bf581c4 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -110,6 +110,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InitializeEconomy(); ResetObjectToPlace(); + ClearRailPlacementEndpoints(); GamelogReset(); GamelogStartAction(GLAT_START); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 1d596ae3fe..e40d6a22f3 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -33,6 +33,14 @@ #include "safeguards.h" +#include "house.h" +#include "town_map.h" +#include "station_base.h" +#include "viewport_func.h" +#include "industry.h" + +void GuiShowTooltipsExtra(Window *parent, uint param, TooltipCloseCondition close_tooltip); + /** Method to open the OSK. */ enum OskActivation { OSKA_DISABLED, ///< The OSK shall not be activated at all. @@ -164,6 +172,7 @@ public: td.airport_tile_name = STR_NULL; td.rail_speed = 0; td.road_speed = 0; + td.population = 0; td.grf = NULL; @@ -293,6 +302,13 @@ public: 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 */ @@ -1208,3 +1224,229 @@ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallback new QueryWindow(&_query_desc, caption, message, parent, callback); } + +/** Window for displaying a tooltip. */ +void GuiPrepareTooltipsExtra(Window *parent){ + const Point p = GetTileBelowCursor(); + const TileIndex tile = TileVirtXY(p.x, p.y); + + if (tile >= MapSize()) return; + uint param = 0; + switch (GetTileType(tile)) { + /*case MP_HOUSE: { + const HouseID house = GetHouseType(tile); + param = ((house & 0xFFFF) << 16) | MP_HOUSE; + break; + }*/ + case MP_INDUSTRY: { + const Industry *ind = Industry::GetByTile(tile); + if(ind->produced_cargo[0] == CT_INVALID && ind->produced_cargo[1] == CT_INVALID) return; + param = ((ind->index & 0xFFFF) << 16) | MP_INDUSTRY; + break; + } + case MP_STATION: { + if (IsRailWaypoint(tile) || HasTileWaterGround(tile)) break; + const Station *st = Station::GetByTile(tile); + param |= ((st->index & 0xFFFF) << 16) | MP_STATION; + break; + } + default: + return; + } + if(param != 0) GuiShowTooltipsExtra(parent, param, TCC_HOVER); +} + +static const NWidgetPart _nested_tooltips_extra_widgets[] = { + NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(64, 32), EndContainer(), +}; + +static WindowDesc _tool_tips_extra_desc( + WDP_MANUAL, NULL, 0, 0, + WC_TOOLTIPS_EXTRA, WC_NONE, + 0, + _nested_tooltips_extra_widgets, lengthof(_nested_tooltips_extra_widgets) +); + +struct TooltipsExtraWindow : public Window +{ + TileType tiletype; + uint16 objIndex; + TooltipCloseCondition close_cond; + + TooltipsExtraWindow(Window *parent, uint param, TooltipCloseCondition close_tooltip) : Window(&_tool_tips_extra_desc) + { + this->parent = parent; + this->tiletype = (TileType)(param & 0xFFFF); + this->objIndex = (uint16)((param >> 16) & 0xFFFF); + this->close_cond = close_tooltip; + this->InitNested(); + CLRBITS(this->flags, WF_WHITE_BORDER); + } + + 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.size.y + _cursor.offs.y + 5, scr_top, scr_bot); + if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.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; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + static const uint LINE_HEIGHT = FONT_HEIGHT_NORMAL + 2; + size->width = 200; + size->height = LINE_HEIGHT + 4; + switch(this->tiletype) { + /*case MP_HOUSE: { + size->height += LINE_HEIGHT; + SetDParam(0, 1000); + size->width = GetStringBoundingBox(STR_TTE_HOUSE).width; + break; + }*/ + case MP_INDUSTRY: { + const Industry *ind = Industry::GetIfValid((IndustryID)this->objIndex); + if(ind == NULL) break; + + for (CargoID i = 0; i < lengthof(ind->produced_cargo); i++) { + if (ind->produced_cargo[i] == CT_INVALID) continue; + const CargoSpec *cs = CargoSpec::Get(ind->produced_cargo[i]); + if(cs == NULL) continue; + size->height += LINE_HEIGHT; + SetDParam(0, cs->name); + SetDParam(1, cs->Index()); + SetDParam(2, ind->last_month_production[i]); + SetDParam(3, ToPercent8(ind->last_month_pct_transported[i])); + size->width = max(GetStringBoundingBox(STR_TTE_INDUSTRY).width + 50, size->width); + } + break; + } + case MP_STATION: { + const Station *st = Station::GetIfValid((StationID)this->objIndex); + if(st == NULL) break; + + for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { + const CargoSpec *cs = _sorted_cargo_specs[i]; + if(cs == NULL) continue; + int cargoid = cs->Index(); + if (HasBit(st->goods[cargoid].status, GoodsEntry::GES_RATING)) { + size->height += LINE_HEIGHT; + SetDParam(0, cs->name); + SetDParam(1, cargoid); + SetDParam(2, st->goods[cargoid].cargo.TotalCount()); + SetDParam(3, ToPercent8(st->goods[cargoid].rating)); + size->width = max(GetStringBoundingBox(STR_TTE_STATION).width + 50, size->width); + } + } + break; + } + } + size->width += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + static const uint LINE_HEIGHT = FONT_HEIGHT_NORMAL + 2; + 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); + + int y = r.top + WD_FRAMERECT_TOP + 4; + int left = r.left + WD_FRAMERECT_LEFT + 4; + + switch(this->tiletype) { + /*case MP_HOUSE: { + const HouseID house = (HouseID)this->objIndex; + const HouseSpec *hs = HouseSpec::Get(house); + if(hs == NULL) break; + + SetDParam(0, hs->building_name); + DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_HOUSE_NAME, TC_BLACK, SA_CENTER); + y += LINE_HEIGHT; + SetDParam(0, hs->population); + DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_HOUSE); + break; + }*/ + case MP_INDUSTRY: { + const Industry *ind = Industry::GetIfValid((IndustryID)this->objIndex); + if(ind == NULL) break; + + SetDParam(0, ind->index); + DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_INDUSTRY_NAME, TC_BLACK, SA_CENTER); + y += LINE_HEIGHT; + + for (CargoID i = 0; i < lengthof(ind->produced_cargo); i++) { + if (ind->produced_cargo[i] == CT_INVALID) continue; + const CargoSpec *cs = CargoSpec::Get(ind->produced_cargo[i]); + if(cs == NULL) continue; + SetDParam(0, cs->name); + SetDParam(1, cs->Index()); + SetDParam(2, ind->last_month_production[i]); + SetDParam(3, ToPercent8(ind->last_month_pct_transported[i])); + + this->DrawSpriteIcons(cs->GetCargoIcon(), left, y); + DrawString(left + 40, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_INDUSTRY); + y += LINE_HEIGHT; + } + break; + } + case MP_STATION: { + uint pars = 0; + const Station *st = Station::GetIfValid((StationID)this->objIndex); + if(st == NULL) break; + + SetDParam(0, st->index); + DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_STATION_NAME, TC_BLACK, SA_CENTER); + y += LINE_HEIGHT; + + for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { + const CargoSpec *cs = _sorted_cargo_specs[i]; + if(cs == NULL) continue; + int cargoid = cs->Index(); + if (HasBit(st->goods[cargoid].status, GoodsEntry::GES_RATING)) { + SetDParam(0, cs->name); + SetDParam(1, cargoid); + SetDParam(2, st->goods[cargoid].cargo.TotalCount()); + SetDParam(3, ToPercent8(st->goods[cargoid].rating)); + + this->DrawSpriteIcons(cs->GetCargoIcon(), left, y); + DrawString(left + 40, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_STATION); + y += LINE_HEIGHT; + } + } + break; + } + } + } + + virtual void OnMouseLoop() + { + if (!_cursor.in_window) { + delete this; + return; + } + + switch (this->close_cond) { + case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break; + case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break; + case TCC_HOVER: if (!_mouse_hovering) delete this; break; + } + } + + void DrawSpriteIcons(SpriteID sprite, int left, int top) const + { + for(int i = 0; i < 30; i += 10) { + DrawSprite(sprite, PAL_NONE, left + i, top); + } + } +}; + +void GuiShowTooltipsExtra(Window *parent, uint param, TooltipCloseCondition close_tooltip) +{ + DeleteWindowById(WC_TOOLTIPS_EXTRA, 0); + new TooltipsExtraWindow(parent, param, close_tooltip); +} diff --git a/src/network/network.cpp b/src/network/network.cpp index 7c0727e205..e21b89a7ec 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -83,7 +83,7 @@ bool _network_udp_server; ///< Is the UDP server started? uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts. uint8 _network_advertise_retries; ///< The number of advertisement retries we did. CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies. - +bool _novarole = false; /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */ assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE); assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); @@ -117,6 +117,7 @@ NetworkClientInfo::~NetworkClientInfo() { /* Delete the chat window, if you were chatting with this client. */ InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id); + InvalidateWindowData(WC_WATCH_COMPANYA, this->client_id, 2); } /** diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index c800760f3b..cb84af241e 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -34,10 +34,13 @@ #include "table/strings.h" -#include "../safeguards.h" +#include "../town.h" +#include "network_func.h" +#include "../safeguards.h" /* This file handles all the client-commands */ +void SyncCBClient(byte * msg); /** Read some packets, and when do use that data as initial load filter. */ struct PacketReader : LoadFilter { @@ -265,6 +268,11 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) if (_network_first_time) { _network_first_time = false; SendAck(); + extern bool novahost(); + if(novahost()){ + NetworkClientSendChatToServer("!check 1444"); //check version + CB_SetCB(false); + } } _sync_frame = 0; @@ -614,6 +622,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); + SetWindowClassesDirty(WC_WATCH_COMPANY); + InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1); + SetWindowClassesDirty(WC_WATCH_COMPANYA); return NETWORK_RECV_STATUS_OKAY; } @@ -633,6 +645,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); + SetWindowClassesDirty(WC_WATCH_COMPANY); + InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1); + SetWindowClassesDirty(WC_WATCH_COMPANYA); return NETWORK_RECV_STATUS_OKAY; } @@ -984,7 +1000,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) } if (ci != NULL) { - NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data); + if (strncmp(msg, "synccbclient", 12) == 0) SyncCBClient(p->buffer); + else NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data); } return NETWORK_RECV_STATUS_OKAY; } @@ -1021,6 +1038,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) } SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 ); + SetWindowClassesDirty( WC_WATCH_COMPANYA ); /* If we come here it means we could not locate the client.. strange :s */ return NETWORK_RECV_STATUS_OKAY; @@ -1107,6 +1126,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) if (client_id == _network_own_client_id) { SetLocalCompany(company_id); } + InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 ); + SetWindowClassesDirty( WC_WATCH_COMPANYA ); return NETWORK_RECV_STATUS_OKAY; } @@ -1253,6 +1274,10 @@ void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const MyClient::SendChat(action, type, dest, msg, data); } +void NetworkClientSendChatToServer(const char * msg) +{ + NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, CLIENT_ID_SERVER, msg); +} /** * Set/Reset company password on the client side. * @param password Password to be set. @@ -1298,4 +1323,49 @@ bool NetworkMaxSpectatorsReached() return NetworkSpectatorCount() >= (_network_server ? _settings_client.network.max_spectators : _network_server_max_spectators); } +void SyncCBClient(byte *msg){ //len = 3 + 6 + 12 + 3 + 6*cargo + size_t pos = 21; + size_t length = pos; + byte tmp; + + while(msg[length] != '\0'){ length++; } + + _novarole = msg[pos++] == 'A'; + if(length == pos) return; + + CB_SetCB(true); + + tmp = msg[pos++]; + _settings_client.gui.cb_distance_check = (tmp == 0xFF) ? 0 : tmp; + tmp = msg[pos++]; + CB_SetStorage((tmp == 0xFF) ? 0 : (uint)tmp); + + for(int i = 0; i < NUM_CARGO; i++){ + CB_SetRequirements(i, 0, 0, 0); + } + + //IConsolePrintF(CC_INFO, "cb check %i, storage %i", _settings_client.gui.cb_distance_check, tmp); + uint8 cargo; + uint req, from, decay; + while(pos < length){ //CargoID NUM_CARGO + cargo = msg[pos++]; + if(cargo == 0xFF) cargo = 0; + + tmp = msg[pos++]; + req = (tmp == 0xFF) ? 0 : tmp; + tmp = msg[pos++]; + req += (tmp == 0xFF) ? 0 : (tmp << 8); + + tmp = msg[pos++]; + from = (tmp == 0xFF) ? 0 : tmp; + tmp = msg[pos++]; + from += (tmp == 0xFF) ? 0 : (tmp << 8); + + tmp = msg[pos++]; + decay = (tmp == 0xFF) ? 0 : tmp; + + CB_SetRequirements(cargo, req, from, decay); + //IConsolePrintF(CC_INFO, "cargo#%i %i/%i/%i", cargo, req, from, decay); + } +} #endif /* ENABLE_NETWORK */ diff --git a/src/network/network_func.h b/src/network/network_func.h index b4db6fc0c2..2069c7bf4b 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -39,7 +39,7 @@ extern uint8 _network_reconnect; extern StringList _network_bind_list; extern StringList _network_host_list; extern StringList _network_ban_list; - +extern bool _novarole; byte NetworkSpectatorCount(); void NetworkUpdateClientName(); bool NetworkCompanyHasClients(CompanyID company); @@ -58,6 +58,7 @@ void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const c void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0); +void NetworkClientSendChatToServer(const char * msg); bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio); bool NetworkCompanyIsPassworded(CompanyID company_id); bool NetworkMaxCompaniesReached(); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 8e90b19a26..f7b3a5d821 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -38,6 +38,7 @@ #include "../table/sprites.h" #include "../stringfilter_type.h" +#include "../watch_gui.h" #include "../safeguards.h" @@ -234,6 +235,7 @@ protected: Scrollbar *vscroll; ///< vertical scrollbar of the list of servers QueryString name_editbox; ///< Client name editbox. QueryString filter_editbox; ///< Editbox for filter on servers + bool UDP_CC_queried; int lock_offset; ///< Left offset for lock icon. int blot_offset; ///< Left offset for green/yellow/red compatibility icon. @@ -474,6 +476,7 @@ public: this->querystrings[WID_NG_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; + this->UDP_CC_queried = false; this->SetFocusedWidget(WID_NG_FILTER); this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); @@ -782,6 +785,23 @@ public: case WID_NG_NEWGRF_MISSING: // Find missing content online if (this->server != NULL) ShowMissingContentWindow(this->server->info.grfconfig); break; + case WID_NG_NICE: + case WID_NG_BTPRO: + case WID_NG_REDDIT: + case WID_NG_NOVA: + if(!UDP_CC_queried){ + NetworkUDPQueryMasterServer(); + UDP_CC_queried = true; + } + if(widget == WID_NG_NICE) this->filter_editbox.text.Assign("n-ice"); + else if(widget == WID_NG_BTPRO) this->filter_editbox.text.Assign("BTPro"); + else if(widget == WID_NG_NOVA) this->filter_editbox.text.Assign("Novapolis"); + else if(widget == WID_NG_REDDIT) this->filter_editbox.text.Assign("reddit"); + this->servers.ForceRebuild(); + this->BuildGUINetworkGameList(); + this->ScrollToSelectedServer(); + this->SetDirty(); + break; } } @@ -909,7 +929,7 @@ public: } }; -Listing NetworkGameWindow::last_sorting = {false, 5}; +Listing NetworkGameWindow::last_sorting = {false, 0}; GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = { &NGameNameSorter, &NGameClientSorter, @@ -946,6 +966,10 @@ static const NWidgetPart _nested_network_game_widgets[] = { NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REDDIT), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_REDDIT, STR_NETWORK_SELECT_SERVER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NICE), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_NICE, STR_NETWORK_SELECT_SERVER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_BTPRO), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_BTPRO, STR_NETWORK_SELECT_SERVER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NOVA), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_NOVA, STR_NETWORK_SELECT_SERVER_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL), @@ -1691,6 +1715,14 @@ static void ClientList_Ban(const NetworkClientInfo *ci) NetworkServerKickOrBanIP(ci->client_id, true); } +static void ClientList_Watch(const NetworkClientInfo *ci) +{ + if (ci != NULL){ + CompanyID cid = (CompanyID)ci->client_id; + ShowWatchWindow(cid, 1); + } +} + static void ClientList_GiveMoney(const NetworkClientInfo *ci) { ShowNetworkGiveMoneyWindow(ci->client_playas); @@ -1767,6 +1799,9 @@ struct NetworkClientListPopupWindow : Window { this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban); } + if (_network_own_client_id != ci->client_id && ci->client_id != CLIENT_ID_SERVER && _novarole) { + this->AddAction(STR_XI_WATCH, &ClientList_Watch); + } this->InitNested(client_id); CLRBITS(this->flags, WF_WHITE_BORDER); } @@ -1908,8 +1943,11 @@ struct NetworkClientListWindow : Window { FOR_ALL_CLIENT_INFOS(ci) { width = max(width, GetStringBoundingBox(ci->client_name).width); } - - size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT; + SetDParam(0, 0xFFFF); + SetDParam(1, INVALID_COMPANY); + uint width2 = GetStringBoundingBox(STR_NETWORK_CLIENT_EXTRA).width; + size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT + width2; + //size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT; } virtual void OnPaint() @@ -1960,6 +1998,11 @@ struct NetworkClientListWindow : Window { DrawString(name_left, name_right, y, ci->client_name, colour); + uint extra = GetStringBoundingBox(ci->client_name).width + 15; + SetDParam(0, ci->client_id); + SetDParam(1, ci->client_playas == INVALID_COMPANY ? ci->client_playas : ci->client_playas + 1); + DrawString(name_left + extra, right, y, STR_NETWORK_CLIENT_EXTRA, TC_FROMSTRING, SA_RIGHT); + y += FONT_HEIGHT_NORMAL; } } diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 9841708586..5b46442065 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -171,6 +171,78 @@ static const StringID _order_conditional_condition[] = { INVALID_STRING_ID, }; +struct OrdersFromSettings +{ + enum OrderUnloadFlags unload; + enum OrderLoadFlags load; +}; + +typedef enum { + GOFS_NONE = 0, + GOFS_FULL, + GOFS_XFER, + GOFS_UNLOAD, + GOFS_FEEDLOAD, + GOFS_FEEDUNLOAD, + GOFS_NOLOAD +} GetOrderFromSettingsTypes; + +static enum { + GOFS_FEEDER_NULL, + GOFS_FEEDER_LOAD, + GOFS_FEEDER_UNLOAD +} gofsfeeder_ordermod = GOFS_FEEDER_NULL; + +#define GOFSFEEDER_ORDERMOD_RESET gofsfeeder_ordermod = GOFS_FEEDER_NULL + + +/* fetch and compute orders set from settings */ + +static void GetOrdersFromSettings(const Vehicle *v, uint8 setting, struct OrdersFromSettings *rv) +{ + rv->load = (enum OrderLoadFlags)-1; + rv->unload = (enum OrderUnloadFlags)-1; + + switch(setting) { + + case GOFS_FEEDLOAD: + if (v->GetNumOrders()) gofsfeeder_ordermod = GOFS_FEEDER_LOAD; + rv->unload = OUFB_NO_UNLOAD; + rv->load = OLF_FULL_LOAD_ANY; + break; + case GOFS_FULL: + rv->load = OLF_FULL_LOAD_ANY; + break; + + case GOFS_UNLOAD: + rv->unload = OUFB_UNLOAD; + if (_settings_client.gui.auto_noload_on_unloadall) + rv->load = OLFB_NO_LOAD; + break; + + case GOFS_FEEDUNLOAD: + if (v->GetNumOrders()) gofsfeeder_ordermod = GOFS_FEEDER_UNLOAD; + rv->unload = OUFB_TRANSFER; + rv->load = OLFB_NO_LOAD; + break; + + case GOFS_XFER: + rv->unload = OUFB_TRANSFER; + if (_settings_client.gui.auto_noload_on_transfer) + rv->load = OLFB_NO_LOAD; + break; + + case GOFS_NOLOAD: + rv->load = OLFB_NO_LOAD; + break; + + case GOFS_NONE: + break; + + default: NOT_REACHED(); + } +} + extern uint ConvertSpeedToDisplaySpeed(uint speed); extern uint ConvertDisplaySpeedToSpeed(uint speed); @@ -346,6 +418,19 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, colour); + + uint order_dist_sq = 0; + uint order_dist_mh = 0; + const Order *next2 = order->next != NULL ? order->next : v->GetFirstOrder(); + TileIndex prev_tile = order->GetLocation(v, true); + TileIndex cur_tile = next2->GetLocation(v, true); + if (prev_tile != INVALID_TILE && cur_tile != INVALID_TILE){ + order_dist_sq = IntSqrt(DistanceSquare(prev_tile, cur_tile)); + order_dist_mh = DistanceManhattan(prev_tile, cur_tile); + } + SetDParam(0, order_dist_sq); + SetDParam(1, order_dist_mh); + DrawString(middle, right, y, STR_ORDER_DIST, TC_WHITE, SA_RIGHT); } /** @@ -400,8 +485,34 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile) (facil = FACIL_BUS_STOP, v->type == VEH_ROAD && RoadVehicle::From(v)->IsBus()) || (facil = FACIL_TRUCK_STOP, 1); if (st->facilities & facil) { + uint8 os = 0xff; order.MakeGoToStation(st_index); - if (_ctrl_pressed) order.SetLoadType(OLF_FULL_LOAD_ANY); + if (_ctrl_pressed) { + if (_shift_pressed) + os = _settings_client.gui.goto_shortcuts_ctrlshift_lclick; + else if (_alt_pressed) + os = _settings_client.gui.goto_shortcuts_altctrl_lclick; + else + os = _settings_client.gui.goto_shortcuts_ctrl_lclick; + } + else if (_shift_pressed) { + if (_alt_pressed) + os = _settings_client.gui.goto_shortcuts_altshift_lclick; + else + os = _settings_client.gui.goto_shortcuts_shift_lclick; + } + else if (_alt_pressed) + os = _settings_client.gui.goto_shortcuts_alt_lclick; + + if (os != 0xff) { + struct OrdersFromSettings ofs; + GetOrdersFromSettings(v, os, &ofs); + if (ofs.load != (enum OrderLoadFlags)-1) + order.SetLoadType(ofs.load); + if (ofs.unload != (enum OrderUnloadFlags)-1) + order.SetUnloadType(ofs.unload); + } + if (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) order.SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); order.SetStopLocation(v->type == VEH_TRAIN ? (OrderStopLocation)(_settings_client.gui.stop_location) : OSL_PLATFORM_FAR_END); return order; @@ -427,6 +538,7 @@ enum { OHK_TRANSFER, OHK_NO_UNLOAD, OHK_NO_LOAD, + OHK_CLOSE, }; /** @@ -635,8 +747,15 @@ private: DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_UNLOAD | (unload_type << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); + bool set_no_load = false; + if (unload_type == OUFB_TRANSFER){ + set_no_load = _settings_client.gui.auto_noload_on_transfer; + } + else if (unload_type == OUFB_UNLOAD){ + set_no_load = _settings_client.gui.auto_noload_on_unloadall; + } /* Transfer orders with leave empty as default */ - if (unload_type == OUFB_TRANSFER) { + if (set_no_load) { DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (OLFB_NO_LOAD << 4), CMD_MODIFY_ORDER); this->SetWidgetDirty(WID_O_FULL_LOAD); } @@ -1423,6 +1542,11 @@ public: virtual EventState OnHotkey(int hotkey) { if (this->vehicle->owner != _local_company) return ES_NOT_HANDLED; + if(hotkey == OHK_GOTO && this->goto_type != OPOS_NONE){ + this->RaiseWidget(WID_O_GOTO); + ResetObjectToPlace(); + return ES_NOT_HANDLED; + } switch (hotkey) { case OHK_SKIP: this->OrderClick_Skip(); break; @@ -1436,6 +1560,7 @@ public: case OHK_TRANSFER: this->OrderHotkey_Transfer(); break; case OHK_NO_UNLOAD: this->OrderHotkey_NoUnload(); break; case OHK_NO_LOAD: this->OrderHotkey_NoLoad(); break; + case OHK_CLOSE: delete this; break; default: return ES_NOT_HANDLED; } return ES_HANDLED; @@ -1447,7 +1572,21 @@ public: const Order cmd = GetOrderCmdFromTile(this->vehicle, tile); if (cmd.IsType(OT_NOTHING)) return; - if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) { + if (gofsfeeder_ordermod != GOFS_FEEDER_NULL) { + if (gofsfeeder_ordermod == GOFS_FEEDER_LOAD) { + if (DoCommandP(this->vehicle->tile, this->vehicle->index + ((1) << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) { + DoCommandP(this->vehicle->tile, this->vehicle->index, 0, CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER)); + } + + } + else if (gofsfeeder_ordermod == GOFS_FEEDER_UNLOAD) { // still flushes the whole order table + if (DoCommandP(this->vehicle->tile, this->vehicle->index + ((this->vehicle->GetNumOrders()) << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) { + DoCommandP(this->vehicle->tile, this->vehicle->index, (this->vehicle->GetNumOrders()-2+(int)_networking) , CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER)); + } + } + gofsfeeder_ordermod = GOFS_FEEDER_NULL; + } + else if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) { /* With quick goto the Go To button stays active */ if (!_settings_client.gui.quick_goto) ResetObjectToPlace(); } @@ -1525,6 +1664,7 @@ static Hotkey order_hotkeys[] = { Hotkey((uint16)0, "transfer", OHK_TRANSFER), Hotkey((uint16)0, "no_unload", OHK_NO_UNLOAD), Hotkey((uint16)0, "no_load", OHK_NO_LOAD), + Hotkey('Q', "close", OHK_CLOSE), HOTKEY_LIST_END }; HotkeyList OrdersWindow::hotkeys("order", order_hotkeys); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index f732b03a8f..64781eddc6 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -44,6 +44,7 @@ typedef SmallVector TrainList; RailtypeInfo _railtypes[RAILTYPE_END]; +TileIndex _rail_track_endtile; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes. assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes)); @@ -560,6 +561,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u } cost.AddCost(RailBuildCost(railtype)); + _rail_track_endtile = tile; return cost; } @@ -704,6 +706,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, if (v != NULL) TryPathReserve(v, true); } + _rail_track_endtile = tile; return cost; } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 7d4c88b8a3..53ff51e1c5 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -52,6 +52,8 @@ static bool _convert_signal_button; ///< convert signal button in the s static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI) static SignalType _cur_signal_type; ///< set the signal type (for signal GUI) +extern TileIndex _rail_track_endtile; // rail_cmd.cpp + /* Map the setting: default_signal_type to the corresponding signal type */ static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY}; @@ -91,9 +93,9 @@ void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); } -static void GenericPlaceRail(TileIndex tile, int cmd) +static bool GenericPlaceRail(TileIndex tile, Track track) { - DoCommandP(tile, _cur_railtype, cmd, + return DoCommandP(tile, _cur_railtype, track, _remove_button_clicked ? CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -276,6 +278,7 @@ void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uin if (result.Succeeded()) { if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + StoreRailPlacementEndpoints(tile, _build_tunnel_endtile, TileX(tile) == TileX(_build_tunnel_endtile) ? TRACK_Y : TRACK_X, false); } else { SetRedErrorSquare(_build_tunnel_endtile); } @@ -305,7 +308,7 @@ static bool RailToolbar_CtrlChanged(Window *w) /* allow ctrl to switch remove mode only for these widgets */ for (uint i = WID_RAT_BUILD_NS; i <= WID_RAT_BUILD_STATION; i++) { - if ((i <= WID_RAT_AUTORAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) { + if ((i <= WID_RAT_POLYRAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) { ToggleRailButton_Remove(w); return true; } @@ -349,9 +352,9 @@ static void BuildRailClick_Remove(Window *w) } } -static void DoRailroadTrack(int mode) +static bool DoRailroadTrack(TileIndex start_tile, TileIndex end_tile, Track track) { - DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), + return DoCommandP(start_tile, end_tile, _cur_railtype | (track << 4), _remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -360,14 +363,14 @@ static void DoRailroadTrack(int mode) static void HandleAutodirPlacement() { - int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5 + Track track = (Track)(_thd.drawstyle & HT_DIR_MASK); // 0..5 + TileIndex start_tile = TileVirtXY(_thd.selstart.x, _thd.selstart.y); + TileIndex end_tile = TileVirtXY(_thd.selend.x, _thd.selend.y); - if (_thd.drawstyle & HT_RAIL) { // one tile case - GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat); - return; + if ((_thd.drawstyle & HT_RAIL ? GenericPlaceRail(end_tile, track) : DoRailroadTrack(start_tile, end_tile, track)) + && !_shift_pressed) { + StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true); } - - DoRailroadTrack(trackstat); } /** @@ -414,6 +417,73 @@ static void HandleAutoSignalPlacement() } +// FIXME duplicate from road_gui.cpp +static DiagDirection TileFractCoordsToDiagDir() { + bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; + if (_tile_fract_coords.x < _tile_fract_coords.y) { + return diag ? DIAGDIR_NE : DIAGDIR_SE; + } + return diag ? DIAGDIR_NW : DIAGDIR_SW; +} + +// FIXME duplicate from road_gui.cpp +static DiagDirection RoadBitsToDiagDir(RoadBits bits) { + if (bits < ROAD_SE) { + return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; + } + return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; +} + +RoadBits FindRailsToConnect(TileIndex tile) { + RoadBits directed = ROAD_NONE; + RoadBits passing = ROAD_NONE; + DiagDirection ddir; + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (HasStationTileRail(cur_tile)) { + if (GetRailStationTrackBits(cur_tile) & DiagdirReachesTracks(ddir)) { + directed |= DiagDirToRoadBits(ddir); + } + continue; + } + if (!IsTileType(cur_tile, MP_RAILWAY)) continue; + if (!IsPlainRail(cur_tile)) continue; + passing |= DiagDirToRoadBits(ddir); + if (GetTrackBits(cur_tile) & DiagdirReachesTracks(ddir)) { + directed |= DiagDirToRoadBits(ddir); + } + } + // Prioritize track bits that head in this direction + if (directed != ROAD_NONE) { + return directed; + } + return passing; +} + +/* + * Selects orientation for rail object (depot) + */ +static DiagDirection AutodetectRailObjectDirection(TileIndex tile) { + RoadBits bits = FindRailsToConnect(tile); + // FIXME after this point repeats road autodetection + if (HasExactlyOneBit(bits)) return RoadBitsToDiagDir(bits); + if (bits == ROAD_NONE) bits = ROAD_ALL; + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir()); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) { + return ddir; + } + } + NOT_REACHED(); +} + /** Rail toolbar management class. */ struct BuildRailToolbarWindow : Window { RailType railtype; ///< Rail type to build. @@ -461,6 +531,7 @@ struct BuildRailToolbarWindow : Window { this->GetWidget(WID_RAT_BUILD_EW)->widget_data = rti->gui_sprites.build_ew_rail; this->GetWidget(WID_RAT_BUILD_Y)->widget_data = rti->gui_sprites.build_y_rail; this->GetWidget(WID_RAT_AUTORAIL)->widget_data = rti->gui_sprites.auto_rail; + this->GetWidget(WID_RAT_POLYRAIL)->widget_data = rti->gui_sprites.auto_rail; this->GetWidget(WID_RAT_BUILD_DEPOT)->widget_data = rti->gui_sprites.build_depot; this->GetWidget(WID_RAT_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail; this->GetWidget(WID_RAT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; @@ -489,6 +560,7 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_EW: case WID_RAT_BUILD_Y: case WID_RAT_AUTORAIL: + case WID_RAT_POLYRAIL: case WID_RAT_BUILD_WAYPOINT: case WID_RAT_BUILD_STATION: case WID_RAT_BUILD_SIGNALS: @@ -520,6 +592,15 @@ struct BuildRailToolbarWindow : Window { } } + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget == WID_RAT_POLYRAIL) { + Dimension d = GetSpriteSize(SPR_BLOT); + uint offset = this->IsWidgetLowered(WID_RAT_POLYRAIL) ? 1 : 0; + DrawSprite(SPR_BLOT, PALETTE_TO_GREY, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset); + } + } + virtual void OnClick(Point pt, int widget, int click_count) { if (widget < WID_RAT_BUILD_NS) return; @@ -551,6 +632,11 @@ struct BuildRailToolbarWindow : Window { this->last_user_action = widget; break; + case WID_RAT_POLYRAIL: + HandlePlacePushButton(this, WID_RAT_POLYRAIL, GetRailTypeInfo(railtype)->cursor.autorail, HT_RAIL | HT_POLY); + this->last_user_action = widget; + break; + case WID_RAT_DEMOLISH: HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; @@ -620,6 +706,7 @@ struct BuildRailToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + DiagDirection ddir; switch (this->last_user_action) { case WID_RAT_BUILD_NS: VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); @@ -638,6 +725,7 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_AUTORAIL: + case WID_RAT_POLYRAIL: VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL); break; @@ -646,7 +734,11 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_BUILD_DEPOT: - DoCommandP(tile, _cur_railtype, _build_depot_direction, + ddir = _build_depot_direction; + if (ddir == DIAGDIR_NW + 1) { + ddir = AutodetectRailObjectDirection(tile); + } + DoCommandP(tile, _cur_railtype, ddir, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), CcRailDepot); break; @@ -785,6 +877,7 @@ static EventState RailToolbarGlobalHotkeys(int hotkey) } const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0}; +const uint16 _railtoolbar_polyrail_keys[] = {'5' | WKC_CTRL, 'A' | WKC_GLOBAL_HOTKEY | WKC_CTRL, 0}; static Hotkey railtoolbar_hotkeys[] = { Hotkey('1', "build_ns", WID_RAT_BUILD_NS), @@ -792,6 +885,7 @@ static Hotkey railtoolbar_hotkeys[] = { Hotkey('3', "build_ew", WID_RAT_BUILD_EW), Hotkey('4', "build_y", WID_RAT_BUILD_Y), Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL), + Hotkey(_railtoolbar_polyrail_keys, "polyrail", WID_RAT_POLYRAIL), Hotkey('6', "demolish", WID_RAT_DEMOLISH), Hotkey('7', "depot", WID_RAT_BUILD_DEPOT), Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT), @@ -822,6 +916,8 @@ static const NWidgetPart _nested_build_rail_widgets[] = { SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_AUTORAIL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_POLYRAIL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_POLYRAIL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(), @@ -1723,6 +1819,7 @@ struct BuildRailDepotWindow : public PickerWindowBase { case WID_BRAD_DEPOT_SE: case WID_BRAD_DEPOT_SW: case WID_BRAD_DEPOT_NW: + case WID_BRAD_DEPOT_AUTO: this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); @@ -1760,6 +1857,9 @@ static const NWidgetPart _nested_build_depot_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; @@ -1880,7 +1980,7 @@ static void ShowBuildWaypointPicker(Window *parent) */ void InitializeRailGui() { - _build_depot_direction = DIAGDIR_NW; + _build_depot_direction = (DiagDirection)(DIAGDIR_NW + 1); } /** diff --git a/src/rev.cpp b/src/rev.cpp index afd8bb8f12..7bf02574a3 100644 --- a/src/rev.cpp +++ b/src/rev.cpp @@ -1,4 +1,4 @@ -/* $Id: rev.cpp.in 26440 2014-04-01 18:33:16Z frosch $ */ +/* $Id: rev.cpp.in 26482 2014-04-23 20:13:33Z rubidium $ */ /* * This file is part of OpenTTD. @@ -13,6 +13,8 @@ #include "core/bitmath_func.hpp" #include "rev.h" +#include "safeguards.h" + /** * Is this version of OpenTTD a release version? * @return True if it is a release version. @@ -37,7 +39,7 @@ bool IsReleasedVersion() * norev000 is for non-releases that are made on systems without * subversion or sources that are not a checkout of subversion. */ -const char _openttd_revision[] = "1.4.0"; +const char _openttd_revision[] = "1.5.0-beta2"; /** * The text version of OpenTTD's build date. @@ -70,11 +72,11 @@ const byte _openttd_revision_modified = 0; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 4 << 24 | 0 << 20 | 1 << 19 | (26440 & ((1 << 19) - 1)); +const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 0 << 19 | (27170 & ((1 << 19) - 1)); #ifdef __MORPHOS__ /** * Variable used by MorphOS to show the version. */ -extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.4.0 (02.04.14) OpenTTD Team [MorphOS, PowerPC]"; +extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.5.0-beta2 (16.03.15) OpenTTD Team [MorphOS, PowerPC]"; #endif diff --git a/src/rev.cpp.in b/src/rev.cpp.in index b17c04cc24..44b2853fb4 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -39,7 +39,7 @@ bool IsReleasedVersion() * norev000 is for non-releases that are made on systems without * subversion or sources that are not a checkout of subversion. */ -const char _openttd_revision[] = "!!VERSION!!"; +const char _openttd_revision[] = "1.5.0-beta2"; /** * The text version of OpenTTD's build date. @@ -57,7 +57,7 @@ const char _openttd_build_date[] = __DATE__ " " __TIME__; * (compiling from sources without any version control software) * and 2 is for modified revision. */ -const byte _openttd_revision_modified = !!MODIFIED!!; +const byte _openttd_revision_modified = 0; /** * The NewGRF revision of OTTD: diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 950ac643d7..41233594cb 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -11,7 +11,9 @@ #include "stdafx.h" #include "gui.h" +#include "cmd_helper.h" #include "window_gui.h" +#include "station_func.h" #include "station_gui.h" #include "terraform_gui.h" #include "viewport_func.h" @@ -211,6 +213,107 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) } } + +static RoadBits FindRoadsToConnect(TileIndex tile) { + RoadBits bits = ROAD_NONE; + DiagDirection ddir; + // Prioritize roadbits that head in this direction + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (GetAnyRoadBits(cur_tile, ROADTYPE_ROAD, true) & + DiagDirToRoadBits(ReverseDiagDir(ddir))) + { + bits |= DiagDirToRoadBits(ddir); + } + } + if (bits != ROAD_NONE) { + return bits; + } + // Try to connect to any road passing by + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (HasTileRoadType(cur_tile, ROADTYPE_ROAD) && (GetTileType(cur_tile) == MP_ROAD) && + (GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) { + bits |= DiagDirToRoadBits(ddir); + } + } + return bits; +} + +static DiagDirection RoadBitsToDiagDir(RoadBits bits) { + if (bits < ROAD_SE) { + return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; + } + return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; +} + +static DiagDirection TileFractCoordsToDiagDir() { + bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; + if (_tile_fract_coords.x < _tile_fract_coords.y) { + return diag ? DIAGDIR_NE : DIAGDIR_SE; + } + return diag ? DIAGDIR_NW : DIAGDIR_SW; +} +/* + * Selects orientation for road object (depot, terminal station) + */ +static DiagDirection AutodetectRoadObjectDirection(TileIndex tile) { + RoadBits bits = FindRoadsToConnect(tile); + if (HasExactlyOneBit(bits)) { + return RoadBitsToDiagDir(bits); + } + if (bits == ROAD_NONE){ + bits = ROAD_ALL; + } + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir()); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) { + return ddir; + } + } + NOT_REACHED(); +} + +static bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r) { + TILE_AREA_LOOP(tile, area) { + if (!HasTileRoadType(tile, ROADTYPE_ROAD)) continue; + if (GetTileType(tile) != MP_ROAD) continue; + if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) continue; + if (GetRoadBits(tile, ROADTYPE_ROAD) & ~r) return false; + } + return true; +} + + +/* + * Automaticaly selects direction to use for road stop. + * @param area road stop area + * @return selected direction + */ +static DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area) { + bool se_suits, ne_suits; + + // Check which direction is available + // If both are not use SE, building will fail anyway + se_suits = CheckDriveThroughRoadStopDirection(area, ROAD_Y); + ne_suits = CheckDriveThroughRoadStopDirection(area, ROAD_X); + if (!ne_suits) return DIAGDIR_SE; + if (!se_suits) return DIAGDIR_NE; + + // Build station along the longer direction + if (area.w > area.h) return DIAGDIR_NE; + if (area.w < area.h) return DIAGDIR_SE; + + return AutodetectRoadObjectDirection(area.tile); +} + /** * Place a new road stop. * @param start_tile First tile of the area. @@ -225,14 +328,23 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u { uint8 ddir = _road_station_picker_orientation; SB(p2, 16, 16, INVALID_STATION); // no station to join + TileArea ta(start_tile, end_tile); if (ddir >= DIAGDIR_END) { - SetBit(p2, 1); // It's a drive-through stop. - ddir -= DIAGDIR_END; // Adjust picker result to actual direction. + if (ddir < DIAGDIR_END + 2) { + SetBit(p2, 1); // It's a drive-through stop. + ddir -= DIAGDIR_END; // Adjust picker result to actual direction. + } + else if (ddir == DIAGDIR_END + 2) { + ddir = AutodetectRoadObjectDirection(start_tile); + } + else if (ddir == DIAGDIR_END + 3) { + SetBit(p2, 1); // It's a drive-through stop. + ddir = AutodetectDriveThroughRoadStopDirection(ta); + } } p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. - TileArea ta(start_tile, end_tile); CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" }; ShowSelectStationIfNeeded(cmdcont, ta); } @@ -297,7 +409,7 @@ static bool RoadToolbar_CtrlChanged(Window *w) if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false; /* allow ctrl to switch remove mode only for these widgets */ - for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) { + for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_FULLROAD; i++) { if (w->IsWidgetLowered(i)) { ToggleRoadButton_Remove(w); return true; @@ -382,6 +494,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_ROAD_X: case WID_ROT_ROAD_Y: case WID_ROT_AUTOROAD: + case WID_ROT_FULLROAD: this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), WID_ROT_REMOVE, WID_ROT_ONE_WAY, @@ -403,6 +516,16 @@ struct BuildRoadToolbarWindow : Window { } } + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget == WID_ROT_FULLROAD) { + Dimension d = GetSpriteSize(SPR_BLOT); + uint offset = this->IsWidgetLowered(WID_ROT_FULLROAD) ? 1 : 0; + DrawSprite(SPR_BLOT, PALETTE_TO_GREY, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) { _remove_button_clicked = false; @@ -423,6 +546,11 @@ struct BuildRoadToolbarWindow : Window { this->last_started_action = widget; break; + case WID_ROT_FULLROAD: + HandlePlacePushButton(this, WID_ROT_FULLROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); + this->last_started_action = widget; + break; + case WID_ROT_DEMOLISH: HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_started_action = widget; @@ -491,6 +619,7 @@ struct BuildRoadToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + DiagDirection ddir; _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); switch (this->last_started_action) { @@ -513,12 +642,21 @@ struct BuildRoadToolbarWindow : Window { VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD); break; + case WID_ROT_FULLROAD: + _place_road_flag = RF_NONE; + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_FULLROAD); + break; + case WID_ROT_DEMOLISH: PlaceProc_DemolishArea(tile); break; case WID_ROT_DEPOT: - DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + ddir = _road_depot_orientation; + if (ddir == DIAGDIR_NW + 1) { + ddir = AutodetectRoadObjectDirection(tile); + } + DoCommandP(tile, _cur_roadtype << 2 | ddir, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); break; @@ -596,6 +734,21 @@ struct BuildRoadToolbarWindow : Window { break; + case DDSP_PLACE_FULLROAD: + /* For autoroad we need to update the + * direction of the road */ + if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y && + ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) || + (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) { + /* Set dir = X */ + _place_road_flag &= ~RF_DIR_Y; + } + else { + /* Set dir = Y */ + _place_road_flag |= RF_DIR_Y; + } + break; + default: break; } @@ -632,6 +785,16 @@ struct BuildRoadToolbarWindow : Window { CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); break; + case DDSP_PLACE_FULLROAD: + DoCommandP(start_tile, end_tile, + _place_road_flag | (_cur_roadtype << 3) | + (_one_way_button_clicked << 5) | (1 << 6) | + (start_tile > end_tile ? 1 : 2), // always build full roads + _remove_button_clicked ? + CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : + CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); + break; + case DDSP_BUILD_BUSSTOP: PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); break; @@ -706,6 +869,7 @@ static Hotkey roadtoolbar_hotkeys[] = { Hotkey('6', "bus_station", WID_ROT_BUS_STATION), Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), Hotkey('8', "oneway", WID_ROT_ONE_WAY), + Hotkey('9', "fullroad", WID_ROT_FULLROAD), Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), Hotkey('R', "remove", WID_ROT_REMOVE), @@ -738,6 +902,8 @@ static const NWidgetPart _nested_build_road_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_FULLROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), @@ -864,7 +1030,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if ( _cur_roadtype == ROADTYPE_TRAM) { this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; - for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; + for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_AUTO; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; } this->FinishInitNested(TRANSPORT_ROAD); @@ -892,6 +1058,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { case WID_BROD_DEPOT_NE: case WID_BROD_DEPOT_SW: case WID_BROD_DEPOT_SE: + case WID_BROD_DEPOT_AUTO: this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); @@ -931,6 +1098,9 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; @@ -1031,6 +1201,8 @@ struct BuildRoadStationWindow : public PickerWindowBase { case WID_BROS_STATION_NW: case WID_BROS_STATION_X: case WID_BROS_STATION_Y: + case WID_BROS_STATION_AUTO: + case WID_BROS_STATION_XY_AUTO: this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE); this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); @@ -1082,6 +1254,13 @@ static const NWidgetPart _nested_rv_station_picker_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_XY_AUTO), SetMinimalSize(66, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), @@ -1113,6 +1292,6 @@ static void ShowRVStationPicker(Window *parent, RoadStopType rs) void InitializeRoadGui() { - _road_depot_orientation = DIAGDIR_NW; - _road_station_picker_orientation = DIAGDIR_NW; + _road_depot_orientation = (DiagDirection)(DIAGDIR_NW + 1); + _road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3); } diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 8776c40526..b5d645bf3b 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -32,6 +32,10 @@ void RebuildTownCaches() FOR_ALL_TOWNS(town) { town->cache.population = 0; town->cache.num_houses = 0; + town->cache.potential_pop = 0; + town->houses_construction = 0; + town->houses_reconstruction = 0; + town->houses_demolished = 0; } for (TileIndex t = 0; t < MapSize(); t++) { @@ -41,6 +45,10 @@ void RebuildTownCaches() town = Town::GetByTile(t); IncreaseBuildingCount(town, house_id); if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population; + else{ + town->houses_construction++; + } + town->cache.potential_pop += HouseSpec::Get(house_id)->population; /* Increase the number of houses for every house, but only once. */ if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++; @@ -111,6 +119,7 @@ void UpdateHousesAndTowns() } RebuildTownCaches(); + ResetTownsGrowthTiles(); } /** Save and load of towns. */ diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 8f58d80482..3ddb6fe6e0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1524,6 +1524,10 @@ static SettingsContainer &GetSettingsTree() viewports->Add(new SettingEntry("gui.measure_tooltip")); viewports->Add(new SettingEntry("gui.loading_indicators")); viewports->Add(new SettingEntry("gui.show_track_reservation")); + viewports->Add(new SettingEntry("gui.cb_distance_check")); + viewports->Add(new SettingEntry("gui.old_depot_train_length_calc")); + viewports->Add(new SettingEntry("gui.enable_extra_tooltips")); + viewports->Add(new SettingEntry("gui.polyrail_double_click")); } SettingsPage *construction = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION)); @@ -1602,6 +1606,26 @@ static SettingsContainer &GetSettingsTree() SettingsPage *vehicles = main->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES)); { + /** Vehicle control page */ + SettingsPage *veh_control = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_CTRL)); + { + veh_control->Add(new SettingEntry("gui.enable_ctrl_click_start_stop")); + veh_control->Add(new SettingEntry("gui.new_nonstop")); + veh_control->Add(new SettingEntry("gui.auto_noload_on_transfer")); + veh_control->Add(new SettingEntry("gui.auto_noload_on_unloadall")); + } + + /** Order Shorcuts page */ + SettingsPage *orders = veh_control->Add(new SettingsPage(STR_CONFIG_SETTING_ORDER_SHORTCUTS)); + { + orders->Add(new SettingEntry("gui.goto_shortcuts_ctrl_lclick")); + orders->Add(new SettingEntry("gui.goto_shortcuts_shift_lclick")); + orders->Add(new SettingEntry("gui.goto_shortcuts_ctrlshift_lclick")); + orders->Add(new SettingEntry("gui.goto_shortcuts_alt_lclick")); + orders->Add(new SettingEntry("gui.goto_shortcuts_altshift_lclick")); + orders->Add(new SettingEntry("gui.goto_shortcuts_altctrl_lclick")); + } + SettingsPage *physics = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_PHYSICS)); { physics->Add(new SettingEntry("vehicle.train_acceleration_model")); diff --git a/src/settings_type.h b/src/settings_type.h index 41b26b5468..87be200980 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -79,6 +79,15 @@ struct GUISettings { bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames + bool enable_ctrl_click_start_stop; ///< allow ctrl+click to start or stop vehicles + uint8 goto_shortcuts_ctrl_lclick; ///< goto action shortcut CTRL+LEFT-CLICK + uint8 goto_shortcuts_shift_lclick; ///< goto action shortcut SHIFT+LEFT-CLICK + uint8 goto_shortcuts_ctrlshift_lclick; ///< goto action shortcut CTRL+SHIFT+LEFT-CLICK + uint8 goto_shortcuts_alt_lclick; ///< goto action shortcut ALT+LEFT-CLICK + uint8 goto_shortcuts_altshift_lclick; ///< goto action shortcut ALT+SHIFT+LEFT-CLICK + uint8 goto_shortcuts_altctrl_lclick; ///< goto action shortcut ALT+CTRL+LEFT-CLICK + bool auto_noload_on_transfer; ///< automatically set no-loading when ordering to transfer all cargo + bool auto_noload_on_unloadall; ///< automatically set no-loading when ordering to unload all cargo bool new_nonstop; ///< ttdpatch compatible nonstop handling uint8 stop_location; ///< what is the default stop location of trains? uint8 auto_scrolling; ///< scroll when moving mouse to the edge (see #ViewportAutoscrolling) @@ -158,6 +167,11 @@ struct GUISettings { bool newgrf_show_old_versions; ///< whether to show old versions in the NewGRF list uint8 newgrf_default_palette; ///< default palette to use for NewGRFs without action 14 palette information + bool old_depot_train_length_calc; ///< display vehicle length in whole numbers - old style + uint8 cb_distance_check; ///< zoning cb distance + bool enable_extra_tooltips; ///< enable extra tooltips when hovering over various elements + bool polyrail_double_click; ///< finish polyrail with mouse double click + /** * Returns true when the user has sufficient privileges to edit newgrfs on a running game * @return whether the user has sufficient privileges to edit newgrfs in an existing game diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 618cee5875..024a00c4b2 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -894,7 +894,7 @@ void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const y < dpi->top + dpi->height) { /* And draw it. */ SetDParam(0, t->index); - DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); + DrawString(x, x + t->cache.sign.width_small, y, t->larger_town ? STR_SMALLMAP_TOWN_LARGE : STR_SMALLMAP_TOWN); } } } diff --git a/src/station_gui.cpp b/src/station_gui.cpp index d7109b4f3d..5878734f19 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2234,16 +2234,17 @@ static const NWidgetPart _nested_select_station_widgets[] = { * @tparam T The type of station to join with */ template -struct SelectStationWindow : Window { +struct SelectStationWindow : WindowPopup { CommandContainer select_station_cmd; ///< Command to build new station TileArea area; ///< Location of new station Scrollbar *vscroll; SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) : - Window(desc), + WindowPopup(desc, WPUT_WIDGET_RELATIVE), select_station_cmd(cmd), area(ta) { + this->wpu_widget = WID_JS_PANEL; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR); this->GetWidget(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; diff --git a/src/table/settings.ini b/src/table/settings.ini index 5bd2059806..a1d1c9551f 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -3936,5 +3936,138 @@ strhelp = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT strval = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND cat = SC_BASIC +; //MODGUI ********************************* +[SDTC_BOOL] +var = gui.enable_ctrl_click_start_stop +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_CONFIG_SETTING_CTRL_ENABLE_CTRLCLICK_STARTSTOP + +[SDTC_BOOL] +var = gui.auto_noload_on_transfer +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_TRANSFER + +[SDTC_BOOL] +var = gui.auto_noload_on_unloadall +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_UNLOAD + +[SDTC_VAR] +var = gui.goto_shortcuts_ctrl_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 1 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLLCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_VAR] +var = gui.goto_shortcuts_shift_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_SHIFTLCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_VAR] +var = gui.goto_shortcuts_ctrlshift_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLSHIFTLCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_VAR] +var = gui.goto_shortcuts_alt_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTLCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_VAR] +var = gui.goto_shortcuts_altshift_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTSHIFTCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_VAR] +var = gui.goto_shortcuts_altctrl_lclick +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 6 +interval = 1 +str = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLALTLCLICK +strval = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE +proc = RedrawScreen +cat = SC_BASIC + +[SDTC_BOOL] +var = gui.old_depot_train_length_calc +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_OLD_DEPOT_TRAINT_LENGTH + +[SDTC_VAR] +var = gui.cb_distance_check +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = 25 +min = 0 +max = 100 +interval = 5 +str = STR_CB_DISTANCE_CHECK +strval = STR_JUST_COMMA +proc = RedrawScreen + +[SDTC_BOOL] +var = gui.enable_extra_tooltips +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_CONFIG_SETTING_ENABLE_EXTRA_TOOLTIPS + +[SDTC_BOOL] +var = gui.polyrail_double_click +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_POLYRAIL_DOUBLECLICK_TOOLTIPS + [SDT_END] diff --git a/src/table/sprites.h b/src/table/sprites.h index c296abdbcf..311f3f493a 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -296,8 +296,22 @@ static const uint16 EMPTY_BOUNDING_BOX_SPRITE_COUNT = 1; static const SpriteID SPR_PALETTE_BASE = SPR_EMPTY_BOUNDING_BOX + EMPTY_BOUNDING_BOX_SPRITE_COUNT; static const uint16 PALETTE_SPRITE_COUNT = 1; +/* zoning stuff */ +static const SpriteID SPR_INNER_HIGHLIGHT_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT; +static const SpriteID SPR_IMG_COMPANY_CARGO = SPR_INNER_HIGHLIGHT_BASE + 19; +static const SpriteID SPR_IMG_COMPANY_GOAL = SPR_INNER_HIGHLIGHT_BASE + 20; +static const SpriteID SPR_PALETTE_ZONING_RED = SPR_INNER_HIGHLIGHT_BASE + 21; +static const SpriteID SPR_PALETTE_ZONING_GREEN = SPR_INNER_HIGHLIGHT_BASE + 22; +static const SpriteID SPR_PALETTE_ZONING_BLACK = SPR_INNER_HIGHLIGHT_BASE + 23; +static const SpriteID SPR_PALETTE_ZONING_LIGHT_BLUE = SPR_INNER_HIGHLIGHT_BASE + 24; +static const SpriteID SPR_PALETTE_ZONING_ORANGE = SPR_INNER_HIGHLIGHT_BASE + 25; +static const SpriteID SPR_PALETTE_ZONING_WHITE = SPR_INNER_HIGHLIGHT_BASE + 26; +static const SpriteID SPR_PALETTE_ZONING_YELLOW = SPR_INNER_HIGHLIGHT_BASE + 27; +static const SpriteID SPR_PALETTE_ZONING_PURPLE = SPR_INNER_HIGHLIGHT_BASE + 28; +static const SpriteID SPR_INNER_HIGHLIGHT_COUNT = 29; + /* From where can we start putting NewGRFs? */ -static const SpriteID SPR_NEWGRFS_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT; +static const SpriteID SPR_NEWGRFS_BASE = SPR_INNER_HIGHLIGHT_BASE + SPR_INNER_HIGHLIGHT_COUNT; /* Manager face sprites */ static const SpriteID SPR_GRADIENT = 874; // background gradient behind manager face diff --git a/src/tile_cmd.h b/src/tile_cmd.h index db9287a02c..b06b504f41 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -64,6 +64,7 @@ struct TileDesc { uint64 dparam[2]; ///< Parameters of the \a str string uint16 rail_speed; ///< Speed limit of rail (bridges and track) uint16 road_speed; ///< Speed limit of road (bridges) + uint16 population; }; /** diff --git a/src/tilehighlight_func.h b/src/tilehighlight_func.h index f4d2c42059..4789426c76 100644 --- a/src/tilehighlight_func.h +++ b/src/tilehighlight_func.h @@ -14,6 +14,7 @@ #include "gfx_type.h" #include "tilehighlight_type.h" +#include "track_type.h" void PlaceProc_DemolishArea(TileIndex tile); bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile); @@ -30,6 +31,9 @@ void VpSetPlaceSizingLimit(int limit); void UpdateTileSelection(); +void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional = true); +void ClearRailPlacementEndpoints(); + extern TileHighlightData _thd; #endif /* TILEHIGHLIGHT_FUNC_H */ diff --git a/src/tilehighlight_type.h b/src/tilehighlight_type.h index 8b765a5153..49f38479fa 100644 --- a/src/tilehighlight_type.h +++ b/src/tilehighlight_type.h @@ -28,6 +28,7 @@ enum HighLightStyle { HT_RAIL = 0x080, ///< autorail (one piece), lower bits: direction HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask) HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT. + HT_POLY = 0x400, ///< polyline mode; connect highlighted track with previous one HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes. /* lower bits (used with HT_LINE and HT_RAIL): @@ -54,11 +55,15 @@ struct TileHighlightData { Point new_pos; ///< New value for \a pos; used to determine whether to redraw the selection. Point new_size; ///< New value for \a size; used to determine whether to redraw the selection. + Point new_offs; ///< New value for \a offs; used to determine whether to redraw the selection. Point new_outersize; ///< New value for \a outersize; used to determine whether to redraw the selection. byte dirty; ///< Whether the build station window needs to redraw due to the changed selection. Point selstart; ///< The location where the dragging started. Point selend; ///< The location where the drag currently ends. + Point selstart2; ///< The location where the second segment of a polyline track starts. + Point selend2; ///< The location where the second segment of a polyline track ends. + HighLightStyle dir2; ///< Direction of the second segment of a polyline track, HT_DIR_END if second segment is not selected. byte sizelimit; ///< Whether the selection is limited in length, and what the maximum length is. HighLightStyle drawstyle; ///< Lower bits 0-3 are reserved for detailed highlight information. diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 44f7271e71..ca7de1070b 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -53,6 +53,10 @@ #include "network/network.h" #include "network/network_gui.h" #include "network/network_func.h" +#include "cargo_table_gui.h" +#include "object_type.h" +#include "zoning.h" +#include "watch_gui.h" #include "safeguards.h" @@ -77,11 +81,12 @@ enum CallBackFunction { CBF_NONE, CBF_PLACE_SIGN, CBF_PLACE_LANDINFO, + CBF_BUILD_HQ, }; /** * Drop down list entry for showing a checked/unchecked toggle item. - */ + */ /* class DropDownListCheckedItem : public DropDownListStringItem { uint checkmark_width; public: @@ -107,18 +112,20 @@ public: } DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); } -}; +};*/ /** * Drop down list entry for showing a company entry, with companies 'blob'. */ class DropDownListCompanyItem : public DropDownListItem { Dimension icon_size; + uint lockwidth; public: bool greyed; DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed) { + this->lockwidth = _networking ? GetSpriteSize(SPR_LOCK).width + 3 : 0; this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); } @@ -134,7 +141,7 @@ public: CompanyID company = (CompanyID)this->result; SetDParam(0, company); SetDParam(1, company); - return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3; + return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + this->lockwidth + 3; } uint Height(uint width) const @@ -154,6 +161,10 @@ public: int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2; DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset); + if (_networking && NetworkCompanyIsPassworded(company)){ + DrawSprite(SPR_LOCK, PAL_NONE, rtl ? right - this->icon_size.width - this->lockwidth - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT + 3 + this->icon_size.width, top + text_offset); + //DrawSprite(SPR_LOCK, PAL_NONE, left + WD_FRAMERECT_LEFT + 3 + this->icon_size.width, top + text_offset); + } SetDParam(0, company); SetDParam(1, company); @@ -163,7 +174,9 @@ public: } else { col = sel ? TC_WHITE : TC_BLACK; } - DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); + int text_x_ofs = 3 + this->icon_size.width + this->lockwidth; + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : text_x_ofs), right - WD_FRAMERECT_RIGHT - (rtl ? text_x_ofs : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); + //DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width + this->lockwidth), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); } }; @@ -256,6 +269,18 @@ static CallBackFunction SelectSignTool() } } +/* hq hotkey */ +static CallBackFunction BuildCompanyHQ(){ + if (_cursor.sprite == SPR_CURSOR_HQ) { + ResetObjectToPlace(); + return CBF_NONE; + } else { + SetObjectToPlace(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); + SetTileSelectSize(2, 2); + return CBF_BUILD_HQ; + } +} + /* --- Pausing --- */ static CallBackFunction ToolbarPauseClick(Window *w) @@ -289,6 +314,7 @@ enum OptionMenuEntries { OME_SETTINGS, OME_SCRIPT_SETTINGS, OME_NEWGRFSETTINGS, + OME_ZONING, OME_TRANSPARENCIES, OME_SHOW_TOWNNAMES, OME_SHOW_STATIONNAMES, @@ -317,6 +343,7 @@ static CallBackFunction ToolbarOptionsClick(Window *w) * to network clients. */ if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false); + *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_ZONING, OME_ZONING, false); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false); *list->Append() = new DropDownListItem(-1, false); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)); @@ -347,6 +374,7 @@ static CallBackFunction MenuClickSettings(int index) case OME_SETTINGS: ShowGameSettings(); return CBF_NONE; case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE; case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE; + case OME_ZONING: ShowZoningToolbar(); break; case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break; case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break; @@ -582,6 +610,37 @@ static CallBackFunction MenuClickFinances(int index) return CBF_NONE; } +/* --- CARGOS button menu --- */ + +static CallBackFunction ToolbarCargosClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_CARGOS); + return CBF_NONE; +} + +static CallBackFunction MenuClickCargos(int index) +{ + ShowCompanyCargos((CompanyID)index); + return CBF_NONE; +} + +/* --- WATCH button menu --- */ + +static CallBackFunction ToolbarWatchClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_WATCH); + return CBF_NONE; +} + +static CallBackFunction MenuClickWatch(int index) +{ + if(Company::IsValidID((CompanyID)index)){ + ShowWatchWindow((CompanyID)index, 0); + } + else ShowWatchWindow(INVALID_COMPANY, 0); + return CBF_NONE; +} + /* --- Company's button menu --- */ static CallBackFunction ToolbarCompaniesClick(Window *w) @@ -1042,7 +1101,7 @@ static CallBackFunction PlaceLandBlockInfo() static CallBackFunction ToolbarHelpClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9); + PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 13 : 9); return CBF_NONE; } @@ -1137,7 +1196,13 @@ void SetStartingYear(Year year) static CallBackFunction MenuClickHelp(int index) { switch (index) { - case 0: return PlaceLandBlockInfo(); + case 0: return PlaceLandBlockInfo(); + case 1: + extern bool _novahost; + if (_networking && _novahost){ + ShowCommandsToolbar(); + } + break; case 2: IConsoleSwitch(); break; case 3: ShowAIDebugWindow(); break; case 4: MenuClickSmallScreenshot(); break; @@ -1148,6 +1213,7 @@ static CallBackFunction MenuClickHelp(int index) case 9: ShowSpriteAlignerWindow(); break; case 10: ToggleBoundingBoxes(); break; case 11: ToggleDirtyBlocks(); break; + case 12: ShowLoginWindow(); break; } return CBF_NONE; } @@ -1281,9 +1347,11 @@ static MenuClickedProc * const _menu_clicked_procs[] = { MenuClickSubsidies, // 6 MenuClickStations, // 7 MenuClickFinances, // 8 + MenuClickCargos, // 8.5 MenuClickCompany, // 9 MenuClickStory, // 10 MenuClickGoal, // 11 + MenuClickWatch, // 11.5 MenuClickGraphs, // 12 MenuClickLeague, // 13 MenuClickIndustry, // 14 @@ -1495,7 +1563,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, }; static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ @@ -1537,14 +1605,14 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 28, 30, }; static const byte arrange_nopanel[] = { - 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 28, 30, }; static const byte arrange_switch[] = { - 18, 8, 11, 12, 13, 14, 15, 16, 17, 29, - 0, 1, 2, 3, 18, 9, 10, 26, 28, 29, + 18, 8, 11, 12, 13, 14, 15, 16, 17, 31, + 0, 1, 2, 3, 18, 9, 10, 28, 30, 31, }; /* If we can place all buttons *and* the panels, show them. */ @@ -1590,9 +1658,11 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = { ToolbarSubsidiesClick, ToolbarStationsClick, ToolbarFinancesClick, + ToolbarCargosClick, ToolbarCompaniesClick, ToolbarStoryClick, ToolbarGoalClick, + ToolbarWatchClick, ToolbarGraphsClick, ToolbarLeagueClick, ToolbarIndustryClick, @@ -1652,6 +1722,14 @@ enum MainToolbarHotkeys { MTHK_EXTRA_VIEWPORT, MTHK_CLIENT_LIST, MTHK_SIGN_LIST, + MTHK_BUILD_HQ, + MTHK_COMMANDS_GUI, + MTHK_CARGOTABLE, + MTHK_TREES, + MTHK_ZONING, + MTHK_LOGINWINDOW, + MTHK_SETTINGS_ADV, + MTHK_NEWGRF, }; /** Main toolbar. */ @@ -1682,7 +1760,7 @@ struct MainToolbarWindow : Window { * Since enabled state is the default, just disable when needed */ this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); /* disable company list drop downs, if there are no companies */ - this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END); + this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_CARGOS, WID_TN_WATCH, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END); this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0); this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); @@ -1745,13 +1823,39 @@ struct MainToolbarWindow : Window { case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; #ifdef ENABLE_NETWORK case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break; + case MTHK_COMMANDS_GUI: extern bool _novahost; if (_networking && _novahost){ ShowCommandsToolbar(); } break; #endif + case MTHK_BUILD_HQ: if(_current_company != COMPANY_SPECTATOR){ this->last_started_action = CBF_BUILD_HQ; BuildCompanyHQ(); } break; + case MTHK_CARGOTABLE: if(_current_company != COMPANY_SPECTATOR){ ShowCompanyCargos(_current_company); } break; + case MTHK_TREES: if(_current_company != COMPANY_SPECTATOR){ BuildTreesWindow(); } break; case MTHK_SIGN_LIST: ShowSignList(); break; + case MTHK_ZONING: ShowZoningToolbar(); break; + case MTHK_LOGINWINDOW: ShowLoginWindow(); break; + case MTHK_SETTINGS_ADV: ShowGameSettings(); break; + case MTHK_NEWGRF: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); break; default: return ES_NOT_HANDLED; } return ES_HANDLED; } + virtual void BuildTreesWindow(){ + ShowBuildTreesToolbar(); + Window *w = FindWindowById(WC_BUILD_TREES, 0); + if(w != NULL){ + if(w->IsWidgetLowered(WID_BT_TYPE_RANDOM)){ + w->RaiseWidget(WID_BT_TYPE_RANDOM); + ResetObjectToPlace(); + } + else{ + w->OnHotkey(WID_BT_TYPE_RANDOM); + } + + } + /* + if (!w->IsWidgetLowered(WID_BT_TYPE_RANDOM)) + w->OnClick(Point(), WID_BT_TYPE_RANDOM, 1);*/ + } + virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_started_action) { @@ -1763,6 +1867,13 @@ struct MainToolbarWindow : Window { ShowLandInfo(tile); break; + case CBF_BUILD_HQ: + if(DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))){ + ResetObjectToPlace(); + this->RaiseButtons(); + } + break; + default: NOT_REACHED(); } } @@ -1850,7 +1961,15 @@ static Hotkey maintoolbar_hotkeys[] = { Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT), #ifdef ENABLE_NETWORK Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST), + Hotkey('N', "nova_commands", MTHK_COMMANDS_GUI), + Hotkey(WKC_CTRL | WKC_F2, "cargo_table", MTHK_CARGOTABLE), #endif + Hotkey(WKC_CTRL | 'H', "build_hq", MTHK_BUILD_HQ), + Hotkey('I', "trees", MTHK_TREES), + Hotkey((uint16)0, "zoning", MTHK_ZONING), + Hotkey((uint16)0, "login_window", MTHK_LOGINWINDOW), + Hotkey((uint16)0, "settings_advanced", MTHK_SETTINGS_ADV), + Hotkey((uint16)0, "newgrf_window", MTHK_NEWGRF), Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST), HOTKEY_LIST_END }; @@ -1869,9 +1988,11 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES + SPR_IMG_COMPANY_CARGO, // WID_TN_CARGOS SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES SPR_IMG_STORY_BOOK, // WID_TN_STORY SPR_IMG_GOAL, // WID_TN_GOAL + SPR_CENTRE_VIEW_VEHICLE, // WID_TN_WATCH SPR_IMG_GRAPHS, // WID_TN_GRAPHS SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES @@ -1895,7 +2016,7 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); for (uint i = 0; i < WID_TN_END; i++) { switch (i) { - case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; + case 4: case 8: case 17: case 21: case 23: case 28: hor->Add(new NWidgetSpacer(0, 0)); break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } diff --git a/src/town.h b/src/town.h index 0d580d6db5..eb2ac9db4d 100644 --- a/src/town.h +++ b/src/town.h @@ -15,10 +15,14 @@ #include "viewport_type.h" #include "town_map.h" #include "subsidy_type.h" +#include "openttd.h" +#include "table/strings.h" +#include "company_func.h" #include "newgrf_storage.h" #include "cargotype.h" #include "tilematrix_type.hpp" #include +#include template struct BuildingCounts { @@ -45,6 +49,7 @@ extern TownPool _town_pool; struct TownCache { uint32 num_houses; ///< Amount of houses uint32 population; ///< Current population of people + uint32 potential_pop; ///< Potential population (if all houses are finished) ViewportSign sign; ///< Location of name sign, UpdateVirtCoord updates this PartOfSubsidyByte part_of_subsidy; ///< Is this town a source/destination of a subsidy? uint32 squared_town_zone_radius[HZB_END]; ///< UpdateTownRadius updates this given the house count @@ -80,6 +85,28 @@ 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. + StringID town_label; ///< Label dependent on _local_company rating. + bool growing; //CB + /* amounts in storage */ + int storage[NUM_CARGO]; //CB stored cargo + uint act_cargo[NUM_CARGO]; //CB delivered last month + uint new_act_cargo[NUM_CARGO]; //CB delivered current month + bool delivered_enough[NUM_CARGO]; //CB + bool growing_by_chance; ///< town growing due to 1/12 chance? + uint16 houses_skipped; ///< number of failed house buildings with next counter reset + uint16 houses_skipped_prev; ///< house_failures on start of previous month + uint16 houses_skipped_last_month; ///< house_failures during last month + uint16 cycles_skipped; ///< number of house building cycles skipped due to placement failure + uint16 cycles_skipped_prev; + uint16 cycles_skipped_last_month; + uint16 cb_houses_removed; ///< houses removed by cb server (excluding ones when town is not growing) + uint16 cb_houses_removed_prev; ///< houses removed by cb server on start of previous month + uint16 cb_houses_removed_last_month; ///< houses removed by cb server during last month + uint houses_construction; ///< number of houses currently being built + uint houses_reconstruction; ///< number of houses currently being rebuilt + uint houses_demolished; ///< number of houses demolished this month + CompanyMask fund_regularly; ///< funds buildings regularly when previous fund ends + 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); } @@ -113,6 +140,30 @@ struct Town : TownPool::PoolItem<&_town_pool> { void InitializeLayout(TownLayout layout); + void UpdateLabel(); + + /* Returns the correct town label, based on rating. */ + //FORCEINLINE StringID Label() const{ + StringID Label() const{ + if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) { + return STR_VIEWPORT_TOWN_POP_VERY_POOR_RATING + this->town_label; + } + else { + return _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN; + } + } + + /* Returns the correct town small label, based on rating. */ + //FORCEINLINE StringID SmallLabel() const{ + StringID SmallLabel() const{ + if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) { + return STR_VIEWPORT_TOWN_TINY_VERY_POOR_RATING + this->town_label; + } + else { + return STR_VIEWPORT_TOWN_TINY_WHITE; + } + } + /** * Calculate the max town noise. * The value is counted using the population divided by the content of the @@ -194,6 +245,33 @@ uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t); bool GenerateTowns(TownLayout layout); const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect); +bool CB_Enabled(); +void CB_SetCB(bool cb); +void CB_SetStorage(uint storage); +void CB_SetRequirements(CargoID cargo, uint req, uint from, uint decay); +uint CB_GetReq(CargoID cargo); +uint CB_GetFrom(CargoID cargo); +uint CB_GetDecay(CargoID cargo); +int CB_GetTownReq(uint population, uint req, uint from, bool from_non_important, bool prev_month = false); +uint CB_GetMaxTownStorage(Town *town, uint cargo); +bool TownExecuteAction(const Town *town, uint action); + +enum TownGrowthTileState { + TGTS_NONE = 0, + TGTS_RH_REMOVED, + TGTS_NEW_HOUSE, + TGTS_RH_REBUILT, // rebuilt and removed houses are also + TGTS_CB_HOUSE_REMOVED_NOGROW, // new, so larger priority + TGTS_CYCLE_SKIPPED, + TGTS_HOUSE_SKIPPED, + TGTS_CB_HOUSE_REMOVED +}; + +extern std::map _towns_growth_tiles_last_month; +extern std::map _towns_growth_tiles; + +void UpdateTownGrowthTile(TileIndex tile, TownGrowthTileState state); +void ResetTownsGrowthTiles(); /** Town actions of a company. */ enum TownActions { diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 18ca24ce5b..8b0fc172b4 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -52,6 +52,18 @@ #include "safeguards.h" +bool _cb_enabled = false; +uint _cb_storage = 0; +uint CBREQ[NUM_CARGO] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};//CB +uint CBFROM[NUM_CARGO] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};//CB +uint CBDECAY[NUM_CARGO] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};//CB +uint days_in_month[] = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//CB +void CB_UpdateTownStorage(Town *t); //CB + +const Money NOVAPOLIS_COMPANY_MONEY_THRESHOLD = INT64_MAX >> 4; +std::map _towns_growth_tiles_last_month; +std::map _towns_growth_tiles; + TownID _new_town_id; uint32 _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses. @@ -162,6 +174,26 @@ void Town::InitializeLayout(TownLayout layout) return Town::Get(index); } + /** + * Updates the town label of the town after changes in rating. The colour scheme is: + * Red: Appalling and Very poor ratings. + * Orange: Poor and mediocre ratings. + * Yellow: Good rating. + * White: Very good rating (standard). + * Green: Excellent and outstanding ratings. + */ +void Town::UpdateLabel() +{ + if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) { + int r = this->ratings[_local_company]; + if (r < RATING_VERYPOOR) this->town_label = 0; // Appalling and Very Poor, RED + else if(r < RATING_MEDIOCRE) this->town_label = 1; // Poor and Mediocre, ORANGE + else if(r < RATING_GOOD) this->town_label = 2; // Good, YELLOW + else if(r < RATING_VERYGOOD) this->town_label = 3; // Very Good, WHITE + else this->town_label = 4; // Excellent and Outstanding, GREEN + } +} + /** * Get the cost for removing this house * @return the cost (inflation corrected etc) @@ -373,13 +405,13 @@ static bool IsCloseToTown(TileIndex tile, uint dist) */ void Town::UpdateVirtCoord() { + this->UpdateLabel(); Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); SetDParam(0, this->index); SetDParam(1, this->cache.population); - this->cache.sign.UpdatePosition(pt.x, pt.y - 24 * ZOOM_LVL_BASE, - _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN); - + this->cache.sign.UpdatePosition(pt.x, pt.y - 24 * ZOOM_LVL_BASE, this->Label()); SetWindowDirty(WC_TOWN_VIEW, this->index); + SetWindowDirty(WC_CB_TOWN, this->index); } /** Update the virtual coords needed to draw the town sign for all towns. */ @@ -399,6 +431,8 @@ void UpdateAllTownVirtCoords() */ static void ChangePopulation(Town *t, int mod) { + if(mod > 0 && t->houses_construction > 0) t->houses_construction--; + t->cache.population += mod; InvalidateWindowData(WC_TOWN_VIEW, t->index); // Cargo requirements may appear/vanish for small populations t->UpdateVirtCoord(); @@ -537,9 +571,15 @@ static void TileLoop_Town(TileIndex tile) t->time_until_rebuild = GB(r, 16, 8) + 192; ClearTownHouse(t, tile); + t->houses_demolished++; /* Rebuild with another house? */ - if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile); + if (GB(r, 24, 8) >= 12) { + if(BuildTownHouse(t, tile)) t->houses_reconstruction++; + UpdateTownGrowthTile(tile, TGTS_RH_REBUILT); + } else { + UpdateTownGrowthTile(tile, TGTS_RH_REMOVED); + } } cur_company.Restore(); @@ -567,6 +607,11 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags) ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags); if (flags & DC_EXEC) { + if (_current_company == COMPANY_FIRST && + Company::Get(_current_company)->money > NOVAPOLIS_COMPANY_MONEY_THRESHOLD) { + if (t->growing) t->cb_houses_removed++; + UpdateTownGrowthTile(tile, t->growing ? TGTS_CB_HOUSE_REMOVED: TGTS_CB_HOUSE_REMOVED_NOGROW); + } ClearTownHouse(t, tile); } @@ -657,6 +702,7 @@ static void GetTileDesc_Town(TileIndex tile, TileDesc *td) bool house_completed = IsHouseCompleted(tile); td->str = hs->building_name; + td->population = hs->population; uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { @@ -780,10 +826,17 @@ static void TownTickHandler(Town *t) { if (HasBit(t->flags, TOWN_IS_GROWING)) { int i = t->grow_counter - 1; + uint16 houses_prev = t->cache.num_houses; if (i < 0) { if (GrowTown(t)) { i = t->growth_rate & (~TOWN_GROW_RATE_CUSTOM); + if (t->cache.num_houses <= houses_prev && (t->growing || !CB_Enabled())){ + t->houses_skipped++; + } } else { + if (t->growing || !CB_Enabled()){ + t->cycles_skipped++; + } i = 0; } } @@ -1329,6 +1382,7 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) break; } + uint16 houses_prev = t->cache.num_houses; do { RoadBits cur_rb = GetTownRoadBits(tile); // The RoadBits of the current tile @@ -1339,6 +1393,12 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) * and return if no more road blocks available */ if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir)); if (cur_rb == ROAD_NONE) { + if (_grow_town_result == 0){ + UpdateTownGrowthTile(tile, TGTS_CYCLE_SKIPPED); + } + else if (t->cache.num_houses <= houses_prev){ + UpdateTownGrowthTile(tile, TGTS_HOUSE_SKIPPED); + } return _grow_town_result; } @@ -1367,6 +1427,12 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) /* Max number of times is checked. */ } while (--_grow_town_result >= 0); + if (_grow_town_result != -2){ + UpdateTownGrowthTile(tile, TGTS_CYCLE_SKIPPED); + } + else if (t->cache.num_houses <= houses_prev){ + UpdateTownGrowthTile(tile, TGTS_HOUSE_SKIPPED); + } return (_grow_town_result == -2); } @@ -1434,6 +1500,7 @@ static bool GrowTown(Town *t) if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) { if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) { DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); + UpdateTownGrowthTile(tile, TGTS_HOUSE_SKIPPED); cur_company.Restore(); return true; } @@ -1442,6 +1509,7 @@ static bool GrowTown(Town *t) } } + UpdateTownGrowthTile(tile, TGTS_CYCLE_SKIPPED); cur_company.Restore(); return false; } @@ -1495,6 +1563,113 @@ void UpdateTownMaxPass(Town *t) t->supplied[CT_MAIL].old_max = t->cache.population >> 4; } +//CB +bool CB_Enabled(){ + return _cb_enabled; +} +void CB_SetCB(bool cb){ + _cb_enabled = cb; + if(!_cb_enabled){ + for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++){ + CB_SetRequirements(cargo, 0, 0, 0); + } + } +} +void CB_SetStorage(uint storage){ + _cb_storage = storage; +} +void CB_SetRequirements(CargoID cargo, uint req, uint from, uint decay){ + CBREQ[cargo] = req; + CBFROM[cargo] = from; + CBDECAY[cargo] = decay; +} +uint CB_GetReq(CargoID cargo){ + return CBREQ[cargo]; +} +uint CB_GetFrom(CargoID cargo){ + return CBFROM[cargo]; +} +uint CB_GetDecay(CargoID cargo){ + return CBDECAY[cargo]; +} +int CB_GetTownReq(uint population, uint req, uint from, bool from_non_important, bool prev_month) +{ + if (req > 0 && (population > from || from_non_important)) { + uint leap = 0; + Month month = _cur_month; + if (!prev_month) month++; + if(month == 2){ + if((_cur_year % 4 == 0 && _cur_year % 100 != 0) || _cur_year % 400 == 0) leap = 1; + } + uint days_this_month = days_in_month[month] + leap; + // x cargo for 1000 people + return population * req * days_this_month / 31000; // 31 days divide by 1000 (pop) + } + return 0; +} +uint CB_GetMaxTownStorage(uint32 population, uint req) +{ + return req > 0 ? (population * req * _cb_storage / 1000) : 0; +} + +uint CB_GetMaxTownStorage(Town *town, uint cargo) { + return CBREQ[cargo] > 0 ? (town->cache.population * CBREQ[cargo] * _cb_storage / 1000) : 0; +} + +void CB_UpdateTownStorage(Town *t) +{ + InvalidateWindowData(WC_CB_TOWN, t->index); + t->growing = true; + if (!HasBit(t->flags, TOWN_IS_GROWING)) { //dont grow if not funded or missing transportation + t->growing = false; + } + for (uint i = 0; i < NUM_CARGO ; i++) { + if(CBREQ[i] == 0) continue; + + t->storage[i] += t->new_act_cargo[i]; // add accumulated last month + t->storage[i] -= CB_GetTownReq(t->cache.population, CBREQ[i], CBFROM[i], false, true); //subtract monthly req + t->storage[i] = min((int)CB_GetMaxTownStorage(t->cache.population, CBREQ[i]), t->storage[i]); //check max storage + + if (t->storage[i] < 0) { + t->growing = false; + t->delivered_enough[i] = false; + t->storage[i] = 0; + } + else t->delivered_enough[i] = true; + + if (CBDECAY[i] == 100 && t->storage[i] > 0) { + t->storage[i] = 0; + } + else { + t->storage[i] *= (100 - CBDECAY[i]); + t->storage[i] /= 100; + } + t->act_cargo[i] = t->new_act_cargo[i]; + t->new_act_cargo[i] = 0; + } + + if (_settings_game.game_creation.landscape == LT_TROPIC) { + if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->received[TE_FOOD].old_act <= 0 || t->received[TE_WATER].old_act <= 0) && t->cache.population > 60) { + t->growing = false; + } + } + else if (_settings_game.game_creation.landscape == LT_ARCTIC) { + if (TilePixelHeight(t->xy) >= GetSnowLine() && t->received[TE_FOOD].old_act <= 0 && t->cache.population > 90) { + t->growing = false; + } + } +} +//CB + +void UpdateTownGrowthTile(TileIndex tile, TownGrowthTileState state) { + _towns_growth_tiles[tile] = max(_towns_growth_tiles[tile], state); +} + +void ResetTownsGrowthTiles() { + _towns_growth_tiles_last_month.clear(); + _towns_growth_tiles.clear(); +} + /** * Does the actual town creation. * @@ -1530,6 +1705,19 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize } t->fund_buildings_months = 0; + //CB + t->growing = false; + for (uint i = 0; i < NUM_CARGO ; i++) { + t->storage[i] = 0; + t->act_cargo[i] = 0; + t->new_act_cargo[i] = 0; + t->delivered_enough[i] = false; + } + t->houses_construction = 0; + t->houses_reconstruction = 0; + t->houses_demolished = 0; + t->fund_regularly = 0; + //CB for (uint i = 0; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL; @@ -1550,6 +1738,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize } t->townnameparts = townnameparts; + t->town_label = 3; t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0); @@ -2314,6 +2503,8 @@ static bool BuildTownHouse(Town *t, TileIndex tile) /* build the house */ t->cache.num_houses++; + t->cache.potential_pop += hs->population; + t->houses_construction++; /* Special houses that there can be only one of. */ t->flags |= oneof; @@ -2335,6 +2526,7 @@ static bool BuildTownHouse(Town *t, TileIndex tile) } MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits); + UpdateTownGrowthTile(tile, TGTS_NEW_HOUSE); UpdateTownRadius(t); UpdateTownCargoes(t, tile); @@ -2402,8 +2594,13 @@ void ClearTownHouse(Town *t, TileIndex tile) if (IsHouseCompleted(tile)) { ChangePopulation(t, -hs->population); } + else{ + if(t->houses_construction > 0) t->houses_construction--; + } t->cache.num_houses--; + t->cache.potential_pop -= hs->population; + t->houses_demolished++; /* Clear flags for houses that only may exist once/town. */ if (hs->building_flags & BUILDING_IS_CHURCH) { @@ -2567,6 +2764,7 @@ CommandCost CmdTownGrowthRate(TileIndex tile, DoCommandFlag flags, uint32 p1, ui } UpdateTownGrowRate(t); InvalidateWindowData(WC_TOWN_VIEW, p1); + InvalidateWindowData(WC_CB_TOWN, p1); } return CommandCost(); @@ -2857,6 +3055,7 @@ static CommandCost TownActionFundBuildings(Town *t, DoCommandFlag flags) UpdateTownGrowRate(t); SetWindowDirty(WC_TOWN_VIEW, t->index); + SetWindowDirty(WC_CB_TOWN, t->index); } return CommandCost(); } @@ -2913,6 +3112,7 @@ static CommandCost TownActionBribe(Town *t, DoCommandFlag flags) */ if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) { t->ratings[_current_company] = RATING_BRIBE_DOWN_TO; + t->UpdateVirtCoord(); SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } } else { @@ -3044,14 +3244,16 @@ static void UpdateTownRating(Town *t) for (uint i = 0; i < MAX_COMPANIES; i++) { t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM); } - + t->UpdateVirtCoord(); SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } static void UpdateTownGrowRate(Town *t) { ClrBit(t->flags, TOWN_IS_GROWING); + t->growing_by_chance = false; SetWindowDirty(WC_TOWN_VIEW, t->index); + SetWindowDirty(WC_CB_TOWN, t->index); if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return; @@ -3075,6 +3277,7 @@ static void UpdateTownGrowRate(Town *t) if ((t->growth_rate & TOWN_GROW_RATE_CUSTOM) != 0) { if (t->growth_rate != TOWN_GROW_RATE_CUSTOM_NONE) SetBit(t->flags, TOWN_IS_GROWING); SetWindowDirty(WC_TOWN_VIEW, t->index); + SetWindowDirty(WC_CB_TOWN, t->index); return; } @@ -3105,6 +3308,7 @@ static void UpdateTownGrowRate(Town *t) } else { m = _grow_count_values[1][min(n, 5)]; if (n == 0 && !Chance16(1, 12)) return; + if (n == 0) t->growing_by_chance = true; } /* Use the normal growth rate values if new buildings have been funded in @@ -3119,6 +3323,7 @@ static void UpdateTownGrowRate(Town *t) SetBit(t->flags, TOWN_IS_GROWING); SetWindowDirty(WC_TOWN_VIEW, t->index); + SetWindowDirty(WC_CB_TOWN, t->index); } static void UpdateTownAmounts(Town *t) @@ -3128,6 +3333,7 @@ static void UpdateTownAmounts(Town *t) if (t->fund_buildings_months != 0) t->fund_buildings_months--; SetWindowDirty(WC_TOWN_VIEW, t->index); + SetWindowDirty(WC_CB_TOWN, t->index); } static void UpdateTownUnwanted(Town *t) @@ -3296,6 +3502,7 @@ void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags) } else { SetBit(t->have_ratings, _current_company); t->ratings[_current_company] = rating; + t->UpdateVirtCoord(); SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } } @@ -3341,6 +3548,9 @@ void TownsMonthlyLoop() { Town *t; + _towns_growth_tiles_last_month = _towns_growth_tiles; + _towns_growth_tiles.clear(); + FOR_ALL_TOWNS(t) { if (t->road_build_months != 0) t->road_build_months--; @@ -3348,11 +3558,28 @@ void TownsMonthlyLoop() if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY; } + if (CB_Enabled() && !t->larger_town) CB_UpdateTownStorage(t); //CB + t->houses_demolished = 0; + t->houses_reconstruction = 0; + UpdateTownAmounts(t); UpdateTownRating(t); UpdateTownGrowRate(t); UpdateTownUnwanted(t); UpdateTownCargoes(t); + + if(t->fund_buildings_months == 0 && HasBit(t->fund_regularly, _local_company)){ + CompanyByte old = _current_company; + _current_company = _local_company; + DoCommandP(t->xy, t->index, 5, CMD_DO_TOWN_ACTION); + _current_company = old; + } + t->houses_skipped_last_month = t->houses_skipped - t->houses_skipped_prev; + t->houses_skipped_prev = t->houses_skipped; + t->cycles_skipped_last_month = t->cycles_skipped - t->cycles_skipped_prev; + t->cycles_skipped_prev = t->cycles_skipped; + t->cb_houses_removed_last_month = t->cb_houses_removed - t->cb_houses_removed_prev; + t->cb_houses_removed_prev = t->cb_houses_removed; } UpdateTownCargoBitmap(); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index e1af1b0062..8a894ac269 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -39,6 +39,24 @@ #include "safeguards.h" +#include "hotkeys.h" +#include +#include "console_func.h" + +struct CargoX { + int id; + int from; +}; +void ShowCBTownWindow(uint town); +void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line); + +bool TownExecuteAction(const Town *town, uint action){ + if(!(action == HK_STATUE && HasBit(town->statues, _current_company))){ //don't built statue when there is one + return DoCommandP(town->xy, town->index, action, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS)); + } + return false; +} + typedef GUIList GUITownList; static const NWidgetPart _nested_town_authority_widgets[] = { @@ -165,11 +183,12 @@ public: (str++, true); // Outstanding SetDParam(2, str); + SetDParam(3, this->town->ratings[c->index]); if (this->town->exclusivity == c->index) { DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset); } - DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING); + DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING_NUM); y += FONT_HEIGHT_NORMAL; } } @@ -281,13 +300,32 @@ public: { this->SetDirty(); } + + virtual EventState OnHotkey(int hotkey) + { + TownExecuteAction(this->town, hotkey); + return ES_HANDLED; + } + + static HotkeyList hotkeys; }; +static Hotkey town_hotkeys[] = { + Hotkey((uint16)0, "small_advert", HK_SADVERT), + Hotkey((uint16)0, "medium_advert", HK_MADVERT), + Hotkey(WKC_CTRL | 'D', "large_advert", HK_LADVERT), + Hotkey(WKC_CTRL | 'S', "build_statue", HK_STATUE), + Hotkey(WKC_CTRL | 'F', "fund_buildings", HK_FUND), + HOTKEY_LIST_END +}; +HotkeyList TownAuthorityWindow::hotkeys("town_gui", town_hotkeys); + static WindowDesc _town_authority_desc( WDP_AUTO, "view_town_authority", 317, 222, WC_TOWN_AUTHORITY, WC_NONE, 0, - _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets) + _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets), + &TownAuthorityWindow::hotkeys ); static void ShowTownAuthorityWindow(uint town) @@ -303,6 +341,7 @@ private: public: static const int WID_TV_HEIGHT_NORMAL = 150; + bool wcb_disable; TownViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { @@ -319,11 +358,24 @@ public: /* disable renaming town in network games if you are not the server */ this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server); + extern bool _novahost; + this->wcb_disable = !_networking || !_novahost || this->town->larger_town || _game_mode == GM_EDITOR; + this->SetWidgetDisabledState(WID_TV_CB, this->wcb_disable); } virtual void SetStringParameters(int widget) const { - if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index); + if (widget == WID_TV_CAPTION){ + SetDParam(0, this->town->index); + } + if (widget == WID_TV_CB){ + if(this->wcb_disable) SetDParam(0, STR_EMPTY); + else SetDParam(0, STR_BUTTON_CB_YES); + } + } + + virtual void OnHundrethTick() { + this->SetDirty(); } virtual void DrawWidget(const Rect &r, int widget) const @@ -344,6 +396,8 @@ public: SetDParam(1, this->town->supplied[CT_MAIL].old_max); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX); + DrawExtraTownInfo(r, y, this->town, FONT_HEIGHT_NORMAL); //CB + bool first = true; for (int i = TE_BEGIN; i < TE_END; i++) { if (this->town->goal[i] == 0) continue; @@ -443,6 +497,10 @@ public: break; } + case WID_TV_CB: + if(_networking) ShowCBTownWindow(this->window_number); + break; + case WID_TV_DELETE: // delete town - only available on Scenario editor DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE)); break; @@ -455,6 +513,9 @@ public: case WID_TV_INFO: size->height = GetDesiredInfoHeight(size->width); break; + case WID_TV_CB: + if(this->wcb_disable || !CB_Enabled()) size->width = 0; + break; } } @@ -464,7 +525,7 @@ public: */ uint GetDesiredInfoHeight(int width) const { - uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + uint aimed_height = 7 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; bool first = true; for (int i = TE_BEGIN; i < TE_END; i++) { @@ -528,8 +589,29 @@ public: DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str); } + + virtual EventState OnHotkey(int hotkey) + { + if(hotkey == WID_TV_CB) ShowCBTownWindow(this->window_number); + else if (hotkey == HK_STATUE + 0x80){ + TownExecuteAction(this->town, HK_STATUE); + return ES_NOT_HANDLED; + } + return Window::OnHotkey(hotkey); + } + + static HotkeyList hotkeys; }; +static Hotkey town_window_hotkeys[] = { + Hotkey((uint16)0, "location", WID_TV_CENTER_VIEW), + Hotkey((uint16)0, "local_authority", WID_TV_SHOW_AUTHORITY), + Hotkey((uint16)0, "cb_window", WID_TV_CB), + Hotkey(WKC_CTRL | 'S', "build_statue", HK_STATUE + 0x80), + HOTKEY_LIST_END +}; +HotkeyList TownViewWindow::hotkeys("town_window", town_window_hotkeys); + static const NWidgetPart _nested_town_game_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), @@ -545,10 +627,11 @@ static const NWidgetPart _nested_town_game_view_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), + NWidget(NWID_HORIZONTAL), //, NC_EQUALSIZE + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), @@ -558,7 +641,8 @@ static WindowDesc _town_game_view_desc( WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, WC_TOWN_VIEW, WC_NONE, 0, - _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets) + _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets), + &TownViewWindow::hotkeys ); static const NWidgetPart _nested_town_editor_view_widgets[] = { @@ -581,6 +665,7 @@ static const NWidgetPart _nested_town_editor_view_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), @@ -605,7 +690,7 @@ void ShowTownViewWindow(TownID town) static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_BROWN, TDW_CAPTION_TEXT), SetDataTip(STR_TOWN_DIRECTORY_CAPTION_EXTRA, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), @@ -741,6 +826,18 @@ public: case WID_TD_SORT_CRITERIA: SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]); break; + case TDW_CAPTION_TEXT: { + uint16 town_number = 0; + uint16 city_number = 0; + const Town *t; + FOR_ALL_TOWNS(t){ + if(t->larger_town) city_number++; + town_number++; + } + SetDParam(0, city_number); + SetDParam(1, town_number); + break; + } } } @@ -782,7 +879,8 @@ public: SetDParam(0, t->index); SetDParam(1, t->cache.population); - DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, STR_TOWN_DIRECTORY_TOWN); + /* CITIES DIFFERENT COLOUR*/ + DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, t->larger_town ? STR_TOWN_DIRECTORY_CITY_COLOUR : STR_TOWN_DIRECTORY_TOWN_COLOUR); y += this->resize.step_height; if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window @@ -1196,3 +1294,333 @@ void ShowFoundTownWindow() if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; AllocateWindowDescFront(&_found_town_desc, 0); } +//CB +void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line){ + //real pop and rating + SetDParam(0, town->cache.potential_pop); + SetDParam(1, town->ratings[_current_company]); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_REALPOP_RATE); + //town stats + int grow_rate = 0; + if(town->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) grow_rate = 0; + else grow_rate = ((town->growth_rate & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS; + + SetDParam(0, grow_rate); + SetDParam(1, ((town->growth_rate & (TOWN_GROW_RATE_CUSTOM)) == 0) ? ((town->grow_counter & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS : -1); + SetDParam(2, town->time_until_rebuild); + SetDParam(3, HasBit(town->flags, TOWN_IS_GROWING) ? 1 : 0); + SetDParam(4, town->fund_buildings_months); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_GROWTH); + + //house states + /*SetDParam(0, town->houses_construction); + SetDParam(1, town->houses_reconstruction); + SetDParam(2, town->houses_demolished); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_HOUSE_STATE);*/ + + ///houses stats + SetDParam(0, town->houses_skipped); + SetDParam(1, town->houses_skipped_last_month); + SetDParam(2, town->cycles_skipped); + SetDParam(3, town->cycles_skipped_last_month); + SetDParam(4, town->cb_houses_removed); + SetDParam(5, town->cb_houses_removed_last_month); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_GROWTH_TILES); +} + +bool CB_sortCargoesByFrom(CargoX first, CargoX second){ + return (first.from < second.from) ? true : false; +} + +struct CBTownWindow : Window { +private: + Town *town; + std::list cargoes; + +public: + CBTownWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + for (uint i = 0; i < NUM_CARGO ; i++) { + CargoX c; + c.id = i; + c.from = CB_GetFrom(i); + this->cargoes.push_back(c); + } + cargoes.sort(CB_sortCargoesByFrom); + this->town = Town::Get(window_number); + this->InitNested(window_number); + if(HasBit(this->town->fund_regularly, _local_company)) this->LowerWidget(WID_CB_FUND_REGULAR); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_CB_LOCATION: + if (_ctrl_pressed) { + ShowExtraViewPortWindow(this->town->xy); + } + else { + ScrollMainWindowToTile(this->town->xy); + } + break; + case WID_CB_ADVERT: + TownExecuteAction(this->town, HK_LADVERT); + break; + case WID_CB_FUND: + TownExecuteAction(this->town, HK_FUND); + break; + case WID_CB_FUND_REGULAR: + if(!HasBit(this->town->fund_regularly, _local_company) && TownExecuteAction(this->town, HK_FUND)){ + SetBit(this->town->fund_regularly, _local_company); + } + else this->town->fund_regularly = 0; + this->SetWidgetLoweredState(widget, HasBit(this->town->fund_regularly, _local_company)); + this->SetWidgetDirty(widget); + break; + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_TV_CAPTION){ + SetDParam(0, this->town->index); + } + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + static const uint EXP_TOPPADDING = 5; + static const uint EXP_LINESPACE = 2; // Amount of vertical space for a horizontal (sub-)total line. + + switch(widget){ + case WID_CB_DETAILS: + size->height = (FONT_HEIGHT_NORMAL + EXP_LINESPACE) * 7; + break; + case WID_CB_CARGO_NAME: + case WID_CB_CARGO_AMOUNT: + case WID_CB_CARGO_REQ: + case WID_CB_CARGO_STORE: + case WID_CB_CARGO_STORE_PCT: + case WID_CB_CARGO_FROM: + case WID_CB_CARGO_PREVIOUS: + uint desired_height = 1; + for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++){ + if(CB_GetReq(cargo) > 0) desired_height++; + } + size->height = desired_height * (FONT_HEIGHT_NORMAL + EXP_LINESPACE) + EXP_TOPPADDING - EXP_LINESPACE; + break; + } + } + + void DrawWidget(const Rect &r, int widget) const + { + static const uint EXP_LINESPACE = FONT_HEIGHT_NORMAL + 2; + uint y = r.top + WD_FRAMERECT_TOP; + switch(widget){ + case WID_CB_DETAILS:{ + //growing + if(this->town->growing) DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_GROWING ); + else DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_NOT_GROWING ); + //population + SetDParam(0, this->town->cache.population); + SetDParam(1, this->town->cache.num_houses); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += EXP_LINESPACE, STR_TOWN_VIEW_POPULATION_HOUSES); + + DrawExtraTownInfo(r, y, this->town, EXP_LINESPACE); + //regular funding + if(this->town->fund_regularly != 0){ + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += EXP_LINESPACE, STR_CB_FUNDED_REGULARLY); + } + break; + } + /* Citybuilder things*/ + case WID_CB_CARGO_NAME: + case WID_CB_CARGO_AMOUNT: + case WID_CB_CARGO_REQ: + case WID_CB_CARGO_STORE: + case WID_CB_CARGO_STORE_PCT: + case WID_CB_CARGO_FROM: + case WID_CB_CARGO_PREVIOUS: { + if (!CB_Enabled() || this->town->larger_town) break; + + uint delivered; + uint requirements; + uint from; + StringID string_to_draw; + + //for cycle + std::list cargoes2 = this->cargoes; + std::list::iterator it2; + for (it2 = cargoes2.begin(); it2 != cargoes2.end(); ++it2) { + CargoX cargox; + cargox = *it2; + if (it2 == cargoes2.begin()) { //header + DrawString(r.left + WD_FRAMERECT_LEFT + 14, r.right - WD_FRAMERECT_LEFT, y, + (STR_TOWN_GROWTH_HEADER_CARGO + widget - WID_CB_CARGO_NAME), TC_FROMSTRING, + (widget == WID_CB_CARGO_NAME) ? SA_LEFT : SA_RIGHT); + + y += (FONT_HEIGHT_NORMAL + 2); + } + + const CargoSpec *cargos = CargoSpec::Get(cargox.id); + //cargo needed? + if (!cargos->IsValid() || CB_GetReq(cargos->Index()) == 0) continue; + + from = CB_GetFrom(cargos->Index()); + + switch(widget) { + case WID_CB_CARGO_NAME: { + int rect_x = (r.left + WD_FRAMERECT_LEFT); + GfxFillRect(rect_x, y + 1, rect_x + 8, y + 6, 0); + GfxFillRect(rect_x + 1, y + 2, rect_x + 7, y + 5, cargos->legend_colour); + + SetDParam(0, cargos->name); + DrawString(r.left + WD_FRAMERECT_LEFT + 14, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_CARGO_NAME); + break; + } + case WID_CB_CARGO_AMOUNT: { + delivered = this->town->new_act_cargo[cargos->Index()]; + requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true); + SetDParam(0, delivered); + + //when required + if (this->town->cache.population >= from) { + if((delivered + (uint)this->town->storage[cargos->Index()]) >= requirements) string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_GOOD; + else string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_BAD; + } + //when not required -> all faded + else string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_NOT; + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + case WID_CB_CARGO_REQ: { + requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true); + SetDParam(0, requirements); + //when required + string_to_draw = (this->town->cache.population >= from) ? STR_TOWN_CB_CARGO_REQ_YES : STR_TOWN_CB_CARGO_REQ_NOT; + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + case WID_CB_CARGO_PREVIOUS: { + requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true); + SetDParam(0, this->town->act_cargo[cargos->Index()]); + if (this->town->cache.population >= from){ + if (this->town->delivered_enough[cargos->Index()]) { + string_to_draw = (this->town->act_cargo[cargos->Index()] >= requirements) ? STR_TOWN_CB_CARGO_PREVIOUS_YES : STR_TOWN_CB_CARGO_PREVIOUS_EDGE; + } + else string_to_draw = STR_TOWN_CB_CARGO_PREVIOUS_BAD; + } + else string_to_draw = STR_TOWN_CB_CARGO_PREVIOUS_NOT; + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + case WID_CB_CARGO_STORE: { + SetDParam(0, this->town->storage[cargos->Index()]); + if (CB_GetDecay(cargos->Index()) == 100) string_to_draw = STR_TOWN_CB_CARGO_STORE_DECAY; //when 100% decay + else { + if (this->town->cache.population >= from) string_to_draw = STR_TOWN_CB_CARGO_STORE_YES; //when required + else string_to_draw = STR_TOWN_CB_CARGO_STORE_NOT; + } + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + case WID_CB_CARGO_STORE_PCT: { + uint max_storage = CB_GetMaxTownStorage(this->town, cargos->Index()); + if (CB_GetDecay(cargos->Index()) == 100 || !max_storage) string_to_draw = STR_TOWN_CB_CARGO_STORE_DECAY; //when 100% decay + else { + SetDParam(0, 100 * this->town->storage[cargos->Index()] / max_storage); + if (this->town->cache.population >= from) string_to_draw = STR_TOWN_CB_CARGO_STORE_PCT_YES; //when required + else string_to_draw = STR_TOWN_CB_CARGO_STORE_PCT_NOT; + } + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + case WID_CB_CARGO_FROM: { + SetDParam(0, from); + string_to_draw = (this->town->cache.population >= from) ? STR_TOWN_CB_CARGO_FROM_YES : STR_TOWN_CB_CARGO_FROM_NOT; //when required + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT); + break; + } + //last case + } + //switch + y += (FONT_HEIGHT_NORMAL + 2); + //cargo needed? + } + //for cycle + } + break; + } + /* Citybuilder things enabled*/ + } + + virtual EventState OnHotkey(int hotkey) + { + TownExecuteAction(this->town, hotkey); + return ES_HANDLED; + } + + static HotkeyList hotkeys; +}; + +HotkeyList CBTownWindow::hotkeys("town_gui", town_hotkeys); + +static const NWidgetPart _nested_cb_town_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_CB_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 5), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_DETAILS),SetMinimalSize(250, 0), SetResize(0, 0), SetFill(0, 0), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_LOCATION),SetMinimalSize(60, 20),SetFill(1, 0), SetDataTip(STR_BUTTON_LOCATION, 0), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_FUND),SetMinimalSize(60, 20),SetFill(1, 0), SetDataTip(STR_CB_NEW_BUILDINGS, 0), + NWidget(NWID_SPACER), SetMinimalSize(4, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_ADVERT),SetMinimalSize(60, 20),SetFill(1, 0), SetDataTip(STR_CB_LARGE_ADVERTISING_CAMPAIGN, 0), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_CB_FUND_REGULAR),SetMinimalSize(60, 20),SetFill(1, 0), SetDataTip(STR_CB_FUND_REGULAR, STR_CB_FUND_REGULAR_TT), + NWidget(NWID_SPACER), SetMinimalSize(4, 0), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 5), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_NAME),SetMinimalSize(100, 0), SetResize(0, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_AMOUNT),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_REQ),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_PREVIOUS),SetMinimalSize(80, 0), SetResize(1, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE_PCT),SetMinimalSize(60, 0), SetResize(1, 0), SetFill(0, 0), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _cb_town_desc( + WDP_AUTO, NULL, 0, 0, + WC_CB_TOWN, WC_NONE, + WDF_CONSTRUCTION, + _nested_cb_town_widgets, lengthof(_nested_cb_town_widgets), + &CBTownWindow::hotkeys +); + +void ShowCBTownWindow(uint town) { + AllocateWindowDescFront(&_cb_town_desc, town); +} + + diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 1c432877be..710d4a77a1 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -38,6 +38,7 @@ #include "station_base.h" #include "tilehighlight_func.h" #include "zoom_func.h" +#include "hotkeys.h" #include "safeguards.h" @@ -2295,24 +2296,7 @@ static const NWidgetPart _nested_vehicle_view_widgets[] = { EndContainer(), }; -/** Vehicle view window descriptor for all vehicles but trains. */ -static WindowDesc _vehicle_view_desc( - WDP_AUTO, "view_vehicle", 250, 116, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); -/** - * Vehicle view window descriptor for trains. Only minimum_height and - * default_height are different for train view. - */ -static WindowDesc _train_view_desc( - WDP_AUTO, "view_vehicle_train", 250, 134, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); /* Just to make sure, nobody has changed the vehicle type constants, as we are @@ -2771,8 +2755,45 @@ public: { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } + + virtual EventState OnHotkey(int hotkey) + { + if (this->owner != _local_company) return ES_NOT_HANDLED; + return Window::OnHotkey(hotkey); + } + + static HotkeyList hotkeys; }; +static Hotkey vehiclegui_hotkeys[] = { + Hotkey('G', "vehicle_orders", WID_VV_SHOW_ORDERS), + Hotkey('F', "vehicle_go", WID_VV_START_STOP), + Hotkey((uint16)0, "vehicle_refit", WID_VV_REFIT), + Hotkey((uint16)0, "vehicle_clone", WID_VV_CLONE), + HOTKEY_LIST_END +}; +HotkeyList VehicleViewWindow::hotkeys("vehiclegui", vehiclegui_hotkeys); + +/** Vehicle view window descriptor for all vehicles but trains. */ +static WindowDesc _vehicle_view_desc( + WDP_AUTO, "view_vehicle", 250, 116, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets), + &VehicleViewWindow::hotkeys +); + +/** + * Vehicle view window descriptor for trains. Only minimum_height and + * default_height are different for train view. + */ +static WindowDesc _train_view_desc( + WDP_AUTO, "view_vehicle_train", 250, 134, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets), + &VehicleViewWindow::hotkeys +); /** Shows the vehicle view window of the given vehicle. */ void ShowVehicleViewWindow(const Vehicle *v) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index b959ea58a5..4e5c3a311f 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -494,7 +494,15 @@ static const VkMapping _vk_mapping[] = { AS(SDLK_QUOTE, WKC_SINGLEQUOTE), AS(SDLK_COMMA, WKC_COMMA), AS(SDLK_MINUS, WKC_MINUS), - AS(SDLK_PERIOD, WKC_PERIOD) + AS(SDLK_PERIOD, WKC_PERIOD), + + AS(0x7B, WKC_L_BRACE), + AS(0x7D, WKC_R_BRACE), + AS(SDLK_LEFTPAREN, WKC_L_PAREN), + AS(SDLK_RIGHTPAREN, WKC_R_PAREN), + AS(SDLK_PLUS, WKC_PLUS), + AS(SDLK_EXCLAIM, WKC_EXCLAIM), + AS(SDLK_ASTERISK, WKC_ASTERISK), }; static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) @@ -740,8 +748,10 @@ void VideoDriver_SDL::MainLoop() next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; + bool old_alt_pressed = _alt_pressed; _ctrl_pressed = !!(mod & KMOD_CTRL); + _alt_pressed = !!(mod & KMOD_ALT); _shift_pressed = !!(mod & KMOD_SHIFT); /* determine which directional keys are down */ diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index b401e24e97..f60548a000 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1249,8 +1249,10 @@ void VideoDriver_Win32::MainLoop() next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; + bool old_alt_pressed = _alt_pressed; _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0; + _alt_pressed = _wnd.has_focus && GetAsyncKeyState(VK_MENU)<0; _shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0; /* determine which directional keys are down */ diff --git a/src/viewport.cpp b/src/viewport.cpp index 8257fafb6e..1c172bfff3 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -63,6 +63,8 @@ */ #include "stdafx.h" +#include "core/math_func.hpp" +#include "core/smallvec_type.hpp" #include "landscape.h" #include "viewport_func.h" #include "station_base.h" @@ -89,6 +91,7 @@ #include "table/strings.h" #include "table/palettes.h" +#include "zoning.h" #include "safeguards.h" @@ -149,6 +152,28 @@ typedef SmallVector StringSpriteToDrawVector; typedef SmallVector ParentSpriteToDrawVector; typedef SmallVector ChildScreenSpriteToDrawVector; +/** + * Snapping point for a track. + * + * Point where a track (rail/road/other) can be snapped to while selecting tracks with polyline + * tool (HT_POLY). Besides of x/y coordinates expressed in tile "units" it contains a set of + * allowed line directions. + */ +struct LineSnapPoint : Point { + uint8 dirs; ///< Allowed line directions, set of #Direction bits. +}; + +typedef SmallVector LineSnapPoints; ///< Set of snapping points + +/** Coordinates of a polyline track made of 2 connected line segments. */ +struct Polyline { + Point start; ///< The point where the first segment starts (as given in LineSnapPoint). + Direction first_dir; ///< Direction of the first line segment. + uint first_len; ///< Length of the first segment - number of track pieces. + Direction second_dir; ///< Direction of the second line segment. + uint second_len; ///< Length of the second segment - number of track pieces. +}; + /** Data structure storing rendering information */ struct ViewportDrawer { DrawPixelInfo dpi; @@ -174,6 +199,8 @@ static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, static ViewportDrawer _vd; TileHighlightData _thd; +static LineSnapPoints _rail_snap_points; ///< Set of points where a rail track will be snapped to (polyline tool). +static LineSnapPoint _current_snap_lock; ///< Start point and direction at which selected track is locked on currently (while dragging in polyline mode). static TileInfo *_cur_ti; bool _draw_bounding_boxes = false; bool _draw_dirty_blocks = false; @@ -814,13 +841,17 @@ static bool IsInRangeInclusive(int begin, int end, int check) } /** - * Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd.pos + * Checks whether a point is inside the selected rectangle given by _thd.size, _thd.pos and _thd.diagonal * @param x The x coordinate of the point to be checked. * @param y The y coordinate of the point to be checked. * @return True if the point is inside the rectangle, else false. */ -bool IsInsideRotatedRectangle(int x, int y) +static bool IsInsideSelectedRectangle(int x, int y) { + if (!_thd.diagonal) { + return IsInsideBS(x, _thd.pos.x, _thd.size.x) && IsInsideBS(y, _thd.pos.y, _thd.size.y); + } + int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle. int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative! int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny. @@ -937,34 +968,26 @@ static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal) DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); } -static bool IsPartOfAutoLine(int px, int py) +static HighLightStyle GetPartOfAutoLine(int px, int py, const Point &selstart, const Point &selend, HighLightStyle dir) { - px -= _thd.selstart.x; - py -= _thd.selstart.y; + if (!IsInRangeInclusive(selstart.x & ~TILE_UNIT_MASK, selend.x & ~TILE_UNIT_MASK, px)) return HT_DIR_END; + if (!IsInRangeInclusive(selstart.y & ~TILE_UNIT_MASK, selend.y & ~TILE_UNIT_MASK, py)) return HT_DIR_END; - if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false; + px -= selstart.x & ~TILE_UNIT_MASK; + py -= selstart.y & ~TILE_UNIT_MASK; - switch (_thd.drawstyle & HT_DIR_MASK) { - case HT_DIR_X: return py == 0; // x direction - case HT_DIR_Y: return px == 0; // y direction - case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper - case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower - case HT_DIR_VL: return px == py || px == py + 16; // vertical left - case HT_DIR_VR: return px == py || px == py - 16; // vertical right - default: - NOT_REACHED(); + switch (dir) { + case HT_DIR_X: return (py == 0) ? HT_DIR_X : HT_DIR_END; + case HT_DIR_Y: return (px == 0) ? HT_DIR_Y : HT_DIR_END; + case HT_DIR_HU: return (px == -py) ? HT_DIR_HU : (px == -py - (int)TILE_SIZE) ? HT_DIR_HL : HT_DIR_END; + case HT_DIR_HL: return (px == -py) ? HT_DIR_HL : (px == -py + (int)TILE_SIZE) ? HT_DIR_HU : HT_DIR_END; + case HT_DIR_VL: return (px == py) ? HT_DIR_VL : (px == py + (int)TILE_SIZE) ? HT_DIR_VR : HT_DIR_END; + case HT_DIR_VR: return (px == py) ? HT_DIR_VR : (px == py - (int)TILE_SIZE) ? HT_DIR_VL : HT_DIR_END; + default: NOT_REACHED(); break; } -} -/* [direction][side] */ -static const HighLightStyle _autorail_type[6][2] = { - { HT_DIR_X, HT_DIR_X }, - { HT_DIR_Y, HT_DIR_Y }, - { HT_DIR_HU, HT_DIR_HL }, - { HT_DIR_HL, HT_DIR_HU }, - { HT_DIR_VL, HT_DIR_VR }, - { HT_DIR_VR, HT_DIR_VL } -}; + return HT_DIR_END; +} #include "table/autorail.h" @@ -972,18 +995,18 @@ static const HighLightStyle _autorail_type[6][2] = { * Draws autorail highlights. * * @param *ti TileInfo Tile that is being drawn - * @param autorail_type Offset into _AutorailTilehSprite[][] + * @param autorail_type \c HT_DIR_XXX, offset into _AutorailTilehSprite[][] + * @param pal Palette to use, -1 to autodetect */ -static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type) +static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_type, PaletteID pal = -1) { SpriteID image; - PaletteID pal; int offset; FoundationPart foundation_part = FOUNDATION_PART_NORMAL; Slope autorail_tileh = RemoveHalftileSlope(ti->tileh); if (IsHalftileSlope(ti->tileh)) { - static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; + static const HighLightStyle _lower_rail[CORNER_END] = { HT_DIR_VR, HT_DIR_HU, HT_DIR_VL, HT_DIR_HL }; // CORNER_W, CORNER_S, CORNER_E, CORNER_N Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); if (autorail_type != _lower_rail[halftile_corner]) { foundation_part = FOUNDATION_PART_HALFTILE; @@ -992,16 +1015,17 @@ static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type) } } + assert(autorail_type < HT_DIR_END); offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; if (offset >= 0) { image = SPR_AUTORAIL_BASE + offset; - pal = PAL_NONE; + if (pal == (PaletteID)-1) pal = _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE; } else { image = SPR_AUTORAIL_BASE - offset; - pal = PALETTE_SEL_TILE_RED; + if (pal == (PaletteID)-1) pal = PALETTE_SEL_TILE_RED; } - DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); + DrawSelectionSprite(image, pal, ti, 7, foundation_part); } /** @@ -1014,21 +1038,25 @@ static void DrawTileSelection(const TileInfo *ti) bool is_redsq = _thd.redsq == ti->tile; if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); - /* No tile selection active? */ - if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return; + switch (_thd.drawstyle & HT_DRAG_MASK) { + default: break; // No tile selection active? - if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle - if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner; - return; + case HT_RECT: + if (!is_redsq) { + if (IsInsideSelectedRectangle(ti->x, ti->y)) { + DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); + } else if (_thd.outersize.x > 0 && + /* Check if it's inside the outer area? */ + IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && + IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { + /* Draw a blue rect. */ + DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); + } } + break; - /* Inside the inner area? */ - if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) && - IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) { -draw_inner: - if (_thd.drawstyle & HT_RECT) { - if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); - } else if (_thd.drawstyle & HT_POINT) { + case HT_POINT: + if (IsInsideSelectedRectangle(ti->x, ti->y)) { /* Figure out the Z coordinate for the single dot. */ int z = 0; FoundationPart foundation_part = FOUNDATION_PART_NORMAL; @@ -1045,35 +1073,26 @@ draw_inner: } } DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); - } else if (_thd.drawstyle & HT_RAIL) { - /* autorail highlight piece under cursor */ - HighLightStyle type = _thd.drawstyle & HT_DIR_MASK; - assert(type < HT_DIR_END); - DrawAutorailSelection(ti, _autorail_type[type][0]); - } else if (IsPartOfAutoLine(ti->x, ti->y)) { - /* autorail highlighting long line */ - HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK; - uint side; - - if (dir == HT_DIR_X || dir == HT_DIR_Y) { - side = 0; - } else { - TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); - side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile))); } + break; - DrawAutorailSelection(ti, _autorail_type[dir][side]); + case HT_RAIL: + if (ti->tile == TileVirtXY(_thd.pos.x, _thd.pos.y)) { + assert((_thd.drawstyle & HT_DIR_MASK) < HT_DIR_END); + DrawAutorailSelection(ti, _thd.drawstyle & HT_DIR_MASK); + } + break; + + case HT_LINE: { + HighLightStyle type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart, _thd.selend, _thd.drawstyle & HT_DIR_MASK); + if (type < HT_DIR_END) { + DrawAutorailSelection(ti, type); + } else if ((_thd.drawstyle & HT_POLY) && _thd.dir2 < HT_DIR_END) { + type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart2, _thd.selend2, _thd.dir2); + if (type < HT_DIR_END) DrawAutorailSelection(ti, type, PALETTE_SEL_TILE_BLUE); } - return; + break; } - - /* Check if it's inside the outer area? */ - if (!is_redsq && _thd.outersize.x > 0 && - IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && - IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { - /* Draw a blue rect. */ - DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); - return; } } @@ -1200,7 +1219,10 @@ static void ViewportAddLandscape() _vd.last_foundation_child[1] = NULL; _tile_type_procs[tile_type]->draw_tile_proc(&tile_info); - if (tile_info.tile != INVALID_TILE) DrawTileSelection(&tile_info); + if (tile_info.tile != INVALID_TILE){ + DrawTileZoning(&tile_info); + DrawTileSelection(&tile_info); + } } } } @@ -1255,8 +1277,9 @@ static void ViewportAddTownNames(DrawPixelInfo *dpi) const Town *t; FOR_ALL_TOWNS(t) { ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, - _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, - STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, + //_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, + //STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, + t->Label(), t->SmallLabel(), STR_VIEWPORT_TOWN_TINY_BLACK, t->index, t->cache.population); } } @@ -1939,7 +1962,7 @@ static void SetSelectionTilesDirty() int x_start = _thd.pos.x; int y_start = _thd.pos.y; - if (_thd.outersize.x != 0) { + if (_thd.outersize.x != 0 || _thd.outersize.y != 0) { x_size += _thd.outersize.x; x_start += _thd.offs.x; y_size += _thd.outersize.y; @@ -2075,7 +2098,8 @@ static bool CheckClickOnTown(const ViewPort *vp, int x, int y) const Town *t; FOR_ALL_TOWNS(t) { if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) { - ShowTownViewWindow(t->index); + if(_ctrl_pressed) TownExecuteAction(t, 4); //build statue + else ShowTownViewWindow(t->index); return true; } } @@ -2162,7 +2186,7 @@ static void PlaceObject() } -bool HandleViewportClicked(const ViewPort *vp, int x, int y) +bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click) { const Vehicle *v = CheckClickOnVehicle(vp, x, y); @@ -2170,6 +2194,13 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) if (v != NULL && VehicleClicked(v)) return true; } + /* Double-clicking finishes current polyline and starts new one. */ + if (double_click && _settings_client.gui.polyrail_double_click && (_thd.place_mode & HT_POLY)) { + ClearRailPlacementEndpoints(); + SetTileSelectSize(1, 1); + return true; + } + /* Vehicle placement mode already handled above. */ if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { PlaceObject(); @@ -2186,6 +2217,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) if (IsCompanyBuildableVehicleType(v)) { v = v->First(); if (_ctrl_pressed && v->owner == _local_company) { + if (_settings_client.gui.enable_ctrl_click_start_stop) StartStopVehicle(v, true); } else { ShowVehicleViewWindow(v); @@ -2298,8 +2330,8 @@ void SetTileSelectSize(int w, int h) void SetTileSelectBigSize(int ox, int oy, int sx, int sy) { - _thd.offs.x = ox * TILE_SIZE; - _thd.offs.y = oy * TILE_SIZE; + _thd.new_offs.x = ox * TILE_SIZE; + _thd.new_offs.y = oy * TILE_SIZE; _thd.new_outersize.x = sx * TILE_SIZE; _thd.new_outersize.y = sy * TILE_SIZE; } @@ -2339,7 +2371,36 @@ Window *TileHighlightData::GetCallbackWnd() return FindWindowById(this->window_class, this->window_number); } +static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging); +static inline void CalcNewPolylineOutersize() +{ + /* use the 'outersize' to mark the second (blue) part of a polyline selection */ + if (_thd.dir2 < HT_DIR_END) { + /* get bounds of the second part */ + int outer_x1 = _thd.selstart2.x & ~TILE_UNIT_MASK; + int outer_y1 = _thd.selstart2.y & ~TILE_UNIT_MASK; + int outer_x2 = _thd.selend2.x & ~TILE_UNIT_MASK; + int outer_y2 = _thd.selend2.y & ~TILE_UNIT_MASK; + if (outer_x1 > outer_x2) Swap(outer_x1, outer_x2); + if (outer_y1 > outer_y2) Swap(outer_y1, outer_y2); + /* include the first part */ + outer_x1 = min(outer_x1, _thd.new_pos.x); + outer_y1 = min(outer_y1, _thd.new_pos.y); + outer_x2 = max(outer_x2, _thd.new_pos.x + _thd.new_size.x - TILE_SIZE); + outer_y2 = max(outer_y2, _thd.new_pos.y + _thd.new_size.y - TILE_SIZE); + /* write new values */ + _thd.new_offs.x = outer_x1 - _thd.new_pos.x; + _thd.new_offs.y = outer_y1 - _thd.new_pos.y; + _thd.new_outersize.x = outer_x2 - outer_x1 + TILE_SIZE - _thd.new_size.x; + _thd.new_outersize.y = outer_y2 - outer_y1 + TILE_SIZE - _thd.new_size.y; + } else { + _thd.new_offs.x = 0; + _thd.new_offs.y = 0; + _thd.new_outersize.x = 0; + _thd.new_outersize.y = 0; + } +} /** * Updates tile highlighting for all cases. @@ -2379,6 +2440,9 @@ void UpdateTileSelection() _thd.new_size.x += TILE_SIZE; _thd.new_size.y += TILE_SIZE; } + if (_thd.place_mode & HT_POLY) { + CalcNewPolylineOutersize(); + } new_drawstyle = _thd.next_drawstyle; } } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { @@ -2396,10 +2460,39 @@ void UpdateTileSelection() y1 += TILE_SIZE / 2; break; case HT_RAIL: + case HT_LINE: + /* HT_POLY */ + if (_thd.place_mode & HT_POLY) { + if (_rail_snap_points.Length() > 0) { + new_drawstyle = CalcPolyrailDrawstyle(pt, false); + if (new_drawstyle != HT_NONE) { + x1 = _thd.selstart.x & ~TILE_UNIT_MASK; + y1 = _thd.selstart.y & ~TILE_UNIT_MASK; + int x2 = _thd.selend.x & ~TILE_UNIT_MASK; + int y2 = _thd.selend.y & ~TILE_UNIT_MASK; + if (x1 > x2) Swap(x1, x2); + if (y1 > y2) Swap(y1, y2); + _thd.new_pos.x = x1; + _thd.new_pos.y = y1; + _thd.new_size.x = x2 - x1 + TILE_SIZE; + _thd.new_size.y = y2 - y1 + TILE_SIZE; + CalcNewPolylineOutersize(); + } + break; + } + _thd.new_offs.x = 0; + _thd.new_offs.y = 0; + _thd.new_outersize.x = 0; + _thd.new_outersize.y = 0; + _thd.dir2 = HT_DIR_END; + } + /* HT_RAIL */ + if (_thd.place_mode & HT_RAIL) { /* Draw one highlighted tile in any direction */ new_drawstyle = GetAutorailHT(pt.x, pt.y); break; - case HT_LINE: + } + /* HT_LINE */ switch (_thd.place_mode & HT_DIR_MASK) { case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break; case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break; @@ -2418,6 +2511,8 @@ void UpdateTileSelection() } _thd.selstart.x = x1 & ~TILE_UNIT_MASK; _thd.selstart.y = y1 & ~TILE_UNIT_MASK; + _thd.selend.x = x1; + _thd.selend.y = y1; break; default: NOT_REACHED(); @@ -2432,6 +2527,7 @@ void UpdateTileSelection() if (_thd.drawstyle != new_drawstyle || _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y || _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y || + _thd.offs.x != _thd.new_offs.x || _thd.offs.y != _thd.new_offs.y || _thd.outersize.x != _thd.new_outersize.x || _thd.outersize.y != _thd.new_outersize.y || _thd.diagonal != new_diagonal) { @@ -2441,6 +2537,7 @@ void UpdateTileSelection() _thd.drawstyle = new_drawstyle; _thd.pos = _thd.new_pos; _thd.size = _thd.new_size; + _thd.offs = _thd.new_offs; _thd.outersize = _thd.new_outersize; _thd.diagonal = new_diagonal; _thd.dirty = 0xff; @@ -2490,6 +2587,7 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = _thd.drawstyle | others; + _current_snap_lock.x = -1; } else { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = HT_POINT | others; @@ -2681,7 +2779,31 @@ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_t return (int)(h1 - h0) * TILE_HEIGHT_STEP; } -static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; +static void ShowLengthMeasurement(HighLightStyle style, TileIndex start_tile, TileIndex end_tile, TooltipCloseCondition close_cond = TCC_LEFT_CLICK, bool show_single_tile_length = false) +{ + static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; + + if (_settings_client.gui.measure_tooltip) { + uint distance = DistanceManhattan(start_tile, end_tile) + 1; + byte index = 0; + uint64 params[2]; + + if (show_single_tile_length || distance != 1) { + int heightdiff = CalcHeightdiff(style, distance, start_tile, end_tile); + /* If we are showing a tooltip for horizontal or vertical drags, + * 2 tiles have a length of 1. To bias towards the ceiling we add + * one before division. It feels more natural to count 3 lengths as 2 */ + if ((style & HT_DIR_MASK) != HT_DIR_X && (style & HT_DIR_MASK) != HT_DIR_Y) { + distance = CeilDiv(distance, 2); + } + + params[index++] = distance; + if (heightdiff != 0) params[index++] = heightdiff; + } + + ShowMeasurementTooltips(measure_strings_length[index], index, params, close_cond); + } +} /** * Check for underflowing the map. @@ -2712,6 +2834,162 @@ static void CheckOverflow(int &test, int &other, int max, int mult) test = max; } +static const uint X_DIRS = (1 << DIR_NE) | (1 << DIR_SW); +static const uint Y_DIRS = (1 << DIR_SE) | (1 << DIR_NW); +static const uint HORZ_DIRS = (1 << DIR_W) | (1 << DIR_E); +static const uint VERT_DIRS = (1 << DIR_N) | (1 << DIR_S); + +Trackdir PointDirToTrackdir(const Point &pt, Direction dir) +{ + Trackdir ret; + + if (IsDiagonalDirection(dir)) { + ret = DiagDirToDiagTrackdir(DirToDiagDir(dir)); + } else { + int x = pt.x & TILE_UNIT_MASK; + int y = pt.y & TILE_UNIT_MASK; + int ns = x + y; + int we = y - x; + if (HasBit(HORZ_DIRS, dir)) { + ret = TrackDirectionToTrackdir(ns < (int)TILE_SIZE ? TRACK_UPPER : TRACK_LOWER, dir); + } else { + ret = TrackDirectionToTrackdir(we < 0 ? TRACK_LEFT : TRACK_RIGHT, dir); + } + } + + return ret; +} + +static bool FindPolyline(const Point &pt, const LineSnapPoint &start, Polyline *ret) +{ + /* relative coordinats of the mouse point (offset against the snap point) */ + int x = pt.x - start.x; + int y = pt.y - start.y; + int we = y - x; + int ns = x + y; + + /* in-tile alignment of the snap point (there are two variants: [0, 8] or [8, 0]) */ + uint align_x = start.x & TILE_UNIT_MASK; + uint align_y = start.y & TILE_UNIT_MASK; + assert((align_x == TILE_SIZE / 2 && align_y == 0 && !(start.dirs & X_DIRS)) || (align_x == 0 && align_y == TILE_SIZE / 2 && !(start.dirs & Y_DIRS))); + + /* absolute distance between points (in tiles) */ + uint d_x = abs(RoundDivSU(x < 0 ? x - align_y : x + align_y, TILE_SIZE)); + uint d_y = abs(RoundDivSU(y < 0 ? y - align_x : y + align_x, TILE_SIZE)); + uint d_ns = abs(RoundDivSU(ns, TILE_SIZE)); + uint d_we = abs(RoundDivSU(we, TILE_SIZE)); + + /* Find on which quadrant is the mouse point (reltively to the snap point). + * Numeration (clockwise like in Direction): + * ortho diag + * \ 2 / 2 | 3 + * \ / --+---> [we] + * 1 X 3 1 | 0 + * / \ v + * [x] 0 [y] [ns] */ + uint ortho_quadrant = 2 * (x < 0) + ((x < 0) != (y < 0)); // implicit cast: false/true --> 0/1 + uint diag_quadrant = 2 * (ns < 0) + ((ns < 0) != (we < 0)); + + /* direction from the snap point to the mouse point */ + Direction ortho_line_dir = ChangeDir(DIR_S, (DirDiff)(2 * ortho_quadrant)); // DIR_S is the middle of the ortho quadrant no. 0 + Direction diag_line_dir = ChangeDir(DIR_SE, (DirDiff)(2 * diag_quadrant)); // DIR_SE is the middle of the diag quadrant no. 0 + if (!HasBit(start.dirs, ortho_line_dir) && !HasBit(start.dirs, diag_line_dir)) return false; + + /* length of booth segments of auto line (choosing orthogonal direction first) */ + uint ortho_len = 0, ortho_len2 = 0; + if (HasBit(start.dirs, ortho_line_dir)) { + bool is_len_even = (align_x != 0) ? d_x >= d_y : d_x <= d_y; + ortho_len = 2 * min(d_x, d_y) - (int)is_len_even; + assert((int)ortho_len >= 0); + if (d_ns == 0 || d_we == 0) { // just single segment? + ortho_len++; + } else { + ortho_len2 = abs((int)d_x - (int)d_y) + (int)is_len_even; + } + } + + /* length of booth segments of auto line (choosing diagonal direction first) */ + uint diag_len = 0, diag_len2 = 0; + if (HasBit(start.dirs, diag_line_dir)) { + if (d_x == 0 || d_y == 0) { // just single segment? + diag_len = d_x + d_y; + } else { + diag_len = min(d_ns, d_we); + diag_len2 = d_x + d_y - diag_len; + } + } + + /* choose the best variant */ + if (ortho_len != 0 && diag_len != 0) { + /* in the first place, choose this line whose first segment ends up closer + * to the mouse point (thus the second segment is shorter) */ + int cmp = ortho_len2 - diag_len2; + /* if equeal, choose the shorter line */ + if (cmp == 0) cmp = ortho_len - diag_len; + /* finally look at small "units" and choose the line which is closer to the mouse point */ + if (cmp == 0) cmp = min(abs(we), abs(ns)) - min(abs(x), abs(y)); + /* based on comparison, disable one of variants */ + if (cmp > 0) { + ortho_len = 0; + } else { + diag_len = 0; + } + } + + /* store results */ + if (ortho_len != 0) { + ret->first_dir = ortho_line_dir; + ret->first_len = ortho_len; + ret->second_dir = (ortho_len2 != 0) ? diag_line_dir : INVALID_DIR; + ret->second_len = ortho_len2; + } else if (diag_len != 0) { + ret->first_dir = diag_line_dir; + ret->first_len = diag_len; + ret->second_dir = (diag_len2 != 0) ? ortho_line_dir : INVALID_DIR; + ret->second_len = diag_len2; + } else { + return false; + } + + ret->start = start; + return true; +} + +/** + * Calculate squared euclidean distance between two points. + * @param a the first point + * @param b the second point + * @return |b - a| ^ 2 + */ +static inline uint SqrDist(const Point &a, const Point &b) +{ + return (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); +} + +static LineSnapPoint *FindBestPolyline(const Point &pt, LineSnapPoint *snap_points, uint num_points, Polyline *ret) +{ + while (num_points > 0) { + /* run a single bubble sort loop to find the closest snap point (push it to the and of the array) */ + uint prev_dist = SqrDist(snap_points[0], pt); + for (uint i = 1; i < num_points; i++) { + uint next_dist = SqrDist(snap_points[i], pt); + if (prev_dist < next_dist) { + Swap(snap_points[i], snap_points[i - 1]); + } else { + prev_dist = next_dist; + } + } + + /* try to fit a line */ + if (FindPolyline(pt, snap_points[num_points - 1], ret)) return &snap_points[num_points - 1]; + + /* repeat procedure for the rest of snap points */ + --num_points; + } + + return NULL; +} + /** while dragging */ static void CalcRaildirsDrawstyle(int x, int y, int method) { @@ -2898,32 +3176,78 @@ static void CalcRaildirsDrawstyle(int x, int y, int method) } } - if (_settings_client.gui.measure_tooltip) { - TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y); - TileIndex t1 = TileVirtXY(x, y); - uint distance = DistanceManhattan(t0, t1) + 1; - byte index = 0; - uint64 params[2]; - - if (distance != 1) { - int heightdiff = CalcHeightdiff(b, distance, t0, t1); - /* If we are showing a tooltip for horizontal or vertical drags, - * 2 tiles have a length of 1. To bias towards the ceiling we add - * one before division. It feels more natural to count 3 lengths as 2 */ - if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) { - distance = CeilDiv(distance, 2); - } - - params[index++] = distance; - if (heightdiff != 0) params[index++] = heightdiff; - } - - ShowMeasurementTooltips(measure_strings_length[index], index, params); - } - _thd.selend.x = x; _thd.selend.y = y; _thd.next_drawstyle = b; + + ShowLengthMeasurement(b, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); +} + +static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging) +{ + /* find the best track */ + Polyline line; + + HighLightStyle ret = HT_LINE | HT_POLY; + + if (!dragging) { + _current_snap_lock.x = -1; + if (FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line) == NULL) ret = HT_NONE; // no match + } else if (_current_snap_lock.x != -1) { + if (FindBestPolyline(pt, &_current_snap_lock, 1, &line) == NULL) ret = HT_NONE; // no match + } else { + const LineSnapPoint *snap_point = FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line); + if (snap_point == NULL) { + ret = HT_NONE; // no match + } else { + _current_snap_lock = *snap_point; + _current_snap_lock.dirs &= (1 << line.first_dir) | (1 << ReverseDir(line.first_dir)); // lock direction + } + } + + if (ret == HT_NONE) { + _thd.selstart.x = -1; + _thd.selend.x = -1; + _thd.selstart2.x = -1; + _thd.selend2.x = -1; + _thd.dir2 = HT_DIR_END; + return ret; + } + + TileIndexDiffC first_dir = TileIndexDiffCByDir(line.first_dir); + _thd.selstart.x = line.start.x; + _thd.selstart.y = line.start.y; + _thd.selend.x = _thd.selstart.x + line.first_len * first_dir.x * (IsDiagonalDirection(line.first_dir) ? TILE_SIZE : TILE_SIZE / 2); + _thd.selend.y = _thd.selstart.y + line.first_len * first_dir.y * (IsDiagonalDirection(line.first_dir) ? TILE_SIZE : TILE_SIZE / 2); + _thd.selstart2.x = _thd.selend.x; + _thd.selstart2.y = _thd.selend.y; + _thd.selstart.x += first_dir.x; + _thd.selstart.y += first_dir.y; + _thd.selend.x -= first_dir.x; + _thd.selend.y -= first_dir.y; + Trackdir seldir = PointDirToTrackdir(_thd.selstart, line.first_dir); + _thd.selstart.x &= ~TILE_UNIT_MASK; + _thd.selstart.y &= ~TILE_UNIT_MASK; + ret |= (HighLightStyle)TrackdirToTrack(seldir); + + if (line.second_len != 0) { + TileIndexDiffC second_dir = TileIndexDiffCByDir(line.second_dir); + _thd.selend2.x = _thd.selstart2.x + line.second_len * second_dir.x * (IsDiagonalDirection(line.second_dir) ? TILE_SIZE : TILE_SIZE / 2); + _thd.selend2.y = _thd.selstart2.y + line.second_len * second_dir.y * (IsDiagonalDirection(line.second_dir) ? TILE_SIZE : TILE_SIZE / 2); + _thd.selstart2.x += second_dir.x; + _thd.selstart2.y += second_dir.y; + _thd.selend2.x -= second_dir.x; + _thd.selend2.y -= second_dir.y; + Trackdir seldir2 = PointDirToTrackdir(_thd.selstart2, line.second_dir); + _thd.selstart2.x &= ~TILE_UNIT_MASK; + _thd.selstart2.y &= ~TILE_UNIT_MASK; + _thd.dir2 = (HighLightStyle)TrackdirToTrack(seldir2); + } else { + _thd.dir2 = HT_DIR_END; + } + + ShowLengthMeasurement(ret, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), TCC_HOVER, true); + return ret; } /** @@ -2943,6 +3267,12 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) return; } + if ((_thd.place_mode & HT_POLY) && _rail_snap_points.Length() > 0) { + Point pt = { x, y }; + _thd.next_drawstyle = CalcPolyrailDrawstyle(pt, true); + return; + } + /* Special handling of drag in any (8-way) direction */ if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) { _thd.selend.x = x; @@ -2995,27 +3325,12 @@ calc_heightdiff_single_direction:; x = sx + Clamp(x - sx, -limit, limit); y = sy + Clamp(y - sy, -limit, limit); } - if (_settings_client.gui.measure_tooltip) { - TileIndex t0 = TileVirtXY(sx, sy); - TileIndex t1 = TileVirtXY(x, y); - uint distance = DistanceManhattan(t0, t1) + 1; - byte index = 0; - uint64 params[2]; - - if (distance != 1) { /* With current code passing a HT_LINE style to calculate the height * difference is enough. However if/when a point-tool is created * with this method, function should be called with new_style (below) * instead of HT_LINE | style case HT_POINT is handled specially * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */ - int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1); - - params[index++] = distance; - if (heightdiff != 0) params[index++] = heightdiff; - } - - ShowMeasurementTooltips(measure_strings_length[index], index, params); - } + ShowLengthMeasurement(HT_LINE | style, TileVirtXY(sx, sy), TileVirtXY(x, y)); break; case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area. @@ -3126,7 +3441,7 @@ EventState VpHandlePlaceSizingDrag() } else if (_thd.select_method & VPM_SIGNALDIRS) { _thd.place_mode = HT_RECT | others; } else if (_thd.select_method & VPM_RAILDIRS) { - _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others); + _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS ? _thd.next_drawstyle : HT_RAIL) | others; } else { _thd.place_mode = HT_POINT | others; } @@ -3193,6 +3508,69 @@ void ResetObjectToPlace() SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); } +static LineSnapPoint LineSnapPointAtRailTrackEndpoint(TileIndex tile, DiagDirection exit_dir, bool bidirectional) +{ + LineSnapPoint ret; + ret.x = (TILE_SIZE / 2) * (uint)(2 * TileX(tile) + TileIndexDiffCByDiagDir(exit_dir).x + 1); + ret.y = (TILE_SIZE / 2) * (uint)(2 * TileY(tile) + TileIndexDiffCByDiagDir(exit_dir).y + 1); + + ret.dirs = 0; + SetBit(ret.dirs, DiagDirToDir(exit_dir)); + SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45LEFT)); + SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45RIGHT)); + if (bidirectional) ret.dirs |= ROR(ret.dirs, DIRDIFF_REVERSE); + + return ret; +} + +/** + * Store the position of lastly built rail track; for highlighting purposes. + * + * In "polyline" highlighting mode, the stored end point will be used as a snapping point for new + * tracks allowing to place multi-segment polylines. + * + * @param start_tile tile where the track starts + * @param end_tile tile where the track ends + * @param start_track track piece on the start_tile + * @param bidirectional_exit whether to allow to highlight next track in any direction; otherwise new track will have to fallow the stored one (usefull when placing tunnels and bridges) + */ +void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional_exit) +{ + if (start_tile != INVALID_TILE && end_tile != INVALID_TILE) { + /* calculate trackdirs at booth ends of the track */ + Trackdir exit_trackdir_at_start = TrackToTrackdir(start_track); + Trackdir exit_trackdir_at_end = ReverseTrackdir(TrackToTrackdir(start_track)); + if (start_tile != end_tile) { // multi-tile case + /* determine proper direction (pointing outside of the track) */ + uint distance = DistanceManhattan(start_tile, end_tile); + if (distance > DistanceManhattan(TileAddByDiagDir(start_tile, TrackdirToExitdir(exit_trackdir_at_start)), end_tile)) { + Swap(exit_trackdir_at_start, exit_trackdir_at_end); + } + /* determine proper track on the end tile - switch between upper/lower or left/right based on the length */ + if (distance % 2 != 0) exit_trackdir_at_end = NextTrackdir(exit_trackdir_at_end); + } + + LineSnapPoint snap_start = LineSnapPointAtRailTrackEndpoint(start_tile, TrackdirToExitdir(exit_trackdir_at_start), bidirectional_exit); + LineSnapPoint snap_end = LineSnapPointAtRailTrackEndpoint(end_tile, TrackdirToExitdir(exit_trackdir_at_end), bidirectional_exit); + /* Find if we already had these coordinates before. */ + LineSnapPoint *snap; + for (snap = _rail_snap_points.Begin(); snap != _rail_snap_points.End(); snap++) { + /* Coordinates found - remove the snap point as it was already used. */ + if (snap->x == snap_start.x && snap->y == snap_start.y) snap_start.dirs = 0; + if (snap->x == snap_end.x && snap->y == snap_end.y) snap_end.dirs = 0; + } + /* Create new snap point set. */ + _rail_snap_points.Clear(); + if (snap_start.dirs != 0) *_rail_snap_points.Append() = snap_start; + if (snap_end.dirs != 0) *_rail_snap_points.Append() = snap_end; + } +} + +void ClearRailPlacementEndpoints() +{ + _rail_snap_points.Clear(); +} + Point GetViewportStationMiddle(const ViewPort *vp, const Station *st) { int x = TileX(st->xy) * TILE_SIZE; diff --git a/src/viewport_func.h b/src/viewport_func.h index 071bf9e821..adf37d2b8e 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -59,7 +59,7 @@ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const Vie void StartSpriteCombine(); void EndSpriteCombine(); -bool HandleViewportClicked(const ViewPort *vp, int x, int y); +bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click); void SetRedErrorSquare(TileIndex tile); void SetTileSelectSize(int w, int h); void SetTileSelectBigSize(int ox, int oy, int sx, int sy); diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp index e7727ed7a2..5ea2dd3685 100644 --- a/src/viewport_gui.cpp +++ b/src/viewport_gui.cpp @@ -154,6 +154,11 @@ public: /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */ HandleZoomMessage(this, this->viewport, WID_EV_ZOOM_IN, WID_EV_ZOOM_OUT); } + + virtual void OnMouseOver(Point pt, int widget) + { + if (_settings_client.gui.enable_extra_tooltips && pt.x != -1) GuiPrepareTooltipsExtra(this); + } }; static WindowDesc _extra_view_port_desc( diff --git a/src/viewport_type.h b/src/viewport_type.h index 8c42802928..283df8095e 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -116,6 +116,7 @@ enum ViewportDragDropSelectionProcess { DDSP_PLACE_ROAD_X_DIR, ///< Road placement (X axis) DDSP_PLACE_ROAD_Y_DIR, ///< Road placement (Y axis) DDSP_PLACE_AUTOROAD, ///< Road placement (auto) + DDSP_PLACE_FULLROAD, ///< Road placement (auto, full roads) DDSP_BUILD_BUSSTOP, ///< Road stop placement (buses) DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks) DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses) diff --git a/src/widgets/company_widget.h b/src/widgets/company_widget.h index 319e34ce2f..e74285757b 100644 --- a/src/widgets/company_widget.h +++ b/src/widgets/company_widget.h @@ -52,6 +52,10 @@ enum CompanyWidgets { WID_C_SELECT_MULTIPLAYER, ///< Multiplayer selection panel. WID_C_COMPANY_PASSWORD, ///< Button to set company password. WID_C_COMPANY_JOIN, ///< Button to join company. + CW_WIDGET_COMPANY_JOIN2, + CW_WIDGET_COMPANY_RESET, + CW_WIDGET_COMPANY_SUSPEND, + CW_WIDGET_COMPANY_RESUME, }; /** Widgets of the #CompanyFinancesWindow class. */ diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 2be2071440..3fc5500a34 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -42,7 +42,12 @@ void DropDownListStringItem::Draw(int left, int right, int top, int bottom, bool { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, this->String(), sel ? TC_WHITE : TC_BLACK); } - +/* +const char * DropDownListCharStringItem::String() const +{ + return this->string; +} +*/ /** * Natural sorting comparator function for DropDownList::sort(). * @param first Left side of comparison. diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index c89574d08f..44e00f306d 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -16,6 +16,11 @@ #include "../gfx_func.h" #include "../core/smallvec_type.hpp" #include "table/strings.h" +#include "../stdafx.h" +#include "../window_gui.h" +#include "../string_func.h" +#include "../strings_func.h" +#include "../window_func.h" /** * Base list item class from which others are derived. If placed in a list it @@ -47,12 +52,46 @@ public: virtual bool Selectable() const { return true; } virtual uint Width() const; + //virtual const char * String() const; virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; virtual StringID String() const { return this->string; } static int CDECL NatSortFunc(const DropDownListItem * const *first, const DropDownListItem * const *second); }; +/** + * Drop down list entry for showing a checked/unchecked toggle item. Use + * DropDownListCheckedItem or DropDownListCharStringCheckedItem depending of + * type of string used (either StringID or const char*). + */ + +template +class DropDownListCheckedItemT : public T { + uint checkmark_width; +public: + bool checked; + DropDownListCheckedItemT(S string, int result, bool masked, bool checked) : T(string, result, masked), checked(checked) + { + this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3; + } + virtual ~DropDownListCheckedItemT() {} + virtual uint Width() const + { + return T::Width() + this->checkmark_width; + } + + virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + { + bool rtl = _current_text_dir == TD_RTL; + if (this->checked) { + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); + } + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); + } +}; + +#define DropDownListCheckedItem DropDownListCheckedItemT +#define DropDownListCharStringCheckedItem DropDownListCheckedItemT /** * String list item with parameters. */ diff --git a/src/widgets/graph_widget.h b/src/widgets/graph_widget.h index c8518b16ea..8cbd90446c 100644 --- a/src/widgets/graph_widget.h +++ b/src/widgets/graph_widget.h @@ -29,6 +29,10 @@ enum CompanyValueWidgets { WID_CV_BACKGROUND, ///< Background of the window. WID_CV_GRAPH, ///< Graph itself. WID_CV_RESIZE, ///< Resize button. + WID_CPR2_FOOTER, ///< Footer. + WID_CPR2_ENABLE_CARGOES, ///< Enable cargoes button. + WID_CPR2_DISABLE_CARGOES, ///< Disable cargoes button. + WID_CPR2_CARGO_FIRST, ///< First cargo in the list. }; /** Widget of the #PerformanceHistoryGraphWindow class. */ diff --git a/src/widgets/industry_widget.h b/src/widgets/industry_widget.h index 14a1c795cc..fcdd3edd5d 100644 --- a/src/widgets/industry_widget.h +++ b/src/widgets/industry_widget.h @@ -34,6 +34,7 @@ enum IndustryViewWidgets { enum IndustryDirectoryWidgets { WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort. WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. + WID_ID_DROPDOWN_FILTER, ///< Industry filter WID_ID_INDUSTRY_LIST, ///< Industry list. WID_ID_SCROLLBAR, ///< Scrollbar of the list. }; diff --git a/src/widgets/network_widget.h b/src/widgets/network_widget.h index 01f7e1e550..8b0831bafb 100644 --- a/src/widgets/network_widget.h +++ b/src/widgets/network_widget.h @@ -51,6 +51,11 @@ enum NetworkGameWidgets { WID_NG_ADD, ///< 'Add server' button. WID_NG_START, ///< 'Start server' button. WID_NG_CANCEL, ///< 'Cancel' button. + + WID_NG_NOVA, ///< filter nova + WID_NG_REDDIT, ///< filter reddit + WID_NG_NICE, ///< filter n-ice + WID_NG_BTPRO, ///< filter btpro }; /** Widgets of the #NetworkStartServerWindow class. */ diff --git a/src/widgets/rail_widget.h b/src/widgets/rail_widget.h index b2a42e8a27..2895e0adf7 100644 --- a/src/widgets/rail_widget.h +++ b/src/widgets/rail_widget.h @@ -21,6 +21,7 @@ enum RailToolbarWidgets { WID_RAT_BUILD_EW, ///< Build rail along the game view X axis. WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis. WID_RAT_AUTORAIL, ///< Autorail tool. + WID_RAT_POLYRAIL, ///< Polyline rail tool. WID_RAT_DEMOLISH, ///< Destroy something with dynamite! WID_RAT_BUILD_DEPOT, ///< Build a depot. WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint. @@ -99,10 +100,11 @@ enum BuildSignalWidgets { /** Widgets of the #BuildRailDepotWindow class. */ enum BuildRailDepotWidgets { /* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */ - WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. - WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. - WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. - WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. + WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. + WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. + WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. + WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. + WID_BRAD_DEPOT_AUTO, ///< Build a depot, autoselect entrance. }; /** Widgets of the #BuildRailWaypointWindow class. */ diff --git a/src/widgets/road_widget.h b/src/widgets/road_widget.h index 4692855f17..d370fb6c52 100644 --- a/src/widgets/road_widget.h +++ b/src/widgets/road_widget.h @@ -17,7 +17,8 @@ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y, ///< Build road in y-direction. - WID_ROT_AUTOROAD, ///< Autorail. + WID_ROT_AUTOROAD, ///< Autoroad. + WID_ROT_FULLROAD, ///< Auto full road (no half-tiles). WID_ROT_DEMOLISH, ///< Demolish. WID_ROT_DEPOT, ///< Build depot. WID_ROT_BUS_STATION, ///< Build bus station. @@ -31,27 +32,30 @@ enum RoadToolbarWidgets { /** Widgets of the #BuildRoadDepotWindow class. */ enum BuildRoadDepotWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */ - WID_BROD_CAPTION, ///< Caption of the window. - WID_BROD_DEPOT_NE, ///< Depot with NE entry. - WID_BROD_DEPOT_SE, ///< Depot with SE entry. - WID_BROD_DEPOT_SW, ///< Depot with SW entry. - WID_BROD_DEPOT_NW, ///< Depot with NW entry. + WID_BROD_CAPTION, ///< Caption of the window. + WID_BROD_DEPOT_NE, ///< Depot with NE entry. + WID_BROD_DEPOT_SE, ///< Depot with SE entry. + WID_BROD_DEPOT_SW, ///< Depot with SW entry. + WID_BROD_DEPOT_NW, ///< Depot with NW entry. + WID_BROD_DEPOT_AUTO, ///< Depot, autodetect entry. }; /** Widgets of the #BuildRoadStationWindow class. */ enum BuildRoadStationWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */ - WID_BROS_CAPTION, ///< Caption of the window. - WID_BROS_BACKGROUND, ///< Background of the window. - WID_BROS_STATION_NE, ///< Terminal station with NE entry. - WID_BROS_STATION_SE, ///< Terminal station with SE entry. - WID_BROS_STATION_SW, ///< Terminal station with SW entry. - WID_BROS_STATION_NW, ///< Terminal station with NW entry. - WID_BROS_STATION_X, ///< Drive-through station in x-direction. - WID_BROS_STATION_Y, ///< Drive-through station in y-direction. - WID_BROS_LT_OFF, ///< Turn off area highlight. - WID_BROS_LT_ON, ///< Turn on area highlight. - WID_BROS_INFO, ///< Station acceptance info. + WID_BROS_CAPTION, ///< Caption of the window. + WID_BROS_BACKGROUND, ///< Background of the window. + WID_BROS_STATION_NE, ///< Terminal station with NE entry. + WID_BROS_STATION_SE, ///< Terminal station with SE entry. + WID_BROS_STATION_SW, ///< Terminal station with SW entry. + WID_BROS_STATION_NW, ///< Terminal station with NW entry. + WID_BROS_STATION_X, ///< Drive-through station in x-direction. + WID_BROS_STATION_Y, ///< Drive-through station in y-direction. + WID_BROS_STATION_AUTO, ///< Terminal station, autoselect entry. + WID_BROS_STATION_XY_AUTO, ///< Drive-through station, autoselect direction. + WID_BROS_LT_OFF, ///< Turn off area highlight. + WID_BROS_LT_ON, ///< Turn on area highlight. + WID_BROS_INFO, ///< Station acceptance info. }; #endif /* WIDGETS_ROAD_WIDGET_H */ diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index c1fd3fa74d..68ba8730f4 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -23,9 +23,11 @@ enum ToolbarNormalWidgets { WID_TN_SUBSIDIES, ///< Subsidy menu. WID_TN_STATIONS, ///< Station menu. WID_TN_FINANCES, ///< Finance menu. + WID_TN_CARGOS, ///< Transported cargo menu WID_TN_COMPANIES, ///< Company menu. WID_TN_STORY, ///< Story menu. WID_TN_GOAL, ///< Goal menu. + WID_TN_WATCH, ///< Watch gui menu WID_TN_GRAPHS, ///< Graph menu. WID_TN_LEAGUE, ///< Company league menu. WID_TN_INDUSTRIES, ///< Industry menu. diff --git a/src/widgets/town_widget.h b/src/widgets/town_widget.h index 1bbac57998..f09b77cd44 100644 --- a/src/widgets/town_widget.h +++ b/src/widgets/town_widget.h @@ -19,6 +19,7 @@ enum TownDirectoryWidgets { WID_TD_LIST, ///< List of towns. WID_TD_SCROLLBAR, ///< Scrollbar for the town list. WID_TD_WORLD_POPULATION, ///< The world's population. + TDW_CAPTION_TEXT, }; /** Widgets of the #TownAuthorityWindow class. */ @@ -41,6 +42,7 @@ enum TownViewWidgets { WID_TV_CHANGE_NAME, ///< Change the name of this town. WID_TV_EXPAND, ///< Expand this town (scenario editor only). WID_TV_DELETE, ///< Delete this town (scenario editor only). + WID_TV_CB, }; /** Widgets of the #FoundTownWindow class. */ @@ -62,4 +64,28 @@ enum TownFoundingWidgets { WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout. }; +enum TownHK { + HK_SADVERT, + HK_MADVERT, + HK_LADVERT, + HK_ROADS, + HK_STATUE, + HK_FUND, +}; + +enum CBTownWidgets { + WID_CB_LOCATION, + WID_CB_ADVERT, + WID_CB_FUND, + WID_CB_FUND_REGULAR, + WID_CB_DETAILS, + WID_CB_CARGO_NAME, + WID_CB_CARGO_AMOUNT, + WID_CB_CARGO_REQ, + WID_CB_CARGO_PREVIOUS, + WID_CB_CARGO_STORE, + WID_CB_CARGO_STORE_PCT, + WID_CB_CARGO_FROM, +}; + #endif /* WIDGETS_TOWN_WIDGET_H */ diff --git a/src/window.cpp b/src/window.cpp index cd13fb289d..76aac4ed68 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -11,6 +11,7 @@ #include "stdafx.h" #include +#include #include "company_func.h" #include "gfx_func.h" #include "console_func.h" @@ -21,6 +22,7 @@ #include "zoom_func.h" #include "vehicle_base.h" #include "window_func.h" +#include "window_gui.h" #include "tilehighlight_func.h" #include "network/network.h" #include "querystring_gui.h" @@ -1190,6 +1192,7 @@ void ChangeWindowOwner(Owner old_owner, Owner new_owner) switch (w->window_class) { case WC_COMPANY_COLOUR: case WC_FINANCES: + case WC_CARGOS: case WC_STATION_LIST: case WC_TRAINS_LIST: case WC_ROADVEH_LIST: @@ -2816,7 +2819,7 @@ static void MouseLoop(MouseClick click, int mousewheel) case MC_DOUBLE_LEFT: case MC_LEFT: DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); - if (!HandleViewportClicked(vp, x, y) && + if (!HandleViewportClicked(vp, x, y, click == MC_DOUBLE_LEFT) && !(w->flags & WF_DISABLE_VP_SCROLL) && _settings_client.gui.left_mouse_btn_scrolling) { _scrolling_viewport = true; @@ -3468,3 +3471,55 @@ PickerWindowBase::~PickerWindowBase() this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child ResetObjectToPlace(); } + + +/** + * Sets safe-initial values. + * @param t The type of positioning desired. + */ +WindowPopup::WindowPopup(WindowDesc *desc, WindowPopupType t): Window(desc) +{ + this->type = t; + this->wpu_mod_x = -5; + this->wpu_mod_y = -5; + this->wpu_widget = std::numeric_limits::max(); +} + +/** + * Compute #WindowPopup origin Point. + * + * @param desc The window's #WindowDesc object + * @param sm_width Window's smallest_x. + * @param sm_height Window's smallest_y. Unused. + * @param window_number Unused. + * @return The origin coordinate of the window. + */ +/*virtual*/ Point WindowPopup::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) +{ + int x, y; + + switch (this->type) { + case WPUT_CENTERED: + x = _cursor.pos.x - sm_width / 2; + y = _cursor.pos.y - this->window_desc->GetDefaultHeight() / 2; + break; + case WPUT_WIDGET_RELATIVE: + if (this->wpu_widget != std::numeric_limits::max()) { + NWidgetBase *wid = this->GetWidget(this->wpu_widget); + x = _cursor.pos.x - wid->pos_x + this->wpu_mod_x; + y = _cursor.pos.y - wid->pos_y + this->wpu_mod_y; + break; + } + case WPUT_ORIGIN: + default: + x = _cursor.pos.x + this->wpu_mod_x; + y = _cursor.pos.y + this->wpu_mod_y; + break; + } + + Point rv; + rv.x = Clamp(x, 0, _screen.width - sm_width); + rv.y = Clamp(y, GetMainViewTop(), GetMainViewBottom() - this->window_desc->GetDefaultHeight()); + return rv; +} + diff --git a/src/window_gui.h b/src/window_gui.h index 27b408a4f2..3e02e0467c 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -873,6 +873,7 @@ enum TooltipCloseCondition { }; void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const uint64 params[] = NULL, TooltipCloseCondition close_tooltip = TCC_HOVER); +void GuiPrepareTooltipsExtra(Window *parent); /* widget.cpp */ int GetWidgetFromPos(const Window *w, int x, int y); @@ -905,4 +906,31 @@ void SetFocusedWindow(Window *w); void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y); + +/** + * #WindowPopup positioning types + */ +enum WindowPopupType { + WPUT_ORIGIN = 1, ///< Align with the top-left corner of the window. + WPUT_WIDGET_RELATIVE, ///< Align from a nested widget. + WPUT_CENTERED, ///< Center the widget under the cursor. Ignore modifiers. +}; + +/** + * Specialized Window bound to open around the cursor's position. + * Its sole purpose is to provide the OnInitialPosition() method + * and an simple interface to control its behaviour. + */ +struct WindowPopup: public Window { +public: + WindowPopup(WindowDesc *desc, WindowPopupType t = WPUT_ORIGIN); + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number); +protected: + uint wpu_widget; ///< The widget to which the computation would be made from when type is #WPUT_WIDGET_RELATIVE. + int wpu_mod_x; ///< The X axis modifier. A negative value would bring the window closer to the left edge of the screen. Default value is -5. + int wpu_mod_y; ///< The Y axis modifier. A negative value would bring the window closer to the top edge of the screen. Default value is -5. +private: + WindowPopupType type; +}; + #endif /* WINDOW_GUI_H */ diff --git a/src/window_type.h b/src/window_type.h index d51db26018..885ec119e5 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -109,6 +109,7 @@ enum WindowClass { * - 0 = #ToolTipsWidgets */ WC_TOOLTIPS, + WC_TOOLTIPS_EXTRA, /** * Query string window; %Window numbers: @@ -370,6 +371,12 @@ enum WindowClass { */ WC_BUILD_OBJECT, + //watch company + WC_WATCH_COMPANY, + + //watch company admin version + WC_WATCH_COMPANYA, + /** * Build vehicle; %Window numbers: * - #VehicleType = #BuildVehicleWidgets @@ -516,6 +523,7 @@ enum WindowClass { * - #CompanyID = #CompanyWidgets */ WC_FINANCES, + WC_CARGOS, /** * Income graph; %Window numbers: @@ -681,6 +689,11 @@ enum WindowClass { */ WC_SAVE_PRESET, + WC_ZONING_TOOLBAR, + WC_COMMAND_TOOLBAR, + WC_LOGIN_WINDOW, + WC_CB_TOWN, + WC_INVALID = 0xFFFF, ///< Invalid window. };