tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@507: #include "table/strings.h" celestar@2187: #include "table/sprites.h" tron@2163: #include "functions.h" truelight@0: #include "window.h" truelight@0: #include "gui.h" truelight@0: #include "gfx.h" truelight@0: #include "player.h" dominik@116: #include "economy.h" truelight@1575: #include "signs.h" truelight@1575: #include "strings.h" truelight@1575: #include "debug.h" tron@2159: #include "variables.h" rubidium@4261: #include "date.h" truelight@0: Darkvater@5291: const byte _cargo_colours[NUM_CARGO] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 48}; Darkvater@5291: dominik@1079: static uint _legend_excludebits; truelight@0: static uint _legend_cargobits; truelight@0: truelight@0: /************************/ truelight@0: /* GENERIC GRAPH DRAWER */ truelight@0: /************************/ truelight@0: darkvater@236: enum {GRAPH_NUM = 16}; darkvater@236: truelight@0: typedef struct GraphDrawer { dominik@1079: uint sel; // bitmask of the players *excluded* (e.g. 11111111 means that no players are shown) truelight@0: byte num_dataset; truelight@0: byte num_on_x_axis; truelight@0: byte month; rubidium@4293: Year year; truelight@0: bool include_neg; truelight@0: byte num_vert_lines; truelight@0: uint16 unk61A; truelight@0: uint16 unk61C; truelight@0: int left, top; truelight@0: uint height; truelight@0: StringID format_str_y_axis; truelight@0: byte color_3, color_2, bg_line_color; darkvater@236: byte colors[GRAPH_NUM]; darkvater@236: uint64 cost[GRAPH_NUM][24]; // last 2 years truelight@0: } GraphDrawer; truelight@0: darkvater@236: #define INVALID_VALUE 0x80000000 darkvater@236: Darkvater@2436: static void DrawGraph(const GraphDrawer *gw) truelight@0: { truelight@193: truelight@0: int i,j,k; dominik@1130: uint x,y,old_x,old_y; truelight@0: int color; truelight@0: int right, bottom; truelight@0: int num_x, num_dataset; Darkvater@2436: const uint64 *row_ptr, *col_ptr; darkvater@236: int64 mx; truelight@0: int adj_height; darkvater@236: uint64 y_scaling, tmp; darkvater@236: int64 value; darkvater@236: int64 cur_val; truelight@0: uint sel; truelight@0: darkvater@240: /* the colors and cost array of GraphDrawer must accomodate darkvater@236: * both values for cargo and players. So if any are higher, quit */ darkvater@236: assert(GRAPH_NUM >= NUM_CARGO && GRAPH_NUM >= MAX_PLAYERS); darkvater@236: tron@4444: color = _colour_gradient[gw->bg_line_color][4]; truelight@0: truelight@0: /* draw the vertical lines */ truelight@0: i = gw->num_vert_lines; assert(i > 0); truelight@0: x = gw->left + 66; truelight@0: bottom = gw->top + gw->height - 1; truelight@0: do { truelight@0: GfxFillRect(x, gw->top, x, bottom, color); truelight@0: x += 22; truelight@0: } while (--i); truelight@193: truelight@0: /* draw the horizontal lines */ truelight@0: i = 9; truelight@0: x = gw->left + 44; truelight@0: y = gw->height + gw->top; truelight@0: right = gw->left + 44 + gw->num_vert_lines*22-1; truelight@0: truelight@0: do { truelight@0: GfxFillRect(x, y, right, y, color); truelight@0: y -= gw->height >> 3; truelight@0: } while (--i); truelight@0: truelight@0: /* draw vertical edge line */ truelight@0: GfxFillRect(x, gw->top, x, bottom, gw->color_2); truelight@0: truelight@0: adj_height = gw->height; truelight@0: if (gw->include_neg) adj_height >>= 1; truelight@0: truelight@0: /* draw horiz edge line */ truelight@0: y = adj_height + gw->top; truelight@0: GfxFillRect(x, y, right, y, gw->color_2); truelight@0: truelight@0: /* find the max element */ truelight@0: if (gw->num_on_x_axis == 0) truelight@0: return; truelight@0: darkvater@236: num_dataset = gw->num_dataset; darkvater@236: assert(num_dataset > 0); darkvater@236: truelight@0: row_ptr = gw->cost[0]; truelight@0: mx = 0; darkvater@236: /* bit selection for the showing of various players, base max element darkvater@236: * on to-be shown player-information. This way the graph can scale */ darkvater@236: sel = gw->sel; truelight@0: do { darkvater@236: if (!(sel&1)) { darkvater@236: num_x = gw->num_on_x_axis; darkvater@236: assert(num_x > 0); darkvater@236: col_ptr = row_ptr; darkvater@236: do { darkvater@236: if (*col_ptr != INVALID_VALUE) { darkvater@236: mx = max64(mx, myabs64(*col_ptr)); darkvater@236: } darkvater@236: } while (col_ptr++, --num_x); darkvater@236: } darkvater@236: } while (sel>>=1, row_ptr+=24, --num_dataset); truelight@193: truelight@0: /* setup scaling */ darkvater@236: y_scaling = INVALID_VALUE; truelight@0: value = adj_height * 2; truelight@0: truelight@0: if (mx > value) { truelight@0: mx = (mx + 7) & ~7; darkvater@236: y_scaling = (((uint64) (value>>1) << 32) / mx); truelight@0: value = mx; truelight@0: } truelight@0: truelight@0: /* draw text strings on the y axis */ truelight@0: tmp = value; truelight@0: if (gw->include_neg) tmp >>= 1; truelight@0: x = gw->left + 45; truelight@0: y = gw->top - 3; truelight@0: i = 9; truelight@0: do { tron@534: SetDParam(0, gw->format_str_y_axis); tron@534: SetDParam64(1, (int64)tmp); truelight@0: tmp -= (value >> 3); truelight@0: DrawStringRightAligned(x, y, STR_0170, gw->color_3); truelight@0: y += gw->height >> 3; truelight@0: } while (--i); truelight@0: truelight@0: /* draw strings on the x axis */ truelight@0: if (gw->month != 0xFF) { truelight@0: x = gw->left + 44; truelight@0: y = gw->top + gw->height + 1; truelight@0: j = gw->month; rubidium@4293: k = gw->year; truelight@0: i = gw->num_on_x_axis;assert(i>0); truelight@0: do { tron@534: SetDParam(2, k); tron@534: SetDParam(0, j + STR_0162_JAN); tron@534: SetDParam(1, j + STR_0162_JAN + 2); truelight@0: DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3); truelight@0: truelight@0: j += 3; truelight@0: if (j >= 12) { truelight@0: j = 0; truelight@0: k++; truelight@0: } truelight@0: x += 22; truelight@0: } while (--i); truelight@0: } else { truelight@0: x = gw->left + 52; truelight@0: y = gw->top + gw->height + 1; truelight@0: j = gw->unk61A; truelight@0: i = gw->num_on_x_axis;assert(i>0); truelight@0: do { tron@534: SetDParam(0, j); truelight@0: DrawString(x, y, STR_01CB, gw->color_3); truelight@0: j += gw->unk61C; truelight@0: x += 22; truelight@0: } while (--i); truelight@0: } truelight@0: truelight@0: /* draw lines and dots */ truelight@0: i = 0; truelight@0: row_ptr = gw->cost[0]; dominik@1079: sel = gw->sel; // show only selected lines. GraphDrawer qw->sel set in Graph-Legend (_legend_excludebits) truelight@0: do { truelight@0: if (!(sel & 1)) { truelight@0: x = gw->left + 55; truelight@0: j = gw->num_on_x_axis;assert(j>0); truelight@0: col_ptr = row_ptr; truelight@0: color = gw->colors[i]; darkvater@236: old_y = old_x = INVALID_VALUE; truelight@0: do { truelight@0: cur_val = *col_ptr++; darkvater@236: if (cur_val != INVALID_VALUE) { darkvater@236: y = adj_height - BIGMULSS64(cur_val, y_scaling >> 1, 31) + gw->top; truelight@0: truelight@0: GfxFillRect(x-1, y-1, x+1, y+1, color); darkvater@236: if (old_x != INVALID_VALUE) truelight@0: GfxDrawLine(old_x, old_y, x, y, color); truelight@0: truelight@0: old_x = x; truelight@0: old_y = y; truelight@0: } else { darkvater@236: old_x = INVALID_VALUE; truelight@0: } truelight@0: } while (x+=22,--j); truelight@0: } truelight@0: } while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset); truelight@0: } truelight@0: truelight@0: /****************/ truelight@0: /* GRAPH LEGEND */ truelight@0: /****************/ truelight@0: KUDr@3733: void DrawPlayerIcon(PlayerID p, int x, int y) truelight@0: { truelight@0: DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y); truelight@0: } truelight@0: truelight@0: static void GraphLegendWndProc(Window *w, WindowEvent *e) truelight@0: { tron@2475: const Player* p; truelight@0: tron@2952: switch (e->event) { belugas@4719: case WE_CREATE: { rubidium@5235: uint i; rubidium@5235: for (i = 3; i < w->widget_count; i++) { rubidium@5235: if (!HASBIT(_legend_excludebits, i - 3)) LowerWindowWidget(w, i); belugas@4719: } belugas@4719: break; belugas@4719: } belugas@4719: truelight@0: case WE_PAINT: truelight@0: FOR_ALL_PLAYERS(p) { belugas@4719: if (!p->is_active) { belugas@4719: SETBIT(_legend_excludebits, p->index); belugas@4719: RaiseWindowWidget(w, p->index + 3); belugas@4719: } truelight@0: } truelight@0: DrawWindowWidgets(w); truelight@0: truelight@0: FOR_ALL_PLAYERS(p) { tron@2639: if (!p->is_active) continue; truelight@0: truelight@0: DrawPlayerIcon(p->index, 4, 18+p->index*12); truelight@0: tron@534: SetDParam(0, p->name_1); tron@534: SetDParam(1, p->name_2); tron@534: SetDParam(2, GetPlayerNameString(p->index, 3)); dominik@1079: DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_excludebits, p->index) ? 0x10 : 0xC); truelight@0: } truelight@0: break; truelight@0: truelight@0: case WE_CLICK: belugas@4634: if (IS_INT_INSIDE(e->we.click.widget, 3, 11)) { belugas@4634: _legend_excludebits ^= (1 << (e->we.click.widget - 3)); belugas@4719: ToggleWidgetLoweredState(w, e->we.click.widget); truelight@0: SetWindowDirty(w); truelight@0: InvalidateWindow(WC_INCOME_GRAPH, 0); truelight@0: InvalidateWindow(WC_OPERATING_PROFIT, 0); truelight@0: InvalidateWindow(WC_DELIVERED_CARGO, 0); truelight@0: InvalidateWindow(WC_PERFORMANCE_HISTORY, 0); truelight@140: InvalidateWindow(WC_COMPANY_VALUE, 0); truelight@0: } truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: static const Widget _graph_legend_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, truelight@867: { WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0, STR_NULL}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 28, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 40, 51, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 52, 63, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 64, 75, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 76, 87, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 88, 99, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 100, 111, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: truelight@0: static const WindowDesc _graph_legend_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 250, 114, truelight@0: WC_GRAPH_LEGEND,0, truelight@0: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, truelight@0: _graph_legend_widgets, truelight@0: GraphLegendWndProc truelight@0: }; truelight@0: tron@1093: static void ShowGraphLegend(void) truelight@0: { truelight@0: AllocateWindowDescFront(&_graph_legend_desc, 0); truelight@0: } truelight@0: truelight@0: /********************/ truelight@0: /* OPERATING PROFIT */ truelight@0: /********************/ truelight@0: truelight@0: static void SetupGraphDrawerForPlayers(GraphDrawer *gd) truelight@0: { tron@2475: const Player* p; dominik@1079: uint excludebits = _legend_excludebits; truelight@0: int nums; truelight@0: int mo,yr; truelight@0: truelight@193: // Exclude the players which aren't valid truelight@0: FOR_ALL_PLAYERS(p) { dominik@1079: if (!p->is_active) SETBIT(excludebits,p->index); truelight@193: } dominik@1079: gd->sel = excludebits; truelight@0: gd->num_vert_lines = 24; truelight@0: truelight@0: nums = 0; truelight@0: FOR_ALL_PLAYERS(p) { truelight@0: if (p->is_active) nums = max(nums,p->num_valid_stat_ent); truelight@0: } truelight@0: gd->num_on_x_axis = min(nums,24); truelight@0: truelight@0: mo = (_cur_month/3-nums)*3; truelight@0: yr = _cur_year; truelight@0: while (mo < 0) { truelight@0: yr--; truelight@0: mo += 12; truelight@0: } truelight@0: truelight@0: gd->year = yr; truelight@0: gd->month = mo; truelight@0: } truelight@0: truelight@0: static void OperatingProfitWndProc(Window *w, WindowEvent *e) truelight@0: { tron@2952: switch (e->event) { truelight@0: case WE_PAINT: { truelight@0: GraphDrawer gd; tron@2475: const Player* p; truelight@0: int i,j; truelight@0: int numd; truelight@0: truelight@0: DrawWindowWidgets(w); truelight@193: truelight@0: gd.left = 2; truelight@0: gd.top = 18; truelight@0: gd.height = 136; truelight@0: gd.include_neg = true; tron@2246: gd.format_str_y_axis = STR_CURRCOMPACT; truelight@0: gd.color_3 = 0x10; truelight@0: gd.color_2 = 0xD7; truelight@0: gd.bg_line_color = 0xE; truelight@193: truelight@0: SetupGraphDrawerForPlayers(&gd); truelight@0: darkvater@1086: numd = 0; truelight@0: FOR_ALL_PLAYERS(p) { darkvater@1086: if (p->is_active) { tron@4444: gd.colors[numd] = _colour_gradient[p->player_color][6]; tron@2952: for (j = gd.num_on_x_axis, i = 0; --j >= 0;) { darkvater@1086: gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)(p->old_economy[j].income + p->old_economy[j].expenses); darkvater@1086: i++; darkvater@1086: } darkvater@1086: } dominik@1079: numd++; truelight@0: } dominik@1085: darkvater@1086: gd.num_dataset = numd; truelight@0: truelight@0: DrawGraph(&gd); darkvater@236: } break; truelight@0: case WE_CLICK: belugas@4634: if (e->we.click.widget == 2) /* Clicked on Legend */ truelight@0: ShowGraphLegend(); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: static const Widget _operating_profit_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, truelight@867: { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL}, darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: truelight@0: static const WindowDesc _operating_profit_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 576, 174, truelight@0: WC_OPERATING_PROFIT,0, truelight@0: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, truelight@0: _operating_profit_widgets, truelight@0: OperatingProfitWndProc truelight@0: }; truelight@0: truelight@0: tron@1093: void ShowOperatingProfitGraph(void) truelight@0: { truelight@0: if (AllocateWindowDescFront(&_operating_profit_desc, 0)) { truelight@0: InvalidateWindow(WC_GRAPH_LEGEND, 0); truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: /****************/ truelight@0: /* INCOME GRAPH */ truelight@0: /****************/ truelight@0: truelight@0: static void IncomeGraphWndProc(Window *w, WindowEvent *e) truelight@0: { tron@2952: switch (e->event) { truelight@0: case WE_PAINT: { truelight@0: GraphDrawer gd; tron@2475: const Player* p; truelight@0: int i,j; truelight@0: int numd; truelight@0: truelight@0: DrawWindowWidgets(w); truelight@0: truelight@0: gd.left = 2; truelight@0: gd.top = 18; truelight@0: gd.height = 104; truelight@0: gd.include_neg = false; tron@2246: gd.format_str_y_axis = STR_CURRCOMPACT; truelight@0: gd.color_3 = 0x10; truelight@0: gd.color_2 = 0xD7; truelight@0: gd.bg_line_color = 0xE; truelight@0: SetupGraphDrawerForPlayers(&gd); truelight@0: darkvater@1086: numd = 0; truelight@0: FOR_ALL_PLAYERS(p) { darkvater@1086: if (p->is_active) { tron@4444: gd.colors[numd] = _colour_gradient[p->player_color][6]; tron@2952: for (j = gd.num_on_x_axis, i = 0; --j >= 0;) { darkvater@1086: gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].income; darkvater@1086: i++; darkvater@1086: } darkvater@1086: } dominik@1079: numd++; truelight@0: } truelight@0: darkvater@1086: gd.num_dataset = numd; truelight@0: truelight@0: DrawGraph(&gd); truelight@0: break; truelight@0: } truelight@0: truelight@0: case WE_CLICK: belugas@4634: if (e->we.click.widget == 2) truelight@0: ShowGraphLegend(); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: static const Widget _income_graph_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, truelight@867: { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL}, darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: truelight@0: static const WindowDesc _income_graph_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 576, 142, truelight@0: WC_INCOME_GRAPH,0, truelight@0: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, truelight@0: _income_graph_widgets, truelight@0: IncomeGraphWndProc truelight@0: }; truelight@0: tron@1093: void ShowIncomeGraph(void) truelight@0: { truelight@0: if (AllocateWindowDescFront(&_income_graph_desc, 0)) { truelight@0: InvalidateWindow(WC_GRAPH_LEGEND, 0); truelight@0: } truelight@0: } truelight@0: truelight@0: /*******************/ truelight@0: /* DELIVERED CARGO */ truelight@0: /*******************/ truelight@0: truelight@0: static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e) truelight@0: { tron@2952: switch (e->event) { truelight@0: case WE_PAINT: { truelight@0: GraphDrawer gd; tron@2475: const Player* p; truelight@0: int i,j; truelight@0: int numd; truelight@0: truelight@0: DrawWindowWidgets(w); truelight@0: truelight@0: gd.left = 2; truelight@0: gd.top = 18; truelight@0: gd.height = 104; truelight@0: gd.include_neg = false; truelight@0: gd.format_str_y_axis = STR_7024; truelight@0: gd.color_3 = 0x10; truelight@0: gd.color_2 = 0xD7; truelight@0: gd.bg_line_color = 0xE; truelight@0: SetupGraphDrawerForPlayers(&gd); truelight@0: darkvater@1086: numd = 0; truelight@0: FOR_ALL_PLAYERS(p) { darkvater@1086: if (p->is_active) { tron@4444: gd.colors[numd] = _colour_gradient[p->player_color][6]; tron@2952: for (j = gd.num_on_x_axis, i = 0; --j >= 0;) { darkvater@1086: gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].delivered_cargo; darkvater@1086: i++; darkvater@1086: } darkvater@1086: } dominik@1079: numd++; truelight@0: } truelight@0: darkvater@1086: gd.num_dataset = numd; truelight@0: truelight@0: DrawGraph(&gd); truelight@0: break; truelight@0: } truelight@0: truelight@0: case WE_CLICK: belugas@4634: if (e->we.click.widget == 2) truelight@0: ShowGraphLegend(); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: static const Widget _delivered_cargo_graph_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, truelight@867: { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL}, darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: truelight@0: static const WindowDesc _delivered_cargo_graph_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 576, 142, truelight@0: WC_DELIVERED_CARGO,0, truelight@0: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, truelight@0: _delivered_cargo_graph_widgets, truelight@0: DeliveredCargoGraphWndProc truelight@0: }; truelight@0: tron@1093: void ShowDeliveredCargoGraph(void) truelight@0: { truelight@0: if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) { truelight@0: InvalidateWindow(WC_GRAPH_LEGEND, 0); truelight@0: } dominik@116: } dominik@116: darkvater@1086: /***********************/ darkvater@1086: /* PERFORMANCE HISTORY */ darkvater@1086: /***********************/ darkvater@1086: darkvater@1086: static void PerformanceHistoryWndProc(Window *w, WindowEvent *e) darkvater@1086: { tron@2952: switch (e->event) { darkvater@1086: case WE_PAINT: { darkvater@1086: GraphDrawer gd; tron@2475: const Player* p; darkvater@1086: int i,j; darkvater@1086: int numd; darkvater@1086: darkvater@1086: DrawWindowWidgets(w); darkvater@1086: darkvater@1086: gd.left = 2; darkvater@1086: gd.top = 18; darkvater@1086: gd.height = 200; darkvater@1086: gd.include_neg = false; darkvater@1086: gd.format_str_y_axis = STR_7024; darkvater@1086: gd.color_3 = 0x10; darkvater@1086: gd.color_2 = 0xD7; darkvater@1086: gd.bg_line_color = 0xE; darkvater@1086: SetupGraphDrawerForPlayers(&gd); darkvater@1086: darkvater@1086: numd = 0; darkvater@1086: FOR_ALL_PLAYERS(p) { darkvater@1086: if (p->is_active) { tron@4444: gd.colors[numd] = _colour_gradient[p->player_color][6]; tron@2952: for (j = gd.num_on_x_axis, i = 0; --j >= 0;) { darkvater@1086: gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].performance_history; darkvater@1086: i++; darkvater@1086: } darkvater@1086: } darkvater@1086: numd++; darkvater@1086: } darkvater@1086: darkvater@1086: gd.num_dataset = numd; darkvater@1086: darkvater@1086: DrawGraph(&gd); darkvater@1086: break; darkvater@1086: } darkvater@1086: darkvater@1086: case WE_CLICK: belugas@4634: if (e->we.click.widget == 2) darkvater@1086: ShowGraphLegend(); belugas@4634: if (e->we.click.widget == 3) darkvater@1086: ShowPerformanceRatingDetail(); darkvater@1086: break; darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: static const Widget _performance_history_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, rubidium@4344: { WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL}, darkvater@1086: { WIDGETS_END}, darkvater@1086: }; darkvater@1086: darkvater@1086: static const WindowDesc _performance_history_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 576, 238, darkvater@1086: WC_PERFORMANCE_HISTORY,0, darkvater@1086: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, darkvater@1086: _performance_history_widgets, darkvater@1086: PerformanceHistoryWndProc darkvater@1086: }; darkvater@1086: tron@1093: void ShowPerformanceHistoryGraph(void) darkvater@1086: { darkvater@1086: if (AllocateWindowDescFront(&_performance_history_desc, 0)) { darkvater@1086: InvalidateWindow(WC_GRAPH_LEGEND, 0); darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: /*****************/ darkvater@1086: /* COMPANY VALUE */ darkvater@1086: /*****************/ darkvater@1086: darkvater@1086: static void CompanyValueGraphWndProc(Window *w, WindowEvent *e) darkvater@1086: { tron@2952: switch (e->event) { darkvater@1086: case WE_PAINT: { darkvater@1086: GraphDrawer gd; tron@2475: const Player* p; darkvater@1086: int i,j; darkvater@1086: int numd; darkvater@1086: darkvater@1086: DrawWindowWidgets(w); darkvater@1086: darkvater@1086: gd.left = 2; darkvater@1086: gd.top = 18; darkvater@1086: gd.height = 200; darkvater@1086: gd.include_neg = false; tron@2246: gd.format_str_y_axis = STR_CURRCOMPACT; darkvater@1086: gd.color_3 = 0x10; darkvater@1086: gd.color_2 = 0xD7; darkvater@1086: gd.bg_line_color = 0xE; darkvater@1086: SetupGraphDrawerForPlayers(&gd); darkvater@1086: darkvater@1086: numd = 0; darkvater@1086: FOR_ALL_PLAYERS(p) { darkvater@1086: if (p->is_active) { tron@4444: gd.colors[numd] = _colour_gradient[p->player_color][6]; tron@2952: for (j = gd.num_on_x_axis, i = 0; --j >= 0;) { darkvater@1086: gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].company_value; darkvater@1086: i++; darkvater@1086: } darkvater@1086: } darkvater@1086: numd++; darkvater@1086: } darkvater@1086: darkvater@1086: gd.num_dataset = numd; darkvater@1086: darkvater@1086: DrawGraph(&gd); darkvater@1086: break; darkvater@1086: } darkvater@1086: darkvater@1086: case WE_CLICK: belugas@4634: if (e->we.click.widget == 2) darkvater@1086: ShowGraphLegend(); darkvater@1086: break; darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: static const Widget _company_value_graph_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, rubidium@4344: { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL}, darkvater@1086: { WIDGETS_END}, darkvater@1086: }; darkvater@1086: darkvater@1086: static const WindowDesc _company_value_graph_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 576, 238, darkvater@1086: WC_COMPANY_VALUE,0, darkvater@1086: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, darkvater@1086: _company_value_graph_widgets, darkvater@1086: CompanyValueGraphWndProc darkvater@1086: }; darkvater@1086: tron@1093: void ShowCompanyValueGraph(void) darkvater@1086: { darkvater@1086: if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) { darkvater@1086: InvalidateWindow(WC_GRAPH_LEGEND, 0); darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: /*****************/ darkvater@1086: /* PAYMENT RATES */ darkvater@1086: /*****************/ darkvater@1086: darkvater@1086: static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e) darkvater@1086: { tron@2952: switch (e->event) { belugas@4719: case WE_CREATE: { rubidium@5235: uint i; rubidium@5235: for (i = 3; i < w->widget_count; i++) { rubidium@5235: if (!HASBIT(_legend_cargobits, i - 3)) LowerWindowWidget(w, i); belugas@4719: } belugas@4719: break; belugas@4719: } belugas@4719: darkvater@1086: case WE_PAINT: { Darkvater@3344: int j, x, y; Darkvater@3344: CargoID i; darkvater@1086: GraphDrawer gd; darkvater@1086: darkvater@1086: DrawWindowWidgets(w); darkvater@1086: darkvater@1086: x = 495; Darkvater@4911: y = 24; darkvater@1086: belugas@4719: gd.sel = _legend_cargobits; darkvater@1086: gd.left = 2; darkvater@1086: gd.top = 24; darkvater@1086: gd.height = 104; darkvater@1086: gd.include_neg = false; tron@2246: gd.format_str_y_axis = STR_CURRCOMPACT; darkvater@1086: gd.color_3 = 16; darkvater@1086: gd.color_2 = 215; darkvater@1086: gd.bg_line_color = 14; darkvater@1086: gd.num_dataset = NUM_CARGO; darkvater@1086: gd.num_on_x_axis = 20; darkvater@1086: gd.num_vert_lines = 20; darkvater@1086: gd.month = 0xFF; darkvater@1086: gd.unk61A = 10; darkvater@1086: gd.unk61C = 10; darkvater@1086: tron@2952: for (i = 0; i != NUM_CARGO; i++) { belugas@4851: /* Since the buttons have no text, no images, belugas@4851: * both the text and the colored box have to be manually painted. belugas@4851: * clk_dif will move one pixel down and one pixel to the right belugas@4851: * when the button is clicked */ belugas@4851: byte clk_dif = IsWindowWidgetLowered(w, i + 3) ? 1 : 0; belugas@4851: belugas@4851: GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0); Darkvater@5291: GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, _cargo_colours[i]); belugas@3801: SetDParam(0, _cargoc.names_s[i]); belugas@4851: DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, 0); belugas@3801: y += 8; Darkvater@5291: gd.colors[i] = _cargo_colours[i]; tron@2952: for (j = 0; j != 20; j++) { tron@2952: gd.cost[i][j] = (uint64)GetTransportedGoodsIncome(10, 20, j * 6 + 6, i); darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: DrawGraph(&gd); darkvater@1086: darkvater@1086: DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0); darkvater@1086: DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0); darkvater@1086: } break; darkvater@1086: darkvater@1086: case WE_CLICK: { belugas@4634: switch (e->we.click.widget) { darkvater@1086: case 3: case 4: case 5: case 6: darkvater@1086: case 7: case 8: case 9: case 10: darkvater@1086: case 11: case 12: case 13: case 14: belugas@4719: TOGGLEBIT(_legend_cargobits, e->we.click.widget - 3); belugas@4719: ToggleWidgetLoweredState(w, e->we.click.widget); darkvater@1086: SetWindowDirty(w); darkvater@1086: break; darkvater@1086: } darkvater@1086: } break; darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: static const Widget _cargo_payment_rates_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, rubidium@4344: { WWT_CAPTION, RESIZE_NONE, 14, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 14, 0, 567, 14, 141, 0x0, STR_NULL}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 24, 31, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 32, 39, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 40, 47, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 48, 55, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 56, 63, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 64, 71, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 72, 79, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 80, 87, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 88, 95, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 96, 103, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 104, 111, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, rubidium@4344: { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 112, 119, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO}, darkvater@1086: { WIDGETS_END}, darkvater@1086: }; darkvater@1086: darkvater@1086: static const WindowDesc _cargo_payment_rates_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 568, 142, darkvater@1086: WC_PAYMENT_RATES,0, darkvater@1086: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, darkvater@1086: _cargo_payment_rates_widgets, darkvater@1086: CargoPaymentRatesWndProc darkvater@1086: }; darkvater@1086: darkvater@1086: tron@1093: void ShowCargoPaymentRates(void) darkvater@1086: { darkvater@1086: AllocateWindowDescFront(&_cargo_payment_rates_desc, 0); darkvater@1086: } darkvater@1086: darkvater@1086: /************************/ darkvater@1086: /* COMPANY LEAGUE TABLE */ darkvater@1086: /************************/ darkvater@1086: darkvater@1086: static const StringID _performance_titles[] = { darkvater@1086: STR_7066_ENGINEER, darkvater@1086: STR_7066_ENGINEER, darkvater@1086: STR_7067_TRAFFIC_MANAGER, darkvater@1086: STR_7067_TRAFFIC_MANAGER, darkvater@1086: STR_7068_TRANSPORT_COORDINATOR, darkvater@1086: STR_7068_TRANSPORT_COORDINATOR, darkvater@1086: STR_7069_ROUTE_SUPERVISOR, darkvater@1086: STR_7069_ROUTE_SUPERVISOR, darkvater@1086: STR_706A_DIRECTOR, darkvater@1086: STR_706A_DIRECTOR, darkvater@1086: STR_706B_CHIEF_EXECUTIVE, darkvater@1086: STR_706B_CHIEF_EXECUTIVE, darkvater@1086: STR_706C_CHAIRMAN, darkvater@1086: STR_706C_CHAIRMAN, darkvater@1086: STR_706D_PRESIDENT, darkvater@1086: STR_706E_TYCOON, darkvater@1086: }; darkvater@1086: darkvater@1086: static inline StringID GetPerformanceTitleFromValue(uint value) darkvater@1086: { darkvater@1086: return _performance_titles[minu(value, 1000) >> 6]; darkvater@1086: } darkvater@1086: tron@2656: static int CDECL PerfHistComp(const void* elem1, const void* elem2) tron@2656: { tron@2656: const Player* p1 = *(const Player* const*)elem1; tron@2656: const Player* p2 = *(const Player* const*)elem2; tron@2656: tron@2656: return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history; darkvater@1086: } darkvater@1086: darkvater@1086: static void CompanyLeagueWndProc(Window *w, WindowEvent *e) darkvater@1086: { Darkvater@2482: switch (e->event) { tron@2656: case WE_PAINT: { tron@2656: const Player* plist[MAX_PLAYERS]; tron@2656: const Player* p; tron@2656: uint pl_num; tron@2656: uint i; darkvater@1086: tron@2656: DrawWindowWidgets(w); darkvater@1086: tron@2656: pl_num = 0; tron@2656: FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p; darkvater@1086: Darkvater@2673: qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp); darkvater@1086: tron@2656: for (i = 0; i != pl_num; i++) { tron@2656: p = plist[i]; tron@2656: SetDParam(0, i + STR_01AC_1ST); tron@2656: SetDParam(1, p->name_1); tron@2656: SetDParam(2, p->name_2); tron@2656: SetDParam(3, GetPlayerNameString(p->index, 4)); tron@2656: SetDParam(5, GetPerformanceTitleFromValue(p->old_economy[1].performance_history)); tron@2656: tron@2656: DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0); tron@2656: DrawPlayerIcon(p->index, 27, 16 + i * 10); tron@2656: } tron@2656: tron@2656: break; tron@2656: } darkvater@1086: } darkvater@1086: } darkvater@1086: darkvater@1086: darkvater@1086: static const Widget _company_league_widgets[] = { peter1138@2869: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, peter1138@2869: { WWT_CAPTION, RESIZE_NONE, 14, 11, 387, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS}, peter1138@2869: { WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL}, darkvater@1086: { WIDGETS_END}, darkvater@1086: }; darkvater@1086: darkvater@1086: static const WindowDesc _company_league_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 400, 97, darkvater@1086: WC_COMPANY_LEAGUE,0, peter1138@2869: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON, darkvater@1086: _company_league_widgets, darkvater@1086: CompanyLeagueWndProc darkvater@1086: }; darkvater@1086: tron@1093: void ShowCompanyLeagueTable(void) darkvater@1086: { darkvater@1086: AllocateWindowDescFront(&_company_league_desc,0); darkvater@1086: } darkvater@1086: dominik@116: /*****************************/ dominik@116: /* PERFORMANCE RATING DETAIL */ dominik@116: /*****************************/ dominik@116: dominik@116: static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e) dominik@116: { belugas@4719: static PlayerID _performance_rating_detail_player = 0; belugas@4719: tron@2952: switch (e->event) { peter1138@3027: case WE_PAINT: { tron@3033: int i; belugas@4719: byte x; tron@3033: uint16 y = 14; peter1138@3027: int total_score = 0; peter1138@3027: int color_done, color_notdone; truelight@193: peter1138@3027: // Draw standard stuff peter1138@3027: DrawWindowWidgets(w); truelight@193: peter1138@3027: // Paint the player icons tron@3033: for (i = 0; i < MAX_PLAYERS; i++) { peter1138@3027: if (!GetPlayer(i)->is_active) { peter1138@3027: // Check if we have the player as an active player belugas@4709: if (!IsWindowWidgetDisabled(w, i + 13)) { peter1138@3027: // Bah, player gone :( belugas@4709: DisableWindowWidget(w, i + 13); peter1138@3027: // Is this player selected? If so, select first player (always save? :s) belugas@4719: if (IsWindowWidgetLowered(w, i + 13)) { belugas@4719: RaiseWindowWidget(w, i + 13); belugas@4719: LowerWindowWidget(w, 13); belugas@4719: _performance_rating_detail_player = 0; belugas@4719: } peter1138@3027: // We need a repaint peter1138@3027: SetWindowDirty(w); peter1138@3027: } peter1138@3027: continue; peter1138@3027: } peter1138@3027: peter1138@3027: // Check if we have the player marked as inactive belugas@4709: if (IsWindowWidgetDisabled(w, i + 13)) { peter1138@3027: // New player! Yippie :p belugas@4709: EnableWindowWidget(w, i + 13); peter1138@3027: // We need a repaint peter1138@3027: SetWindowDirty(w); peter1138@3027: } peter1138@3027: belugas@4719: x = (i == _performance_rating_detail_player) ? 1 : 0; peter1138@3027: DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x); peter1138@3027: } peter1138@3027: peter1138@3027: // The colors used to show how the progress is going tron@4444: color_done = _colour_gradient[COLOUR_GREEN][4]; tron@4444: color_notdone = _colour_gradient[COLOUR_RED][4]; peter1138@3027: peter1138@3027: // Draw all the score parts tron@3033: for (i = 0; i < NUM_SCORE; i++) { belugas@4719: int val = _score_part[_performance_rating_detail_player][i]; tron@3033: int needed = _score_info[i].needed; tron@3033: int score = _score_info[i].score; tron@3033: peter1138@3027: y += 20; peter1138@3027: // SCORE_TOTAL has his own rulez ;) peter1138@3027: if (i == SCORE_TOTAL) { peter1138@3027: needed = total_score; peter1138@3027: score = SCORE_MAX; peter1138@3027: } else { peter1138@3027: total_score += score; peter1138@3027: } peter1138@3027: peter1138@3027: DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0); peter1138@3027: peter1138@3027: // Draw the score peter1138@3027: SetDParam(0, score); peter1138@3027: DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0); peter1138@3027: peter1138@3027: // Calculate the %-bar tron@3033: if (val > needed) { tron@3033: x = 50; tron@3033: } else if (val == 0) { tron@3033: x = 0; tron@3033: } else { tron@3033: x = val * 50 / needed; tron@3033: } peter1138@3027: peter1138@3027: // SCORE_LOAN is inversed tron@3033: if (val < 0 && i == SCORE_LOAN) x = 0; peter1138@3027: peter1138@3027: // Draw the bar tron@3033: if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, color_done); tron@3033: if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone); peter1138@3027: peter1138@3027: // Calculate the % tron@3033: x = (val <= needed) ? val * 100 / needed : 100; peter1138@3027: peter1138@3027: // SCORE_LOAN is inversed tron@3033: if (val < 0 && i == SCORE_LOAN) x = 0; peter1138@3027: peter1138@3027: // Draw it peter1138@3027: SetDParam(0, x); peter1138@3027: DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0); peter1138@3027: peter1138@3027: // SCORE_LOAN is inversed tron@3033: if (i == SCORE_LOAN) val = needed - val; peter1138@3027: peter1138@3027: // Draw the amount we have against what is needed peter1138@3027: // For some of them it is in currency format peter1138@3027: SetDParam(0, val); peter1138@3027: SetDParam(1, needed); peter1138@3027: switch (i) { peter1138@3027: case SCORE_MIN_PROFIT: peter1138@3027: case SCORE_MIN_INCOME: peter1138@3027: case SCORE_MAX_INCOME: peter1138@3027: case SCORE_MONEY: peter1138@3027: case SCORE_LOAN: peter1138@3027: DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0); peter1138@3027: break; peter1138@3027: default: peter1138@3027: DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0); peter1138@3027: } peter1138@3027: } peter1138@3027: peter1138@3027: break; dominik@116: } truelight@193: peter1138@3027: case WE_CLICK: peter1138@3027: // Check which button is clicked belugas@4634: if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) { peter1138@3027: // Is it no on disable? belugas@4709: if (!IsWindowWidgetDisabled(w, e->we.click.widget)) { belugas@4719: RaiseWindowWidget(w, _performance_rating_detail_player + 13); belugas@4719: _performance_rating_detail_player = e->we.click.widget - 13; belugas@4719: LowerWindowWidget(w, _performance_rating_detail_player + 13); peter1138@3027: SetWindowDirty(w); peter1138@3027: } peter1138@3027: } peter1138@3027: break; truelight@193: peter1138@3027: case WE_CREATE: { peter1138@3027: int i; peter1138@3027: Player *p2; belugas@4702: belugas@4709: /* Disable the players who are not active */ tron@3033: for (i = 0; i < MAX_PLAYERS; i++) { belugas@4709: SetWindowWidgetDisabledState(w, i + 13, !GetPlayer(i)->is_active); dominik@116: } belugas@4719: /* Update all player stats with the current data belugas@4719: * (this is because _score_info is not saved to a savegame) */ tron@3033: FOR_ALL_PLAYERS(p2) { tron@3033: if (p2->is_active) UpdateCompanyRatingAndValue(p2, false); tron@3033: } dominik@116: peter1138@3027: w->custom[0] = DAY_TICKS; peter1138@3027: w->custom[1] = 5; dominik@116: belugas@4719: _performance_rating_detail_player = 0; belugas@4719: LowerWindowWidget(w, _performance_rating_detail_player + 13); dominik@116: SetWindowDirty(w); peter1138@3027: peter1138@3027: break; peter1138@3027: } peter1138@3027: peter1138@3027: case WE_TICK: { peter1138@3027: // Update the player score every 5 days peter1138@3027: if (--w->custom[0] == 0) { peter1138@3027: w->custom[0] = DAY_TICKS; peter1138@3027: if (--w->custom[1] == 0) { peter1138@3027: Player *p2; tron@3033: peter1138@3027: w->custom[1] = 5; tron@3033: FOR_ALL_PLAYERS(p2) { peter1138@3027: // Skip if player is not active tron@3033: if (p2->is_active) UpdateCompanyRatingAndValue(p2, false); tron@3033: } peter1138@3027: SetWindowDirty(w); peter1138@3027: } peter1138@3027: } peter1138@3027: peter1138@3027: break; peter1138@3027: } dominik@116: } dominik@116: } dominik@116: dominik@116: static const Widget _performance_rating_detail_widgets[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, rubidium@4344: { WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL}, dominik@116: Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 28, 47, 0x0, STR_PERFORMANCE_DETAIL_VEHICLES_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 48, 67, 0x0, STR_PERFORMANCE_DETAIL_STATIONS_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 68, 87, 0x0, STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 88, 107, 0x0, STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 108, 127, 0x0, STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 128, 147, 0x0, STR_PERFORMANCE_DETAIL_DELIVERED_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 148, 167, 0x0, STR_PERFORMANCE_DETAIL_CARGO_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 168, 187, 0x0, STR_PERFORMANCE_DETAIL_MONEY_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 188, 207, 0x0, STR_PERFORMANCE_DETAIL_LOAN_TIP}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 208, 227, 0x0, STR_PERFORMANCE_DETAIL_TOTAL_TIP}, dominik@116: Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 2, 38, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 39, 75, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 76, 112, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 113, 149, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 150, 186, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 187, 223, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 224, 260, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 14, 261, 297, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, darkvater@176: { WIDGETS_END}, dominik@116: }; dominik@116: dominik@116: static const WindowDesc _performance_rating_detail_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 299, 228, dominik@116: WC_PERFORMANCE_DETAIL,0, dominik@116: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, dominik@116: _performance_rating_detail_widgets, dominik@116: PerformanceRatingDetailWndProc dominik@116: }; dominik@116: tron@1093: void ShowPerformanceRatingDetail(void) dominik@116: { dominik@116: AllocateWindowDescFront(&_performance_rating_detail_desc, 0); dominik@116: } truelight@1575: truelight@1575: tron@4353: static const Sign **_sign_sort; tron@4353: static uint _num_sign_sort; truelight@1575: truelight@1575: static char _bufcache[64]; tron@4353: static const Sign *_last_sign; truelight@1575: truelight@1575: static int CDECL SignNameSorter(const void *a, const void *b) truelight@1575: { tron@4353: const Sign *sign0 = *(const Sign**)a; tron@4353: const Sign *sign1 = *(const Sign**)b; truelight@1575: char buf1[64]; truelight@1575: Darkvater@4912: GetString(buf1, sign0->str, lastof(buf1)); truelight@1575: tron@4353: if (sign1 != _last_sign) { tron@4353: _last_sign = sign1; Darkvater@4912: GetString(_bufcache, sign1->str, lastof(_bufcache)); truelight@1575: } truelight@1575: belugas@3801: return strcmp(buf1, _bufcache); // sort by name truelight@1575: } truelight@1575: truelight@1575: static void GlobalSortSignList(void) truelight@1575: { truelight@4349: const Sign *si; tron@4353: uint n = 0; truelight@1575: truelight@1575: /* Create array for sorting */ matthijs@5247: _sign_sort = realloc((void *)_sign_sort, (GetMaxSignIndex() + 1)* sizeof(_sign_sort[0])); Darkvater@5568: if (_sign_sort == NULL) error("Could not allocate memory for the sign-sorting-list"); truelight@1575: tron@4353: FOR_ALL_SIGNS(si) _sign_sort[n++] = si; tron@4353: _num_sign_sort = n; tron@4353: tron@4353: qsort((void*)_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter); truelight@1575: truelight@1575: _sign_sort_dirty = false; truelight@1575: Darkvater@5568: DEBUG(misc, 3, "Resorting global signs list"); truelight@1575: } truelight@1575: truelight@1575: static void SignListWndProc(Window *w, WindowEvent *e) truelight@1575: { truelight@1575: switch (e->event) { truelight@1575: case WE_PAINT: { truelight@1575: int y = 16; // offset from top of widget truelight@1575: truelight@1575: if (_sign_sort_dirty) truelight@1575: GlobalSortSignList(); truelight@1575: truelight@1575: SetVScrollCount(w, _num_sign_sort); truelight@1575: truelight@1575: SetDParam(0, w->vscroll.count); truelight@1575: DrawWindowWidgets(w); truelight@1575: truelight@1575: /* No signs? */ truelight@1575: if (w->vscroll.count == 0) { truelight@1575: DrawString(2, y, STR_304A_NONE, 0); truelight@1575: return; truelight@1575: } truelight@1575: truelight@4349: { Darkvater@2135: uint16 i; truelight@1575: truelight@1575: /* Start drawing the signs */ tron@2133: for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) { tron@4353: const Sign *si = _sign_sort[i]; truelight@1575: truelight@4349: if (si->owner != OWNER_NONE) truelight@4349: DrawPlayerIcon(si->owner, 4, y + 1); truelight@1575: truelight@4349: DrawString(22, y, si->str, 8); truelight@1575: y += 10; truelight@1575: } truelight@1575: } truelight@1575: } break; truelight@1575: truelight@1575: case WE_CLICK: { belugas@4634: switch (e->we.click.widget) { truelight@1575: case 3: { belugas@4634: uint32 id_v = (e->we.click.pt.y - 15) / 10; truelight@4349: const Sign *si; truelight@1575: truelight@1575: if (id_v >= w->vscroll.cap) truelight@1575: return; truelight@1575: truelight@1575: id_v += w->vscroll.pos; truelight@1575: truelight@1575: if (id_v >= w->vscroll.count) truelight@1575: return; truelight@1575: tron@4353: si = _sign_sort[id_v]; truelight@4349: ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); truelight@1575: } break; truelight@1575: } truelight@1575: } break; truelight@1575: truelight@1575: case WE_RESIZE: belugas@4634: w->vscroll.cap += e->we.sizing.diff.y / 10; truelight@1575: break; truelight@1575: } truelight@1575: } truelight@1575: truelight@1575: static const Widget _sign_list_widget[] = { rubidium@4344: { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, rubidium@4344: { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 345, 0, 13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, rubidium@4344: { WWT_STICKYBOX, RESIZE_LR, 14, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON}, rubidium@4344: { WWT_PANEL, RESIZE_RB, 14, 0, 345, 14, 137, 0x0, STR_NULL}, rubidium@4344: { WWT_SCROLLBAR, RESIZE_LRB, 14, 346, 357, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, rubidium@4344: { WWT_RESIZEBOX, RESIZE_LRTB, 14, 346, 357, 126, 137, 0x0, STR_RESIZE_BUTTON}, truelight@1575: { WIDGETS_END}, truelight@1575: }; truelight@1575: truelight@1575: static const WindowDesc _sign_list_desc = { Darkvater@5070: WDP_AUTO, WDP_AUTO, 358, 138, truelight@1575: WC_SIGN_LIST,0, truelight@1575: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE, truelight@1575: _sign_list_widget, truelight@1575: SignListWndProc truelight@1575: }; truelight@1575: truelight@1575: truelight@1575: void ShowSignList(void) truelight@1575: { truelight@1575: Window *w; truelight@1575: truelight@1575: w = AllocateWindowDescFront(&_sign_list_desc, 0); truelight@1575: if (w != NULL) { truelight@1575: w->vscroll.cap = 12; truelight@1575: w->resize.step_height = 10; truelight@1575: w->resize.height = w->height - 10 * 7; // minimum if 5 in the list truelight@1575: } truelight@1575: }