00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gui.h"
00008 #include "window_gui.h"
00009 #include "player_base.h"
00010 #include "player_gui.h"
00011 #include "economy_func.h"
00012 #include "variables.h"
00013 #include "cargotype.h"
00014 #include "strings_func.h"
00015 #include "core/alloc_func.hpp"
00016 #include "window_func.h"
00017 #include "date_func.h"
00018 #include "gfx_func.h"
00019
00020 #include "table/strings.h"
00021 #include "table/sprites.h"
00022
00023
00024 static uint _legend_excluded_players;
00025 static uint _legend_excluded_cargo;
00026
00027
00028
00029
00030
00031 enum {
00032 GRAPH_MAX_DATASETS = 32,
00033 GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
00034 GRAPH_AXIS_LINE_COLOUR = 215,
00035
00036 GRAPH_X_POSITION_BEGINNING = 44,
00037 GRAPH_X_POSITION_SEPARATION = 22,
00038
00039 GRAPH_NUM_LINES_Y = 9,
00040
00041
00042
00043 };
00044
00045
00046 static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX);
00047 static const uint INVALID_DATAPOINT_POS = UINT_MAX;
00048
00049 struct GraphDrawer {
00050 uint excluded_data;
00051 byte num_dataset;
00052 byte num_on_x_axis;
00053 bool has_negative_values;
00054 byte num_vert_lines;
00055
00056
00057
00058 byte month;
00059 Year year;
00060
00061
00062
00063 uint16 x_values_start;
00064 uint16 x_values_increment;
00065
00066 int left, top;
00067 uint height;
00068 StringID format_str_y_axis;
00069 byte colors[GRAPH_MAX_DATASETS];
00070 OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24];
00071 };
00072
00073 static void DrawGraph(const GraphDrawer *gw)
00074 {
00075 uint x, y;
00076 OverflowSafeInt64 highest_value;
00077 int x_axis_offset;
00078
00079
00080
00081 assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
00082 assert(gw->num_vert_lines > 0);
00083
00084 byte grid_colour = _colour_gradient[14][4];
00085
00086
00087 int bottom = gw->top + gw->height - 1;
00088 int right = gw->left + GRAPH_X_POSITION_BEGINNING + gw->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
00089
00090
00091
00092
00093 x = gw->left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
00094
00095 for (int i = 0; i < gw->num_vert_lines; i++) {
00096 GfxFillRect(x, gw->top, x, bottom, grid_colour);
00097 x += GRAPH_X_POSITION_SEPARATION;
00098 }
00099
00100
00101 x = gw->left + GRAPH_X_POSITION_BEGINNING;
00102 y = gw->height + gw->top;
00103
00104 for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
00105 GfxFillRect(x, y, right, y, grid_colour);
00106 y -= (gw->height / (GRAPH_NUM_LINES_Y - 1));
00107 }
00108
00109
00110 GfxFillRect(x, gw->top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
00111
00112
00113 x_axis_offset = gw->height;
00114
00115
00116 if (gw->has_negative_values) x_axis_offset /= 2;
00117
00118
00119 y = x_axis_offset + gw->top;
00120 GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
00121
00122
00123 if (gw->num_on_x_axis == 0)
00124 return;
00125
00126 assert(gw->num_on_x_axis > 0);
00127 assert(gw->num_dataset > 0);
00128
00129
00130
00131
00132
00133 highest_value = x_axis_offset * 2;
00134
00135 for (int i = 0; i < gw->num_dataset; i++) {
00136 if (!HasBit(gw->excluded_data, i)) {
00137 for (int j = 0; j < gw->num_on_x_axis; j++) {
00138 OverflowSafeInt64 datapoint = gw->cost[i][j];
00139
00140 if (datapoint != INVALID_DATAPOINT) {
00141
00142
00143
00144 highest_value = max(highest_value, abs(datapoint));
00145 }
00146 }
00147 }
00148 }
00149
00150
00151
00152 int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
00153 if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
00154
00155
00156 int64 y_label = highest_value;
00157 int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
00158
00159
00160
00161 if (gw->has_negative_values) y_label_separation *= 2;
00162
00163 x = gw->left + GRAPH_X_POSITION_BEGINNING + 1;
00164 y = gw->top - 3;
00165
00166 for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
00167 SetDParam(0, gw->format_str_y_axis);
00168 SetDParam(1, y_label);
00169 DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
00170
00171 y_label -= y_label_separation;
00172 y += (gw->height / (GRAPH_NUM_LINES_Y - 1));
00173 }
00174
00175
00176 if (gw->month != 0xFF) {
00177 x = gw->left + GRAPH_X_POSITION_BEGINNING;
00178 y = gw->top + gw->height + 1;
00179 byte month = gw->month;
00180 Year year = gw->year;
00181 for (int i = 0; i < gw->num_on_x_axis; i++) {
00182 SetDParam(0, month + STR_0162_JAN);
00183 SetDParam(1, month + STR_0162_JAN + 2);
00184 SetDParam(2, year);
00185 DrawString(x, y, month == 0 ? STR_016F : STR_016E, GRAPH_AXIS_LABEL_COLOUR);
00186
00187 month += 3;
00188 if (month >= 12) {
00189 month = 0;
00190 year++;
00191 }
00192 x += GRAPH_X_POSITION_SEPARATION;
00193 }
00194 } else {
00195
00196 x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
00197 y = gw->top + gw->height + 1;
00198 uint16 label = gw->x_values_start;
00199
00200 for (int i = 0; i < gw->num_on_x_axis; i++) {
00201 SetDParam(0, label);
00202 DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
00203
00204 label += gw->x_values_increment;
00205 x += GRAPH_X_POSITION_SEPARATION;
00206 }
00207 }
00208
00209
00210 for (int i = 0; i < gw->num_dataset; i++) {
00211 if (!HasBit(gw->excluded_data, i)) {
00212
00213 x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
00214
00215 byte color = gw->colors[i];
00216 uint prev_x = INVALID_DATAPOINT_POS;
00217 uint prev_y = INVALID_DATAPOINT_POS;
00218
00219 for (int j = 0; j < gw->num_on_x_axis; j++) {
00220 OverflowSafeInt64 datapoint = gw->cost[i][j];
00221
00222 if (datapoint != INVALID_DATAPOINT) {
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
00235 int reduce_range = max(mult_range - 31, 0);
00236
00237
00238 if (datapoint < 0) {
00239 datapoint = -(abs(datapoint) >> reduce_range);
00240 } else {
00241 datapoint >>= reduce_range;
00242 }
00243
00244 y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
00245
00246
00247 GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
00248
00249
00250 if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
00251
00252 prev_x = x;
00253 prev_y = y;
00254 } else {
00255 prev_x = INVALID_DATAPOINT_POS;
00256 prev_y = INVALID_DATAPOINT_POS;
00257 }
00258
00259 x += GRAPH_X_POSITION_SEPARATION;
00260 }
00261 }
00262 }
00263 }
00264
00265
00266
00267
00268
00269 static void GraphLegendWndProc(Window *w, WindowEvent *e)
00270 {
00271 switch (e->event) {
00272 case WE_CREATE:
00273 for (uint i = 3; i < w->widget_count; i++) {
00274 if (!HasBit(_legend_excluded_players, i - 3)) w->LowerWidget(i);
00275 }
00276 break;
00277
00278 case WE_PAINT: {
00279 const Player *p;
00280
00281 FOR_ALL_PLAYERS(p) {
00282 if (p->is_active) continue;
00283
00284 SetBit(_legend_excluded_players, p->index);
00285 w->RaiseWidget(p->index + 3);
00286 }
00287
00288 DrawWindowWidgets(w);
00289
00290 FOR_ALL_PLAYERS(p) {
00291 if (!p->is_active) continue;
00292
00293 DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
00294
00295 SetDParam(0, p->index);
00296 SetDParam(1, p->index);
00297 DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
00298 }
00299 break;
00300 }
00301
00302 case WE_CLICK:
00303 if (!IsInsideMM(e->we.click.widget, 3, 11)) return;
00304
00305 ToggleBit(_legend_excluded_players, e->we.click.widget - 3);
00306 w->ToggleWidgetLoweredState(e->we.click.widget);
00307 SetWindowDirty(w);
00308 InvalidateWindow(WC_INCOME_GRAPH, 0);
00309 InvalidateWindow(WC_OPERATING_PROFIT, 0);
00310 InvalidateWindow(WC_DELIVERED_CARGO, 0);
00311 InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
00312 InvalidateWindow(WC_COMPANY_VALUE, 0);
00313 break;
00314 }
00315 }
00316
00317 static const Widget _graph_legend_widgets[] = {
00318 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00319 { WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00320 { WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0, STR_NULL},
00321 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00322 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 28, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00323 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 40, 51, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00324 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 52, 63, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00325 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 64, 75, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00326 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 76, 87, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00327 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 88, 99, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00328 { WWT_PANEL, RESIZE_NONE, 14, 2, 247, 100, 111, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
00329 { WIDGETS_END},
00330 };
00331
00332 static const WindowDesc _graph_legend_desc = {
00333 WDP_AUTO, WDP_AUTO, 250, 114, 250, 114,
00334 WC_GRAPH_LEGEND, WC_NONE,
00335 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00336 _graph_legend_widgets,
00337 GraphLegendWndProc
00338 };
00339
00340 static void ShowGraphLegend()
00341 {
00342 AllocateWindowDescFront(&_graph_legend_desc, 0);
00343 }
00344
00345
00346
00347
00348
00349 static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
00350 {
00351 const Player* p;
00352 uint excluded_players = _legend_excluded_players;
00353 byte nums;
00354 int mo, yr;
00355
00356
00357 FOR_ALL_PLAYERS(p) {
00358 if (!p->is_active) SetBit(excluded_players, p->index);
00359 }
00360 gd->excluded_data = excluded_players;
00361 gd->num_vert_lines = 24;
00362
00363 nums = 0;
00364 FOR_ALL_PLAYERS(p) {
00365 if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
00366 }
00367 gd->num_on_x_axis = min(nums, 24);
00368
00369 mo = (_cur_month / 3 - nums) * 3;
00370 yr = _cur_year;
00371 while (mo < 0) {
00372 yr--;
00373 mo += 12;
00374 }
00375
00376 gd->year = yr;
00377 gd->month = mo;
00378 }
00379
00380 static void OperatingProfitWndProc(Window *w, WindowEvent *e)
00381 {
00382 switch (e->event) {
00383 case WE_PAINT: {
00384 GraphDrawer gd;
00385 const Player* p;
00386
00387 DrawWindowWidgets(w);
00388
00389 gd.left = 2;
00390 gd.top = 18;
00391 gd.height = 136;
00392 gd.has_negative_values = true;
00393 gd.format_str_y_axis = STR_CURRCOMPACT;
00394
00395 SetupGraphDrawerForPlayers(&gd);
00396
00397 int numd = 0;
00398 FOR_ALL_PLAYERS(p) {
00399 if (p->is_active) {
00400 gd.colors[numd] = _colour_gradient[p->player_color][6];
00401 for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
00402 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (p->old_economy[j].income + p->old_economy[j].expenses);
00403 i++;
00404 }
00405 }
00406 numd++;
00407 }
00408
00409 gd.num_dataset = numd;
00410
00411 DrawGraph(&gd);
00412 break;
00413 }
00414
00415 case WE_CLICK:
00416
00417 if (e->we.click.widget == 2) ShowGraphLegend();
00418 break;
00419 }
00420 }
00421
00422 static const Widget _operating_profit_widgets[] = {
00423 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00424 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
00425 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00426 { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL},
00427 { WIDGETS_END},
00428 };
00429
00430 static const WindowDesc _operating_profit_desc = {
00431 WDP_AUTO, WDP_AUTO, 576, 174, 576, 174,
00432 WC_OPERATING_PROFIT, WC_NONE,
00433 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00434 _operating_profit_widgets,
00435 OperatingProfitWndProc
00436 };
00437
00438
00439 void ShowOperatingProfitGraph()
00440 {
00441 if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
00442 InvalidateWindow(WC_GRAPH_LEGEND, 0);
00443 }
00444 }
00445
00446
00447
00448
00449
00450
00451 static void IncomeGraphWndProc(Window *w, WindowEvent *e)
00452 {
00453 switch (e->event) {
00454 case WE_PAINT: {
00455 GraphDrawer gd;
00456 const Player* p;
00457
00458 DrawWindowWidgets(w);
00459
00460 gd.left = 2;
00461 gd.top = 18;
00462 gd.height = 104;
00463 gd.has_negative_values = false;
00464 gd.format_str_y_axis = STR_CURRCOMPACT;
00465 SetupGraphDrawerForPlayers(&gd);
00466
00467 int numd = 0;
00468 FOR_ALL_PLAYERS(p) {
00469 if (p->is_active) {
00470 gd.colors[numd] = _colour_gradient[p->player_color][6];
00471 for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
00472 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].income;
00473 i++;
00474 }
00475 }
00476 numd++;
00477 }
00478
00479 gd.num_dataset = numd;
00480
00481 DrawGraph(&gd);
00482 break;
00483 }
00484
00485 case WE_CLICK:
00486 if (e->we.click.widget == 2) ShowGraphLegend();
00487 break;
00488 }
00489 }
00490
00491 static const Widget _income_graph_widgets[] = {
00492 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00493 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
00494 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00495 { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
00496 { WIDGETS_END},
00497 };
00498
00499 static const WindowDesc _income_graph_desc = {
00500 WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
00501 WC_INCOME_GRAPH, WC_NONE,
00502 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00503 _income_graph_widgets,
00504 IncomeGraphWndProc
00505 };
00506
00507 void ShowIncomeGraph()
00508 {
00509 if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
00510 InvalidateWindow(WC_GRAPH_LEGEND, 0);
00511 }
00512 }
00513
00514
00515
00516
00517
00518 static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
00519 {
00520 switch (e->event) {
00521 case WE_PAINT: {
00522 GraphDrawer gd;
00523 const Player* p;
00524
00525 DrawWindowWidgets(w);
00526
00527 gd.left = 2;
00528 gd.top = 18;
00529 gd.height = 104;
00530 gd.has_negative_values = false;
00531 gd.format_str_y_axis = STR_7024;
00532 SetupGraphDrawerForPlayers(&gd);
00533
00534 int numd = 0;
00535 FOR_ALL_PLAYERS(p) {
00536 if (p->is_active) {
00537 gd.colors[numd] = _colour_gradient[p->player_color][6];
00538 for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
00539 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].delivered_cargo;
00540 i++;
00541 }
00542 }
00543 numd++;
00544 }
00545
00546 gd.num_dataset = numd;
00547
00548 DrawGraph(&gd);
00549 break;
00550 }
00551
00552 case WE_CLICK:
00553 if (e->we.click.widget == 2) ShowGraphLegend();
00554 break;
00555 }
00556 }
00557
00558 static const Widget _delivered_cargo_graph_widgets[] = {
00559 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00560 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
00561 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00562 { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
00563 { WIDGETS_END},
00564 };
00565
00566 static const WindowDesc _delivered_cargo_graph_desc = {
00567 WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
00568 WC_DELIVERED_CARGO, WC_NONE,
00569 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00570 _delivered_cargo_graph_widgets,
00571 DeliveredCargoGraphWndProc
00572 };
00573
00574 void ShowDeliveredCargoGraph()
00575 {
00576 if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
00577 InvalidateWindow(WC_GRAPH_LEGEND, 0);
00578 }
00579 }
00580
00581
00582
00583
00584
00585 static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
00586 {
00587 switch (e->event) {
00588 case WE_PAINT: {
00589 GraphDrawer gd;
00590 const Player* p;
00591
00592 DrawWindowWidgets(w);
00593
00594 gd.left = 2;
00595 gd.top = 18;
00596 gd.height = 200;
00597 gd.has_negative_values = false;
00598 gd.format_str_y_axis = STR_7024;
00599 SetupGraphDrawerForPlayers(&gd);
00600
00601 int numd = 0;
00602 FOR_ALL_PLAYERS(p) {
00603 if (p->is_active) {
00604 gd.colors[numd] = _colour_gradient[p->player_color][6];
00605 for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
00606 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].performance_history;
00607 i++;
00608 }
00609 }
00610 numd++;
00611 }
00612
00613 gd.num_dataset = numd;
00614
00615 DrawGraph(&gd);
00616 break;
00617 }
00618
00619 case WE_CLICK:
00620 if (e->we.click.widget == 2) ShowGraphLegend();
00621 if (e->we.click.widget == 3) ShowPerformanceRatingDetail();
00622 break;
00623 }
00624 }
00625
00626 static const Widget _performance_history_widgets[] = {
00627 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00628 { WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00629 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00630 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00631 { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
00632 { WIDGETS_END},
00633 };
00634
00635 static const WindowDesc _performance_history_desc = {
00636 WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
00637 WC_PERFORMANCE_HISTORY, WC_NONE,
00638 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00639 _performance_history_widgets,
00640 PerformanceHistoryWndProc
00641 };
00642
00643 void ShowPerformanceHistoryGraph()
00644 {
00645 if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
00646 InvalidateWindow(WC_GRAPH_LEGEND, 0);
00647 }
00648 }
00649
00650
00651
00652
00653
00654 static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
00655 {
00656 switch (e->event) {
00657 case WE_PAINT: {
00658 GraphDrawer gd;
00659 const Player* p;
00660
00661 DrawWindowWidgets(w);
00662
00663 gd.left = 2;
00664 gd.top = 18;
00665 gd.height = 200;
00666 gd.has_negative_values = false;
00667 gd.format_str_y_axis = STR_CURRCOMPACT;
00668 SetupGraphDrawerForPlayers(&gd);
00669
00670 int numd = 0;
00671 FOR_ALL_PLAYERS(p) {
00672 if (p->is_active) {
00673 gd.colors[numd] = _colour_gradient[p->player_color][6];
00674 for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
00675 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].company_value;
00676 i++;
00677 }
00678 }
00679 numd++;
00680 }
00681
00682 gd.num_dataset = numd;
00683
00684 DrawGraph(&gd);
00685 break;
00686 }
00687
00688 case WE_CLICK:
00689 if (e->we.click.widget == 2) ShowGraphLegend();
00690 break;
00691 }
00692 }
00693
00694 static const Widget _company_value_graph_widgets[] = {
00695 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00696 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
00697 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
00698 { WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
00699 { WIDGETS_END},
00700 };
00701
00702 static const WindowDesc _company_value_graph_desc = {
00703 WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
00704 WC_COMPANY_VALUE, WC_NONE,
00705 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00706 _company_value_graph_widgets,
00707 CompanyValueGraphWndProc
00708 };
00709
00710 void ShowCompanyValueGraph()
00711 {
00712 if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
00713 InvalidateWindow(WC_GRAPH_LEGEND, 0);
00714 }
00715 }
00716
00717
00718
00719
00720
00721 static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
00722 {
00723 switch (e->event) {
00724 case WE_PAINT: {
00725 GraphDrawer gd;
00726
00727 DrawWindowWidgets(w);
00728
00729 int x = 495;
00730 int y = 24;
00731
00732 gd.excluded_data = _legend_excluded_cargo;
00733 gd.left = 2;
00734 gd.top = 24;
00735 gd.height = w->height - 38;
00736 gd.has_negative_values = false;
00737 gd.format_str_y_axis = STR_CURRCOMPACT;
00738 gd.num_on_x_axis = 20;
00739 gd.num_vert_lines = 20;
00740 gd.month = 0xFF;
00741 gd.x_values_start = 10;
00742 gd.x_values_increment = 10;
00743
00744 uint i = 0;
00745 for (CargoID c = 0; c < NUM_CARGO; c++) {
00746 const CargoSpec *cs = GetCargo(c);
00747 if (!cs->IsValid()) continue;
00748
00749
00750
00751
00752 if (i + 3 < w->widget_count) {
00753
00754
00755
00756
00757 byte clk_dif = w->IsWidgetLowered(i + 3) ? 1 : 0;
00758
00759 GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
00760 GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
00761 SetDParam(0, cs->name);
00762 DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
00763 y += 8;
00764 }
00765
00766 gd.colors[i] = cs->legend_colour;
00767 for (uint j = 0; j != 20; j++) {
00768 gd.cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, c);
00769 }
00770
00771 i++;
00772 }
00773 gd.num_dataset = i;
00774
00775 DrawGraph(&gd);
00776
00777 DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
00778 DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
00779 break;
00780 }
00781
00782 case WE_CLICK:
00783 if (e->we.click.widget >= 3) {
00784 ToggleBit(_legend_excluded_cargo, e->we.click.widget - 3);
00785 w->ToggleWidgetLoweredState(e->we.click.widget);
00786 SetWindowDirty(w);
00787 }
00788 break;
00789 }
00790 }
00791
00792 static const Widget _cargo_payment_rates_widgets[] = {
00793 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00794 { WWT_CAPTION, RESIZE_NONE, 14, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
00795 { WWT_PANEL, RESIZE_BOTTOM, 14, 0, 567, 14, 45, 0x0, STR_NULL},
00796 { WIDGETS_END},
00797 };
00798
00799 static const WindowDesc _cargo_payment_rates_desc = {
00800 WDP_AUTO, WDP_AUTO, 568, 46, 568, 46,
00801 WC_PAYMENT_RATES, WC_NONE,
00802 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00803 _cargo_payment_rates_widgets,
00804 CargoPaymentRatesWndProc
00805 };
00806
00807
00808 void ShowCargoPaymentRates()
00809 {
00810 Window *w = AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
00811 if (w == NULL) return;
00812
00813
00814 uint num_active = 0;
00815 for (CargoID c = 0; c < NUM_CARGO; c++) {
00816 if (GetCargo(c)->IsValid()) num_active++;
00817 }
00818
00819
00820 ResizeWindow(w, 0, max(num_active, 12U) * 8);
00821
00822
00823 w->widget_count += num_active;
00824 w->widget = ReallocT(w->widget, w->widget_count + 1);
00825 w->widget[w->widget_count].type = WWT_LAST;
00826
00827
00828 for (uint i = 0; i != num_active; i++) {
00829 Widget *wi = &w->widget[3 + i];
00830 wi->type = WWT_PANEL;
00831 wi->display_flags = RESIZE_NONE;
00832 wi->color = 12;
00833 wi->left = 493;
00834 wi->right = 562;
00835 wi->top = 24 + i * 8;
00836 wi->bottom = wi->top + 7;
00837 wi->data = 0;
00838 wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
00839
00840 if (!HasBit(_legend_excluded_cargo, i)) w->LowerWidget(i + 3);
00841 }
00842
00843 SetWindowDirty(w);
00844 }
00845
00846
00847
00848
00849
00850 static const StringID _performance_titles[] = {
00851 STR_7066_ENGINEER,
00852 STR_7066_ENGINEER,
00853 STR_7067_TRAFFIC_MANAGER,
00854 STR_7067_TRAFFIC_MANAGER,
00855 STR_7068_TRANSPORT_COORDINATOR,
00856 STR_7068_TRANSPORT_COORDINATOR,
00857 STR_7069_ROUTE_SUPERVISOR,
00858 STR_7069_ROUTE_SUPERVISOR,
00859 STR_706A_DIRECTOR,
00860 STR_706A_DIRECTOR,
00861 STR_706B_CHIEF_EXECUTIVE,
00862 STR_706B_CHIEF_EXECUTIVE,
00863 STR_706C_CHAIRMAN,
00864 STR_706C_CHAIRMAN,
00865 STR_706D_PRESIDENT,
00866 STR_706E_TYCOON,
00867 };
00868
00869 static inline StringID GetPerformanceTitleFromValue(uint value)
00870 {
00871 return _performance_titles[minu(value, 1000) >> 6];
00872 }
00873
00874 static int CDECL PerfHistComp(const void* elem1, const void* elem2)
00875 {
00876 const Player* p1 = *(const Player* const*)elem1;
00877 const Player* p2 = *(const Player* const*)elem2;
00878
00879 return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
00880 }
00881
00882 static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
00883 {
00884 switch (e->event) {
00885 case WE_PAINT: {
00886 const Player* plist[MAX_PLAYERS];
00887 const Player* p;
00888
00889 DrawWindowWidgets(w);
00890
00891 uint pl_num = 0;
00892 FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
00893
00894 qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
00895
00896 for (uint i = 0; i != pl_num; i++) {
00897 p = plist[i];
00898 SetDParam(0, i + STR_01AC_1ST);
00899 SetDParam(1, p->index);
00900 SetDParam(2, p->index);
00901 SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
00902
00903 DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
00904 DrawPlayerIcon(p->index, 27, 16 + i * 10);
00905 }
00906
00907 break;
00908 }
00909 }
00910 }
00911
00912
00913 static const Widget _company_league_widgets[] = {
00914 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00915 { WWT_CAPTION, RESIZE_NONE, 14, 11, 387, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
00916 { WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON},
00917 { WWT_PANEL, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL},
00918 { WIDGETS_END},
00919 };
00920
00921 static const WindowDesc _company_league_desc = {
00922 WDP_AUTO, WDP_AUTO, 400, 97, 400, 97,
00923 WC_COMPANY_LEAGUE, WC_NONE,
00924 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
00925 _company_league_widgets,
00926 CompanyLeagueWndProc
00927 };
00928
00929 void ShowCompanyLeagueTable()
00930 {
00931 AllocateWindowDescFront(&_company_league_desc, 0);
00932 }
00933
00934
00935
00936
00937
00938 static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
00939 {
00940 static PlayerID _performance_rating_detail_player = INVALID_PLAYER;
00941
00942 switch (e->event) {
00943 case WE_PAINT: {
00944 byte x;
00945 uint16 y = 14;
00946 int total_score = 0;
00947 int color_done, color_notdone;
00948
00949
00950 DrawWindowWidgets(w);
00951
00952
00953 if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
00954 if (_performance_rating_detail_player != INVALID_PLAYER) {
00955
00956 w->RaiseWidget(_performance_rating_detail_player + 13);
00957 w->DisableWidget(_performance_rating_detail_player + 13);
00958 SetWindowDirty(w);
00959
00960 _performance_rating_detail_player = INVALID_PLAYER;
00961 }
00962
00963 for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
00964 if (GetPlayer(i)->is_active) {
00965
00966 w->LowerWidget(i + 13);
00967 SetWindowDirty(w);
00968
00969 _performance_rating_detail_player = i;
00970 break;
00971 }
00972 }
00973 }
00974
00975
00976 if (_performance_rating_detail_player == INVALID_PLAYER) break;
00977
00978
00979 for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
00980 if (!GetPlayer(i)->is_active) {
00981
00982 if (!w->IsWidgetDisabled(i + 13)) {
00983
00984 w->DisableWidget(i + 13);
00985
00986
00987 SetWindowDirty(w);
00988 }
00989 continue;
00990 }
00991
00992
00993 if (w->IsWidgetDisabled(i + 13)) {
00994
00995 w->EnableWidget(i + 13);
00996
00997 SetWindowDirty(w);
00998 }
00999
01000 x = (i == _performance_rating_detail_player) ? 1 : 0;
01001 DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
01002 }
01003
01004
01005 color_done = _colour_gradient[COLOUR_GREEN][4];
01006 color_notdone = _colour_gradient[COLOUR_RED][4];
01007
01008
01009 for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
01010 int val = _score_part[_performance_rating_detail_player][i];
01011 int needed = _score_info[i].needed;
01012 int score = _score_info[i].score;
01013
01014 y += 20;
01015
01016 if (i == SCORE_TOTAL) {
01017 needed = total_score;
01018 score = SCORE_MAX;
01019 } else {
01020 total_score += score;
01021 }
01022
01023 DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
01024
01025
01026 SetDParam(0, score);
01027 DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
01028
01029
01030 x = Clamp(val, 0, needed) * 50 / needed;
01031
01032
01033 if (val < 0 && i == SCORE_LOAN) x = 0;
01034
01035
01036 if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, color_done);
01037 if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
01038
01039
01040 x = Clamp(val, 0, needed) * 100 / needed;
01041
01042
01043 if (val < 0 && i == SCORE_LOAN) x = 0;
01044
01045
01046 SetDParam(0, x);
01047 DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
01048
01049
01050 if (i == SCORE_LOAN) val = needed - val;
01051
01052
01053
01054 SetDParam(0, val);
01055 SetDParam(1, needed);
01056 switch (i) {
01057 case SCORE_MIN_PROFIT:
01058 case SCORE_MIN_INCOME:
01059 case SCORE_MAX_INCOME:
01060 case SCORE_MONEY:
01061 case SCORE_LOAN:
01062 DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
01063 break;
01064 default:
01065 DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
01066 }
01067 }
01068
01069 break;
01070 }
01071
01072 case WE_CLICK:
01073
01074 if (IsInsideMM(e->we.click.widget, 13, 21)) {
01075
01076 if (!w->IsWidgetDisabled(e->we.click.widget)) {
01077 w->RaiseWidget(_performance_rating_detail_player + 13);
01078 _performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
01079 w->LowerWidget(_performance_rating_detail_player + 13);
01080 SetWindowDirty(w);
01081 }
01082 }
01083 break;
01084
01085 case WE_CREATE: {
01086 Player *p2;
01087
01088
01089 for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
01090 w->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
01091 }
01092
01093
01094 FOR_ALL_PLAYERS(p2) {
01095 if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
01096 }
01097
01098 w->custom[0] = DAY_TICKS;
01099 w->custom[1] = 5;
01100
01101 if (_performance_rating_detail_player != INVALID_PLAYER) w->LowerWidget(_performance_rating_detail_player + 13);
01102 SetWindowDirty(w);
01103
01104 break;
01105 }
01106
01107 case WE_TICK:
01108 if (_pause_game != 0) break;
01109
01110
01111 if (--w->custom[0] == 0) {
01112 w->custom[0] = DAY_TICKS;
01113 if (--w->custom[1] == 0) {
01114 Player *p2;
01115
01116 w->custom[1] = 5;
01117 FOR_ALL_PLAYERS(p2) {
01118
01119 if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
01120 }
01121 SetWindowDirty(w);
01122 }
01123 }
01124
01125 break;
01126 }
01127 }
01128
01129 static const Widget _performance_rating_detail_widgets[] = {
01130 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01131 { WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
01132 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL},
01133
01134 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 28, 47, 0x0, STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
01135 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 48, 67, 0x0, STR_PERFORMANCE_DETAIL_STATIONS_TIP},
01136 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 68, 87, 0x0, STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
01137 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 88, 107, 0x0, STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
01138 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 108, 127, 0x0, STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
01139 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 128, 147, 0x0, STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
01140 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 148, 167, 0x0, STR_PERFORMANCE_DETAIL_CARGO_TIP},
01141 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 168, 187, 0x0, STR_PERFORMANCE_DETAIL_MONEY_TIP},
01142 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 188, 207, 0x0, STR_PERFORMANCE_DETAIL_LOAN_TIP},
01143 { WWT_PANEL, RESIZE_NONE, 14, 0, 298, 208, 227, 0x0, STR_PERFORMANCE_DETAIL_TOTAL_TIP},
01144
01145 { WWT_PANEL, RESIZE_NONE, 14, 2, 38, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01146 { WWT_PANEL, RESIZE_NONE, 14, 39, 75, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01147 { WWT_PANEL, RESIZE_NONE, 14, 76, 112, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01148 { WWT_PANEL, RESIZE_NONE, 14, 113, 149, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01149 { WWT_PANEL, RESIZE_NONE, 14, 150, 186, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01150 { WWT_PANEL, RESIZE_NONE, 14, 187, 223, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01151 { WWT_PANEL, RESIZE_NONE, 14, 224, 260, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01152 { WWT_PANEL, RESIZE_NONE, 14, 261, 297, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
01153 { WIDGETS_END},
01154 };
01155
01156 static const WindowDesc _performance_rating_detail_desc = {
01157 WDP_AUTO, WDP_AUTO, 299, 228, 299, 228,
01158 WC_PERFORMANCE_DETAIL, WC_NONE,
01159 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
01160 _performance_rating_detail_widgets,
01161 PerformanceRatingDetailWndProc
01162 };
01163
01164 void ShowPerformanceRatingDetail()
01165 {
01166 AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
01167 }