player_gui.cpp

Go to the documentation of this file.
00001 /* $Id: player_gui.cpp 13735 2008-07-19 12:23:14Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gui.h"
00008 #include "window_gui.h"
00009 #include "textbuf_gui.h"
00010 #include "viewport_func.h"
00011 #include "gfx_func.h"
00012 #include "player_func.h"
00013 #include "player_base.h"
00014 #include "command_func.h"
00015 #include "network/network.h"
00016 #include "variables.h"
00017 #include "roadveh.h"
00018 #include "train.h"
00019 #include "aircraft.h"
00020 #include "newgrf.h"
00021 #include "network/network_data.h"
00022 #include "network/network_client.h"
00023 #include "network/network_gui.h"
00024 #include "player_face.h"
00025 #include "strings_func.h"
00026 #include "functions.h"
00027 #include "window_func.h"
00028 #include "date_func.h"
00029 #include "string_func.h"
00030 #include "settings_type.h"
00031 #include "widgets/dropdown_func.h"
00032 
00033 #include "table/sprites.h"
00034 #include "table/strings.h"
00035 
00036 /* player face selection window */
00037 struct facesel_d {
00038   PlayerFace face; // player face bits
00039   bool advanced;   // advance player face selection window
00040 };
00041 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(facesel_d));
00042 
00043 static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied);
00044 static void DoSelectPlayerFace(PlayerID player, bool show_big);
00045 
00046 static void DrawPlayerEconomyStats(const Player *p, byte mode)
00047 {
00048   int x, y, i, j, year;
00049   const Money (*tbl)[EXPENSES_END];
00050   Money sum, cost;
00051   StringID str;
00052 
00053   if (!(mode & 1)) { // normal sized economics window (mode&1) is minimized status
00054     /* draw categories */
00055     DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, TC_FROMSTRING);
00056     for (i = 0; i != 13; i++)
00057       DrawString(2, 27 + i * 10, STR_7011_CONSTRUCTION + i, TC_FROMSTRING);
00058     DrawStringRightAligned(111, 27 + 10 * 13 + 2, STR_7020_TOTAL, TC_FROMSTRING);
00059 
00060     /* draw the price columns */
00061     year = _cur_year - 2;
00062     j = 3;
00063     x = 215;
00064     tbl = p->yearly_expenses + 2;
00065     do {
00066       if (year >= p->inaugurated_year) {
00067         SetDParam(0, year);
00068         DrawStringRightAlignedUnderline(x, 15, STR_7010, TC_FROMSTRING);
00069         sum = 0;
00070         for (i = 0; i != 13; i++) {
00071           /* draw one row in the price column */
00072           cost = (*tbl)[i];
00073           if (cost != 0) {
00074             sum += cost;
00075 
00076             str = STR_701E;
00077             if (cost < 0) { cost = -cost; str++; }
00078             SetDParam(0, cost);
00079             DrawStringRightAligned(x, 27 + i * 10, str, TC_FROMSTRING);
00080           }
00081         }
00082 
00083         str = STR_701E;
00084         if (sum < 0) { sum = -sum; str++; }
00085         SetDParam(0, sum);
00086         DrawStringRightAligned(x, 27 + 13 * 10 + 2, str, TC_FROMSTRING);
00087 
00088         GfxFillRect(x - 75, 27 + 10 * 13, x, 27 + 10 * 13, 215);
00089         x += 95;
00090       }
00091       year++;
00092       tbl--;
00093     } while (--j != 0);
00094 
00095     y = 171;
00096 
00097     /* draw max loan aligned to loan below (y += 10) */
00098     SetDParam(0, _economy.max_loan);
00099     DrawString(202, y + 10, STR_MAX_LOAN, TC_FROMSTRING);
00100   } else {
00101     y = 15;
00102   }
00103 
00104   DrawString(2, y, STR_7026_BANK_BALANCE, TC_FROMSTRING);
00105   SetDParam(0, p->player_money);
00106   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
00107 
00108   y += 10;
00109 
00110   DrawString(2, y, STR_7027_LOAN, TC_FROMSTRING);
00111   SetDParam(0, p->current_loan);
00112   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
00113 
00114   y += 12;
00115 
00116   GfxFillRect(182 - 75, y - 2, 182, y - 2, 215);
00117 
00118   SetDParam(0, p->player_money - p->current_loan);
00119   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
00120 }
00121 
00122 enum PlayerFinancesWindowWidgets {
00123   PFW_WIDGET_TOGGLE_SIZE   = 2,
00124   PFW_WIDGET_INCREASE_LOAN = 6,
00125   PFW_WIDGET_REPAY_LOAN    = 7,
00126 };
00127 
00128 static const Widget _player_finances_widgets[] = {
00129 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
00130 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
00131 {     WWT_IMGBTN,   RESIZE_NONE,    14,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
00132 {  WWT_STICKYBOX,   RESIZE_NONE,    14,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
00133 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,    14,   169, 0x0,                    STR_NULL},
00134 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,   170,   203, 0x0,                    STR_NULL},
00135 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   202,   204,   215, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
00136 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   203,   406,   204,   215, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
00137 {   WIDGETS_END},
00138 };
00139 
00140 static const Widget _player_finances_small_widgets[] = {
00141 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
00142 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
00143 {     WWT_IMGBTN,   RESIZE_NONE,    14,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
00144 {  WWT_STICKYBOX,   RESIZE_NONE,    14,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
00145 {      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                    STR_NULL},
00146 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    47, STR_NULL,               STR_NULL},
00147 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   139,    48,    59, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
00148 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   140,   279,    48,    59, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
00149 {   WIDGETS_END},
00150 };
00151 
00152 
00153 static void PlayerFinancesWndProc(Window *w, WindowEvent *e)
00154 {
00155   switch (e->event) {
00156   case WE_PAINT: {
00157     PlayerID player = (PlayerID)w->window_number;
00158     const Player *p = GetPlayer(player);
00159 
00160     /* Recheck the size of the window as it might need to be resized due to the local player changing */
00161     int new_height = ((player != _local_player) ? 0 : 12) + ((WP(w, def_d).data_1 != 0) ? 48 : 204);
00162     if (w->height != new_height) {
00163       /* Make window dirty before and after resizing */
00164       SetWindowDirty(w);
00165       w->height = new_height;
00166       SetWindowDirty(w);
00167 
00168       w->SetWidgetHiddenState(PFW_WIDGET_INCREASE_LOAN, player != _local_player);
00169       w->SetWidgetHiddenState(PFW_WIDGET_REPAY_LOAN,    player != _local_player);
00170     }
00171 
00172     /* Borrow button only shows when there is any more money to loan */
00173     w->SetWidgetDisabledState(PFW_WIDGET_INCREASE_LOAN, p->current_loan == _economy.max_loan);
00174 
00175     /* Repay button only shows when there is any more money to repay */
00176     w->SetWidgetDisabledState(PFW_WIDGET_REPAY_LOAN, player != _local_player || p->current_loan == 0);
00177 
00178     SetDParam(0, p->index);
00179     SetDParam(1, p->index);
00180     SetDParam(2, LOAN_INTERVAL);
00181     DrawWindowWidgets(w);
00182 
00183     DrawPlayerEconomyStats(p, (byte)WP(w, def_d).data_1);
00184   } break;
00185 
00186   case WE_CLICK:
00187     switch (e->we.click.widget) {
00188     case PFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
00189       byte mode = (byte)WP(w, def_d).data_1;
00190       bool stickied = !!(w->flags4 & WF_STICKY);
00191       PlayerID player = (PlayerID)w->window_number;
00192       DeleteWindow(w);
00193       DoShowPlayerFinances(player, !HasBit(mode, 0), stickied);
00194     } break;
00195 
00196     case PFW_WIDGET_INCREASE_LOAN: /* increase loan */
00197       DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
00198       break;
00199 
00200     case PFW_WIDGET_REPAY_LOAN: /* repay loan */
00201       DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
00202       break;
00203     }
00204     break;
00205   }
00206 }
00207 
00208 static const WindowDesc _player_finances_desc = {
00209   WDP_AUTO, WDP_AUTO, 407, 216, 407, 216,
00210   WC_FINANCES, WC_NONE,
00211   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
00212   _player_finances_widgets,
00213   PlayerFinancesWndProc
00214 };
00215 
00216 static const WindowDesc _player_finances_small_desc = {
00217   WDP_AUTO, WDP_AUTO, 280, 60, 280, 60,
00218   WC_FINANCES, WC_NONE,
00219   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
00220   _player_finances_small_widgets,
00221   PlayerFinancesWndProc
00222 };
00223 
00224 static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied)
00225 {
00226   if (!IsValidPlayer(player)) return;
00227 
00228   Window *w = AllocateWindowDescFront(show_small ? &_player_finances_small_desc : &_player_finances_desc, player);
00229   if (w != NULL) {
00230     w->caption_color = w->window_number;
00231     WP(w, def_d).data_1 = show_small;
00232     if (show_stickied) w->flags4 |= WF_STICKY;
00233   }
00234 }
00235 
00236 void ShowPlayerFinances(PlayerID player)
00237 {
00238   DoShowPlayerFinances(player, false, false);
00239 }
00240 
00241 /* List of colours for the livery window */
00242 static const StringID _colour_dropdown[] = {
00243   STR_00D1_DARK_BLUE,
00244   STR_00D2_PALE_GREEN,
00245   STR_00D3_PINK,
00246   STR_00D4_YELLOW,
00247   STR_00D5_RED,
00248   STR_00D6_LIGHT_BLUE,
00249   STR_00D7_GREEN,
00250   STR_00D8_DARK_GREEN,
00251   STR_00D9_BLUE,
00252   STR_00DA_CREAM,
00253   STR_00DB_MAUVE,
00254   STR_00DC_PURPLE,
00255   STR_00DD_ORANGE,
00256   STR_00DE_BROWN,
00257   STR_00DF_GREY,
00258   STR_00E0_WHITE,
00259   INVALID_STRING_ID
00260 };
00261 
00262 /* Association of liveries to livery classes */
00263 static const LiveryClass livery_class[LS_END] = {
00264   LC_OTHER,
00265   LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
00266   LC_ROAD, LC_ROAD,
00267   LC_SHIP, LC_SHIP,
00268   LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
00269   LC_ROAD, LC_ROAD,
00270 };
00271 
00272 /* Number of liveries in each class, used to determine the height of the livery window */
00273 static const byte livery_height[] = {
00274   1,
00275   13,
00276   4,
00277   2,
00278   3,
00279 };
00280 
00281 struct livery_d {
00282   uint32 sel;
00283   LiveryClass livery_class;
00284 };
00285 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d));
00286 
00287 
00288 enum PlayerLiveryWindowWidgets {
00289   PLW_WIDGET_CLASS_GENERAL = 2,
00290   PLW_WIDGET_CLASS_RAIL,
00291   PLW_WIDGET_CLASS_ROAD,
00292   PLW_WIDGET_CLASS_SHIP,
00293   PLW_WIDGET_CLASS_AIRCRAFT,
00294 
00295   PLW_WIDGET_PRI_COL_DROPDOWN = 9,
00296   PLW_WIDGET_SEC_COL_DROPDOWN,
00297   PLW_WIDGET_MATRIX,
00298 };
00299 
00300 static void ShowColourDropDownMenu(Window *w, uint32 widget)
00301 {
00302   uint32 used_colours = 0;
00303   const Livery *livery;
00304   LiveryScheme scheme;
00305 
00306   /* Disallow other player colours for the primary colour */
00307   if (HasBit(WP(w, livery_d).sel, LS_DEFAULT) && widget == PLW_WIDGET_PRI_COL_DROPDOWN) {
00308     const Player *p;
00309     FOR_ALL_PLAYERS(p) {
00310       if (p->is_active && p->index != _local_player) SetBit(used_colours, p->player_color);
00311     }
00312   }
00313 
00314   /* Get the first selected livery to use as the default dropdown item */
00315   for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
00316     if (HasBit(WP(w, livery_d).sel, scheme)) break;
00317   }
00318   if (scheme == LS_END) scheme = LS_DEFAULT;
00319   livery = &GetPlayer((PlayerID)w->window_number)->livery[scheme];
00320 
00321   ShowDropDownMenu(w, _colour_dropdown, widget == PLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget, used_colours, 0);
00322 }
00323 
00324 static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e)
00325 {
00326   switch (e->event) {
00327     case WE_CREATE:
00328       w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
00329       if (!_loaded_newgrf_features.has_2CC) {
00330         w->HideWidget(PLW_WIDGET_SEC_COL_DROPDOWN);
00331       }
00332       break;
00333 
00334     case WE_PAINT: {
00335       const Player *p = GetPlayer((PlayerID)w->window_number);
00336       LiveryScheme scheme = LS_DEFAULT;
00337       int y = 51;
00338 
00339       /* Disable dropdown controls if no scheme is selected */
00340       w->SetWidgetDisabledState(PLW_WIDGET_PRI_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
00341       w->SetWidgetDisabledState(PLW_WIDGET_SEC_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
00342 
00343       if (!(WP(w, livery_d).sel == 0)) {
00344         for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
00345           if (HasBit(WP(w, livery_d).sel, scheme)) break;
00346         }
00347         if (scheme == LS_END) scheme = LS_DEFAULT;
00348       }
00349 
00350       SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
00351       SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
00352 
00353       DrawWindowWidgets(w);
00354 
00355       for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00356         if (livery_class[scheme] == WP(w, livery_d).livery_class) {
00357           bool sel = HasBit(WP(w, livery_d).sel, scheme) != 0;
00358 
00359           if (scheme != LS_DEFAULT) {
00360             DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
00361           }
00362 
00363           DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
00364 
00365           DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour1), 152, y);
00366           DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
00367 
00368           if (_loaded_newgrf_features.has_2CC) {
00369             DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour2), 277, y);
00370             DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
00371           }
00372 
00373           y += 14;
00374         }
00375       }
00376       break;
00377     }
00378 
00379     case WE_CLICK: {
00380       switch (e->we.click.widget) {
00381         /* Livery Class buttons */
00382         case PLW_WIDGET_CLASS_GENERAL:
00383         case PLW_WIDGET_CLASS_RAIL:
00384         case PLW_WIDGET_CLASS_ROAD:
00385         case PLW_WIDGET_CLASS_SHIP:
00386         case PLW_WIDGET_CLASS_AIRCRAFT: {
00387           LiveryScheme scheme;
00388 
00389           w->RaiseWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
00390           WP(w, livery_d).livery_class = (LiveryClass)(e->we.click.widget - PLW_WIDGET_CLASS_GENERAL);
00391           WP(w, livery_d).sel = 0;
00392           w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
00393 
00394           /* Select the first item in the list */
00395           for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00396             if (livery_class[scheme] == WP(w, livery_d).livery_class) {
00397               WP(w, livery_d).sel = 1 << scheme;
00398               break;
00399             }
00400           }
00401           w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14;
00402           w->widget[PLW_WIDGET_MATRIX].bottom = w->height - 1;
00403           w->widget[PLW_WIDGET_MATRIX].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1;
00404           MarkWholeScreenDirty();
00405           break;
00406         }
00407 
00408         case PLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
00409           ShowColourDropDownMenu(w, PLW_WIDGET_PRI_COL_DROPDOWN);
00410           break;
00411 
00412         case PLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
00413           ShowColourDropDownMenu(w, PLW_WIDGET_SEC_COL_DROPDOWN);
00414           break;
00415 
00416         case PLW_WIDGET_MATRIX: {
00417           LiveryScheme scheme;
00418           LiveryScheme j = (LiveryScheme)((e->we.click.pt.y - 48) / 14);
00419 
00420           for (scheme = LS_BEGIN; scheme <= j; scheme++) {
00421             if (livery_class[scheme] != WP(w, livery_d).livery_class) j++;
00422             if (scheme >= LS_END) return;
00423           }
00424           if (j >= LS_END) return;
00425 
00426           /* If clicking on the left edge, toggle using the livery */
00427           if (e->we.click.pt.x < 10) {
00428             DoCommandP(0, j | (2 << 8), !GetPlayer((PlayerID)w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
00429           }
00430 
00431           if (_ctrl_pressed) {
00432             ToggleBit(WP(w, livery_d).sel, j);
00433           } else {
00434             WP(w, livery_d).sel = 1 << j;
00435           }
00436           SetWindowDirty(w);
00437           break;
00438         }
00439       }
00440       break;
00441     }
00442 
00443     case WE_DROPDOWN_SELECT: {
00444       LiveryScheme scheme;
00445 
00446       for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00447         if (HasBit(WP(w, livery_d).sel, scheme)) {
00448           DoCommandP(0, scheme | (e->we.dropdown.button == PLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), e->we.dropdown.index, NULL, CMD_SET_PLAYER_COLOR);
00449         }
00450       }
00451       break;
00452     }
00453   }
00454 }
00455 
00456 static const Widget _select_player_livery_2cc_widgets[] = {
00457 { WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
00458 {  WWT_CAPTION, RESIZE_NONE, 14,  11, 399,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
00459 {   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
00460 {   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
00461 {   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
00462 {   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
00463 {   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
00464 {    WWT_PANEL, RESIZE_NONE, 14, 110, 399,  14,  35, 0x0,                       STR_NULL },
00465 {    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
00466 { WWT_DROPDOWN, RESIZE_NONE, 14, 150, 274,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
00467 { WWT_DROPDOWN, RESIZE_NONE, 14, 275, 399,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
00468 {   WWT_MATRIX, RESIZE_NONE, 14,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
00469 { WIDGETS_END },
00470 };
00471 
00472 static const WindowDesc _select_player_livery_2cc_desc = {
00473   WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
00474   WC_PLAYER_COLOR, WC_NONE,
00475   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00476   _select_player_livery_2cc_widgets,
00477   SelectPlayerLiveryWndProc
00478 };
00479 
00480 
00481 static const Widget _select_player_livery_widgets[] = {
00482 { WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
00483 {  WWT_CAPTION, RESIZE_NONE, 14,  11, 274,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
00484 {   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
00485 {   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
00486 {   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
00487 {   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
00488 {   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
00489 {    WWT_PANEL, RESIZE_NONE, 14, 110, 274,  14,  35, 0x0,                       STR_NULL },
00490 {    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
00491 { WWT_DROPDOWN, RESIZE_NONE, 14, 150, 274,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
00492 { WWT_DROPDOWN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
00493 {   WWT_MATRIX, RESIZE_NONE, 14,   0, 274,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
00494 { WIDGETS_END },
00495 };
00496 
00497 static const WindowDesc _select_player_livery_desc = {
00498   WDP_AUTO, WDP_AUTO, 275, 49 + 1 * 14, 275, 49 + 1 * 14,
00499   WC_PLAYER_COLOR, WC_NONE,
00500   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00501   _select_player_livery_widgets,
00502   SelectPlayerLiveryWndProc
00503 };
00504 
00512 void DrawPlayerFace(PlayerFace pf, int color, int x, int y)
00513 {
00514   GenderEthnicity ge = (GenderEthnicity)GetPlayerFaceBits(pf, PFV_GEN_ETHN, GE_WM);
00515 
00516   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetPlayerFaceBits(pf, PFV_HAS_MOUSTACHE,   ge) != 0;
00517   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetPlayerFaceBits(pf, PFV_HAS_TIE_EARRING, ge) != 0;
00518   bool has_glasses     = GetPlayerFaceBits(pf, PFV_HAS_GLASSES, ge) != 0;
00519   SpriteID pal;
00520 
00521   /* Modify eye colour palette only if 2 or more valid values exist */
00522   if (_pf_info[PFV_EYE_COLOUR].valid_values[ge] < 2) {
00523     pal = PAL_NONE;
00524   } else {
00525     switch (GetPlayerFaceBits(pf, PFV_EYE_COLOUR, ge)) {
00526       default: NOT_REACHED();
00527       case 0: pal = PALETTE_TO_BROWN; break;
00528       case 1: pal = PALETTE_TO_BLUE;  break;
00529       case 2: pal = PALETTE_TO_GREEN; break;
00530     }
00531   }
00532 
00533   /* Draw the gradient (background) */
00534   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOR(color), x, y);
00535 
00536   for (PlayerFaceVariable pfv = PFV_CHEEKS; pfv < PFV_END; pfv++) {
00537     switch (pfv) {
00538       case PFV_MOUSTACHE:   if (!has_moustache)   continue; break;
00539       case PFV_LIPS:        /* FALL THROUGH */
00540       case PFV_NOSE:        if (has_moustache)    continue; break;
00541       case PFV_TIE_EARRING: if (!has_tie_earring) continue; break;
00542       case PFV_GLASSES:     if (!has_glasses)     continue; break;
00543       default: break;
00544     }
00545     DrawSprite(GetPlayerFaceSprite(pf, pfv, ge), (pfv == PFV_EYEBROWS) ? pal : PAL_NONE, x, y);
00546   }
00547 }
00548 
00554 enum PlayerFaceWindowWidgets {
00555   PFW_WIDGET_CLOSEBOX = 0,
00556   PFW_WIDGET_CAPTION,
00557   PFW_WIDGET_TOGGLE_LARGE_SMALL,
00558   PFW_WIDGET_SELECT_FACE,
00559   PFW_WIDGET_CANCEL,
00560   PFW_WIDGET_ACCEPT,
00561   PFW_WIDGET_MALE,
00562   PFW_WIDGET_FEMALE,
00563   PFW_WIDGET_RANDOM_NEW_FACE,
00564   PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
00565   /* from here is the advanced player face selection window */
00566   PFW_WIDGET_LOAD,
00567   PFW_WIDGET_FACECODE,
00568   PFW_WIDGET_SAVE,
00569   PFW_WIDGET_ETHNICITY_EUR,
00570   PFW_WIDGET_ETHNICITY_AFR,
00571   PFW_WIDGET_HAS_MOUSTACHE_EARRING,
00572   PFW_WIDGET_HAS_GLASSES,
00573   PFW_WIDGET_EYECOLOUR_L,
00574   PFW_WIDGET_EYECOLOUR,
00575   PFW_WIDGET_EYECOLOUR_R,
00576   PFW_WIDGET_CHIN_L,
00577   PFW_WIDGET_CHIN,
00578   PFW_WIDGET_CHIN_R,
00579   PFW_WIDGET_EYEBROWS_L,
00580   PFW_WIDGET_EYEBROWS,
00581   PFW_WIDGET_EYEBROWS_R,
00582   PFW_WIDGET_LIPS_MOUSTACHE_L,
00583   PFW_WIDGET_LIPS_MOUSTACHE,
00584   PFW_WIDGET_LIPS_MOUSTACHE_R,
00585   PFW_WIDGET_NOSE_L,
00586   PFW_WIDGET_NOSE,
00587   PFW_WIDGET_NOSE_R,
00588   PFW_WIDGET_HAIR_L,
00589   PFW_WIDGET_HAIR,
00590   PFW_WIDGET_HAIR_R,
00591   PFW_WIDGET_JACKET_L,
00592   PFW_WIDGET_JACKET,
00593   PFW_WIDGET_JACKET_R,
00594   PFW_WIDGET_COLLAR_L,
00595   PFW_WIDGET_COLLAR,
00596   PFW_WIDGET_COLLAR_R,
00597   PFW_WIDGET_TIE_EARRING_L,
00598   PFW_WIDGET_TIE_EARRING,
00599   PFW_WIDGET_TIE_EARRING_R,
00600   PFW_WIDGET_GLASSES_L,
00601   PFW_WIDGET_GLASSES,
00602   PFW_WIDGET_GLASSES_R,
00603 };
00604 
00606 static const Widget _select_player_face_widgets[] = {
00607 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // PFW_WIDGET_CLOSEBOX
00608 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   174,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // PFW_WIDGET_CAPTION
00609 {     WWT_IMGBTN,   RESIZE_NONE,    14,   175,   189,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_ADVANCED_TIP},              // PFW_WIDGET_TOGGLE_LARGE_SMALL
00610 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   189,    14,   150, 0x0,                     STR_NULL},                           // PFW_WIDGET_SELECT_FACE
00611 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    94,   151,   162, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // PFW_WIDGET_CANCEL
00612 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   189,   151,   162, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // PFW_WIDGET_ACCEPT
00613 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    75,    86, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // PFW_WIDGET_MALE
00614 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    87,    98, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // PFW_WIDGET_FEMALE
00615 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     2,    93,   137,   148, STR_7046_NEW_FACE,       STR_704B_GENERATE_RANDOM_NEW_FACE},  // PFW_WIDGET_RANDOM_NEW_FACE
00616 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   187,    16,    27, STR_FACE_ADVANCED,       STR_FACE_ADVANCED_TIP},              // PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
00617 {   WIDGETS_END},
00618 };
00619 
00621 static const Widget _select_player_face_adv_widgets[] = {
00622 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // PFW_WIDGET_CLOSEBOX
00623 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   204,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // PFW_WIDGET_CAPTION
00624 {     WWT_IMGBTN,   RESIZE_NONE,    14,   205,   219,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_SIMPLE_TIP},                // PFW_WIDGET_TOGGLE_LARGE_SMALL
00625 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   219,    14,   207, 0x0,                     STR_NULL},                           // PFW_WIDGET_SELECT_FACE
00626 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    94,   208,   219, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // PFW_WIDGET_CANCEL
00627 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   219,   208,   219, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // PFW_WIDGET_ACCEPT
00628 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    96,   156,    32,    43, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // PFW_WIDGET_MALE
00629 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   157,   217,    32,    43, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // PFW_WIDGET_FEMALE
00630 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     2,    93,   137,   148, STR_RANDOM,              STR_704B_GENERATE_RANDOM_NEW_FACE},  // PFW_WIDGET_RANDOM_NEW_FACE
00631 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   217,    16,    27, STR_FACE_SIMPLE,         STR_FACE_SIMPLE_TIP},                // PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
00632 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     2,    93,   158,   169, STR_FACE_LOAD,           STR_FACE_LOAD_TIP},                  // PFW_WIDGET_LOAD
00633 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     2,    93,   170,   181, STR_FACE_FACECODE,       STR_FACE_FACECODE_TIP},              // PFW_WIDGET_FACECODE
00634 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     2,    93,   182,   193, STR_FACE_SAVE,           STR_FACE_SAVE_TIP},                  // PFW_WIDGET_SAVE
00635 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    96,   156,    46,    57, STR_FACE_EUROPEAN,       STR_FACE_SELECT_EUROPEAN},           // PFW_WIDGET_ETHNICITY_EUR
00636 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   157,   217,    46,    57, STR_FACE_AFRICAN,        STR_FACE_SELECT_AFRICAN},            // PFW_WIDGET_ETHNICITY_AFR
00637 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   175,   217,    60,    71, STR_EMPTY,               STR_FACE_MOUSTACHE_EARRING_TIP},     // PFW_WIDGET_HAS_MOUSTACHE_EARRING
00638 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   175,   217,    72,    83, STR_EMPTY,               STR_FACE_GLASSES_TIP},               // PFW_WIDGET_HAS_GLASSES
00639 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   110,   121, SPR_ARROW_LEFT,          STR_FACE_EYECOLOUR_TIP},             // PFW_WIDGET_EYECOLOUR_L
00640 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   110,   121, STR_EMPTY,               STR_FACE_EYECOLOUR_TIP},             // PFW_WIDGET_EYECOLOUR
00641 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   110,   121, SPR_ARROW_RIGHT,         STR_FACE_EYECOLOUR_TIP},             // PFW_WIDGET_EYECOLOUR_R
00642 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   158,   169, SPR_ARROW_LEFT,          STR_FACE_CHIN_TIP},                  // PFW_WIDGET_CHIN_L
00643 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   158,   169, STR_EMPTY,               STR_FACE_CHIN_TIP},                  // PFW_WIDGET_CHIN
00644 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   158,   169, SPR_ARROW_RIGHT,         STR_FACE_CHIN_TIP},                  // PFW_WIDGET_CHIN_R
00645 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,    98,   109, SPR_ARROW_LEFT,          STR_FACE_EYEBROWS_TIP},              // PFW_WIDGET_EYEBROWS_L
00646 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,    98,   109, STR_EMPTY,               STR_FACE_EYEBROWS_TIP},              // PFW_WIDGET_EYEBROWS
00647 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,    98,   109, SPR_ARROW_RIGHT,         STR_FACE_EYEBROWS_TIP},              // PFW_WIDGET_EYEBROWS_R
00648 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   146,   157, SPR_ARROW_LEFT,          STR_FACE_LIPS_MOUSTACHE_TIP},        // PFW_WIDGET_LIPS_MOUSTACHE_L
00649 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   146,   157, STR_EMPTY,               STR_FACE_LIPS_MOUSTACHE_TIP},        // PFW_WIDGET_LIPS_MOUSTACHE
00650 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   146,   157, SPR_ARROW_RIGHT,         STR_FACE_LIPS_MOUSTACHE_TIP},        // PFW_WIDGET_LIPS_MOUSTACHE_R
00651 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   134,   145, SPR_ARROW_LEFT,          STR_FACE_NOSE_TIP},                  // PFW_WIDGET_NOSE_L
00652 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   134,   145, STR_EMPTY,               STR_FACE_NOSE_TIP},                  // PFW_WIDGET_NOSE
00653 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   134,   145, SPR_ARROW_RIGHT,         STR_FACE_NOSE_TIP},                  // PFW_WIDGET_NOSE_R
00654 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,    86,    97, SPR_ARROW_LEFT,          STR_FACE_HAIR_TIP},                  // PFW_WIDGET_HAIR_L
00655 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,    86,    97, STR_EMPTY,               STR_FACE_HAIR_TIP},                  // PFW_WIDGET_HAIR
00656 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,    86,    97, SPR_ARROW_RIGHT,         STR_FACE_HAIR_TIP},                  // PFW_WIDGET_HAIR_R
00657 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   170,   181, SPR_ARROW_LEFT,          STR_FACE_JACKET_TIP},                // PFW_WIDGET_JACKET_L
00658 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   170,   181, STR_EMPTY,               STR_FACE_JACKET_TIP},                // PFW_WIDGET_JACKET
00659 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   170,   181, SPR_ARROW_RIGHT,         STR_FACE_JACKET_TIP},                // PFW_WIDGET_JACKET_R
00660 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   182,   193, SPR_ARROW_LEFT,          STR_FACE_COLLAR_TIP},                // PFW_WIDGET_COLLAR_L
00661 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   182,   193, STR_EMPTY,               STR_FACE_COLLAR_TIP},                // PFW_WIDGET_COLLAR
00662 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   182,   193, SPR_ARROW_RIGHT,         STR_FACE_COLLAR_TIP},                // PFW_WIDGET_COLLAR_R
00663 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   194,   205, SPR_ARROW_LEFT,          STR_FACE_TIE_EARRING_TIP},           // PFW_WIDGET_TIE_EARRING_L
00664 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   194,   205, STR_EMPTY,               STR_FACE_TIE_EARRING_TIP},           // PFW_WIDGET_TIE_EARRING
00665 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   194,   205, SPR_ARROW_RIGHT,         STR_FACE_TIE_EARRING_TIP},           // PFW_WIDGET_TIE_EARRING_R
00666 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    175,  183,   122,   133, SPR_ARROW_LEFT,          STR_FACE_GLASSES_TIP_2},             // PFW_WIDGET_GLASSES_L
00667 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    184,  208,   122,   133, STR_EMPTY,               STR_FACE_GLASSES_TIP_2},             // PFW_WIDGET_GLASSES
00668 { WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    209,  217,   122,   133, SPR_ARROW_RIGHT,         STR_FACE_GLASSES_TIP_2},             // PFW_WIDGET_GLASSES_R
00669 {   WIDGETS_END},
00670 };
00671 
00681 void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget)
00682 {
00683   /* Write the label in gold (0x2) to the left of the button. */
00684   DrawStringRightAligned(w->widget[widget_index].left - (is_bool_widget ? 5 : 14), w->widget[widget_index].top + 1, str, TC_GOLD);
00685 
00686   if (!w->IsWidgetDisabled(widget_index)) {
00687     if (is_bool_widget) {
00688       /* if it a bool button write yes or no */
00689       str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
00690     } else {
00691       /* else write the value + 1 */
00692       SetDParam(0, val + 1);
00693       str = STR_JUST_INT;
00694     }
00695 
00696     /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
00697     DrawStringCentered(w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 +
00698       w->IsWidgetLowered(widget_index), w->widget[widget_index].top + 1 + w->IsWidgetLowered(widget_index), str, TC_WHITE);
00699   }
00700 }
00701 
00708 static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e)
00709 {
00710   PlayerFace *pf = &WP(w, facesel_d).face; // pointer to the player face bits
00711   GenderEthnicity ge = (GenderEthnicity)GB(*pf, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // get the gender and ethnicity
00712   bool is_female = HasBit(ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
00713   bool is_moust_male = !is_female && GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE, ge) != 0; // is a male face with moustache
00714 
00715   switch (e->event) {
00716     case WE_PAINT:
00717       /* lower the non-selected gender button */
00718       w->SetWidgetLoweredState(PFW_WIDGET_MALE,  !is_female);
00719       w->SetWidgetLoweredState(PFW_WIDGET_FEMALE, is_female);
00720 
00721       /* advanced player face selection window */
00722       if (WP(w, facesel_d).advanced) {
00723         /* lower the non-selected ethnicity button */
00724         w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_EUR, !HasBit(ge, ETHNICITY_BLACK));
00725         w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_AFR,  HasBit(ge, ETHNICITY_BLACK));
00726 
00727 
00728         /* Disable dynamically the widgets which PlayerFaceVariable has less than 2 options
00729         * (or in other words you haven't any choice).
00730         * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
00731 
00732         /* Eye colour buttons */
00733         w->SetWidgetsDisabledState(_pf_info[PFV_EYE_COLOUR].valid_values[ge] < 2,
00734           PFW_WIDGET_EYECOLOUR, PFW_WIDGET_EYECOLOUR_L, PFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
00735 
00736         /* Chin buttons */
00737         w->SetWidgetsDisabledState(_pf_info[PFV_CHIN].valid_values[ge] < 2,
00738           PFW_WIDGET_CHIN, PFW_WIDGET_CHIN_L, PFW_WIDGET_CHIN_R, WIDGET_LIST_END);
00739 
00740         /* Eyebrows buttons */
00741         w->SetWidgetsDisabledState(_pf_info[PFV_EYEBROWS].valid_values[ge] < 2,
00742           PFW_WIDGET_EYEBROWS, PFW_WIDGET_EYEBROWS_L, PFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
00743 
00744         /* Lips or (if it a male face with a moustache) moustache buttons */
00745         w->SetWidgetsDisabledState(_pf_info[is_moust_male ? PFV_MOUSTACHE : PFV_LIPS].valid_values[ge] < 2,
00746           PFW_WIDGET_LIPS_MOUSTACHE, PFW_WIDGET_LIPS_MOUSTACHE_L, PFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
00747 
00748         /* Nose buttons | male faces with moustache haven't any nose options */
00749         w->SetWidgetsDisabledState(_pf_info[PFV_NOSE].valid_values[ge] < 2 || is_moust_male,
00750           PFW_WIDGET_NOSE, PFW_WIDGET_NOSE_L, PFW_WIDGET_NOSE_R, WIDGET_LIST_END);
00751 
00752         /* Hair buttons */
00753         w->SetWidgetsDisabledState(_pf_info[PFV_HAIR].valid_values[ge] < 2,
00754           PFW_WIDGET_HAIR, PFW_WIDGET_HAIR_L, PFW_WIDGET_HAIR_R, WIDGET_LIST_END);
00755 
00756         /* Jacket buttons */
00757         w->SetWidgetsDisabledState(_pf_info[PFV_JACKET].valid_values[ge] < 2,
00758           PFW_WIDGET_JACKET, PFW_WIDGET_JACKET_L, PFW_WIDGET_JACKET_R, WIDGET_LIST_END);
00759 
00760         /* Collar buttons */
00761         w->SetWidgetsDisabledState(_pf_info[PFV_COLLAR].valid_values[ge] < 2,
00762           PFW_WIDGET_COLLAR, PFW_WIDGET_COLLAR_L, PFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
00763 
00764         /* Tie/earring buttons | female faces without earring haven't any earring options */
00765         w->SetWidgetsDisabledState(_pf_info[PFV_TIE_EARRING].valid_values[ge] < 2 ||
00766             (is_female && GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge) == 0),
00767           PFW_WIDGET_TIE_EARRING, PFW_WIDGET_TIE_EARRING_L, PFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
00768 
00769         /* Glasses buttons | faces without glasses haven't any glasses options */
00770         w->SetWidgetsDisabledState(_pf_info[PFV_GLASSES].valid_values[ge] < 2 || GetPlayerFaceBits(*pf, PFV_HAS_GLASSES, ge) == 0,
00771           PFW_WIDGET_GLASSES, PFW_WIDGET_GLASSES_L, PFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
00772       }
00773 
00774       DrawWindowWidgets(w);
00775 
00776       /* Draw dynamic button value and labels for the advanced player face selection window */
00777       if (WP(w, facesel_d).advanced) {
00778         if (is_female) {
00779           /* Only for female faces */
00780           DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge), true );
00781           DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetPlayerFaceBits(*pf, PFV_TIE_EARRING,     ge), false);
00782         } else {
00783           /* Only for male faces */
00784           DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE,   ge), true );
00785           DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetPlayerFaceBits(*pf, PFV_TIE_EARRING,     ge), false);
00786         }
00787         if (is_moust_male) {
00788           /* Only for male faces with moustache */
00789           DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_MOUSTACHE,       ge), false);
00790         } else {
00791           /* Only for female faces or male faces without moustache */
00792           DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetPlayerFaceBits(*pf, PFV_LIPS,            ge), false);
00793         }
00794         /* For all faces */
00795         DrawFaceStringLabel(w, PFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetPlayerFaceBits(*pf, PFV_HAS_GLASSES,     ge), true );
00796         DrawFaceStringLabel(w, PFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetPlayerFaceBits(*pf, PFV_HAIR,            ge), false);
00797         DrawFaceStringLabel(w, PFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetPlayerFaceBits(*pf, PFV_EYEBROWS,        ge), false);
00798         DrawFaceStringLabel(w, PFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetPlayerFaceBits(*pf, PFV_EYE_COLOUR,      ge), false);
00799         DrawFaceStringLabel(w, PFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetPlayerFaceBits(*pf, PFV_GLASSES,         ge), false);
00800         DrawFaceStringLabel(w, PFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetPlayerFaceBits(*pf, PFV_NOSE,            ge), false);
00801         DrawFaceStringLabel(w, PFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetPlayerFaceBits(*pf, PFV_CHIN,            ge), false);
00802         DrawFaceStringLabel(w, PFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetPlayerFaceBits(*pf, PFV_JACKET,          ge), false);
00803         DrawFaceStringLabel(w, PFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetPlayerFaceBits(*pf, PFV_COLLAR,          ge), false);
00804       }
00805 
00806       /* Draw the player face picture */
00807       DrawPlayerFace(*pf, GetPlayer((PlayerID)w->window_number)->player_color, 2, 16);
00808       break;
00809 
00810     case WE_CLICK:
00811       switch (e->we.click.widget) {
00812         /* Toggle size, advanced/simple face selection */
00813         case PFW_WIDGET_TOGGLE_LARGE_SMALL:
00814         case PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON:
00815           DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
00816           DeleteWindow(w);
00817           DoSelectPlayerFace((PlayerID)w->window_number, !WP(w, facesel_d).advanced);
00818           break;
00819 
00820         /* Cancel button */
00821         case PFW_WIDGET_CANCEL:
00822           DeleteWindow(w);
00823           break;
00824 
00825         /* OK button */
00826         case PFW_WIDGET_ACCEPT:
00827           DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
00828           DeleteWindow(w);
00829           break;
00830 
00831         /* Load button */
00832         case PFW_WIDGET_LOAD:
00833           *pf = _player_face;
00834           ScaleAllPlayerFaceBits(*pf);
00835           ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
00836           SetWindowDirty(w);
00837           break;
00838 
00839         /* 'Player face number' button, view and/or set player face number */
00840         case PFW_WIDGET_FACECODE:
00841           SetDParam(0, *pf);
00842           ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, w, CS_NUMERAL);
00843           break;
00844 
00845         /* Save button */
00846         case PFW_WIDGET_SAVE:
00847           _player_face = *pf;
00848           ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
00849           break;
00850 
00851         /* Toggle gender (male/female) button */
00852         case PFW_WIDGET_MALE:
00853         case PFW_WIDGET_FEMALE:
00854           SetPlayerFaceBits(*pf, PFV_GENDER, ge, e->we.click.widget - PFW_WIDGET_MALE);
00855           ScaleAllPlayerFaceBits(*pf);
00856           SetWindowDirty(w);
00857           break;
00858 
00859         /* Randomize face button */
00860         case PFW_WIDGET_RANDOM_NEW_FACE:
00861           RandomPlayerFaceBits(*pf, ge, WP(w, facesel_d).advanced);
00862           SetWindowDirty(w);
00863           break;
00864 
00865         /* Toggle ethnicity (european/african) button */
00866         case PFW_WIDGET_ETHNICITY_EUR:
00867         case PFW_WIDGET_ETHNICITY_AFR:
00868           SetPlayerFaceBits(*pf, PFV_ETHNICITY, ge, e->we.click.widget - PFW_WIDGET_ETHNICITY_EUR);
00869           ScaleAllPlayerFaceBits(*pf);
00870           SetWindowDirty(w);
00871           break;
00872 
00873         default:
00874           /* For all buttons from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R is the same function.
00875           * Therefor is this combined function.
00876           * First it checks which PlayerFaceVariable will be change and then
00877           * a: invert the value for boolean variables
00878           * or b: it checks inside of IncreasePlayerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
00879           if (WP(w, facesel_d).advanced && e->we.click.widget >= PFW_WIDGET_HAS_MOUSTACHE_EARRING && e->we.click.widget <= PFW_WIDGET_GLASSES_R) {
00880             PlayerFaceVariable pfv; // which PlayerFaceVariable shall be edited
00881 
00882             if (e->we.click.widget < PFW_WIDGET_EYECOLOUR_L) { // Bool buttons
00883               switch (e->we.click.widget - PFW_WIDGET_HAS_MOUSTACHE_EARRING) {
00884                 default: NOT_REACHED();
00885                 case 0: pfv = is_female ? PFV_HAS_TIE_EARRING : PFV_HAS_MOUSTACHE; break; // Has earring/moustache button
00886                 case 1: pfv = PFV_HAS_GLASSES; break; // Has glasses button
00887               }
00888               SetPlayerFaceBits(*pf, pfv, ge, !GetPlayerFaceBits(*pf, pfv, ge));
00889               ScaleAllPlayerFaceBits(*pf);
00890 
00891             } else { // Value buttons
00892               switch ((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) / 3) {
00893                 default: NOT_REACHED();
00894                 case 0: pfv = PFV_EYE_COLOUR; break;  // Eye colour buttons
00895                 case 1: pfv = PFV_CHIN; break;        // Chin buttons
00896                 case 2: pfv = PFV_EYEBROWS; break;    // Eyebrows buttons
00897                 case 3: pfv = is_moust_male ? PFV_MOUSTACHE : PFV_LIPS; break; // Moustache or lips buttons
00898                 case 4: pfv = PFV_NOSE; break;        // Nose buttons
00899                 case 5: pfv = PFV_HAIR; break;        // Hair buttons
00900                 case 6: pfv = PFV_JACKET; break;      // Jacket buttons
00901                 case 7: pfv = PFV_COLLAR; break;      // Collar buttons
00902                 case 8: pfv = PFV_TIE_EARRING; break; // Tie/earring buttons
00903                 case 9: pfv = PFV_GLASSES; break;     // Glasses buttons
00904               }
00905               /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
00906               IncreasePlayerFaceBits(*pf, pfv, ge, (((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
00907             }
00908 
00909             SetWindowDirty(w);
00910           }
00911           break;
00912       }
00913       break;
00914 
00915     case WE_ON_EDIT_TEXT:
00916       /* Set a new player face number */
00917       if (!StrEmpty(e->we.edittext.str)) {
00918         *pf = strtoul(e->we.edittext.str, NULL, 10);
00919         ScaleAllPlayerFaceBits(*pf);
00920         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
00921         SetWindowDirty(w);
00922       } else {
00923         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
00924       }
00925       break;
00926   }
00927 }
00928 
00930 static const WindowDesc _select_player_face_desc = {
00931   WDP_AUTO, WDP_AUTO, 190, 163, 190, 163,
00932   WC_PLAYER_FACE, WC_NONE,
00933   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00934   _select_player_face_widgets,
00935   SelectPlayerFaceWndProc
00936 };
00937 
00939 static const WindowDesc _select_player_face_adv_desc = {
00940   WDP_AUTO, WDP_AUTO, 220, 220, 220, 220,
00941   WC_PLAYER_FACE, WC_NONE,
00942   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00943   _select_player_face_adv_widgets,
00944   SelectPlayerFaceWndProc
00945 };
00946 
00955 static void DoSelectPlayerFace(PlayerID player, bool adv)
00956 {
00957   if (!IsValidPlayer(player)) return;
00958 
00959   Window *w = AllocateWindowDescFront(adv ? &_select_player_face_adv_desc : &_select_player_face_desc, player); // simple or advanced window
00960 
00961   if (w != NULL) {
00962     w->caption_color = w->window_number;
00963     WP(w, facesel_d).face = GetPlayer((PlayerID)w->window_number)->face;
00964     WP(w, facesel_d).advanced = adv;
00965   }
00966 }
00967 
00968 
00969 /* Names of the widgets. Keep them in the same order as in the widget array */
00970 enum PlayerCompanyWindowWidgets {
00971   PCW_WIDGET_CLOSEBOX = 0,
00972   PCW_WIDGET_CAPTION,
00973   PCW_WIDGET_FACE,
00974   PCW_WIDGET_NEW_FACE,
00975   PCW_WIDGET_COLOR_SCHEME,
00976   PCW_WIDGET_PRESIDENT_NAME,
00977   PCW_WIDGET_COMPANY_NAME,
00978   PCW_WIDGET_BUILD_VIEW_HQ,
00979   PCW_WIDGET_RELOCATE_HQ,
00980   PCW_WIDGET_BUY_SHARE,
00981   PCW_WIDGET_SELL_SHARE,
00982   PCW_WIDGET_COMPANY_PASSWORD,
00983 };
00984 
00985 static const Widget _player_company_widgets[] = {
00986 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
00987 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
00988 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   359,    14,   157, 0x0,                               STR_NULL},
00989 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
00990 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    90,   179,   158,   169, STR_7005_COLOR_SCHEME,             STR_7031_CHANGE_THE_COMPANY_VEHICLE},
00991 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
00992 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
00993 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
00994 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
00995 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   179,   158,   169, STR_7077_BUY_25_SHARE_IN_COMPANY,  STR_7079_BUY_25_SHARE_IN_THIS_COMPANY},
00996 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   359,   158,   169, STR_7078_SELL_25_SHARE_IN_COMPANY, STR_707A_SELL_25_SHARE_IN_THIS_COMPANY},
00997 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
00998 {   WIDGETS_END},
00999 };
01000 
01001 
01006 static void DrawPlayerVehiclesAmount(PlayerID player)
01007 {
01008   const int x = 110;
01009   int y = 63;
01010   const Vehicle *v;
01011   uint train = 0;
01012   uint road  = 0;
01013   uint air   = 0;
01014   uint ship  = 0;
01015 
01016   DrawString(x, y, STR_7039_VEHICLES, TC_FROMSTRING);
01017 
01018   FOR_ALL_VEHICLES(v) {
01019     if (v->owner == player) {
01020       switch (v->type) {
01021         case VEH_TRAIN:    if (IsFrontEngine(v)) train++; break;
01022         case VEH_ROAD:     if (IsRoadVehFront(v)) road++; break;
01023         case VEH_AIRCRAFT: if (IsNormalAircraft(v)) air++; break;
01024         case VEH_SHIP:     ship++; break;
01025         default: break;
01026       }
01027     }
01028   }
01029 
01030   if (train + road + air + ship == 0) {
01031     DrawString(x + 70, y, STR_7042_NONE, TC_FROMSTRING);
01032   } else {
01033     if (train != 0) {
01034       SetDParam(0, train);
01035       DrawString(x + 70, y, STR_TRAINS, TC_FROMSTRING);
01036       y += 10;
01037     }
01038 
01039     if (road != 0) {
01040       SetDParam(0, road);
01041       DrawString(x + 70, y, STR_ROAD_VEHICLES, TC_FROMSTRING);
01042       y += 10;
01043     }
01044 
01045     if (air != 0) {
01046       SetDParam(0, air);
01047       DrawString(x + 70, y, STR_AIRCRAFT, TC_FROMSTRING);
01048       y += 10;
01049     }
01050 
01051     if (ship != 0) {
01052       SetDParam(0, ship);
01053       DrawString(x + 70, y, STR_SHIPS, TC_FROMSTRING);
01054     }
01055   }
01056 }
01057 
01058 int GetAmountOwnedBy(const Player *p, PlayerID owner)
01059 {
01060   return (p->share_owners[0] == owner) +
01061          (p->share_owners[1] == owner) +
01062          (p->share_owners[2] == owner) +
01063          (p->share_owners[3] == owner);
01064 }
01065 
01070 static void DrawCompanyOwnerText(const Player *p)
01071 {
01072   const Player *p2;
01073   uint num = 0;
01074   const byte height = GetCharacterHeight(FS_NORMAL);
01075 
01076   FOR_ALL_PLAYERS(p2) {
01077     uint amt = GetAmountOwnedBy(p, p2->index);
01078     if (amt != 0) {
01079       SetDParam(0, amt * 25);
01080       SetDParam(1, p2->index);
01081 
01082       DrawString(120, (num++) * height + 116, STR_707D_OWNED_BY, TC_FROMSTRING);
01083     }
01084   }
01085 }
01086 
01093 static void PlayerCompanyWndProc(Window *w, WindowEvent *e)
01094 {
01095   switch (e->event) {
01096     case WE_PAINT: {
01097       const Player *p = GetPlayer((PlayerID)w->window_number);
01098       bool local = w->window_number == _local_player;
01099 
01100       w->SetWidgetHiddenState(PCW_WIDGET_NEW_FACE,       !local);
01101       w->SetWidgetHiddenState(PCW_WIDGET_COLOR_SCHEME,   !local);
01102       w->SetWidgetHiddenState(PCW_WIDGET_PRESIDENT_NAME, !local);
01103       w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_NAME,   !local);
01104       w->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
01105       if (local && p->location_of_house != 0) w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
01106       w->SetWidgetDisabledState(PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
01107       w->SetWidgetHiddenState(PCW_WIDGET_RELOCATE_HQ,      !local || p->location_of_house == 0);
01108       w->SetWidgetHiddenState(PCW_WIDGET_BUY_SHARE,        local);
01109       w->SetWidgetHiddenState(PCW_WIDGET_SELL_SHARE,       local);
01110       w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
01111 
01112       if (!local) {
01113         if (_patches.allow_shares) { // Shares are allowed
01114           /* If all shares are owned by someone (none by nobody), disable buy button */
01115           w->SetWidgetDisabledState(PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
01116               /* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
01117               (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
01118               /* Spectators cannot do anything of course */
01119               _local_player == PLAYER_SPECTATOR);
01120 
01121           /* If the player doesn't own any shares, disable sell button */
01122           w->SetWidgetDisabledState(PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
01123               /* Spectators cannot do anything of course */
01124               _local_player == PLAYER_SPECTATOR);
01125         } else { // Shares are not allowed, disable buy/sell buttons
01126           w->DisableWidget(PCW_WIDGET_BUY_SHARE);
01127           w->DisableWidget(PCW_WIDGET_SELL_SHARE);
01128         }
01129       }
01130 
01131       SetDParam(0, p->index);
01132       SetDParam(1, p->index);
01133 
01134       DrawWindowWidgets(w);
01135 
01136       /* Player face */
01137       DrawPlayerFace(p->face, p->player_color, 2, 16);
01138 
01139       /* "xxx (Manager)" */
01140       SetDParam(0, p->index);
01141       DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
01142 
01143       /* "Inaugurated:" */
01144       SetDParam(0, p->inaugurated_year);
01145       DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
01146 
01147       /* "Colour scheme:" */
01148       DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
01149       /* Draw company-colour bus */
01150       DrawSprite(SPR_VEH_BUS_SW_VIEW, PLAYER_SPRITE_COLOR(p->index), 215, 44);
01151 
01152       /* "Vehicles:" */
01153       DrawPlayerVehiclesAmount((PlayerID)w->window_number);
01154 
01155       /* "Company value:" */
01156       SetDParam(0, CalculateCompanyValue(p));
01157       DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
01158 
01159       /* Shares list */
01160       DrawCompanyOwnerText(p);
01161 
01162       break;
01163     }
01164 
01165     case WE_CLICK:
01166       switch (e->we.click.widget) {
01167         case PCW_WIDGET_NEW_FACE: DoSelectPlayerFace((PlayerID)w->window_number, false); break;
01168 
01169         case PCW_WIDGET_COLOR_SCHEME: {
01170           Window *wf = AllocateWindowDescFront(_loaded_newgrf_features.has_2CC ? &_select_player_livery_2cc_desc : &_select_player_livery_desc, w->window_number);
01171           if (wf != NULL) {
01172             wf->caption_color = wf->window_number;
01173             WP(wf, livery_d).livery_class = LC_OTHER;
01174             WP(wf, livery_d).sel = 1;
01175             wf->LowerWidget(2);
01176           }
01177           break;
01178         }
01179 
01180         case PCW_WIDGET_PRESIDENT_NAME: {
01181           const Player *p = GetPlayer((PlayerID)w->window_number);
01182           WP(w, def_d).byte_1 = 0;
01183           SetDParam(0, p->index);
01184           ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, MAX_LENGTH_PRESIDENT_NAME, 94, w, CS_ALPHANUMERAL);
01185           break;
01186         }
01187 
01188         case PCW_WIDGET_COMPANY_NAME: {
01189           Player *p = GetPlayer((PlayerID)w->window_number);
01190           WP(w, def_d).byte_1 = 1;
01191           SetDParam(0, p->index);
01192           ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, MAX_LENGTH_PRESIDENT_NAME, 150, w, CS_ALPHANUMERAL);
01193           break;
01194         }
01195 
01196         case PCW_WIDGET_BUILD_VIEW_HQ: {
01197           TileIndex tile = GetPlayer((PlayerID)w->window_number)->location_of_house;
01198           if (tile == 0) {
01199             if ((byte)w->window_number != _local_player)
01200               return;
01201             SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
01202             SetTileSelectSize(2, 2);
01203             w->LowerWidget(PCW_WIDGET_BUILD_VIEW_HQ);
01204             w->InvalidateWidget(PCW_WIDGET_BUILD_VIEW_HQ);
01205           } else {
01206             ScrollMainWindowToTile(tile);
01207           }
01208           break;
01209         }
01210 
01211         case PCW_WIDGET_RELOCATE_HQ:
01212           SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
01213           SetTileSelectSize(2, 2);
01214           w->LowerWidget(PCW_WIDGET_RELOCATE_HQ);
01215           w->InvalidateWidget(PCW_WIDGET_RELOCATE_HQ);
01216           break;
01217 
01218         case PCW_WIDGET_BUY_SHARE:
01219           DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
01220           break;
01221 
01222         case PCW_WIDGET_SELL_SHARE:
01223           DoCommandP(0, w->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
01224           break;
01225 
01226 #ifdef ENABLE_NETWORK
01227         case PCW_WIDGET_COMPANY_PASSWORD:
01228           if (w->window_number == _local_player) ShowNetworkCompanyPasswordWindow();
01229           break;
01230 #endif /* ENABLE_NETWORK */
01231       }
01232       break;
01233 
01234     case WE_MOUSELOOP:
01235       /* redraw the window every now and then */
01236       if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w);
01237       break;
01238 
01239     case WE_PLACE_OBJ:
01240       if (DoCommandP(e->we.place.tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
01241         ResetObjectToPlace();
01242         w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
01243         w->RaiseButtons();
01244       break;
01245 
01246     case WE_ABORT_PLACE_OBJ:
01247       w->RaiseButtons();
01248       break;
01249 
01250     case WE_DESTROY:
01251       DeleteWindowById(WC_PLAYER_FACE, w->window_number);
01252       if (w->window_number == _local_player) DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
01253       break;
01254 
01255     case WE_ON_EDIT_TEXT:
01256       if (StrEmpty(e->we.edittext.str)) return;
01257 
01258       _cmd_text = e->we.edittext.str;
01259       switch (WP(w, def_d).byte_1) {
01260         case 0: /* Change president name */
01261           DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
01262           break;
01263         case 1: /* Change company name */
01264           DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
01265           break;
01266       }
01267       break;
01268   }
01269 }
01270 
01271 
01272 static const WindowDesc _player_company_desc = {
01273   WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
01274   WC_COMPANY, WC_NONE,
01275   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01276   _player_company_widgets,
01277   PlayerCompanyWndProc
01278 };
01279 
01280 void ShowPlayerCompany(PlayerID player)
01281 {
01282   Window *w;
01283 
01284   if (!IsValidPlayer(player)) return;
01285 
01286   w = AllocateWindowDescFront(&_player_company_desc, player);
01287   if (w != NULL) w->caption_color = w->window_number;
01288 }
01289 
01290 
01291 
01292 static void BuyCompanyWndProc(Window *w, WindowEvent *e)
01293 {
01294   switch (e->event) {
01295   case WE_PAINT: {
01296     Player *p = GetPlayer((PlayerID)w->window_number);
01297     SetDParam(0, STR_COMPANY_NAME);
01298     SetDParam(1, p->index);
01299     DrawWindowWidgets(w);
01300 
01301     DrawPlayerFace(p->face, p->player_color, 2, 16);
01302 
01303     SetDParam(0, p->index);
01304     SetDParam(1, p->bankrupt_value);
01305     DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
01306     break;
01307   }
01308 
01309   case WE_CLICK:
01310     switch (e->we.click.widget) {
01311     case 3:
01312       DeleteWindow(w);
01313       break;
01314     case 4: {
01315       DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
01316       break;
01317     }
01318     }
01319     break;
01320   }
01321 }
01322 
01323 static const Widget _buy_company_widgets[] = {
01324 {   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
01325 {    WWT_CAPTION,   RESIZE_NONE,     5,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
01326 {      WWT_PANEL,   RESIZE_NONE,     5,     0,   333,    14,   136, 0x0,                   STR_NULL},
01327 {    WWT_TEXTBTN,   RESIZE_NONE,     5,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
01328 {    WWT_TEXTBTN,   RESIZE_NONE,     5,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
01329 {   WIDGETS_END},
01330 };
01331 
01332 static const WindowDesc _buy_company_desc = {
01333   153, 171, 334, 137, 334, 137,
01334   WC_BUY_COMPANY, WC_NONE,
01335   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
01336   _buy_company_widgets,
01337   BuyCompanyWndProc
01338 };
01339 
01340 
01341 void ShowBuyCompanyDialog(uint player)
01342 {
01343   AllocateWindowDescFront(&_buy_company_desc, player);
01344 }
01345 
01346 /********** HIGHSCORE and ENDGAME windows */
01347 
01348 /* Always draw a maximized window and within there the centered background */
01349 static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
01350 {
01351   uint i;
01352   /* resize window to "full-screen" */
01353   w->width = _screen.width;
01354   w->height = _screen.height;
01355   w->widget[0].right = w->width - 1;
01356   w->widget[0].bottom = w->height - 1;
01357 
01358   DrawWindowWidgets(w);
01359 
01360   /* Center Highscore/Endscreen background */
01361   *x = max(0, (_screen.width  / 2) - (640 / 2));
01362   *y = max(0, (_screen.height / 2) - (480 / 2));
01363   for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
01364     DrawSprite(WP(w, highscore_d).background_img + i, PAL_NONE, *x, *y + (i * 50));
01365 }
01366 
01367 extern StringID EndGameGetPerformanceTitleFromValue(uint value);
01368 
01370 static void EndGameWndProc(Window *w, WindowEvent *e)
01371 {
01372   switch (e->event) {
01373   case WE_PAINT: {
01374     const Player *p;
01375     uint x, y;
01376 
01377     SetupHighScoreEndWindow(w, &x, &y);
01378 
01379     if (!IsValidPlayer(_local_player)) break;
01380 
01381     p = GetPlayer(_local_player);
01382     /* We need to get performance from last year because the image is shown
01383      * at the start of the new year when these things have already been copied */
01384     if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
01385       SetDParam(0, p->index);
01386       SetDParam(1, p->index);
01387       SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
01388       DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
01389     } else {
01390       SetDParam(0, p->index);
01391       SetDParam(1, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
01392       DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
01393     }
01394   } break;
01395   case WE_CLICK: /* Close the window (and show the highscore window) */
01396     DeleteWindow(w);
01397     break;
01398   case WE_DESTROY: /* Show the highscore window when this one is closed */
01399     if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
01400     ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
01401     break;
01402   }
01403 }
01404 
01405 static void HighScoreWndProc(Window *w, WindowEvent *e)
01406 {
01407   switch (e->event) {
01408   case WE_PAINT: {
01409     const HighScore *hs = _highscore_table[w->window_number];
01410     uint x, y;
01411     uint8 i;
01412 
01413     SetupHighScoreEndWindow(w, &x, &y);
01414 
01415     SetDParam(0, _patches.ending_year);
01416     SetDParam(1, w->window_number + STR_6801_EASY);
01417     DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
01418 
01419     /* Draw Highscore peepz */
01420     for (i = 0; i < lengthof(_highscore_table[0]); i++) {
01421       SetDParam(0, i + 1);
01422       DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
01423 
01424       if (hs[i].company[0] != '\0') {
01425         TextColour colour = (WP(w, highscore_d).rank == (int8)i) ? TC_RED : TC_BLACK; // draw new highscore in red
01426 
01427         DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
01428         SetDParam(0, hs[i].title);
01429         SetDParam(1, hs[i].score);
01430         DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
01431       }
01432     }
01433   } break;
01434 
01435   case WE_CLICK: /* Onclick to close window, and in destroy event handle the rest */
01436     DeleteWindow(w);
01437     break;
01438 
01439   case WE_DESTROY: /* Get back all the hidden windows */
01440     if (_game_mode != GM_MENU) ShowVitalWindows();
01441 
01442     if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
01443     break;
01444   }
01445   }
01446 
01447 static const Widget _highscore_widgets[] = {
01448 {      WWT_PANEL, RESIZE_NONE, 16, 0, 640, 0, 480, 0x0, STR_NULL},
01449 {   WIDGETS_END},
01450 };
01451 
01452 static const WindowDesc _highscore_desc = {
01453   0, 0, 641, 481, 641, 481,
01454   WC_HIGHSCORE, WC_NONE,
01455   0,
01456   _highscore_widgets,
01457   HighScoreWndProc
01458 };
01459 
01460 static const WindowDesc _endgame_desc = {
01461   0, 0, 641, 481, 641, 481,
01462   WC_ENDSCREEN, WC_NONE,
01463   0,
01464   _highscore_widgets,
01465   EndGameWndProc
01466 };
01467 
01471 void ShowHighscoreTable(int difficulty, int8 ranking)
01472 {
01473   Window *w;
01474 
01475   /* pause game to show the chart */
01476   if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
01477 
01478   /* Close all always on-top windows to get a clean screen */
01479   if (_game_mode != GM_MENU) HideVitalWindows();
01480 
01481   DeleteWindowByClass(WC_HIGHSCORE);
01482   w = AllocateWindowDesc(&_highscore_desc);
01483 
01484   if (w != NULL) {
01485     MarkWholeScreenDirty();
01486     w->window_number = difficulty; // show highscore chart for difficulty...
01487     WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
01488     WP(w, highscore_d).rank = ranking;
01489   }
01490 }
01491 
01494 void ShowEndGameChart()
01495 {
01496   Window *w;
01497 
01498   /* Dedicated server doesn't need the highscore window */
01499   if (_network_dedicated) return;
01500   /* Pause in single-player to have a look at the highscore at your own leisure */
01501   if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
01502 
01503   HideVitalWindows();
01504   DeleteWindowByClass(WC_ENDSCREEN);
01505   w = AllocateWindowDesc(&_endgame_desc);
01506 
01507   if (w != NULL) {
01508     MarkWholeScreenDirty();
01509 
01510     WP(w, highscore_d).background_img = SPR_TYCOON_IMG1_BEGIN;
01511 
01512     if (_local_player != PLAYER_SPECTATOR) {
01513       const Player *p = GetPlayer(_local_player);
01514       if (p->old_economy[0].performance_history == SCORE_MAX)
01515         WP(w, highscore_d).background_img = SPR_TYCOON_IMG2_BEGIN;
01516     }
01517 
01518     /* In a network game show the endscores of the custom difficulty 'network' which is the last one
01519      * as well as generate a TOP5 of that game, and not an all-time top5. */
01520     if (_networking) {
01521       w->window_number = lengthof(_highscore_table) - 1;
01522       WP(w, highscore_d).rank = SaveHighScoreValueNetwork();
01523     } else {
01524       /* in single player _local player is always valid */
01525       const Player *p = GetPlayer(_local_player);
01526       w->window_number = _opt.diff_level;
01527       WP(w, highscore_d).rank = SaveHighScoreValue(p);
01528     }
01529   }
01530 }

Generated on Wed Oct 1 17:03:22 2008 for openttd by  doxygen 1.5.6