00001
00002
00005 #ifdef ENABLE_NETWORK
00006 #include "../stdafx.h"
00007 #include "../openttd.h"
00008 #include "../strings_func.h"
00009 #include "../date_func.h"
00010 #include "../fios.h"
00011 #include "network_internal.h"
00012 #include "network_client.h"
00013 #include "network_gui.h"
00014 #include "network_gamelist.h"
00015 #include "../gui.h"
00016 #include "network_server.h"
00017 #include "network_udp.h"
00018 #include "../window_func.h"
00019 #include "../string_func.h"
00020 #include "../gfx_func.h"
00021 #include "../settings_type.h"
00022 #include "../widgets/dropdown_func.h"
00023 #include "../querystring_gui.h"
00024 #include "../sortlist_type.h"
00025 #include "../company_base.h"
00026
00027 #include "table/strings.h"
00028 #include "../table/sprites.h"
00029
00030
00031 static void ShowNetworkStartServerWindow();
00032 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
00033 extern void SwitchToMode(SwitchMode new_mode);
00034
00035 static const StringID _connection_types_dropdown[] = {
00036 STR_NETWORK_LAN_INTERNET,
00037 STR_NETWORK_INTERNET_ADVERTISE,
00038 INVALID_STRING_ID
00039 };
00040
00041 static const StringID _lan_internet_types_dropdown[] = {
00042 STR_NETWORK_LAN,
00043 STR_NETWORK_INTERNET,
00044 INVALID_STRING_ID
00045 };
00046
00047 static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL};
00048
00049 void SortNetworkLanguages()
00050 {
00051
00052 if (_language_dropdown[0] == STR_NULL) {
00053 for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i;
00054 _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID;
00055 }
00056
00057
00058 qsort(&_language_dropdown[1], NETLANG_COUNT - 1, sizeof(StringID), &StringIDSorter);
00059 }
00060
00061 enum {
00062 NET_PRC__OFFSET_TOP_WIDGET = 54,
00063 NET_PRC__OFFSET_TOP_WIDGET_COMPANY = 52,
00064 NET_PRC__SIZE_OF_ROW = 14,
00065 };
00066
00070 void UpdateNetworkGameWindow(bool unselect)
00071 {
00072 InvalidateWindowData(WC_NETWORK_WINDOW, 0, unselect ? 1 : 0);
00073 }
00074
00076 enum NetworkGameWindowWidgets {
00077 NGWW_CLOSE,
00078 NGWW_CAPTION,
00079 NGWW_MAIN,
00080
00081 NGWW_CONNECTION,
00082 NGWW_CONN_BTN,
00083 NGWW_CLIENT,
00084
00085 NGWW_NAME,
00086 NGWW_CLIENTS,
00087 NGWW_MAPSIZE,
00088 NGWW_DATE,
00089 NGWW_YEARS,
00090 NGWW_INFO,
00091
00092 NGWW_MATRIX,
00093 NGWW_SCROLLBAR,
00094
00095 NGWW_LASTJOINED_LABEL,
00096 NGWW_LASTJOINED,
00097
00098 NGWW_DETAILS,
00099 NGWW_JOIN,
00100 NGWW_REFRESH,
00101 NGWW_NEWGRF,
00102
00103 NGWW_FIND,
00104 NGWW_ADD,
00105 NGWW_START,
00106 NGWW_CANCEL,
00107
00108 NGWW_RESIZE,
00109 };
00110
00111 typedef GUIList<NetworkGameList*> GUIGameServerList;
00112 typedef uint16 ServerListPosition;
00113 static const ServerListPosition SLP_INVALID = 0xFFFF;
00114
00115 class NetworkGameWindow : public QueryStringBaseWindow {
00116 protected:
00117
00118 static Listing last_sorting;
00119
00120
00121 static GUIGameServerList::SortFunction * const sorter_funcs[];
00122
00123 byte field;
00124 NetworkGameList *server;
00125 GUIGameServerList servers;
00126 ServerListPosition list_pos;
00127
00132 void BuildNetworkGameList()
00133 {
00134 if (!this->servers.NeedRebuild()) return;
00135
00136
00137 this->servers.Clear();
00138
00139 for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
00140 *this->servers.Append() = ngl;
00141 }
00142
00143 this->servers.Compact();
00144 this->servers.RebuildDone();
00145 }
00146
00148 static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00149 {
00150 return strcasecmp((*a)->info.server_name, (*b)->info.server_name);
00151 }
00152
00156 static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00157 {
00158
00159 int r = (*a)->info.clients_on - (*b)->info.clients_on;
00160
00161 if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max;
00162 if (r == 0) r = NGameNameSorter(a, b);
00163
00164 return r;
00165 }
00166
00168 static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00169 {
00170
00171 int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width);
00172
00173 if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width;
00174 return (r != 0) ? r : NGameClientSorter(a, b);
00175 }
00176
00178 static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00179 {
00180 int r = (*a)->info.game_date - (*b)->info.game_date;
00181 return (r != 0) ? r : NGameClientSorter(a, b);
00182 }
00183
00185 static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00186 {
00187 int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date;
00188 return (r != 0) ? r : NGameDateSorter(a, b);
00189 }
00190
00193 static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00194 {
00195
00196 int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision);
00197
00198
00199 if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible;
00200
00201 if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible;
00202
00203 if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password;
00204
00205 if (r == 0) r = NGameNameSorter(a, b);
00206
00207 return r;
00208 }
00209
00211 void SortNetworkGameList()
00212 {
00213 if (!this->servers.Sort()) return;
00214
00215
00216
00217
00218
00219 this->list_pos = SLP_INVALID;
00220 _network_game_list = this->servers[0];
00221 NetworkGameList *item = _network_game_list;
00222 if (item == this->server) this->list_pos = 0;
00223 for (uint i = 1; i != this->servers.Length(); i++) {
00224 item->next = this->servers[i];
00225 item = item->next;
00226 if (item == this->server) this->list_pos = i;
00227 }
00228 item->next = NULL;
00229 }
00230
00237 void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight)
00238 {
00239
00240 if (highlight) GfxFillRect(this->widget[NGWW_NAME].left + 1, y - 2, this->widget[NGWW_INFO].right - 1, y + 9, 10);
00241
00242 SetDParamStr(0, cur_item->info.server_name);
00243 DrawStringTruncated(this->widget[NGWW_NAME].left + 5, y, STR_JUST_RAW_STRING, TC_BLACK, this->widget[NGWW_NAME].right - this->widget[NGWW_NAME].left - 5);
00244
00245
00246 if (cur_item->online) {
00247 SetDParam(0, cur_item->info.clients_on);
00248 SetDParam(1, cur_item->info.clients_max);
00249 SetDParam(2, cur_item->info.companies_on);
00250 SetDParam(3, cur_item->info.companies_max);
00251 DrawStringCentered(this->widget[NGWW_CLIENTS].left + 39, y, STR_NETWORK_GENERAL_ONLINE, TC_GOLD);
00252
00253
00254 if (!this->IsWidgetHidden(NGWW_MAPSIZE)) {
00255 SetDParam(0, cur_item->info.map_width);
00256 SetDParam(1, cur_item->info.map_height);
00257 DrawStringCentered(this->widget[NGWW_MAPSIZE].left + 39, y, STR_NETWORK_MAP_SIZE_SHORT, TC_BLACK);
00258 }
00259
00260
00261 if (!this->IsWidgetHidden(NGWW_DATE)) {
00262 YearMonthDay ymd;
00263 ConvertDateToYMD(cur_item->info.game_date, &ymd);
00264 SetDParam(0, ymd.year);
00265 DrawStringCentered(this->widget[NGWW_DATE].left + 29, y, STR_JUST_INT, TC_BLACK);
00266 }
00267
00268
00269 if (!this->IsWidgetHidden(NGWW_YEARS)) {
00270 YearMonthDay ymd_cur, ymd_start;
00271 ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
00272 ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
00273 SetDParam(0, ymd_cur.year - ymd_start.year);
00274 DrawStringCentered(this->widget[NGWW_YEARS].left + 29, y, STR_JUST_INT, TC_BLACK);
00275 }
00276
00277
00278 if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, this->widget[NGWW_INFO].left + 5, y - 1);
00279
00280
00281 DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), this->widget[NGWW_INFO].left + 15, y);
00282
00283
00284 DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, this->widget[NGWW_INFO].left + 25, y);
00285 }
00286 }
00287
00295 void ScrollToSelectedServer()
00296 {
00297 if (this->list_pos == SLP_INVALID) return;
00298 if (this->list_pos < this->vscroll.pos) {
00299
00300 this->vscroll.pos = this->list_pos;
00301 } else if (this->list_pos >= this->vscroll.pos + this->vscroll.cap) {
00302
00303 this->vscroll.pos = this->list_pos - this->vscroll.cap + 1;
00304 }
00305 }
00306
00307 public:
00308 NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH, desc)
00309 {
00310 ttd_strlcpy(this->edit_str_buf, _settings_client.network.client_name, this->edit_str_size);
00311 this->afilter = CS_ALPHANUMERAL;
00312 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 120);
00313 this->SetFocusedWidget(NGWW_CLIENT);
00314
00315 UpdateNetworkGameWindow(true);
00316
00317 this->vscroll.cap = 11;
00318 this->resize.step_height = NET_PRC__SIZE_OF_ROW;
00319
00320 this->field = NGWW_CLIENT;
00321 this->server = NULL;
00322 this->list_pos = SLP_INVALID;
00323
00324 this->servers.SetListing(this->last_sorting);
00325 this->servers.SetSortFuncs(this->sorter_funcs);
00326 this->servers.ForceRebuild();
00327 this->SortNetworkGameList();
00328
00329 this->FindWindowPlacementAndResize(desc);
00330 }
00331
00332 ~NetworkGameWindow()
00333 {
00334 this->last_sorting = this->servers.GetListing();
00335 }
00336
00337 virtual void OnPaint()
00338 {
00339 const NetworkGameList *sel = this->server;
00340 const SortButtonState arrow = this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
00341
00342 if (this->servers.NeedRebuild()) {
00343 this->BuildNetworkGameList();
00344 SetVScrollCount(this, this->servers.Length());
00345 }
00346 this->SortNetworkGameList();
00347
00348
00349 this->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
00350
00351 this->SetWidgetDisabledState(NGWW_JOIN, sel == NULL ||
00352 !sel->online ||
00353 sel->info.clients_on >= sel->info.clients_max ||
00354 !sel->info.compatible);
00355
00356
00357 this->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
00358 !sel->online ||
00359 sel->info.grfconfig == NULL);
00360
00361 SetDParam(0, 0x00);
00362 SetDParam(1, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
00363 this->DrawWidgets();
00364
00365
00366 this->DrawEditBox(NGWW_CLIENT);
00367
00368 DrawString(this->widget[NGWW_CLIENT].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
00369
00370
00371 switch (this->servers.SortType()) {
00372 case NGWW_NAME - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME, arrow); break;
00373 case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
00374 case NGWW_MAPSIZE - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_MAPSIZE)) this->DrawSortButtonState(NGWW_MAPSIZE, arrow); break;
00375 case NGWW_DATE - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_DATE)) this->DrawSortButtonState(NGWW_DATE, arrow); break;
00376 case NGWW_YEARS - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_YEARS)) this->DrawSortButtonState(NGWW_YEARS, arrow); break;
00377 case NGWW_INFO - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO, arrow); break;
00378 }
00379
00380 uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
00381
00382 const int max = min(this->vscroll.pos + this->vscroll.cap, (int)this->servers.Length());
00383
00384 for (int i = this->vscroll.pos; i < max; ++i) {
00385 const NetworkGameList *ngl = this->servers[i];
00386 this->DrawServerLine(ngl, y, ngl == sel);
00387 y += NET_PRC__SIZE_OF_ROW;
00388 }
00389
00390 const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
00391
00392 if (last_joined != NULL) this->DrawServerLine(last_joined, y = this->widget[NGWW_LASTJOINED].top + 3, last_joined == sel);
00393
00394
00395 GfxFillRect(this->widget[NGWW_DETAILS].left + 1, 43, this->widget[NGWW_DETAILS].right - 1, 92, 157);
00396 if (sel == NULL) {
00397 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 58, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
00398 } else if (!sel->online) {
00399 SetDParamStr(0, sel->info.server_name);
00400 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 68, STR_JUST_RAW_STRING, TC_ORANGE);
00401
00402 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 132, STR_NETWORK_SERVER_OFFLINE, TC_FROMSTRING);
00403 } else {
00404 uint16 y = 100;
00405 const uint16 x = this->widget[NGWW_DETAILS].left + 5;
00406
00407 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 48, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
00408
00409
00410 SetDParamStr(0, sel->info.server_name);
00411 DrawStringCenteredTruncated(this->widget[NGWW_DETAILS].left, this->widget[NGWW_DETAILS].right, 62, STR_JUST_RAW_STRING, TC_ORANGE);
00412
00413 SetDParamStr(0, sel->info.map_name);
00414 DrawStringCenteredTruncated(this->widget[NGWW_DETAILS].left, this->widget[NGWW_DETAILS].right, 74, STR_JUST_RAW_STRING, TC_BLACK);
00415
00416 SetDParam(0, sel->info.clients_on);
00417 SetDParam(1, sel->info.clients_max);
00418 SetDParam(2, sel->info.companies_on);
00419 SetDParam(3, sel->info.companies_max);
00420 DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
00421 y += 10;
00422
00423 SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
00424 DrawString(x, y, STR_NETWORK_LANGUAGE, TC_GOLD);
00425 y += 10;
00426
00427 SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
00428 DrawString(x, y, STR_NETWORK_TILESET, TC_GOLD);
00429 y += 10;
00430
00431 SetDParam(0, sel->info.map_width);
00432 SetDParam(1, sel->info.map_height);
00433 DrawString(x, y, STR_NETWORK_MAP_SIZE, TC_GOLD);
00434 y += 10;
00435
00436 SetDParamStr(0, sel->info.server_revision);
00437 DrawString(x, y, STR_NETWORK_SERVER_VERSION, TC_GOLD);
00438 y += 10;
00439
00440 SetDParamStr(0, sel->info.hostname);
00441 SetDParam(1, sel->port);
00442 DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, TC_GOLD);
00443 y += 10;
00444
00445 SetDParam(0, sel->info.start_date);
00446 DrawString(x, y, STR_NETWORK_START_DATE, TC_GOLD);
00447 y += 10;
00448
00449 SetDParam(0, sel->info.game_date);
00450 DrawString(x, y, STR_NETWORK_CURRENT_DATE, TC_GOLD);
00451 y += 10;
00452
00453 y += 2;
00454
00455 if (!sel->info.compatible) {
00456 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, TC_FROMSTRING);
00457 } else if (sel->info.clients_on == sel->info.clients_max) {
00458
00459 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING);
00460 } else if (sel->info.use_password) {
00461 DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING);
00462 }
00463
00464 y += 10;
00465 }
00466 }
00467
00468 virtual void OnClick(Point pt, int widget)
00469 {
00470 this->field = widget;
00471 switch (widget) {
00472 case NGWW_CANCEL:
00473 DeleteWindowById(WC_NETWORK_WINDOW, 0);
00474 break;
00475
00476 case NGWW_CONN_BTN:
00477 ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, NGWW_CONN_BTN, 0, 0);
00478 break;
00479
00480 case NGWW_NAME:
00481 case NGWW_CLIENTS:
00482 case NGWW_MAPSIZE:
00483 case NGWW_DATE:
00484 case NGWW_YEARS:
00485 case NGWW_INFO:
00486 if (this->servers.SortType() == widget - NGWW_NAME) {
00487 this->servers.ToggleSortOrder();
00488 if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1;
00489 } else {
00490 this->servers.SetSortType(widget - NGWW_NAME);
00491 this->servers.ForceResort();
00492 this->SortNetworkGameList();
00493 }
00494 this->ScrollToSelectedServer();
00495 this->SetDirty();
00496 break;
00497
00498 case NGWW_MATRIX: {
00499 uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
00500
00501 if (id_v >= this->vscroll.cap) return;
00502 id_v += this->vscroll.pos;
00503
00504 this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL;
00505 this->list_pos = (server == NULL) ? SLP_INVALID : id_v;
00506 this->SetDirty();
00507 } break;
00508
00509 case NGWW_LASTJOINED: {
00510 NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
00511 if (last_joined != NULL) {
00512 this->server = last_joined;
00513
00514
00515 for (uint i = 0; i < this->servers.Length(); i++) {
00516 if (this->servers[i] == this->server) {
00517 this->list_pos = i;
00518 break;
00519 }
00520 }
00521 this->ScrollToSelectedServer();
00522 this->SetDirty();
00523 }
00524 } break;
00525
00526 case NGWW_FIND:
00527 switch (_settings_client.network.lan_internet) {
00528 case 0: NetworkUDPSearchGame(); break;
00529 case 1: NetworkUDPQueryMasterServer(); break;
00530 }
00531 break;
00532
00533 case NGWW_ADD:
00534 SetDParamStr(0, _settings_client.network.connect_to_ip);
00535 ShowQueryString(
00536 STR_JUST_RAW_STRING,
00537 STR_NETWORK_ENTER_IP,
00538 31,
00539 250,
00540 this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED);
00541 break;
00542
00543 case NGWW_START:
00544 ShowNetworkStartServerWindow();
00545 break;
00546
00547 case NGWW_JOIN:
00548 if (this->server != NULL) {
00549 snprintf(_settings_client.network.last_host, sizeof(_settings_client.network.last_host), "%s", inet_ntoa(*(struct in_addr *)&this->server->ip));
00550 _settings_client.network.last_port = this->server->port;
00551 ShowNetworkLobbyWindow(this->server);
00552 }
00553 break;
00554
00555 case NGWW_REFRESH:
00556 if (this->server != NULL) NetworkUDPQueryServer(NetworkAddress(this->server->info.hostname, this->server->port));
00557 break;
00558
00559 case NGWW_NEWGRF:
00560 if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
00561 break;
00562 }
00563 }
00564
00565 virtual void OnDoubleClick(Point pt, int widget)
00566 {
00567 if (widget == NGWW_MATRIX || widget == NGWW_LASTJOINED) {
00568
00569 if (!this->IsWidgetDisabled(NGWW_JOIN)) this->OnClick(pt, NGWW_JOIN);
00570 }
00571 }
00572
00573 virtual void OnDropdownSelect(int widget, int index)
00574 {
00575 switch (widget) {
00576 case NGWW_CONN_BTN:
00577 _settings_client.network.lan_internet = index;
00578 break;
00579
00580 default:
00581 NOT_REACHED();
00582 }
00583
00584 this->SetDirty();
00585 }
00586
00587 virtual void OnMouseLoop()
00588 {
00589 if (this->field == NGWW_CLIENT) this->HandleEditBox(NGWW_CLIENT);
00590 }
00591
00592 virtual void OnInvalidateData(int data)
00593 {
00594 switch (data) {
00595
00596 case 1:
00597 this->server = NULL;
00598 this->list_pos = SLP_INVALID;
00599 break;
00600
00601
00602 case 2:
00603 for (NetworkGameList **iter = this->servers.Begin(); iter != this->servers.End(); iter++) {
00604 NetworkGameList *item = *iter;
00605 bool missing_grfs = false;
00606 for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) {
00607 if (c->status != GCS_NOT_FOUND) continue;
00608
00609 const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
00610 if (f == NULL) {
00611 missing_grfs = true;
00612 continue;
00613 }
00614
00615 c->filename = f->filename;
00616 c->name = f->name;
00617 c->info = f->info;
00618 c->status = GCS_UNKNOWN;
00619 }
00620
00621 if (!missing_grfs) item->info.compatible = item->info.version_compatible;
00622 }
00623 break;
00624 }
00625 this->servers.ForceRebuild();
00626 this->SetDirty();
00627 }
00628
00629 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00630 {
00631 EventState state = ES_NOT_HANDLED;
00632
00633
00634 if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
00635 if (this->servers.Length() == 0) return ES_HANDLED;
00636 switch (keycode) {
00637 case WKC_UP:
00638
00639 if (this->server == NULL) return ES_HANDLED;
00640 if (this->list_pos > 0) this->list_pos--;
00641 break;
00642 case WKC_DOWN:
00643
00644 if (this->server == NULL) return ES_HANDLED;
00645 if (this->list_pos < this->servers.Length() - 1) this->list_pos++;
00646 break;
00647 case WKC_PAGEUP:
00648
00649 if (this->server == NULL) return ES_HANDLED;
00650 this->list_pos = (this->list_pos < this->vscroll.cap) ? 0 : this->list_pos - this->vscroll.cap;
00651 break;
00652 case WKC_PAGEDOWN:
00653
00654 if (this->server == NULL) return ES_HANDLED;
00655 this->list_pos = min(this->list_pos + this->vscroll.cap, (int)this->servers.Length() - 1);
00656 break;
00657 case WKC_HOME:
00658
00659 this->list_pos = 0;
00660 break;
00661 case WKC_END:
00662
00663 this->list_pos = this->servers.Length() - 1;
00664 break;
00665 default: break;
00666 }
00667
00668 this->server = this->servers[this->list_pos];
00669
00670
00671 this->ScrollToSelectedServer();
00672
00673
00674 this->SetDirty();
00675 return ES_HANDLED;
00676 }
00677
00678 if (this->field != NGWW_CLIENT) {
00679 if (this->server != NULL) {
00680 if (keycode == WKC_DELETE) {
00681 NetworkGameListRemoveItem(this->server);
00682 NetworkRebuildHostList();
00683 this->server = NULL;
00684 this->list_pos = SLP_INVALID;
00685 }
00686 }
00687 return state;
00688 }
00689
00690 if (this->HandleEditBoxKey(NGWW_CLIENT, key, keycode, state) == HEBR_CONFIRM) return state;
00691
00692
00693 if (!StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
00694 strecpy(_settings_client.network.client_name, this->edit_str_buf, lastof(_settings_client.network.client_name));
00695 } else {
00696 strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
00697 }
00698 return state;
00699 }
00700
00701 virtual void OnQueryTextFinished(char *str)
00702 {
00703 if (!StrEmpty(str)) {
00704 NetworkAddServer(str);
00705 NetworkRebuildHostList();
00706 }
00707 }
00708
00709 virtual void OnResize(Point new_size, Point delta)
00710 {
00711 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00712
00713 this->widget[NGWW_MATRIX].data = (this->vscroll.cap << 8) + 1;
00714
00715 SetVScrollCount(this, this->servers.Length());
00716
00717
00718 if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) +
00719 GetWidgetWidth(NGWW_DATE) + GetWidgetWidth(NGWW_YEARS)) {
00720
00721 this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00722 AlignWidgetRight(NGWW_YEARS, NGWW_INFO);
00723 AlignWidgetRight(NGWW_DATE, NGWW_YEARS);
00724 AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00725 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00726 } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) + GetWidgetWidth(NGWW_DATE)) {
00727
00728 this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, WIDGET_LIST_END);
00729 this->HideWidget(NGWW_YEARS);
00730 AlignWidgetRight(NGWW_DATE, NGWW_INFO);
00731 AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00732 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00733 } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE)) {
00734
00735 this->ShowWidget(NGWW_MAPSIZE);
00736 this->SetWidgetsHiddenState(true, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00737 AlignWidgetRight(NGWW_MAPSIZE, NGWW_INFO);
00738 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00739 } else {
00740
00741 this->SetWidgetsHiddenState(true, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00742 AlignWidgetRight(NGWW_CLIENTS, NGWW_INFO);
00743 }
00744 this->widget[NGWW_NAME].right = this->widget[NGWW_CLIENTS].left - 1;
00745
00746
00747 int widget_width = this->widget[NGWW_FIND].right - this->widget[NGWW_FIND].left;
00748 int space = (this->width - 4 * widget_width - 25) / 3;
00749
00750 int offset = 10;
00751 for (uint i = 0; i < 4; i++) {
00752 this->widget[NGWW_FIND + i].left = offset;
00753 offset += widget_width;
00754 this->widget[NGWW_FIND + i].right = offset;
00755 offset += space;
00756 }
00757 }
00758
00759 static const int MIN_EXTRA_COLUMNS_WIDTH = 550;
00760 };
00761
00762 Listing NetworkGameWindow::last_sorting = {false, 5};
00763 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
00764 &NGameNameSorter,
00765 &NGameClientSorter,
00766 &NGameMapSizeSorter,
00767 &NGameDateSorter,
00768 &NGameYearsSorter,
00769 &NGameAllowedSorter
00770 };
00771
00772
00773 static const Widget _network_game_window_widgets[] = {
00774
00775 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00776 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_LIGHT_BLUE, 11, 449, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
00777 { WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 263, 0x0, STR_NULL},
00778
00779 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 9, 85, 23, 35, STR_NETWORK_CONNECTION, STR_NULL},
00780 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 90, 181, 22, 33, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP},
00781
00782 { WWT_EDITBOX, RESIZE_LR, COLOUR_LIGHT_BLUE, 290, 440, 22, 33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP},
00783
00784
00785 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 70, 42, 53, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP},
00786 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 150, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
00787 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 150, 42, 53, STR_NETWORK_MAP_SIZE_CAPTION, STR_NETWORK_MAP_SIZE_CAPTION_TIP},
00788 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 130, 42, 53, STR_NETWORK_DATE_CAPTION, STR_NETWORK_DATE_CAPTION_TIP},
00789 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 130, 42, 53, STR_NETWORK_YEARS_CAPTION, STR_NETWORK_YEARS_CAPTION_TIP},
00790 { WWT_PUSHTXTBTN, RESIZE_LR, COLOUR_WHITE, 151, 190, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP},
00791
00792 { WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 10, 190, 54, 208, (11 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT},
00793 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 42, 208, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00794 { WWT_TEXT, RESIZE_RTB, COLOUR_LIGHT_BLUE, 10, 190, 211, 222, STR_NETWORK_LAST_JOINED_SERVER, STR_NULL},
00795 { WWT_PANEL, RESIZE_RTB, COLOUR_LIGHT_BLUE, 10, 190, 223, 236, 0x0, STR_NETWORK_CLICK_TO_SELECT_LAST},
00796
00797
00798 { WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 42, 236, 0x0, STR_NULL},
00799
00800 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 215, 315, 215, 226, STR_NETWORK_JOIN_GAME, STR_NULL},
00801 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 330, 435, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
00802
00803 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 330, 435, 197, 208, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL},
00804
00805
00806 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 246, 257, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
00807 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 246, 257, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
00808 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 226, 326, 246, 257, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
00809 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 334, 434, 246, 257, STR_012E_CANCEL, STR_NULL},
00810
00811 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 252, 263, 0x0, STR_RESIZE_BUTTON },
00812
00813 { WIDGETS_END},
00814 };
00815
00816 static const WindowDesc _network_game_window_desc(
00817 WDP_CENTER, WDP_CENTER, 450, 264, 780, 264,
00818 WC_NETWORK_WINDOW, WC_NONE,
00819 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00820 _network_game_window_widgets
00821 );
00822
00823 void ShowNetworkGameWindow()
00824 {
00825 static bool first = true;
00826 DeleteWindowById(WC_NETWORK_WINDOW, 0);
00827
00828
00829 if (first) {
00830 char * const *srv;
00831
00832 first = false;
00833
00834 for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
00835 NetworkAddServer(*srv);
00836 }
00837 }
00838
00839 new NetworkGameWindow(&_network_game_window_desc);
00840 }
00841
00842 enum {
00843 NSSWND_START = 64,
00844 NSSWND_ROWSIZE = 12
00845 };
00846
00848 enum NetworkStartServerWidgets {
00849 NSSW_CLOSE = 0,
00850 NSSW_GAMENAME = 4,
00851 NSSW_SETPWD = 5,
00852 NSSW_SELMAP = 7,
00853 NSSW_CONNTYPE_BTN = 10,
00854 NSSW_CLIENTS_BTND = 12,
00855 NSSW_CLIENTS_TXT = 13,
00856 NSSW_CLIENTS_BTNU = 14,
00857 NSSW_COMPANIES_BTND = 16,
00858 NSSW_COMPANIES_TXT = 17,
00859 NSSW_COMPANIES_BTNU = 18,
00860 NSSW_SPECTATORS_BTND = 20,
00861 NSSW_SPECTATORS_TXT = 21,
00862 NSSW_SPECTATORS_BTNU = 22,
00863 NSSW_LANGUAGE_BTN = 24,
00864 NSSW_START = 25,
00865 NSSW_LOAD = 26,
00866 NSSW_CANCEL = 27,
00867 };
00868
00869 struct NetworkStartServerWindow : public QueryStringBaseWindow {
00870 byte field;
00871 FiosItem *map;
00872 byte widget_id;
00873
00874 NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH, desc)
00875 {
00876 ttd_strlcpy(this->edit_str_buf, _settings_client.network.server_name, this->edit_str_size);
00877
00878 _saveload_mode = SLD_NEW_GAME;
00879 BuildFileList();
00880 this->vscroll.cap = 12;
00881 this->vscroll.count = _fios_items.Length() + 1;
00882
00883 this->afilter = CS_ALPHANUMERAL;
00884 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 160);
00885 this->SetFocusedWidget(NSSW_GAMENAME);
00886
00887 this->field = NSSW_GAMENAME;
00888
00889 this->FindWindowPlacementAndResize(desc);
00890 }
00891
00892 virtual void OnPaint()
00893 {
00894 int y = NSSWND_START;
00895 const FiosItem *item;
00896
00897
00898 SetDParam(1, _connection_types_dropdown[_settings_client.network.server_advertise]);
00899 SetDParam(2, _settings_client.network.max_clients);
00900 SetDParam(3, _settings_client.network.max_companies);
00901 SetDParam(4, _settings_client.network.max_spectators);
00902 SetDParam(5, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
00903 this->DrawWidgets();
00904
00905
00906 this->DrawEditBox(NSSW_GAMENAME);
00907
00908
00909 if (!StrEmpty(_settings_client.network.server_password)) DoDrawString("*", 408, 23, TC_RED);
00910
00911
00912 GfxFillRect(11, 63, 258, 215, 0xD7);
00913
00914 for (uint pos = this->vscroll.pos; pos < _fios_items.Length() + 1; pos++) {
00915 item = _fios_items.Get(pos - 1);
00916 if (item == this->map || (pos == 0 && this->map == NULL))
00917 GfxFillRect(11, y - 1, 258, y + 10, 155);
00918
00919 if (pos == 0) {
00920 DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
00921 } else {
00922 DoDrawString(item->title, 14, y, _fios_colours[item->type] );
00923 }
00924 y += NSSWND_ROWSIZE;
00925
00926 if (y >= this->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
00927 }
00928 }
00929
00930 virtual void OnClick(Point pt, int widget)
00931 {
00932 this->field = widget;
00933 switch (widget) {
00934 case NSSW_CLOSE:
00935 case NSSW_CANCEL:
00936 ShowNetworkGameWindow();
00937 break;
00938
00939 case NSSW_SETPWD:
00940 this->widget_id = NSSW_SETPWD;
00941 SetDParamStr(0, _settings_client.network.server_password);
00942 ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL, QSF_NONE);
00943 break;
00944
00945 case NSSW_SELMAP: {
00946 int y = (pt.y - NSSWND_START) / NSSWND_ROWSIZE;
00947
00948 y += this->vscroll.pos;
00949 if (y >= this->vscroll.count) return;
00950
00951 this->map = (y == 0) ? NULL : _fios_items.Get(y - 1);
00952 this->SetDirty();
00953 } break;
00954
00955 case NSSW_CONNTYPE_BTN:
00956 ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, NSSW_CONNTYPE_BTN, 0, 0);
00957 break;
00958
00959 case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
00960 case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
00961 case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
00962
00963 if ((this->flags4 & WF_TIMEOUT_MASK) <= WF_TIMEOUT_TRIGGER) {
00964 this->HandleButtonClick(widget);
00965 this->SetDirty();
00966 switch (widget) {
00967 default: NOT_REACHED();
00968 case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
00969 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - NSSW_CLIENTS_TXT, 2, MAX_CLIENTS);
00970 break;
00971 case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
00972 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - NSSW_COMPANIES_TXT, 1, MAX_COMPANIES);
00973 break;
00974 case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
00975 _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
00976 break;
00977 }
00978 }
00979 _left_button_clicked = false;
00980 break;
00981
00982 case NSSW_CLIENTS_TXT:
00983 this->widget_id = NSSW_CLIENTS_TXT;
00984 SetDParam(0, _settings_client.network.max_clients);
00985 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_CLIENTS, 4, 50, this, CS_NUMERAL, QSF_NONE);
00986 break;
00987
00988 case NSSW_COMPANIES_TXT:
00989 this->widget_id = NSSW_COMPANIES_TXT;
00990 SetDParam(0, _settings_client.network.max_companies);
00991 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_COMPANIES, 3, 50, this, CS_NUMERAL, QSF_NONE);
00992 break;
00993
00994 case NSSW_SPECTATORS_TXT:
00995 this->widget_id = NSSW_SPECTATORS_TXT;
00996 SetDParam(0, _settings_client.network.max_spectators);
00997 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 4, 50, this, CS_NUMERAL, QSF_NONE);
00998 break;
00999
01000 case NSSW_LANGUAGE_BTN: {
01001 uint sel = 0;
01002 for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
01003 if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
01004 sel = i;
01005 break;
01006 }
01007 }
01008 ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
01009 } break;
01010
01011 case NSSW_START:
01012 _is_network_server = true;
01013
01014 if (this->map == NULL) {
01015 ShowGenerateLandscape();
01016 } else {
01017 const char *name = FiosBrowseTo(this->map);
01018 if (name != NULL) {
01019 SetFiosType(this->map->type);
01020 _file_to_saveload.filetype = FT_SCENARIO;
01021 strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
01022 strecpy(_file_to_saveload.title, this->map->title, lastof(_file_to_saveload.title));
01023
01024 delete this;
01025 SwitchToMode(SM_START_SCENARIO);
01026 }
01027 }
01028 break;
01029
01030 case NSSW_LOAD:
01031 _is_network_server = true;
01032
01033
01034 delete this;
01035 ShowSaveLoadDialog(SLD_LOAD_GAME);
01036 break;
01037 }
01038 }
01039
01040 virtual void OnDropdownSelect(int widget, int index)
01041 {
01042 switch (widget) {
01043 case NSSW_CONNTYPE_BTN:
01044 _settings_client.network.server_advertise = (index != 0);
01045 break;
01046 case NSSW_LANGUAGE_BTN:
01047 _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
01048 break;
01049 default:
01050 NOT_REACHED();
01051 }
01052
01053 this->SetDirty();
01054 }
01055
01056 virtual void OnMouseLoop()
01057 {
01058 if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
01059 }
01060
01061 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01062 {
01063 EventState state = ES_NOT_HANDLED;
01064 if (this->field == NSSW_GAMENAME) {
01065 if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == HEBR_CONFIRM) return state;
01066
01067 strecpy(_settings_client.network.server_name, this->text.buf, lastof(_settings_client.network.server_name));
01068 }
01069
01070 return state;
01071 }
01072
01073 virtual void OnQueryTextFinished(char *str)
01074 {
01075 if (str == NULL) return;
01076
01077 if (this->widget_id == NSSW_SETPWD) {
01078 strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password));
01079 } else {
01080 int32 value = atoi(str);
01081 this->InvalidateWidget(this->widget_id);
01082 switch (this->widget_id) {
01083 default: NOT_REACHED();
01084 case NSSW_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(value, 2, MAX_CLIENTS); break;
01085 case NSSW_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break;
01086 case NSSW_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
01087 }
01088 }
01089
01090 this->SetDirty();
01091 }
01092 };
01093
01094 static const Widget _network_start_server_window_widgets[] = {
01095
01096 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
01097 { WWT_CAPTION, RESIZE_NONE, COLOUR_LIGHT_BLUE, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
01098 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 419, 14, 243, 0x0, STR_NULL},
01099
01100
01101 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 90, 22, 34, STR_NETWORK_NEW_GAME_NAME, STR_NULL},
01102 { WWT_EDITBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 100, 272, 22, 33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP},
01103 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP},
01104
01105
01106 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 110, 43, 55, STR_NETWORK_SELECT_MAP, STR_NULL},
01107 { WWT_INSET, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 271, 62, 216, STR_NULL, STR_NETWORK_SELECT_MAP_TIP},
01108 { WWT_SCROLLBAR, RESIZE_NONE, COLOUR_LIGHT_BLUE, 259, 270, 63, 215, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01109
01110
01111 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 63, 75, STR_NETWORK_CONNECTION, STR_NULL},
01112 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 410, 77, 88, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP},
01113
01114 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 95, 107, STR_NETWORK_NUMBER_OF_CLIENTS, STR_NULL},
01115 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 109, 120, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01116 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 109, 120, STR_NETWORK_CLIENTS_SELECT, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01117 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 109, 120, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01118
01119 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 127, 139, STR_NETWORK_NUMBER_OF_COMPANIES, STR_NULL},
01120 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 141, 152, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01121 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 141, 152, STR_NETWORK_COMPANIES_SELECT, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01122 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 141, 152, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01123
01124 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 159, 171, STR_NETWORK_NUMBER_OF_SPECTATORS, STR_NULL},
01125 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 173, 184, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01126 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 173, 184, STR_NETWORK_SPECTATORS_SELECT, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01127 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 173, 184, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01128
01129 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 191, 203, STR_NETWORK_LANGUAGE_SPOKEN, STR_NULL},
01130 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 410, 205, 216, STR_NETWORK_LANGUAGE_COMBO, STR_NETWORK_LANGUAGE_TIP},
01131
01132
01133 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 40, 140, 224, 235, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP},
01134 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 150, 250, 224, 235, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP},
01135 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 260, 360, 224, 235, STR_012E_CANCEL, STR_NULL},
01136
01137 { WIDGETS_END},
01138 };
01139
01140 static const WindowDesc _network_start_server_window_desc(
01141 WDP_CENTER, WDP_CENTER, 420, 244, 420, 244,
01142 WC_NETWORK_WINDOW, WC_NONE,
01143 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01144 _network_start_server_window_widgets
01145 );
01146
01147 static void ShowNetworkStartServerWindow()
01148 {
01149 DeleteWindowById(WC_NETWORK_WINDOW, 0);
01150
01151 new NetworkStartServerWindow(&_network_start_server_window_desc);
01152 }
01153
01155 enum NetworkLobbyWindowWidgets {
01156 NLWW_CLOSE = 0,
01157 NLWW_MATRIX = 5,
01158 NLWW_DETAILS = 7,
01159 NLWW_JOIN = 8,
01160 NLWW_NEW = 9,
01161 NLWW_SPECTATE = 10,
01162 NLWW_REFRESH = 11,
01163 NLWW_CANCEL = 12,
01164 };
01165
01166 struct NetworkLobbyWindow : public Window {
01167 CompanyID company;
01168 NetworkGameList *server;
01169 NetworkCompanyInfo company_info[MAX_COMPANIES];
01170
01171 NetworkLobbyWindow(const WindowDesc *desc, NetworkGameList *ngl) :
01172 Window(desc), company(INVALID_COMPANY), server(ngl)
01173 {
01174 this->vscroll.cap = 10;
01175
01176 this->FindWindowPlacementAndResize(desc);
01177 }
01178
01179 CompanyID NetworkLobbyFindCompanyIndex(byte pos)
01180 {
01181
01182 for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
01183 if (!StrEmpty(this->company_info[i].company_name)) {
01184 if (pos-- == 0) return i;
01185 }
01186 }
01187
01188 return COMPANY_FIRST;
01189 }
01190
01191 virtual void OnPaint()
01192 {
01193 const NetworkGameInfo *gi = &this->server->info;
01194 int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
01195
01196
01197 this->SetWidgetDisabledState(NLWW_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
01198
01199 this->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
01200
01201 this->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
01202
01203
01204 SetDParamStr(0, gi->server_name);
01205 this->DrawWidgets();
01206
01207 SetVScrollCount(this, gi->companies_on);
01208
01209
01210 pos = this->vscroll.pos;
01211 while (pos < gi->companies_on) {
01212 byte company = NetworkLobbyFindCompanyIndex(pos);
01213 bool income = false;
01214 if (this->company == company) {
01215 GfxFillRect(11, y - 1, 154, y + 10, 10);
01216 }
01217
01218 DoDrawStringTruncated(this->company_info[company].company_name, 13, y, TC_BLACK, 135 - 13);
01219 if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, 135, y);
01220
01221
01222 if (this->company_info[company].income >= 0) income = true;
01223 DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, 145, y);
01224
01225 pos++;
01226 y += NET_PRC__SIZE_OF_ROW;
01227 if (pos >= this->vscroll.pos + this->vscroll.cap) break;
01228 }
01229
01230
01231 GfxFillRect(174, 39, 403, 75, 157);
01232 DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, TC_FROMSTRING);
01233 if (this->company != INVALID_COMPANY && !StrEmpty(this->company_info[this->company].company_name)) {
01234 const uint x = 183;
01235 const uint trunc_width = this->widget[NLWW_DETAILS].right - x;
01236 y = 80;
01237
01238 SetDParam(0, gi->clients_on);
01239 SetDParam(1, gi->clients_max);
01240 SetDParam(2, gi->companies_on);
01241 SetDParam(3, gi->companies_max);
01242 DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
01243 y += 10;
01244
01245 SetDParamStr(0, this->company_info[this->company].company_name);
01246 DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, TC_GOLD, trunc_width);
01247 y += 10;
01248
01249 SetDParam(0, this->company_info[this->company].inaugurated_year);
01250 DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, TC_GOLD);
01251 y += 10;
01252
01253 SetDParam(0, this->company_info[this->company].company_value);
01254 DrawString(x, y, STR_NETWORK_VALUE, TC_GOLD);
01255 y += 10;
01256
01257 SetDParam(0, this->company_info[this->company].money);
01258 DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, TC_GOLD);
01259 y += 10;
01260
01261 SetDParam(0, this->company_info[this->company].income);
01262 DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, TC_GOLD);
01263 y += 10;
01264
01265 SetDParam(0, this->company_info[this->company].performance);
01266 DrawString(x, y, STR_NETWORK_PERFORMANCE, TC_GOLD);
01267 y += 10;
01268
01269 SetDParam(0, this->company_info[this->company].num_vehicle[0]);
01270 SetDParam(1, this->company_info[this->company].num_vehicle[1]);
01271 SetDParam(2, this->company_info[this->company].num_vehicle[2]);
01272 SetDParam(3, this->company_info[this->company].num_vehicle[3]);
01273 SetDParam(4, this->company_info[this->company].num_vehicle[4]);
01274 DrawString(x, y, STR_NETWORK_VEHICLES, TC_GOLD);
01275 y += 10;
01276
01277 SetDParam(0, this->company_info[this->company].num_station[0]);
01278 SetDParam(1, this->company_info[this->company].num_station[1]);
01279 SetDParam(2, this->company_info[this->company].num_station[2]);
01280 SetDParam(3, this->company_info[this->company].num_station[3]);
01281 SetDParam(4, this->company_info[this->company].num_station[4]);
01282 DrawString(x, y, STR_NETWORK_STATIONS, TC_GOLD);
01283 y += 10;
01284
01285 SetDParamStr(0, this->company_info[this->company].clients);
01286 DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, TC_GOLD, trunc_width);
01287 }
01288 }
01289
01290 virtual void OnClick(Point pt, int widget)
01291 {
01292 switch (widget) {
01293 case NLWW_CLOSE:
01294 case NLWW_CANCEL:
01295 ShowNetworkGameWindow();
01296 break;
01297
01298 case NLWW_MATRIX: {
01299 uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
01300
01301 if (id_v >= this->vscroll.cap) break;
01302
01303 id_v += this->vscroll.pos;
01304 this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
01305 this->SetDirty();
01306 } break;
01307
01308 case NLWW_JOIN:
01309
01310 _network_playas = this->company;
01311 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01312 break;
01313
01314 case NLWW_NEW:
01315 _network_playas = COMPANY_NEW_COMPANY;
01316 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01317 break;
01318
01319 case NLWW_SPECTATE:
01320 _network_playas = COMPANY_SPECTATOR;
01321 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01322 break;
01323
01324 case NLWW_REFRESH:
01325 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01326 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01327
01328 memset(this->company_info, 0, sizeof(this->company_info));
01329 break;
01330 }
01331 }
01332
01333 virtual void OnDoubleClick(Point pt, int widget)
01334 {
01335 if (widget == NLWW_MATRIX) {
01336
01337 if (!this->IsWidgetDisabled(NLWW_JOIN)) this->OnClick(pt, NLWW_JOIN);
01338 }
01339 }
01340 };
01341
01342 static const Widget _network_lobby_window_widgets[] = {
01343 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
01344 { WWT_CAPTION, RESIZE_NONE, COLOUR_LIGHT_BLUE, 11, 419, 0, 13, STR_NETWORK_GAME_LOBBY, STR_NULL},
01345 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 419, 14, 234, 0x0, STR_NULL},
01346 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 419, 22, 34, STR_NETWORK_PREPARE_TO_JOIN, STR_NULL},
01347
01348
01349 { WWT_PANEL, RESIZE_NONE, COLOUR_WHITE, 10, 155, 38, 49, 0x0, STR_NULL},
01350 { WWT_MATRIX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 155, 50, 190, (10 << 8) + 1, STR_NETWORK_COMPANY_LIST_TIP},
01351 { WWT_SCROLLBAR, RESIZE_NONE, COLOUR_LIGHT_BLUE, 156, 167, 38, 190, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01352
01353
01354 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 173, 404, 38, 190, 0x0, STR_NULL},
01355
01356
01357 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 151, 200, 211, STR_NETWORK_JOIN_COMPANY, STR_NETWORK_JOIN_COMPANY_TIP},
01358 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 151, 215, 226, STR_NETWORK_NEW_COMPANY, STR_NETWORK_NEW_COMPANY_TIP},
01359 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 158, 268, 200, 211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP},
01360 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 158, 268, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
01361 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 278, 388, 200, 211, STR_012E_CANCEL, STR_NULL},
01362
01363 { WIDGETS_END},
01364 };
01365
01366 static const WindowDesc _network_lobby_window_desc(
01367 WDP_CENTER, WDP_CENTER, 420, 235, 420, 235,
01368 WC_NETWORK_WINDOW, WC_NONE,
01369 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01370 _network_lobby_window_widgets
01371 );
01372
01373
01374
01375 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
01376 {
01377 DeleteWindowById(WC_NETWORK_WINDOW, 0);
01378
01379 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01380 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01381
01382 new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
01383 }
01384
01390 NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
01391 {
01392 NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, 0));
01393 return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL;
01394 }
01395
01396
01397
01398
01399
01400 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
01401
01402
01403 typedef void ClientList_Action_Proc(byte client_no);
01404
01405
01406 #define MAX_CLIENTLIST_ACTION 10
01407
01408 enum {
01409 CLNWND_OFFSET = 16,
01410 CLNWND_ROWSIZE = 10
01411 };
01412
01413 static const Widget _client_list_widgets[] = {
01414 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01415 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 237, 0, 13, STR_NETWORK_CLIENT_LIST, STR_018C_WINDOW_TITLE_DRAG_THIS},
01416 { WWT_STICKYBOX, RESIZE_NONE, COLOUR_GREY, 238, 249, 0, 13, STR_NULL, STR_STICKY_BUTTON},
01417
01418 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 249, 14, 14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL},
01419 { WIDGETS_END},
01420 };
01421
01422 static const Widget _client_list_popup_widgets[] = {
01423 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 99, 0, 0, 0, STR_NULL},
01424 { WIDGETS_END},
01425 };
01426
01427 static const WindowDesc _client_list_desc(
01428 WDP_AUTO, WDP_AUTO, 250, 1, 250, 1,
01429 WC_CLIENT_LIST, WC_NONE,
01430 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
01431 _client_list_widgets
01432 );
01433
01434
01435 static const NetworkClientInfo *NetworkFindClientInfo(byte client_no)
01436 {
01437 const NetworkClientInfo *ci;
01438
01439 FOR_ALL_CLIENT_INFOS(ci) {
01440 if (client_no == 0) return ci;
01441 client_no--;
01442 }
01443
01444 return NULL;
01445 }
01446
01447
01448 static void ClientList_Kick(byte client_no)
01449 {
01450 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01451
01452 if (ci == NULL) return;
01453
01454 NetworkServerKickClient(ci->client_id);
01455 }
01456
01457 static void ClientList_Ban(byte client_no)
01458 {
01459 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01460
01461 if (ci == NULL) return;
01462
01463 NetworkServerBanIP(GetClientIP(ci));
01464 }
01465
01466 static void ClientList_GiveMoney(byte client_no)
01467 {
01468 if (NetworkFindClientInfo(client_no) != NULL) {
01469 ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
01470 }
01471 }
01472
01473 static void ClientList_SpeakToClient(byte client_no)
01474 {
01475 if (NetworkFindClientInfo(client_no) != NULL) {
01476 ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
01477 }
01478 }
01479
01480 static void ClientList_SpeakToCompany(byte client_no)
01481 {
01482 if (NetworkFindClientInfo(client_no) != NULL) {
01483 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
01484 }
01485 }
01486
01487 static void ClientList_SpeakToAll(byte client_no)
01488 {
01489 ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
01490 }
01491
01492 static void ClientList_None(byte client_no)
01493 {
01494
01495 }
01496
01497
01498
01499 struct NetworkClientListPopupWindow : Window {
01500 int sel_index;
01501 int client_no;
01502 char action[MAX_CLIENTLIST_ACTION][50];
01503 ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
01504
01505 NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
01506 Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
01507 sel_index(0), client_no(client_no)
01508 {
01509
01510
01511
01512
01513
01514 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01515
01516 int i = 0;
01517 if (_network_own_client_id != ci->client_id) {
01518 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
01519 this->proc[i++] = &ClientList_SpeakToClient;
01520 }
01521
01522 if (IsValidCompanyID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
01523 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
01524 this->proc[i++] = &ClientList_SpeakToCompany;
01525 }
01526 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
01527 this->proc[i++] = &ClientList_SpeakToAll;
01528
01529 if (_network_own_client_id != ci->client_id) {
01530
01531 if (IsValidCompanyID(_network_playas) && IsValidCompanyID(ci->client_playas) && _settings_game.economy.give_money) {
01532 GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
01533 this->proc[i++] = &ClientList_GiveMoney;
01534 }
01535 }
01536
01537
01538 if (_network_server && _network_own_client_id != ci->client_id) {
01539 GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
01540 this->proc[i++] = &ClientList_Kick;
01541
01542 seprintf(this->action[i], lastof(this->action[i]), "Ban");
01543 this->proc[i++] = &ClientList_Ban;
01544 }
01545
01546 if (i == 0) {
01547 GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
01548 this->proc[i++] = &ClientList_None;
01549 }
01550
01551
01552 int h = ClientListPopupHeight();
01553
01554
01555 this->widget[0].bottom = this->widget[0].top + h;
01556 this->widget[0].right = this->widget[0].left + 150;
01557
01558 this->flags4 &= ~WF_WHITE_BORDER_MASK;
01559
01560 this->FindWindowPlacementAndResize(150, h + 1);
01561 }
01562
01566 void HandleClientListPopupClick(byte index)
01567 {
01568
01569 if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
01570 this->proc[index](this->client_no);
01571 }
01572 }
01573
01577 uint ClientListPopupHeight()
01578 {
01579 int num = 0;
01580
01581
01582 for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
01583 if (this->action[i][0] == '\0') continue;
01584 if (this->proc[i] == NULL) continue;
01585 num++;
01586 }
01587
01588 num *= CLNWND_ROWSIZE;
01589
01590 return num + 1;
01591 }
01592
01593
01594 virtual void OnPaint()
01595 {
01596 this->DrawWidgets();
01597
01598
01599 int sel = this->sel_index;
01600 int y = 1;
01601 for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
01602 if (this->action[i][0] == '\0') continue;
01603 if (this->proc[i] == NULL) continue;
01604
01605 TextColour colour;
01606 if (sel-- == 0) {
01607 GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
01608 colour = TC_WHITE;
01609 } else {
01610 colour = TC_BLACK;
01611 }
01612
01613 DoDrawString(this->action[i], 4, y, colour);
01614 }
01615 }
01616
01617 virtual void OnMouseLoop()
01618 {
01619
01620 int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
01621
01622 if (_left_button_down) {
01623 if (index == -1 || index == this->sel_index) return;
01624
01625 this->sel_index = index;
01626 this->SetDirty();
01627 } else {
01628 if (index >= 0 && _cursor.pos.y >= this->top) {
01629 HandleClientListPopupClick(index);
01630 }
01631
01632 DeleteWindowById(WC_TOOLBAR_MENU, 0);
01633 }
01634 }
01635 };
01636
01640 static void PopupClientList(int client_no, int x, int y)
01641 {
01642 DeleteWindowById(WC_TOOLBAR_MENU, 0);
01643
01644 if (NetworkFindClientInfo(client_no) == NULL) return;
01645
01646 new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
01647 }
01648
01652 struct NetworkClientListWindow : Window
01653 {
01654 int selected_item;
01655 int selected_y;
01656
01657 NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
01658 Window(desc, window_number),
01659 selected_item(-1),
01660 selected_y(0)
01661 {
01662 this->FindWindowPlacementAndResize(desc);
01663 }
01664
01668 bool CheckClientListHeight()
01669 {
01670 int num = 0;
01671 const NetworkClientInfo *ci;
01672
01673
01674 FOR_ALL_CLIENT_INFOS(ci) {
01675 if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
01676 }
01677
01678 num *= CLNWND_ROWSIZE;
01679
01680
01681 if (this->height != CLNWND_OFFSET + num + 1) {
01682
01683 this->SetDirty();
01684 this->widget[3].bottom = this->widget[3].top + num + 2;
01685 this->height = CLNWND_OFFSET + num + 1;
01686 this->SetDirty();
01687 return false;
01688 }
01689 return true;
01690 }
01691
01692 virtual void OnPaint()
01693 {
01694 NetworkClientInfo *ci;
01695 int i = 0;
01696
01697
01698 if (!this->CheckClientListHeight()) return;
01699
01700 this->DrawWidgets();
01701
01702 int y = CLNWND_OFFSET;
01703
01704 FOR_ALL_CLIENT_INFOS(ci) {
01705 TextColour colour;
01706 if (this->selected_item == i++) {
01707 GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
01708 colour = TC_WHITE;
01709 } else {
01710 colour = TC_BLACK;
01711 }
01712
01713 if (ci->client_id == CLIENT_ID_SERVER) {
01714 DrawString(4, y, STR_NETWORK_SERVER, colour);
01715 } else {
01716 DrawString(4, y, STR_NETWORK_CLIENT, colour);
01717 }
01718
01719
01720 if (IsValidCompanyID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, 64, y + 1);
01721
01722 DoDrawString(ci->client_name, 81, y, colour);
01723
01724 y += CLNWND_ROWSIZE;
01725 }
01726 }
01727
01728 virtual void OnClick(Point pt, int widget)
01729 {
01730
01731 if (this->selected_item != -1) {
01732 PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
01733 }
01734 }
01735
01736 virtual void OnMouseOver(Point pt, int widget)
01737 {
01738
01739 if (pt.y == -1) {
01740 this->selected_y = 0;
01741 this->selected_item = -1;
01742 this->SetDirty();
01743 return;
01744 }
01745
01746 if (pt.y == this->selected_y) return;
01747
01748
01749 this->selected_y = pt.y;
01750 if (pt.y > CLNWND_OFFSET) {
01751 this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
01752 } else {
01753 this->selected_item = -1;
01754 }
01755
01756
01757 this->SetDirty();
01758 }
01759 };
01760
01761 void ShowClientList()
01762 {
01763 AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
01764 }
01765
01766
01767 static NetworkPasswordType pw_type;
01768
01769
01770 void ShowNetworkNeedPassword(NetworkPasswordType npt)
01771 {
01772 StringID caption;
01773
01774 pw_type = npt;
01775 switch (npt) {
01776 default: NOT_REACHED();
01777 case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
01778 case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
01779 }
01780 ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL, QSF_NONE);
01781 }
01782
01783
01784 NetworkJoinStatus _network_join_status;
01785 uint8 _network_join_waiting;
01786 uint32 _network_join_bytes;
01787 uint32 _network_join_bytes_total;
01788
01789 struct NetworkJoinStatusWindow : Window {
01790 NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
01791 {
01792 this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
01793 this->FindWindowPlacementAndResize(desc);
01794 }
01795
01796 virtual void OnPaint()
01797 {
01798 uint8 progress;
01799 this->DrawWidgets();
01800
01801 DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
01802 switch (_network_join_status) {
01803 case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
01804 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
01805 progress = 10;
01806 break;
01807 case NETWORK_JOIN_STATUS_WAITING:
01808 SetDParam(0, _network_join_waiting);
01809 DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
01810 progress = 15;
01811 break;
01812 case NETWORK_JOIN_STATUS_DOWNLOADING:
01813 SetDParam(0, _network_join_bytes);
01814 SetDParam(1, _network_join_bytes_total);
01815 DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
01816
01817 default:
01818 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
01819 }
01820
01821
01822 DrawFrameRect(20, 18, (int)((this->width - 20) * progress / 100), 28, COLOUR_MAUVE, FR_NONE);
01823 }
01824
01825 virtual void OnClick(Point pt, int widget)
01826 {
01827 if (widget == 2) {
01828 NetworkDisconnect();
01829 SwitchToMode(SM_MENU);
01830 ShowNetworkGameWindow();
01831 }
01832 }
01833
01834 virtual void OnQueryTextFinished(char *str)
01835 {
01836 if (StrEmpty(str)) {
01837 NetworkDisconnect();
01838 ShowNetworkGameWindow();
01839 } else {
01840 SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
01841 }
01842 }
01843 };
01844
01845 static const Widget _network_join_status_window_widget[] = {
01846 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 0, 249, 0, 13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
01847 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 249, 14, 84, 0x0, STR_NULL},
01848 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 75, 175, 69, 80, STR_NETWORK_DISCONNECT, STR_NULL},
01849 { WIDGETS_END},
01850 };
01851
01852 static const WindowDesc _network_join_status_window_desc(
01853 WDP_CENTER, WDP_CENTER, 250, 85, 250, 85,
01854 WC_NETWORK_STATUS_WINDOW, WC_NONE,
01855 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
01856 _network_join_status_window_widget
01857 );
01858
01859 void ShowJoinStatusWindow()
01860 {
01861 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
01862 new NetworkJoinStatusWindow(&_network_join_status_window_desc);
01863 }
01864
01865
01867 enum NetworkCompanyPasswordWindowWidgets {
01868 NCPWW_CLOSE,
01869 NCPWW_CAPTION,
01870 NCPWW_BACKGROUND,
01871 NCPWW_LABEL,
01872 NCPWW_PASSWORD,
01873 NCPWW_SAVE_AS_DEFAULT_PASSWORD,
01874 NCPWW_CANCEL,
01875 NCPWW_OK,
01876 };
01877
01878 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
01879 NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(lengthof(_settings_client.network.default_company_pass), desc)
01880 {
01881 this->parent = parent;
01882 this->afilter = CS_ALPHANUMERAL;
01883 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
01884 this->SetFocusedWidget(NCPWW_PASSWORD);
01885
01886 this->FindWindowPlacementAndResize(desc);
01887 }
01888
01889 void OnOk()
01890 {
01891 if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
01892 snprintf(_settings_client.network.default_company_pass, lengthof(_settings_client.network.default_company_pass), "%s", this->edit_str_buf);
01893 }
01894
01895
01896 if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, this->edit_str_size, "*");
01897 char *password = this->edit_str_buf;
01898 NetworkChangeCompanyPassword(1, &password);
01899 }
01900
01901 virtual void OnPaint()
01902 {
01903 this->DrawWidgets();
01904 this->DrawEditBox(4);
01905 }
01906
01907 virtual void OnClick(Point pt, int widget)
01908 {
01909 switch (widget) {
01910 case NCPWW_OK:
01911 this->OnOk();
01912
01913
01914 case NCPWW_CANCEL:
01915 delete this;
01916 break;
01917
01918 case NCPWW_SAVE_AS_DEFAULT_PASSWORD:
01919 this->ToggleWidgetLoweredState(NCPWW_SAVE_AS_DEFAULT_PASSWORD);
01920 this->SetDirty();
01921 break;
01922 }
01923 }
01924
01925 virtual void OnMouseLoop()
01926 {
01927 this->HandleEditBox(4);
01928 }
01929
01930 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01931 {
01932 EventState state = ES_NOT_HANDLED;
01933 switch (this->HandleEditBoxKey(4, key, keycode, state)) {
01934 default: break;
01935
01936 case HEBR_CONFIRM:
01937 this->OnOk();
01938
01939
01940 case HEBR_CANCEL:
01941 delete this;
01942 break;
01943 }
01944 return state;
01945 }
01946
01947 virtual void OnOpenOSKWindow(int wid)
01948 {
01949 ShowOnScreenKeyboard(this, wid, NCPWW_CANCEL, NCPWW_OK);
01950 }
01951 };
01952
01953 static const Widget _ncp_window_widgets[] = {
01954 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01955 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 299, 0, 13, STR_COMPANY_PASSWORD_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
01956 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 299, 14, 50, 0x0, STR_NULL},
01957 { WWT_TEXT, RESIZE_NONE, COLOUR_GREY, 5, 100, 19, 30, STR_COMPANY_PASSWORD, STR_NULL},
01958 { WWT_EDITBOX, RESIZE_NONE, COLOUR_GREY, 101, 294, 19, 30, STR_SET_COMPANY_PASSWORD, STR_NULL},
01959 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 101, 294, 35, 46, STR_MAKE_DEFAULT_COMPANY_PASSWORD, STR_MAKE_DEFAULT_COMPANY_PASSWORD_TIP},
01960 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 149, 51, 62, STR_012E_CANCEL, STR_COMPANY_PASSWORD_CANCEL},
01961 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 150, 299, 51, 62, STR_012F_OK, STR_COMPANY_PASSWORD_OK},
01962 { WIDGETS_END},
01963 };
01964
01965 static const WindowDesc _ncp_window_desc(
01966 WDP_AUTO, WDP_AUTO, 300, 63, 300, 63,
01967 WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
01968 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
01969 _ncp_window_widgets
01970 );
01971
01972 void ShowNetworkCompanyPasswordWindow(Window *parent)
01973 {
01974 DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
01975
01976 new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
01977 }
01978
01979 #endif