00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "town.h"
00008 #include "viewport_func.h"
00009 #include "gfx_func.h"
00010 #include "gui.h"
00011 #include "window_gui.h"
00012 #include "textbuf_gui.h"
00013 #include "command_func.h"
00014 #include "company_func.h"
00015 #include "company_base.h"
00016 #include "company_gui.h"
00017 #include "network/network.h"
00018 #include "variables.h"
00019 #include "strings_func.h"
00020 #include "sound_func.h"
00021 #include "economy_func.h"
00022 #include "tilehighlight_func.h"
00023 #include "sortlist_type.h"
00024 #include "road_cmd.h"
00025 #include "landscape_type.h"
00026 #include "landscape.h"
00027 #include "cargotype.h"
00028 #include "tile_map.h"
00029
00030 #include "table/sprites.h"
00031 #include "table/strings.h"
00032
00033 typedef GUIList<const Town*> GUITownList;
00034
00035 static const Widget _town_authority_widgets[] = {
00036 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00037 { WWT_CAPTION, RESIZE_NONE, COLOUR_BROWN, 11, 316, 0, 13, STR_2022_LOCAL_AUTHORITY, STR_018C_WINDOW_TITLE_DRAG_THIS},
00038 { WWT_PANEL, RESIZE_NONE, COLOUR_BROWN, 0, 316, 14, 105, 0x0, STR_NULL},
00039 { WWT_PANEL, RESIZE_NONE, COLOUR_BROWN, 0, 304, 106, 157, 0x0, STR_2043_LIST_OF_THINGS_TO_DO_AT},
00040 { WWT_SCROLLBAR, RESIZE_NONE, COLOUR_BROWN, 305, 316, 106, 157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00041 { WWT_PANEL, RESIZE_NONE, COLOUR_BROWN, 0, 316, 158, 209, 0x0, STR_NULL},
00042 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 0, 316, 210, 221, STR_2042_DO_IT, STR_2044_CARRY_OUT_THE_HIGHLIGHTED},
00043 { WIDGETS_END},
00044 };
00045
00046 extern const byte _town_action_costs[8];
00047
00048 struct TownAuthorityWindow : Window {
00049 private:
00050 Town *town;
00051 int sel_index;
00052
00053 enum TownAuthorityWidget {
00054 TWA_CLOSEBOX = 0,
00055 TWA_CAPTION,
00056 TWA_RATING_INFO,
00057 TWA_COMMAND_LIST,
00058 TWA_SCROLLBAR,
00059 TWA_ACTION_INFO,
00060 TWA_EXECUTE,
00061 };
00062
00072 static int GetNthSetBit(uint32 bits, int n)
00073 {
00074 if (n >= 0) {
00075 uint i;
00076 FOR_EACH_SET_BIT(i, bits) {
00077 n--;
00078 if (n < 0) return i;
00079 }
00080 }
00081 return -1;
00082 }
00083
00084 public:
00085 TownAuthorityWindow(const WindowDesc *desc, WindowNumber window_number) :
00086 Window(desc, window_number), sel_index(-1)
00087 {
00088 this->town = GetTown(this->window_number);
00089 this->vscroll.cap = 5;
00090
00091 this->FindWindowPlacementAndResize(desc);
00092 }
00093
00094 virtual void OnPaint()
00095 {
00096 int numact;
00097 uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town);
00098
00099 SetVScrollCount(this, numact + 1);
00100
00101 if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) {
00102 this->sel_index = -1;
00103 }
00104
00105 this->SetWidgetDisabledState(6, this->sel_index == -1);
00106
00107 SetDParam(0, this->window_number);
00108 this->DrawWidgets();
00109
00110 int y = this->widget[TWA_RATING_INFO].top + 1;
00111
00112 DrawString(2, y, STR_2023_TRANSPORT_COMPANY_RATINGS, TC_FROMSTRING);
00113 y += 10;
00114
00115
00116 const Company *c;
00117 FOR_ALL_COMPANIES(c) {
00118 if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) {
00119 DrawCompanyIcon(c->index, 2, y);
00120
00121 SetDParam(0, c->index);
00122 SetDParam(1, c->index);
00123
00124 int r = this->town->ratings[c->index];
00125 StringID str;
00126 (str = STR_3035_APPALLING, r <= RATING_APPALLING) ||
00127 (str++, r <= RATING_VERYPOOR) ||
00128 (str++, r <= RATING_POOR) ||
00129 (str++, r <= RATING_MEDIOCRE) ||
00130 (str++, r <= RATING_GOOD) ||
00131 (str++, r <= RATING_VERYGOOD) ||
00132 (str++, r <= RATING_EXCELLENT) ||
00133 (str++, true);
00134
00135 SetDParam(2, str);
00136 if (this->town->exclusivity == c->index) {
00137 DrawSprite(SPR_BLOT, PALETTE_TO_RED, 18, y);
00138 }
00139
00140 DrawString(28, y, STR_2024, TC_FROMSTRING);
00141 y += 10;
00142 }
00143 }
00144
00145 if (y > this->widget[TWA_RATING_INFO].bottom) {
00146
00147 ResizeWindowForWidget(this, TWA_RATING_INFO, 0, y - this->widget[TWA_RATING_INFO].bottom);
00148 this->SetDirty();
00149 return;
00150 }
00151
00152 y = this->widget[TWA_COMMAND_LIST].top + 1;
00153 int pos = this->vscroll.pos;
00154
00155 if (--pos < 0) {
00156 DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, TC_FROMSTRING);
00157 y += 10;
00158 }
00159
00160 for (int i = 0; buttons; i++, buttons >>= 1) {
00161 if (pos <= -5) break;
00162
00163 if ((buttons & 1) && --pos < 0) {
00164 DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, TC_ORANGE);
00165 y += 10;
00166 }
00167 }
00168
00169 if (this->sel_index != -1) {
00170 SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[this->sel_index]);
00171 SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + this->sel_index);
00172 DrawStringMultiLine(2, this->widget[TWA_ACTION_INFO].top + 1, STR_204D_INITIATE_A_SMALL_LOCAL + this->sel_index, 313);
00173 }
00174 }
00175
00176 virtual void OnDoubleClick(Point pt, int widget) { HandleClick(pt, widget, true); }
00177 virtual void OnClick(Point pt, int widget) { HandleClick(pt, widget, false); }
00178
00179 void HandleClick(Point pt, int widget, bool double_click)
00180 {
00181 switch (widget) {
00182 case TWA_COMMAND_LIST: {
00183 int y = (pt.y - this->widget[TWA_COMMAND_LIST].top - 1) / 10;
00184
00185 if (!IsInsideMM(y, 0, 5)) return;
00186
00187 y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll.pos - 1);
00188 if (y >= 0) {
00189 this->sel_index = y;
00190 this->SetDirty();
00191 }
00192
00193 if (!double_click || y < 0) break;
00194 }
00195
00196 case TWA_EXECUTE:
00197 DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
00198 break;
00199 }
00200 }
00201
00202 virtual void OnHundredthTick()
00203 {
00204 this->SetDirty();
00205 }
00206 };
00207
00208 static const WindowDesc _town_authority_desc = {
00209 WDP_AUTO, WDP_AUTO, 317, 222, 317, 222,
00210 WC_TOWN_AUTHORITY, WC_NONE,
00211 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00212 _town_authority_widgets,
00213 };
00214
00215 static void ShowTownAuthorityWindow(uint town)
00216 {
00217 AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
00218 }
00219
00220 struct TownViewWindow : Window {
00221 private:
00222 Town *town;
00223
00224 enum TownViewWidget {
00225 TVW_CAPTION = 1,
00226 TVW_STICKY,
00227 TVW_VIEWPORTPANEL,
00228 TVW_INFOPANEL = 5,
00229 TVW_CENTERVIEW,
00230 TVW_SHOWAUTORITY,
00231 TVW_CHANGENAME,
00232 TVW_EXPAND,
00233 TVW_DELETE,
00234 };
00235
00236 public:
00237 enum {
00238 TVW_HEIGHT_NORMAL = 150,
00239 };
00240
00241 TownViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00242 {
00243 this->town = GetTown(this->window_number);
00244 bool ingame = _game_mode != GM_EDITOR;
00245
00246 this->flags4 |= WF_DISABLE_VP_SCROLL;
00247 InitializeWindowViewport(this, 3, 17, 254, 86, this->town->xy, ZOOM_LVL_TOWN);
00248
00249 if (this->town->larger_town) this->widget[TVW_CAPTION].data = STR_CITY;
00250 this->SetWidgetHiddenState(TVW_DELETE, ingame);
00251 this->SetWidgetHiddenState(TVW_EXPAND, ingame);
00252 this->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame);
00253
00254 if (ingame) {
00255
00256 this->widget[TVW_CAPTION].right = this->widget[TVW_STICKY].left -1;
00257
00258 this->widget[TVW_CHANGENAME].top = this->widget[TVW_EXPAND].top;
00259 this->widget[TVW_CHANGENAME].bottom = this->widget[TVW_EXPAND].bottom;
00260 this->widget[TVW_CHANGENAME].right = this->widget[TVW_STICKY].right;
00261 }
00262
00263 this->ResizeWindowAsNeeded();
00264
00265 this->FindWindowPlacementAndResize(desc);
00266 }
00267
00268 virtual void OnPaint()
00269 {
00270
00271 this->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
00272
00273 SetDParam(0, this->town->index);
00274 this->DrawWidgets();
00275
00276 uint y = 107;
00277
00278 SetDParam(0, this->town->population);
00279 SetDParam(1, this->town->num_houses);
00280 DrawString(2, y, STR_2006_POPULATION, TC_FROMSTRING);
00281
00282 SetDParam(0, this->town->act_pass);
00283 SetDParam(1, this->town->max_pass);
00284 DrawString(2, y += 10, STR_200D_PASSENGERS_LAST_MONTH_MAX, TC_FROMSTRING);
00285
00286 SetDParam(0, this->town->act_mail);
00287 SetDParam(1, this->town->max_mail);
00288 DrawString(2, y += 10, STR_200E_MAIL_LAST_MONTH_MAX, TC_FROMSTRING);
00289
00290 uint cargo_needed_for_growth = 0;
00291 switch (_settings_game.game_creation.landscape) {
00292 case LT_ARCTIC:
00293 if (TilePixelHeight(this->town->xy) >= LowestSnowLine()) cargo_needed_for_growth = 1;
00294 break;
00295
00296 case LT_TROPIC:
00297 if (GetTropicZone(this->town->xy) == TROPICZONE_DESERT) cargo_needed_for_growth = 2;
00298 break;
00299
00300 default: break;
00301 }
00302
00303 if (cargo_needed_for_growth > 0) {
00304 DrawString(2, y += 10, STR_CARGO_FOR_TOWNGROWTH, TC_FROMSTRING);
00305
00306 CargoID first_food_cargo = CT_INVALID;
00307 StringID food_name = STR_001E_FOOD;
00308 CargoID first_water_cargo = CT_INVALID;
00309 StringID water_name = STR_0021_WATER;
00310 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00311 const CargoSpec *cs = GetCargo(cid);
00312 if (first_food_cargo == CT_INVALID && cs->town_effect == TE_FOOD) {
00313 first_food_cargo = cid;
00314 food_name = cs->name;
00315 }
00316 if (first_water_cargo == CT_INVALID && cs->town_effect == TE_WATER) {
00317 first_water_cargo = cid;
00318 water_name = cs->name;
00319 }
00320 }
00321
00322 if (first_food_cargo != CT_INVALID && this->town->act_food > 0) {
00323 SetDParam(0, first_food_cargo);
00324 SetDParam(1, this->town->act_food);
00325 DrawString(2, y += 10, STR_CARGO_FOR_TOWNGROWTH_LAST_MONTH, TC_FROMSTRING);
00326 } else {
00327 SetDParam(0, food_name);
00328 DrawString(2, y += 10, STR_CARGO_FOR_TOWNGROWTH_REQUIRED, TC_FROMSTRING);
00329 }
00330
00331 if (cargo_needed_for_growth > 1) {
00332 if (first_water_cargo != CT_INVALID && this->town->act_water > 0) {
00333 SetDParam(0, first_water_cargo);
00334 SetDParam(1, this->town->act_water);
00335 DrawString(2, y += 10, STR_CARGO_FOR_TOWNGROWTH_LAST_MONTH, TC_FROMSTRING);
00336 } else {
00337 SetDParam(0, water_name);
00338 DrawString(2, y += 10, STR_CARGO_FOR_TOWNGROWTH_REQUIRED, TC_FROMSTRING);
00339 }
00340 }
00341 }
00342
00343 this->DrawViewport();
00344
00345
00346 if (_settings_game.economy.station_noise_level) {
00347 SetDParam(0, this->town->noise_reached);
00348 SetDParam(1, this->town->MaxTownNoise());
00349 DrawString(2, y += 10, STR_NOISE_IN_TOWN, TC_FROMSTRING);
00350 }
00351 }
00352
00353 virtual void OnClick(Point pt, int widget)
00354 {
00355 switch (widget) {
00356 case TVW_CENTERVIEW:
00357 if (_ctrl_pressed) {
00358 ShowExtraViewPortWindow(this->town->xy);
00359 } else {
00360 ScrollMainWindowToTile(this->town->xy);
00361 }
00362 break;
00363
00364 case TVW_SHOWAUTORITY:
00365 ShowTownAuthorityWindow(this->window_number);
00366 break;
00367
00368 case TVW_CHANGENAME:
00369 SetDParam(0, this->window_number);
00370 ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, MAX_LENGTH_TOWN_NAME_BYTES, MAX_LENGTH_TOWN_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
00371 break;
00372
00373 case TVW_EXPAND:
00374 ExpandTown(this->town);
00375 break;
00376
00377 case TVW_DELETE:
00378 delete this->town;
00379 break;
00380 }
00381 }
00382
00383 void ResizeWindowAsNeeded()
00384 {
00385 int aimed_height = TVW_HEIGHT_NORMAL;
00386
00387 switch (_settings_game.game_creation.landscape) {
00388 case LT_ARCTIC:
00389 if (TilePixelHeight(this->town->xy) >= LowestSnowLine()) aimed_height += 20;
00390 break;
00391
00392 case LT_TROPIC:
00393 if (GetTropicZone(this->town->xy) == TROPICZONE_DESERT) aimed_height += 30;
00394 break;
00395
00396 default: break;
00397 }
00398
00399 if (_settings_game.economy.station_noise_level) aimed_height += 10;
00400
00401 if (this->height != aimed_height) ResizeWindowForWidget(this, TVW_INFOPANEL, 0, aimed_height - this->height);
00402 }
00403
00404 virtual void OnInvalidateData(int data = 0)
00405 {
00406
00407 this->SetDirty();
00408 this->ResizeWindowAsNeeded();
00409 }
00410
00411 virtual void OnQueryTextFinished(char *str)
00412 {
00413 if (str == NULL) return;
00414
00415 DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN), NULL, str);
00416 }
00417 };
00418
00419
00420 static const Widget _town_view_widgets[] = {
00421 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00422 { WWT_CAPTION, RESIZE_NONE, COLOUR_BROWN, 11, 172, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS},
00423 { WWT_STICKYBOX, RESIZE_NONE, COLOUR_BROWN, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
00424 { WWT_PANEL, RESIZE_NONE, COLOUR_BROWN, 0, 259, 14, 105, 0x0, STR_NULL},
00425 { WWT_INSET, RESIZE_NONE, COLOUR_BROWN, 2, 257, 16, 103, 0x0, STR_NULL},
00426 { WWT_PANEL, RESIZE_NONE, COLOUR_BROWN, 0, 259, 106, 137, 0x0, STR_NULL},
00427 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 0, 85, 138, 149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON},
00428 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 86, 171, 138, 149, STR_2020_LOCAL_AUTHORITY, STR_2021_SHOW_INFORMATION_ON_LOCAL},
00429 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 172, 247, 0, 13, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME},
00430 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 86, 171, 138, 149, STR_023C_EXPAND, STR_023B_INCREASE_SIZE_OF_TOWN},
00431 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 172, 259, 138, 149, STR_0290_DELETE, STR_0291_DELETE_THIS_TOWN_COMPLETELY},
00432 { WIDGETS_END},
00433 };
00434
00435 static const WindowDesc _town_view_desc = {
00436 WDP_AUTO, WDP_AUTO, 260, TownViewWindow::TVW_HEIGHT_NORMAL, 260, TownViewWindow::TVW_HEIGHT_NORMAL,
00437 WC_TOWN_VIEW, WC_NONE,
00438 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
00439 _town_view_widgets,
00440 };
00441
00442 void ShowTownViewWindow(TownID town)
00443 {
00444 AllocateWindowDescFront<TownViewWindow>(&_town_view_desc, town);
00445 }
00446
00447 static const Widget _town_directory_widgets[] = {
00448 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00449 { WWT_CAPTION, RESIZE_NONE, COLOUR_BROWN, 11, 195, 0, 13, STR_2000_TOWNS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00450 { WWT_STICKYBOX, RESIZE_NONE, COLOUR_BROWN, 196, 207, 0, 13, 0x0, STR_STICKY_BUTTON},
00451 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 0, 98, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
00452 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_BROWN, 99, 195, 14, 25, STR_SORT_BY_POPULATION, STR_SORT_ORDER_TIP},
00453 { WWT_PANEL, RESIZE_BOTTOM, COLOUR_BROWN, 0, 195, 26, 189, 0x0, STR_200A_TOWN_NAMES_CLICK_ON_NAME},
00454 { WWT_SCROLLBAR, RESIZE_BOTTOM, COLOUR_BROWN, 196, 207, 14, 189, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00455 { WWT_PANEL, RESIZE_TB, COLOUR_BROWN, 0, 195, 190, 201, 0x0, STR_NULL},
00456 { WWT_RESIZEBOX, RESIZE_TB, COLOUR_BROWN, 196, 207, 190, 201, 0x0, STR_RESIZE_BUTTON},
00457 { WIDGETS_END},
00458 };
00459
00460
00461 struct TownDirectoryWindow : public Window {
00462 private:
00463 enum TownDirectoryWidget {
00464 TDW_SORTNAME = 3,
00465 TDW_SORTPOPULATION,
00466 TDW_CENTERTOWN,
00467 };
00468
00469
00470 static Listing last_sorting;
00471 static const Town *last_town;
00472
00473
00474 static GUITownList::SortFunction * const sorter_funcs[];
00475
00476 GUITownList towns;
00477
00478 void BuildTownList()
00479 {
00480 if (!this->towns.NeedRebuild()) return;
00481
00482 this->towns.Clear();
00483
00484 const Town *t;
00485 FOR_ALL_TOWNS(t) {
00486 *this->towns.Append() = t;
00487 }
00488
00489 this->towns.Compact();
00490 this->towns.RebuildDone();
00491 }
00492
00493 void SortTownList()
00494 {
00495 last_town = NULL;
00496 this->towns.Sort();
00497 }
00498
00500 static int CDECL TownNameSorter(const Town * const *a, const Town * const *b)
00501 {
00502 static char buf_cache[64];
00503 const Town *ta = *a;
00504 const Town *tb = *b;
00505 char buf[64];
00506
00507 SetDParam(0, ta->index);
00508 GetString(buf, STR_TOWN, lastof(buf));
00509
00510
00511
00512
00513 if (tb != last_town) {
00514 last_town = tb;
00515 SetDParam(0, tb->index);
00516 GetString(buf_cache, STR_TOWN, lastof(buf_cache));
00517 }
00518
00519 return strcmp(buf, buf_cache);
00520 }
00521
00523 static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b)
00524 {
00525 return (*a)->population - (*b)->population;
00526 }
00527
00528 public:
00529 TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
00530 {
00531 this->vscroll.cap = 16;
00532 this->resize.step_height = 10;
00533 this->resize.height = this->height - 10 * 6;
00534
00535 this->towns.SetListing(this->last_sorting);
00536 this->towns.SetSortFuncs(this->sorter_funcs);
00537 this->towns.ForceRebuild();
00538
00539 this->FindWindowPlacementAndResize(desc);
00540 }
00541
00542 ~TownDirectoryWindow()
00543 {
00544 this->last_sorting = this->towns.GetListing();
00545 }
00546
00547 virtual void OnPaint()
00548 {
00549 this->BuildTownList();
00550 this->SortTownList();
00551
00552 SetVScrollCount(this, this->towns.Length());
00553
00554 this->DrawWidgets();
00555 this->DrawSortButtonState(this->towns.SortType() == 0 ? TDW_SORTNAME : TDW_SORTPOPULATION, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00556
00557 {
00558 int n = 0;
00559 uint16 i = this->vscroll.pos;
00560 int y = 28;
00561
00562 while (i < this->towns.Length()) {
00563 const Town *t = this->towns[i];
00564
00565 assert(t->xy != INVALID_TILE);
00566
00567 SetDParam(0, t->index);
00568 SetDParam(1, t->population);
00569 DrawString(2, y, STR_2057, TC_FROMSTRING);
00570
00571 y += 10;
00572 i++;
00573 if (++n == this->vscroll.cap) break;
00574 }
00575
00576 SetDParam(0, GetWorldPopulation());
00577 DrawString(3, this->height - 12 + 2, STR_TOWN_POPULATION, TC_FROMSTRING);
00578 }
00579 }
00580
00581 virtual void OnClick(Point pt, int widget)
00582 {
00583 switch (widget) {
00584 case TDW_SORTNAME:
00585 if (this->towns.SortType() == 0) {
00586 this->towns.ToggleSortOrder();
00587 } else {
00588 this->towns.SetSortType(0);
00589 }
00590 this->SetDirty();
00591 break;
00592
00593 case TDW_SORTPOPULATION:
00594 if (this->towns.SortType() == 1) {
00595 this->towns.ToggleSortOrder();
00596 } else {
00597 this->towns.SetSortType(1);
00598 }
00599 this->SetDirty();
00600 break;
00601
00602 case TDW_CENTERTOWN: {
00603 uint16 id_v = (pt.y - 28) / 10;
00604
00605 if (id_v >= this->vscroll.cap) return;
00606
00607 id_v += this->vscroll.pos;
00608
00609 if (id_v >= this->towns.Length()) return;
00610
00611 const Town *t = this->towns[id_v];
00612 assert(t->xy != INVALID_TILE);
00613 if (_ctrl_pressed) {
00614 ShowExtraViewPortWindow(t->xy);
00615 } else {
00616 ScrollMainWindowToTile(t->xy);
00617 }
00618 break;
00619 }
00620 }
00621 }
00622
00623 virtual void OnHundredthTick()
00624 {
00625 this->SetDirty();
00626 }
00627
00628 virtual void OnResize(Point new_size, Point delta)
00629 {
00630 this->vscroll.cap += delta.y / 10;
00631 }
00632
00633 virtual void OnInvalidateData(int data)
00634 {
00635 if (data == 0) {
00636 this->towns.ForceRebuild();
00637 } else {
00638 this->towns.ForceResort();
00639 }
00640 }
00641 };
00642
00643 Listing TownDirectoryWindow::last_sorting = {false, 0};
00644 const Town *TownDirectoryWindow::last_town = NULL;
00645
00646
00647 GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
00648 &TownNameSorter,
00649 &TownPopulationSorter,
00650 };
00651
00652 static const WindowDesc _town_directory_desc = {
00653 WDP_AUTO, WDP_AUTO, 208, 202, 208, 202,
00654 WC_TOWN_DIRECTORY, WC_NONE,
00655 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00656 _town_directory_widgets,
00657 };
00658
00659 void ShowTownDirectory()
00660 {
00661 if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return;
00662 new TownDirectoryWindow(&_town_directory_desc);
00663 }
00664
00665 void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
00666 {
00667 if (success) {
00668 SndPlayTileFx(SND_1F_SPLAT, tile);
00669 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00670 }
00671 }
00672
00673 static const Widget _found_town_widgets[] = {
00674 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00675 { WWT_CAPTION, RESIZE_NONE, COLOUR_DARK_GREEN, 11, 147, 0, 13, STR_0233_TOWN_GENERATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
00676 { WWT_STICKYBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 148, 159, 0, 13, 0x0, STR_STICKY_BUTTON},
00677 { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 159, 14, 161, 0x0, STR_NULL},
00678
00679 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 157, 16, 27, STR_0234_NEW_TOWN, STR_0235_CONSTRUCT_NEW_TOWN},
00680 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 157, 29, 40, STR_023D_RANDOM_TOWN, STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION},
00681 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 157, 42, 53, STR_MANY_RANDOM_TOWNS, STR_RANDOM_TOWNS_TIP},
00682
00683 { WWT_LABEL, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 147, 54, 67, STR_02A5_TOWN_SIZE, STR_NULL},
00684 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 79, 68, 79, STR_02A1_SMALL, STR_02A4_SELECT_TOWN_SIZE},
00685 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 80, 157, 68, 79, STR_02A2_MEDIUM, STR_02A4_SELECT_TOWN_SIZE},
00686 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 79, 81, 92, STR_02A3_LARGE, STR_02A4_SELECT_TOWN_SIZE},
00687 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 80, 157, 81, 92, STR_SELECT_TOWN_SIZE_RANDOM, STR_02A4_SELECT_TOWN_SIZE},
00688 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 157, 96, 107, STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP},
00689
00690 { WWT_LABEL, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 147, 108, 121, STR_TOWN_ROAD_LAYOUT, STR_NULL},
00691 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 79, 122, 133, STR_SELECT_LAYOUT_ORIGINAL, STR_SELECT_TOWN_ROAD_LAYOUT},
00692 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 80, 157, 122, 133, STR_SELECT_LAYOUT_BETTER_ROADS, STR_SELECT_TOWN_ROAD_LAYOUT},
00693 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 79, 135, 146, STR_SELECT_LAYOUT_2X2_GRID, STR_SELECT_TOWN_ROAD_LAYOUT},
00694 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 80, 157, 135, 146, STR_SELECT_LAYOUT_3X3_GRID, STR_SELECT_TOWN_ROAD_LAYOUT},
00695 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 2, 157, 148, 159, STR_SELECT_LAYOUT_RANDOM, STR_SELECT_TOWN_ROAD_LAYOUT},
00696
00697 { WIDGETS_END},
00698 };
00699
00700 struct FoundTownWindow : Window
00701 {
00702 private:
00703 enum TownScenarioEditorWidget {
00704 TSEW_NEWTOWN = 4,
00705 TSEW_RANDOMTOWN,
00706 TSEW_MANYRANDOMTOWNS,
00707 TSEW_TOWNSIZE,
00708 TSEW_SIZE_SMALL,
00709 TSEW_SIZE_MEDIUM,
00710 TSEW_SIZE_LARGE,
00711 TSEW_SIZE_RANDOM,
00712 TSEW_CITY,
00713 TSEW_TOWNLAYOUT,
00714 TSEW_LAYOUT_ORIGINAL,
00715 TSEW_LAYOUT_BETTER,
00716 TSEW_LAYOUT_GRID2,
00717 TSEW_LAYOUT_GRID3,
00718 TSEW_LAYOUT_RANDOM,
00719 };
00720
00721 static TownSize town_size;
00722 static bool city;
00723 static TownLayout town_layout;
00724
00725 public:
00726 FoundTownWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00727 {
00728 this->FindWindowPlacementAndResize(desc);
00729 town_layout = _settings_game.economy.town_layout;
00730 city = false;
00731 this->UpdateButtons();
00732 }
00733
00734 void UpdateButtons()
00735 {
00736 for (int i = TSEW_SIZE_SMALL; i <= TSEW_SIZE_RANDOM; i++) {
00737 this->SetWidgetLoweredState(i, i == TSEW_SIZE_SMALL + town_size);
00738 }
00739
00740 this->SetWidgetLoweredState(TSEW_CITY, city);
00741
00742 for (int i = TSEW_LAYOUT_ORIGINAL; i <= TSEW_LAYOUT_RANDOM; i++) {
00743 this->SetWidgetLoweredState(i, i == TSEW_LAYOUT_ORIGINAL + town_layout);
00744 }
00745
00746 this->SetDirty();
00747 }
00748
00749 virtual void OnPaint()
00750 {
00751 this->DrawWidgets();
00752 }
00753
00754 virtual void OnClick(Point pt, int widget)
00755 {
00756 switch (widget) {
00757 case TSEW_NEWTOWN:
00758 HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
00759 break;
00760
00761 case TSEW_RANDOMTOWN: {
00762 this->HandleButtonClick(TSEW_RANDOMTOWN);
00763 _generating_world = true;
00764 UpdateNearestTownForRoadTiles(true);
00765 const Town *t = CreateRandomTown(20, town_size, city, town_layout);
00766 UpdateNearestTownForRoadTiles(false);
00767 _generating_world = false;
00768
00769 if (t == NULL) {
00770 ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
00771 } else {
00772 ScrollMainWindowToTile(t->xy);
00773 }
00774 } break;
00775
00776 case TSEW_MANYRANDOMTOWNS:
00777 this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
00778
00779 _generating_world = true;
00780 UpdateNearestTownForRoadTiles(true);
00781 if (!GenerateTowns(town_layout)) {
00782 ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
00783 }
00784 UpdateNearestTownForRoadTiles(false);
00785 _generating_world = false;
00786 break;
00787
00788 case TSEW_SIZE_SMALL: case TSEW_SIZE_MEDIUM: case TSEW_SIZE_LARGE: case TSEW_SIZE_RANDOM:
00789 town_size = (TownSize)(widget - TSEW_SIZE_SMALL);
00790 this->UpdateButtons();
00791 break;
00792
00793 case TSEW_CITY:
00794 city ^= true;
00795 this->SetWidgetLoweredState(TSEW_CITY, city);
00796 this->SetDirty();
00797 break;
00798
00799 case TSEW_LAYOUT_ORIGINAL: case TSEW_LAYOUT_BETTER: case TSEW_LAYOUT_GRID2:
00800 case TSEW_LAYOUT_GRID3: case TSEW_LAYOUT_RANDOM:
00801 town_layout = (TownLayout)(widget - TSEW_LAYOUT_ORIGINAL);
00802 this->UpdateButtons();
00803 break;
00804 }
00805 }
00806
00807 virtual void OnTimeout()
00808 {
00809 this->RaiseWidget(TSEW_RANDOMTOWN);
00810 this->RaiseWidget(TSEW_MANYRANDOMTOWNS);
00811 this->SetDirty();
00812 }
00813
00814 virtual void OnPlaceObject(Point pt, TileIndex tile)
00815 {
00816 _place_proc(tile);
00817 }
00818
00819 virtual void OnPlaceObjectAbort()
00820 {
00821 this->RaiseButtons();
00822 this->UpdateButtons();
00823 }
00824
00825 static void PlaceProc_Town(TileIndex tile)
00826 {
00827 uint32 townnameparts;
00828 if (!GenerateTownName(&townnameparts)) {
00829 ShowErrorMessage(STR_023A_TOO_MANY_TOWNS, STR_0236_CAN_T_BUILD_TOWN_HERE, 0, 0);
00830 return;
00831 }
00832
00833 DoCommandP(tile, town_size | city << 2 | town_layout << 3, townnameparts, CMD_BUILD_TOWN | CMD_MSG(STR_0236_CAN_T_BUILD_TOWN_HERE), CcBuildTown);
00834 }
00835 };
00836
00837 TownSize FoundTownWindow::town_size = TS_MEDIUM;
00838 bool FoundTownWindow::city;
00839 TownLayout FoundTownWindow::town_layout;
00840
00841 static const WindowDesc _found_town_desc = {
00842 WDP_AUTO, WDP_AUTO, 160, 162, 160, 162,
00843 WC_FOUND_TOWN, WC_NONE,
00844 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_CONSTRUCTION,
00845 _found_town_widgets,
00846 };
00847
00848 void ShowBuildTownWindow()
00849 {
00850 if (_game_mode != GM_EDITOR && !IsValidCompanyID(_local_company)) return;
00851 AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
00852 }