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