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_CLIENT_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 NETWORK_HOSTNAME_LENGTH,
00539 0,
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 this->server = NULL;
00683 this->list_pos = SLP_INVALID;
00684 }
00685 }
00686 return state;
00687 }
00688
00689 if (this->HandleEditBoxKey(NGWW_CLIENT, key, keycode, state) == HEBR_CONFIRM) return state;
00690
00691
00692 if (!StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
00693 strecpy(_settings_client.network.client_name, this->edit_str_buf, lastof(_settings_client.network.client_name));
00694 } else {
00695 strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
00696 }
00697 return state;
00698 }
00699
00700 virtual void OnQueryTextFinished(char *str)
00701 {
00702 if (!StrEmpty(str)) NetworkAddServer(str);
00703 }
00704
00705 virtual void OnResize(Point new_size, Point delta)
00706 {
00707 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00708
00709 this->widget[NGWW_MATRIX].data = (this->vscroll.cap << 8) + 1;
00710
00711 SetVScrollCount(this, this->servers.Length());
00712
00713
00714 if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) +
00715 GetWidgetWidth(NGWW_DATE) + GetWidgetWidth(NGWW_YEARS)) {
00716
00717 this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00718 AlignWidgetRight(NGWW_YEARS, NGWW_INFO);
00719 AlignWidgetRight(NGWW_DATE, NGWW_YEARS);
00720 AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00721 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00722 } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) + GetWidgetWidth(NGWW_DATE)) {
00723
00724 this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, WIDGET_LIST_END);
00725 this->HideWidget(NGWW_YEARS);
00726 AlignWidgetRight(NGWW_DATE, NGWW_INFO);
00727 AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00728 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00729 } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE)) {
00730
00731 this->ShowWidget(NGWW_MAPSIZE);
00732 this->SetWidgetsHiddenState(true, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00733 AlignWidgetRight(NGWW_MAPSIZE, NGWW_INFO);
00734 AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00735 } else {
00736
00737 this->SetWidgetsHiddenState(true, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00738 AlignWidgetRight(NGWW_CLIENTS, NGWW_INFO);
00739 }
00740 this->widget[NGWW_NAME].right = this->widget[NGWW_CLIENTS].left - 1;
00741
00742
00743 int widget_width = this->widget[NGWW_FIND].right - this->widget[NGWW_FIND].left;
00744 int space = (this->width - 4 * widget_width - 25) / 3;
00745
00746 int offset = 10;
00747 for (uint i = 0; i < 4; i++) {
00748 this->widget[NGWW_FIND + i].left = offset;
00749 offset += widget_width;
00750 this->widget[NGWW_FIND + i].right = offset;
00751 offset += space;
00752 }
00753 }
00754
00755 static const int MIN_EXTRA_COLUMNS_WIDTH = 550;
00756 };
00757
00758 Listing NetworkGameWindow::last_sorting = {false, 5};
00759 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
00760 &NGameNameSorter,
00761 &NGameClientSorter,
00762 &NGameMapSizeSorter,
00763 &NGameDateSorter,
00764 &NGameYearsSorter,
00765 &NGameAllowedSorter
00766 };
00767
00768
00769 static const Widget _network_game_window_widgets[] = {
00770
00771 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00772 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_LIGHT_BLUE, 11, 449, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
00773 { WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 263, 0x0, STR_NULL},
00774
00775 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 9, 85, 23, 35, STR_NETWORK_CONNECTION, STR_NULL},
00776 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 90, 181, 22, 33, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP},
00777
00778 { WWT_EDITBOX, RESIZE_LR, COLOUR_LIGHT_BLUE, 290, 440, 22, 33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP},
00779
00780
00781 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 70, 42, 53, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP},
00782 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 150, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
00783 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 150, 42, 53, STR_NETWORK_MAP_SIZE_CAPTION, STR_NETWORK_MAP_SIZE_CAPTION_TIP},
00784 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 130, 42, 53, STR_NETWORK_DATE_CAPTION, STR_NETWORK_DATE_CAPTION_TIP},
00785 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 71, 130, 42, 53, STR_NETWORK_YEARS_CAPTION, STR_NETWORK_YEARS_CAPTION_TIP},
00786 { WWT_PUSHTXTBTN, RESIZE_LR, COLOUR_WHITE, 151, 190, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP},
00787
00788 { WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 10, 190, 54, 208, (11 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT},
00789 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 42, 208, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00790 { WWT_TEXT, RESIZE_RTB, COLOUR_LIGHT_BLUE, 10, 190, 211, 222, STR_NETWORK_LAST_JOINED_SERVER, STR_NULL},
00791 { WWT_PANEL, RESIZE_RTB, COLOUR_LIGHT_BLUE, 10, 190, 223, 236, 0x0, STR_NETWORK_CLICK_TO_SELECT_LAST},
00792
00793
00794 { WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 42, 236, 0x0, STR_NULL},
00795
00796 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 215, 315, 215, 226, STR_NETWORK_JOIN_GAME, STR_NULL},
00797 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 330, 435, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
00798
00799 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 330, 435, 197, 208, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL},
00800
00801
00802 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 246, 257, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
00803 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 246, 257, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
00804 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 226, 326, 246, 257, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
00805 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 334, 434, 246, 257, STR_012E_CANCEL, STR_NULL},
00806
00807 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 252, 263, 0x0, STR_RESIZE_BUTTON },
00808
00809 { WIDGETS_END},
00810 };
00811
00812 static const WindowDesc _network_game_window_desc(
00813 WDP_CENTER, WDP_CENTER, 450, 264, 780, 264,
00814 WC_NETWORK_WINDOW, WC_NONE,
00815 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00816 _network_game_window_widgets
00817 );
00818
00819 void ShowNetworkGameWindow()
00820 {
00821 static bool first = true;
00822 DeleteWindowById(WC_NETWORK_WINDOW, 0);
00823
00824
00825 if (first) {
00826 char * const *srv;
00827
00828 first = false;
00829
00830 for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
00831 NetworkAddServer(*srv);
00832 }
00833 }
00834
00835 new NetworkGameWindow(&_network_game_window_desc);
00836 }
00837
00838 enum {
00839 NSSWND_START = 64,
00840 NSSWND_ROWSIZE = 12
00841 };
00842
00844 enum NetworkStartServerWidgets {
00845 NSSW_CLOSE = 0,
00846 NSSW_GAMENAME = 4,
00847 NSSW_SETPWD = 5,
00848 NSSW_SELMAP = 7,
00849 NSSW_CONNTYPE_BTN = 10,
00850 NSSW_CLIENTS_BTND = 12,
00851 NSSW_CLIENTS_TXT = 13,
00852 NSSW_CLIENTS_BTNU = 14,
00853 NSSW_COMPANIES_BTND = 16,
00854 NSSW_COMPANIES_TXT = 17,
00855 NSSW_COMPANIES_BTNU = 18,
00856 NSSW_SPECTATORS_BTND = 20,
00857 NSSW_SPECTATORS_TXT = 21,
00858 NSSW_SPECTATORS_BTNU = 22,
00859 NSSW_LANGUAGE_BTN = 24,
00860 NSSW_START = 25,
00861 NSSW_LOAD = 26,
00862 NSSW_CANCEL = 27,
00863 };
00864
00865 struct NetworkStartServerWindow : public QueryStringBaseWindow {
00866 byte field;
00867 FiosItem *map;
00868 byte widget_id;
00869
00870 NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH, desc)
00871 {
00872 ttd_strlcpy(this->edit_str_buf, _settings_client.network.server_name, this->edit_str_size);
00873
00874 _saveload_mode = SLD_NEW_GAME;
00875 BuildFileList();
00876 this->vscroll.cap = 12;
00877 this->vscroll.count = _fios_items.Length() + 1;
00878
00879 this->afilter = CS_ALPHANUMERAL;
00880 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 160);
00881 this->SetFocusedWidget(NSSW_GAMENAME);
00882
00883 this->field = NSSW_GAMENAME;
00884
00885 this->FindWindowPlacementAndResize(desc);
00886 }
00887
00888 virtual void OnPaint()
00889 {
00890 int y = NSSWND_START;
00891 const FiosItem *item;
00892
00893
00894 SetDParam(1, _connection_types_dropdown[_settings_client.network.server_advertise]);
00895 SetDParam(2, _settings_client.network.max_clients);
00896 SetDParam(3, _settings_client.network.max_companies);
00897 SetDParam(4, _settings_client.network.max_spectators);
00898 SetDParam(5, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
00899 this->DrawWidgets();
00900
00901
00902 this->DrawEditBox(NSSW_GAMENAME);
00903
00904
00905 if (!StrEmpty(_settings_client.network.server_password)) DoDrawString("*", 408, 23, TC_RED);
00906
00907
00908 GfxFillRect(11, 63, 258, 215, 0xD7);
00909
00910 for (uint pos = this->vscroll.pos; pos < _fios_items.Length() + 1; pos++) {
00911 item = _fios_items.Get(pos - 1);
00912 if (item == this->map || (pos == 0 && this->map == NULL))
00913 GfxFillRect(11, y - 1, 258, y + 10, 155);
00914
00915 if (pos == 0) {
00916 DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
00917 } else {
00918 DoDrawString(item->title, 14, y, _fios_colours[item->type] );
00919 }
00920 y += NSSWND_ROWSIZE;
00921
00922 if (y >= this->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
00923 }
00924 }
00925
00926 virtual void OnClick(Point pt, int widget)
00927 {
00928 this->field = widget;
00929 switch (widget) {
00930 case NSSW_CLOSE:
00931 case NSSW_CANCEL:
00932 ShowNetworkGameWindow();
00933 break;
00934
00935 case NSSW_SETPWD:
00936 this->widget_id = NSSW_SETPWD;
00937 SetDParamStr(0, _settings_client.network.server_password);
00938 ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL, QSF_NONE);
00939 break;
00940
00941 case NSSW_SELMAP: {
00942 int y = (pt.y - NSSWND_START) / NSSWND_ROWSIZE;
00943
00944 y += this->vscroll.pos;
00945 if (y >= this->vscroll.count) return;
00946
00947 this->map = (y == 0) ? NULL : _fios_items.Get(y - 1);
00948 this->SetDirty();
00949 } break;
00950
00951 case NSSW_CONNTYPE_BTN:
00952 ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, NSSW_CONNTYPE_BTN, 0, 0);
00953 break;
00954
00955 case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
00956 case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
00957 case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
00958
00959 if ((this->flags4 & WF_TIMEOUT_MASK) <= WF_TIMEOUT_TRIGGER) {
00960 this->HandleButtonClick(widget);
00961 this->SetDirty();
00962 switch (widget) {
00963 default: NOT_REACHED();
00964 case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
00965 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - NSSW_CLIENTS_TXT, 2, MAX_CLIENTS);
00966 break;
00967 case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
00968 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - NSSW_COMPANIES_TXT, 1, MAX_COMPANIES);
00969 break;
00970 case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
00971 _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
00972 break;
00973 }
00974 }
00975 _left_button_clicked = false;
00976 break;
00977
00978 case NSSW_CLIENTS_TXT:
00979 this->widget_id = NSSW_CLIENTS_TXT;
00980 SetDParam(0, _settings_client.network.max_clients);
00981 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_CLIENTS, 4, 50, this, CS_NUMERAL, QSF_NONE);
00982 break;
00983
00984 case NSSW_COMPANIES_TXT:
00985 this->widget_id = NSSW_COMPANIES_TXT;
00986 SetDParam(0, _settings_client.network.max_companies);
00987 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_COMPANIES, 3, 50, this, CS_NUMERAL, QSF_NONE);
00988 break;
00989
00990 case NSSW_SPECTATORS_TXT:
00991 this->widget_id = NSSW_SPECTATORS_TXT;
00992 SetDParam(0, _settings_client.network.max_spectators);
00993 ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 4, 50, this, CS_NUMERAL, QSF_NONE);
00994 break;
00995
00996 case NSSW_LANGUAGE_BTN: {
00997 uint sel = 0;
00998 for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
00999 if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
01000 sel = i;
01001 break;
01002 }
01003 }
01004 ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
01005 } break;
01006
01007 case NSSW_START:
01008 _is_network_server = true;
01009
01010 if (this->map == NULL) {
01011 ShowGenerateLandscape();
01012 } else {
01013 const char *name = FiosBrowseTo(this->map);
01014 if (name != NULL) {
01015 SetFiosType(this->map->type);
01016 _file_to_saveload.filetype = FT_SCENARIO;
01017 strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
01018 strecpy(_file_to_saveload.title, this->map->title, lastof(_file_to_saveload.title));
01019
01020 delete this;
01021 SwitchToMode(SM_START_SCENARIO);
01022 }
01023 }
01024 break;
01025
01026 case NSSW_LOAD:
01027 _is_network_server = true;
01028
01029
01030 delete this;
01031 ShowSaveLoadDialog(SLD_LOAD_GAME);
01032 break;
01033 }
01034 }
01035
01036 virtual void OnDropdownSelect(int widget, int index)
01037 {
01038 switch (widget) {
01039 case NSSW_CONNTYPE_BTN:
01040 _settings_client.network.server_advertise = (index != 0);
01041 break;
01042 case NSSW_LANGUAGE_BTN:
01043 _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
01044 break;
01045 default:
01046 NOT_REACHED();
01047 }
01048
01049 this->SetDirty();
01050 }
01051
01052 virtual void OnMouseLoop()
01053 {
01054 if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
01055 }
01056
01057 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01058 {
01059 EventState state = ES_NOT_HANDLED;
01060 if (this->field == NSSW_GAMENAME) {
01061 if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == HEBR_CONFIRM) return state;
01062
01063 strecpy(_settings_client.network.server_name, this->text.buf, lastof(_settings_client.network.server_name));
01064 }
01065
01066 return state;
01067 }
01068
01069 virtual void OnQueryTextFinished(char *str)
01070 {
01071 if (str == NULL) return;
01072
01073 if (this->widget_id == NSSW_SETPWD) {
01074 strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password));
01075 } else {
01076 int32 value = atoi(str);
01077 this->InvalidateWidget(this->widget_id);
01078 switch (this->widget_id) {
01079 default: NOT_REACHED();
01080 case NSSW_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(value, 2, MAX_CLIENTS); break;
01081 case NSSW_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break;
01082 case NSSW_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
01083 }
01084 }
01085
01086 this->SetDirty();
01087 }
01088 };
01089
01090 static const Widget _network_start_server_window_widgets[] = {
01091
01092 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
01093 { WWT_CAPTION, RESIZE_NONE, COLOUR_LIGHT_BLUE, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
01094 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 419, 14, 243, 0x0, STR_NULL},
01095
01096
01097 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 90, 22, 34, STR_NETWORK_NEW_GAME_NAME, STR_NULL},
01098 { WWT_EDITBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 100, 272, 22, 33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP},
01099 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP},
01100
01101
01102 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 110, 43, 55, STR_NETWORK_SELECT_MAP, STR_NULL},
01103 { WWT_INSET, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 271, 62, 216, STR_NULL, STR_NETWORK_SELECT_MAP_TIP},
01104 { WWT_SCROLLBAR, RESIZE_NONE, COLOUR_LIGHT_BLUE, 259, 270, 63, 215, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01105
01106
01107 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 63, 75, STR_NETWORK_CONNECTION, STR_NULL},
01108 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 410, 77, 88, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP},
01109
01110 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 95, 107, STR_NETWORK_NUMBER_OF_CLIENTS, STR_NULL},
01111 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 109, 120, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01112 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 109, 120, STR_NETWORK_CLIENTS_SELECT, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01113 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 109, 120, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
01114
01115 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 127, 139, STR_NETWORK_NUMBER_OF_COMPANIES, STR_NULL},
01116 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 141, 152, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01117 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 141, 152, STR_NETWORK_COMPANIES_SELECT, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01118 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 141, 152, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
01119
01120 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 159, 171, STR_NETWORK_NUMBER_OF_SPECTATORS, STR_NULL},
01121 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 291, 173, 184, SPR_ARROW_DOWN, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01122 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 292, 397, 173, 184, STR_NETWORK_SPECTATORS_SELECT, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01123 { WWT_IMGBTN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 398, 410, 173, 184, SPR_ARROW_UP, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
01124
01125 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 419, 191, 203, STR_NETWORK_LANGUAGE_SPOKEN, STR_NULL},
01126 { WWT_DROPDOWNIN, RESIZE_NONE, COLOUR_LIGHT_BLUE, 280, 410, 205, 216, STR_NETWORK_LANGUAGE_COMBO, STR_NETWORK_LANGUAGE_TIP},
01127
01128
01129 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 40, 140, 224, 235, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP},
01130 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 150, 250, 224, 235, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP},
01131 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 260, 360, 224, 235, STR_012E_CANCEL, STR_NULL},
01132
01133 { WIDGETS_END},
01134 };
01135
01136 static const WindowDesc _network_start_server_window_desc(
01137 WDP_CENTER, WDP_CENTER, 420, 244, 420, 244,
01138 WC_NETWORK_WINDOW, WC_NONE,
01139 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01140 _network_start_server_window_widgets
01141 );
01142
01143 static void ShowNetworkStartServerWindow()
01144 {
01145 DeleteWindowById(WC_NETWORK_WINDOW, 0);
01146
01147 new NetworkStartServerWindow(&_network_start_server_window_desc);
01148 }
01149
01151 enum NetworkLobbyWindowWidgets {
01152 NLWW_CLOSE = 0,
01153 NLWW_MATRIX = 5,
01154 NLWW_DETAILS = 7,
01155 NLWW_JOIN = 8,
01156 NLWW_NEW = 9,
01157 NLWW_SPECTATE = 10,
01158 NLWW_REFRESH = 11,
01159 NLWW_CANCEL = 12,
01160 };
01161
01162 struct NetworkLobbyWindow : public Window {
01163 CompanyID company;
01164 NetworkGameList *server;
01165 NetworkCompanyInfo company_info[MAX_COMPANIES];
01166
01167 NetworkLobbyWindow(const WindowDesc *desc, NetworkGameList *ngl) :
01168 Window(desc), company(INVALID_COMPANY), server(ngl)
01169 {
01170 this->vscroll.cap = 10;
01171
01172 this->FindWindowPlacementAndResize(desc);
01173 }
01174
01175 CompanyID NetworkLobbyFindCompanyIndex(byte pos)
01176 {
01177
01178 for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
01179 if (!StrEmpty(this->company_info[i].company_name)) {
01180 if (pos-- == 0) return i;
01181 }
01182 }
01183
01184 return COMPANY_FIRST;
01185 }
01186
01187 virtual void OnPaint()
01188 {
01189 const NetworkGameInfo *gi = &this->server->info;
01190 int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
01191
01192
01193 this->SetWidgetDisabledState(NLWW_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
01194
01195 this->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
01196
01197 this->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
01198
01199
01200 SetDParamStr(0, gi->server_name);
01201 this->DrawWidgets();
01202
01203 SetVScrollCount(this, gi->companies_on);
01204
01205
01206 pos = this->vscroll.pos;
01207 while (pos < gi->companies_on) {
01208 byte company = NetworkLobbyFindCompanyIndex(pos);
01209 bool income = false;
01210 if (this->company == company) {
01211 GfxFillRect(11, y - 1, 154, y + 10, 10);
01212 }
01213
01214 DoDrawStringTruncated(this->company_info[company].company_name, 13, y, TC_BLACK, 135 - 13);
01215 if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, 135, y);
01216
01217
01218 if (this->company_info[company].income >= 0) income = true;
01219 DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, 145, y);
01220
01221 pos++;
01222 y += NET_PRC__SIZE_OF_ROW;
01223 if (pos >= this->vscroll.pos + this->vscroll.cap) break;
01224 }
01225
01226
01227 GfxFillRect(174, 39, 403, 75, 157);
01228 DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, TC_FROMSTRING);
01229 if (this->company != INVALID_COMPANY && !StrEmpty(this->company_info[this->company].company_name)) {
01230 const uint x = 183;
01231 const uint trunc_width = this->widget[NLWW_DETAILS].right - x;
01232 y = 80;
01233
01234 SetDParam(0, gi->clients_on);
01235 SetDParam(1, gi->clients_max);
01236 SetDParam(2, gi->companies_on);
01237 SetDParam(3, gi->companies_max);
01238 DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
01239 y += 10;
01240
01241 SetDParamStr(0, this->company_info[this->company].company_name);
01242 DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, TC_GOLD, trunc_width);
01243 y += 10;
01244
01245 SetDParam(0, this->company_info[this->company].inaugurated_year);
01246 DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, TC_GOLD);
01247 y += 10;
01248
01249 SetDParam(0, this->company_info[this->company].company_value);
01250 DrawString(x, y, STR_NETWORK_VALUE, TC_GOLD);
01251 y += 10;
01252
01253 SetDParam(0, this->company_info[this->company].money);
01254 DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, TC_GOLD);
01255 y += 10;
01256
01257 SetDParam(0, this->company_info[this->company].income);
01258 DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, TC_GOLD);
01259 y += 10;
01260
01261 SetDParam(0, this->company_info[this->company].performance);
01262 DrawString(x, y, STR_NETWORK_PERFORMANCE, TC_GOLD);
01263 y += 10;
01264
01265 SetDParam(0, this->company_info[this->company].num_vehicle[0]);
01266 SetDParam(1, this->company_info[this->company].num_vehicle[1]);
01267 SetDParam(2, this->company_info[this->company].num_vehicle[2]);
01268 SetDParam(3, this->company_info[this->company].num_vehicle[3]);
01269 SetDParam(4, this->company_info[this->company].num_vehicle[4]);
01270 DrawString(x, y, STR_NETWORK_VEHICLES, TC_GOLD);
01271 y += 10;
01272
01273 SetDParam(0, this->company_info[this->company].num_station[0]);
01274 SetDParam(1, this->company_info[this->company].num_station[1]);
01275 SetDParam(2, this->company_info[this->company].num_station[2]);
01276 SetDParam(3, this->company_info[this->company].num_station[3]);
01277 SetDParam(4, this->company_info[this->company].num_station[4]);
01278 DrawString(x, y, STR_NETWORK_STATIONS, TC_GOLD);
01279 y += 10;
01280
01281 SetDParamStr(0, this->company_info[this->company].clients);
01282 DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, TC_GOLD, trunc_width);
01283 }
01284 }
01285
01286 virtual void OnClick(Point pt, int widget)
01287 {
01288 switch (widget) {
01289 case NLWW_CLOSE:
01290 case NLWW_CANCEL:
01291 ShowNetworkGameWindow();
01292 break;
01293
01294 case NLWW_MATRIX: {
01295 uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
01296
01297 if (id_v >= this->vscroll.cap) break;
01298
01299 id_v += this->vscroll.pos;
01300 this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
01301 this->SetDirty();
01302 } break;
01303
01304 case NLWW_JOIN:
01305
01306 _network_playas = this->company;
01307 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01308 break;
01309
01310 case NLWW_NEW:
01311 _network_playas = COMPANY_NEW_COMPANY;
01312 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01313 break;
01314
01315 case NLWW_SPECTATE:
01316 _network_playas = COMPANY_SPECTATOR;
01317 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01318 break;
01319
01320 case NLWW_REFRESH:
01321 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01322 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01323
01324 memset(this->company_info, 0, sizeof(this->company_info));
01325 break;
01326 }
01327 }
01328
01329 virtual void OnDoubleClick(Point pt, int widget)
01330 {
01331 if (widget == NLWW_MATRIX) {
01332
01333 if (!this->IsWidgetDisabled(NLWW_JOIN)) this->OnClick(pt, NLWW_JOIN);
01334 }
01335 }
01336 };
01337
01338 static const Widget _network_lobby_window_widgets[] = {
01339 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
01340 { WWT_CAPTION, RESIZE_NONE, COLOUR_LIGHT_BLUE, 11, 419, 0, 13, STR_NETWORK_GAME_LOBBY, STR_NULL},
01341 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 419, 14, 234, 0x0, STR_NULL},
01342 { WWT_TEXT, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 419, 22, 34, STR_NETWORK_PREPARE_TO_JOIN, STR_NULL},
01343
01344
01345 { WWT_PANEL, RESIZE_NONE, COLOUR_WHITE, 10, 155, 38, 49, 0x0, STR_NULL},
01346 { WWT_MATRIX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 10, 155, 50, 190, (10 << 8) + 1, STR_NETWORK_COMPANY_LIST_TIP},
01347 { WWT_SCROLLBAR, RESIZE_NONE, COLOUR_LIGHT_BLUE, 156, 167, 38, 190, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01348
01349
01350 { WWT_PANEL, RESIZE_NONE, COLOUR_LIGHT_BLUE, 173, 404, 38, 190, 0x0, STR_NULL},
01351
01352
01353 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 151, 200, 211, STR_NETWORK_JOIN_COMPANY, STR_NETWORK_JOIN_COMPANY_TIP},
01354 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 10, 151, 215, 226, STR_NETWORK_NEW_COMPANY, STR_NETWORK_NEW_COMPANY_TIP},
01355 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 158, 268, 200, 211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP},
01356 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 158, 268, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
01357 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 278, 388, 200, 211, STR_012E_CANCEL, STR_NULL},
01358
01359 { WIDGETS_END},
01360 };
01361
01362 static const WindowDesc _network_lobby_window_desc(
01363 WDP_CENTER, WDP_CENTER, 420, 235, 420, 235,
01364 WC_NETWORK_WINDOW, WC_NONE,
01365 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01366 _network_lobby_window_widgets
01367 );
01368
01369
01370
01371 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
01372 {
01373 DeleteWindowById(WC_NETWORK_WINDOW, 0);
01374
01375 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01376 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01377
01378 new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
01379 }
01380
01386 NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
01387 {
01388 NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, 0));
01389 return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL;
01390 }
01391
01392
01393
01394
01395
01396 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
01397
01398
01399 typedef void ClientList_Action_Proc(byte client_no);
01400
01401
01402 #define MAX_CLIENTLIST_ACTION 10
01403
01404 enum {
01405 CLNWND_OFFSET = 16,
01406 CLNWND_ROWSIZE = 10
01407 };
01408
01409 static const Widget _client_list_widgets[] = {
01410 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01411 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 237, 0, 13, STR_NETWORK_CLIENT_LIST, STR_018C_WINDOW_TITLE_DRAG_THIS},
01412 { WWT_STICKYBOX, RESIZE_NONE, COLOUR_GREY, 238, 249, 0, 13, STR_NULL, STR_STICKY_BUTTON},
01413
01414 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 249, 14, 14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL},
01415 { WIDGETS_END},
01416 };
01417
01418 static const Widget _client_list_popup_widgets[] = {
01419 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 99, 0, 0, 0, STR_NULL},
01420 { WIDGETS_END},
01421 };
01422
01423 static const WindowDesc _client_list_desc(
01424 WDP_AUTO, WDP_AUTO, 250, 1, 250, 1,
01425 WC_CLIENT_LIST, WC_NONE,
01426 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
01427 _client_list_widgets
01428 );
01429
01430
01431 static const NetworkClientInfo *NetworkFindClientInfo(byte client_no)
01432 {
01433 const NetworkClientInfo *ci;
01434
01435 FOR_ALL_CLIENT_INFOS(ci) {
01436 if (client_no == 0) return ci;
01437 client_no--;
01438 }
01439
01440 return NULL;
01441 }
01442
01443
01444 static void ClientList_Kick(byte client_no)
01445 {
01446 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01447
01448 if (ci == NULL) return;
01449
01450 NetworkServerKickClient(ci->client_id);
01451 }
01452
01453 static void ClientList_Ban(byte client_no)
01454 {
01455 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01456
01457 if (ci == NULL) return;
01458
01459 NetworkServerBanIP(GetClientIP(ci));
01460 }
01461
01462 static void ClientList_GiveMoney(byte client_no)
01463 {
01464 if (NetworkFindClientInfo(client_no) != NULL) {
01465 ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
01466 }
01467 }
01468
01469 static void ClientList_SpeakToClient(byte client_no)
01470 {
01471 if (NetworkFindClientInfo(client_no) != NULL) {
01472 ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
01473 }
01474 }
01475
01476 static void ClientList_SpeakToCompany(byte client_no)
01477 {
01478 if (NetworkFindClientInfo(client_no) != NULL) {
01479 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
01480 }
01481 }
01482
01483 static void ClientList_SpeakToAll(byte client_no)
01484 {
01485 ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
01486 }
01487
01488 static void ClientList_None(byte client_no)
01489 {
01490
01491 }
01492
01493
01494
01495 struct NetworkClientListPopupWindow : Window {
01496 int sel_index;
01497 int client_no;
01498 char action[MAX_CLIENTLIST_ACTION][50];
01499 ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
01500
01501 NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
01502 Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
01503 sel_index(0), client_no(client_no)
01504 {
01505
01506
01507
01508
01509
01510 const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01511
01512 int i = 0;
01513 if (_network_own_client_id != ci->client_id) {
01514 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
01515 this->proc[i++] = &ClientList_SpeakToClient;
01516 }
01517
01518 if (IsValidCompanyID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
01519 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
01520 this->proc[i++] = &ClientList_SpeakToCompany;
01521 }
01522 GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
01523 this->proc[i++] = &ClientList_SpeakToAll;
01524
01525 if (_network_own_client_id != ci->client_id) {
01526
01527 if (IsValidCompanyID(_network_playas) && IsValidCompanyID(ci->client_playas) && _settings_game.economy.give_money) {
01528 GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
01529 this->proc[i++] = &ClientList_GiveMoney;
01530 }
01531 }
01532
01533
01534 if (_network_server && _network_own_client_id != ci->client_id) {
01535 GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
01536 this->proc[i++] = &ClientList_Kick;
01537
01538 seprintf(this->action[i], lastof(this->action[i]), "Ban");
01539 this->proc[i++] = &ClientList_Ban;
01540 }
01541
01542 if (i == 0) {
01543 GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
01544 this->proc[i++] = &ClientList_None;
01545 }
01546
01547
01548 int h = ClientListPopupHeight();
01549
01550
01551 this->widget[0].bottom = this->widget[0].top + h;
01552 this->widget[0].right = this->widget[0].left + 150;
01553
01554 this->flags4 &= ~WF_WHITE_BORDER_MASK;
01555
01556 this->FindWindowPlacementAndResize(150, h + 1);
01557 }
01558
01562 void HandleClientListPopupClick(byte index)
01563 {
01564
01565 if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
01566 this->proc[index](this->client_no);
01567 }
01568 }
01569
01573 uint ClientListPopupHeight()
01574 {
01575 int num = 0;
01576
01577
01578 for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
01579 if (this->action[i][0] == '\0') continue;
01580 if (this->proc[i] == NULL) continue;
01581 num++;
01582 }
01583
01584 num *= CLNWND_ROWSIZE;
01585
01586 return num + 1;
01587 }
01588
01589
01590 virtual void OnPaint()
01591 {
01592 this->DrawWidgets();
01593
01594
01595 int sel = this->sel_index;
01596 int y = 1;
01597 for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
01598 if (this->action[i][0] == '\0') continue;
01599 if (this->proc[i] == NULL) continue;
01600
01601 TextColour colour;
01602 if (sel-- == 0) {
01603 GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
01604 colour = TC_WHITE;
01605 } else {
01606 colour = TC_BLACK;
01607 }
01608
01609 DoDrawString(this->action[i], 4, y, colour);
01610 }
01611 }
01612
01613 virtual void OnMouseLoop()
01614 {
01615
01616 int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
01617
01618 if (_left_button_down) {
01619 if (index == -1 || index == this->sel_index) return;
01620
01621 this->sel_index = index;
01622 this->SetDirty();
01623 } else {
01624 if (index >= 0 && _cursor.pos.y >= this->top) {
01625 HandleClientListPopupClick(index);
01626 }
01627
01628 DeleteWindowById(WC_TOOLBAR_MENU, 0);
01629 }
01630 }
01631 };
01632
01636 static void PopupClientList(int client_no, int x, int y)
01637 {
01638 DeleteWindowById(WC_TOOLBAR_MENU, 0);
01639
01640 if (NetworkFindClientInfo(client_no) == NULL) return;
01641
01642 new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
01643 }
01644
01648 struct NetworkClientListWindow : Window
01649 {
01650 int selected_item;
01651 int selected_y;
01652
01653 NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
01654 Window(desc, window_number),
01655 selected_item(-1),
01656 selected_y(0)
01657 {
01658 this->FindWindowPlacementAndResize(desc);
01659 }
01660
01664 bool CheckClientListHeight()
01665 {
01666 int num = 0;
01667 const NetworkClientInfo *ci;
01668
01669
01670 FOR_ALL_CLIENT_INFOS(ci) {
01671 if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
01672 }
01673
01674 num *= CLNWND_ROWSIZE;
01675
01676
01677 if (this->height != CLNWND_OFFSET + num + 1) {
01678
01679 this->SetDirty();
01680 this->widget[3].bottom = this->widget[3].top + num + 2;
01681 this->height = CLNWND_OFFSET + num + 1;
01682 this->SetDirty();
01683 return false;
01684 }
01685 return true;
01686 }
01687
01688 virtual void OnPaint()
01689 {
01690 NetworkClientInfo *ci;
01691 int i = 0;
01692
01693
01694 if (!this->CheckClientListHeight()) return;
01695
01696 this->DrawWidgets();
01697
01698 int y = CLNWND_OFFSET;
01699
01700 FOR_ALL_CLIENT_INFOS(ci) {
01701 TextColour colour;
01702 if (this->selected_item == i++) {
01703 GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
01704 colour = TC_WHITE;
01705 } else {
01706 colour = TC_BLACK;
01707 }
01708
01709 if (ci->client_id == CLIENT_ID_SERVER) {
01710 DrawString(4, y, STR_NETWORK_SERVER, colour);
01711 } else {
01712 DrawString(4, y, STR_NETWORK_CLIENT, colour);
01713 }
01714
01715
01716 if (IsValidCompanyID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, 64, y + 1);
01717
01718 DoDrawString(ci->client_name, 81, y, colour);
01719
01720 y += CLNWND_ROWSIZE;
01721 }
01722 }
01723
01724 virtual void OnClick(Point pt, int widget)
01725 {
01726
01727 if (this->selected_item != -1) {
01728 PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
01729 }
01730 }
01731
01732 virtual void OnMouseOver(Point pt, int widget)
01733 {
01734
01735 if (pt.y == -1) {
01736 this->selected_y = 0;
01737 this->selected_item = -1;
01738 this->SetDirty();
01739 return;
01740 }
01741
01742 if (pt.y == this->selected_y) return;
01743
01744
01745 this->selected_y = pt.y;
01746 if (pt.y > CLNWND_OFFSET) {
01747 this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
01748 } else {
01749 this->selected_item = -1;
01750 }
01751
01752
01753 this->SetDirty();
01754 }
01755 };
01756
01757 void ShowClientList()
01758 {
01759 AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
01760 }
01761
01762
01763 static NetworkPasswordType pw_type;
01764
01765
01766 void ShowNetworkNeedPassword(NetworkPasswordType npt)
01767 {
01768 StringID caption;
01769
01770 pw_type = npt;
01771 switch (npt) {
01772 default: NOT_REACHED();
01773 case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
01774 case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
01775 }
01776 ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL, QSF_NONE);
01777 }
01778
01779
01780 NetworkJoinStatus _network_join_status;
01781 uint8 _network_join_waiting;
01782 uint32 _network_join_bytes;
01783 uint32 _network_join_bytes_total;
01784
01785 struct NetworkJoinStatusWindow : Window {
01786 NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
01787 {
01788 this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
01789 this->FindWindowPlacementAndResize(desc);
01790 }
01791
01792 virtual void OnPaint()
01793 {
01794 uint8 progress;
01795 this->DrawWidgets();
01796
01797 DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
01798 switch (_network_join_status) {
01799 case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
01800 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
01801 progress = 10;
01802 break;
01803 case NETWORK_JOIN_STATUS_WAITING:
01804 SetDParam(0, _network_join_waiting);
01805 DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
01806 progress = 15;
01807 break;
01808 case NETWORK_JOIN_STATUS_DOWNLOADING:
01809 SetDParam(0, _network_join_bytes);
01810 SetDParam(1, _network_join_bytes_total);
01811 DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
01812
01813 default:
01814 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
01815 }
01816
01817
01818 DrawFrameRect(20, 18, (int)((this->width - 20) * progress / 100), 28, COLOUR_MAUVE, FR_NONE);
01819 }
01820
01821 virtual void OnClick(Point pt, int widget)
01822 {
01823 if (widget == 2) {
01824 NetworkDisconnect();
01825 SwitchToMode(SM_MENU);
01826 ShowNetworkGameWindow();
01827 }
01828 }
01829
01830 virtual void OnQueryTextFinished(char *str)
01831 {
01832 if (StrEmpty(str)) {
01833 NetworkDisconnect();
01834 ShowNetworkGameWindow();
01835 } else {
01836 SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
01837 }
01838 }
01839 };
01840
01841 static const Widget _network_join_status_window_widget[] = {
01842 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 0, 249, 0, 13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
01843 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 249, 14, 84, 0x0, STR_NULL},
01844 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 75, 175, 69, 80, STR_NETWORK_DISCONNECT, STR_NULL},
01845 { WIDGETS_END},
01846 };
01847
01848 static const WindowDesc _network_join_status_window_desc(
01849 WDP_CENTER, WDP_CENTER, 250, 85, 250, 85,
01850 WC_NETWORK_STATUS_WINDOW, WC_NONE,
01851 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
01852 _network_join_status_window_widget
01853 );
01854
01855 void ShowJoinStatusWindow()
01856 {
01857 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
01858 new NetworkJoinStatusWindow(&_network_join_status_window_desc);
01859 }
01860
01861
01863 enum NetworkCompanyPasswordWindowWidgets {
01864 NCPWW_CLOSE,
01865 NCPWW_CAPTION,
01866 NCPWW_BACKGROUND,
01867 NCPWW_LABEL,
01868 NCPWW_PASSWORD,
01869 NCPWW_SAVE_AS_DEFAULT_PASSWORD,
01870 NCPWW_CANCEL,
01871 NCPWW_OK,
01872 };
01873
01874 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
01875 NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(lengthof(_settings_client.network.default_company_pass), desc)
01876 {
01877 this->parent = parent;
01878 this->afilter = CS_ALPHANUMERAL;
01879 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
01880 this->SetFocusedWidget(NCPWW_PASSWORD);
01881
01882 this->FindWindowPlacementAndResize(desc);
01883 }
01884
01885 void OnOk()
01886 {
01887 if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
01888 snprintf(_settings_client.network.default_company_pass, lengthof(_settings_client.network.default_company_pass), "%s", this->edit_str_buf);
01889 }
01890
01891
01892 if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, this->edit_str_size, "*");
01893 char *password = this->edit_str_buf;
01894 NetworkChangeCompanyPassword(1, &password);
01895 }
01896
01897 virtual void OnPaint()
01898 {
01899 this->DrawWidgets();
01900 this->DrawEditBox(4);
01901 }
01902
01903 virtual void OnClick(Point pt, int widget)
01904 {
01905 switch (widget) {
01906 case NCPWW_OK:
01907 this->OnOk();
01908
01909
01910 case NCPWW_CANCEL:
01911 delete this;
01912 break;
01913
01914 case NCPWW_SAVE_AS_DEFAULT_PASSWORD:
01915 this->ToggleWidgetLoweredState(NCPWW_SAVE_AS_DEFAULT_PASSWORD);
01916 this->SetDirty();
01917 break;
01918 }
01919 }
01920
01921 virtual void OnMouseLoop()
01922 {
01923 this->HandleEditBox(4);
01924 }
01925
01926 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01927 {
01928 EventState state = ES_NOT_HANDLED;
01929 switch (this->HandleEditBoxKey(4, key, keycode, state)) {
01930 default: break;
01931
01932 case HEBR_CONFIRM:
01933 this->OnOk();
01934
01935
01936 case HEBR_CANCEL:
01937 delete this;
01938 break;
01939 }
01940 return state;
01941 }
01942
01943 virtual void OnOpenOSKWindow(int wid)
01944 {
01945 ShowOnScreenKeyboard(this, wid, NCPWW_CANCEL, NCPWW_OK);
01946 }
01947 };
01948
01949 static const Widget _ncp_window_widgets[] = {
01950 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01951 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 299, 0, 13, STR_COMPANY_PASSWORD_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
01952 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 299, 14, 50, 0x0, STR_NULL},
01953 { WWT_TEXT, RESIZE_NONE, COLOUR_GREY, 5, 100, 19, 30, STR_COMPANY_PASSWORD, STR_NULL},
01954 { WWT_EDITBOX, RESIZE_NONE, COLOUR_GREY, 101, 294, 19, 30, STR_SET_COMPANY_PASSWORD, STR_NULL},
01955 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 101, 294, 35, 46, STR_MAKE_DEFAULT_COMPANY_PASSWORD, STR_MAKE_DEFAULT_COMPANY_PASSWORD_TIP},
01956 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 149, 51, 62, STR_012E_CANCEL, STR_COMPANY_PASSWORD_CANCEL},
01957 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 150, 299, 51, 62, STR_012F_OK, STR_COMPANY_PASSWORD_OK},
01958 { WIDGETS_END},
01959 };
01960
01961 static const WindowDesc _ncp_window_desc(
01962 WDP_AUTO, WDP_AUTO, 300, 63, 300, 63,
01963 WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
01964 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
01965 _ncp_window_widgets
01966 );
01967
01968 void ShowNetworkCompanyPasswordWindow(Window *parent)
01969 {
01970 DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
01971
01972 new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
01973 }
01974
01975 #endif