diff options
-rw-r--r-- | economy.c | 68 | ||||
-rw-r--r-- | economy.h | 42 | ||||
-rw-r--r-- | graph_gui.c | 228 | ||||
-rw-r--r-- | gui.h | 1 | ||||
-rw-r--r-- | lang/english.txt | 31 | ||||
-rw-r--r-- | main_gui.c | 7 | ||||
-rw-r--r-- | misc.c | 15 | ||||
-rw-r--r-- | ttd.c | 3 | ||||
-rw-r--r-- | ttd.h | 1 | ||||
-rw-r--r-- | window.c | 2 | ||||
-rw-r--r-- | window.h | 1 |
11 files changed, 373 insertions, 26 deletions
@@ -80,10 +80,14 @@ uint32 CalculateCompanyValue(Player *p) { return value; } -static void UpdateCompanyRatingAndValue(Player *p) +// if update is set to true, the economy is updated with this score +// (also the house is updated, should only be true in the on-tick event) +void UpdateCompanyRatingAndValue(Player *p, bool update) { byte owner = p->index; - uint score; + int score = 0; + + memset(_score_part[owner], 0, sizeof(_score_part[owner])); /* Count vehicles */ { @@ -100,16 +104,16 @@ static void UpdateCompanyRatingAndValue(Player *p) v->type == VEH_Ship) { num++; if (v->age > 730) { - if (min_profit >= v->profit_last_year) + if (min_profit > v->profit_last_year) min_profit = v->profit_last_year; } } } - score = (num < 120) ? num * 100 / 120 : 100; + _score_part[owner][SCORE_VEHICLES] = num; if (min_profit != MAX_INT && min_profit > 0) - score += (min_profit < 10000) ? min_profit/100 : 100; + _score_part[owner][SCORE_MIN_PROFIT] = min_profit; } /* Count stations */ @@ -123,7 +127,7 @@ static void UpdateCompanyRatingAndValue(Player *p) do num += facil&1; while (facil>>=1); } } - score += (num < 80) ? num * 100 / 80 : 100; + _score_part[owner][SCORE_STATIONS] = num; } /* Generate statistics depending on recent income statistics */ @@ -144,9 +148,9 @@ static void UpdateCompanyRatingAndValue(Player *p) } while (++pee,--numec); if (min_income > 0) - score += min_income >= 50000 ? 50 : min_income / 1000; + _score_part[owner][SCORE_MIN_INCOME] = min_income; - score += max_income >= 100000 ? 100 : max_income / 1000; + _score_part[owner][SCORE_MAX_INCOME] = max_income; } } @@ -164,35 +168,63 @@ static void UpdateCompanyRatingAndValue(Player *p) total_delivered += pee->delivered_cargo; } while (++pee,--numec); - score += total_delivered >= 40000 ? 400 : total_delivered / 100; + _score_part[owner][SCORE_DELIVERED] = total_delivered; } } - + /* Generate score for variety of cargo */ { uint cargo = p->cargo_types; uint num = 0; do num += cargo&1; while (cargo>>=1); - score += num < 8 ? num * 50 / 8 : 50; - p->cargo_types = 0; + _score_part[owner][SCORE_CARGO] = num; + if (update) + p->cargo_types = 0; } /* Generate score for player money */ { int32 money = p->player_money; if (money > 0) { - score += money < 10000000 ? money / (10000000/50) : 50; + _score_part[owner][SCORE_MONEY] = money; } } /* Generate score for loan */ { - score += (250000 - p->current_loan) >= 0 ? (250000 - p->current_loan) / 5000 : 0; + _score_part[owner][SCORE_LOAN] = score_info[SCORE_LOAN].needed - p->current_loan; + } + + // Now we calculate the score for each item.. + { + int i; + int total_score = 0; + int s; + score = 0; + for (i=0;i<NUM_SCORE;i++) { + // Skip the total + if (i == SCORE_TOTAL) continue; + // Check the score + s = (_score_part[owner][i] >= score_info[i].needed) ? score_info[i].score : ((_score_part[owner][i] * score_info[i].score) / score_info[i].needed); + if (s < 0) s = 0; + score += s; + total_score += score_info[i].score; + } + + _score_part[owner][SCORE_TOTAL] = score; + + // We always want the score scaled to SCORE_MAX (1000) + if (total_score != SCORE_MAX) + score = score * SCORE_MAX / total_score; } - p->old_economy[0].performance_history = score; - UpdatePlayerHouse(p, score); - p->old_economy[0].company_value = CalculateCompanyValue(p); + if (update) { + p->old_economy[0].performance_history = score; + UpdatePlayerHouse(p, score); + p->old_economy[0].company_value = CalculateCompanyValue(p); + } + + InvalidateWindow(WC_PERFORMANCE_DETAIL, 0); } // use 255 as new_player to delete the player. @@ -495,7 +527,7 @@ static void PlayersGenStatistics() if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++; - UpdateCompanyRatingAndValue(p); + UpdateCompanyRatingAndValue(p, true); PlayersCheckBankrupt(p); if (p->block_preview != 0) @@ -23,6 +23,48 @@ typedef struct Subsidy { } Subsidy; +enum { + SCORE_VEHICLES = 0, + SCORE_STATIONS = 1, + SCORE_MIN_PROFIT = 2, + SCORE_MIN_INCOME = 3, + SCORE_MAX_INCOME = 4, + SCORE_DELIVERED = 5, + SCORE_CARGO = 6, + SCORE_MONEY = 7, + SCORE_LOAN = 8, + SCORE_TOTAL = 9, // This must always be the last entry + + NUM_SCORE = 10, // How many scores are there.. + + SCORE_MAX = 1000, // The max score that can be in the performance history + // the scores together of score_info is allowed to be more! +}; + +typedef struct ScoreInfo { + byte id; // Unique ID of the score + int needed; // How much you need to get the perfect score + int score; // How much score it will give +} ScoreInfo; + +static const ScoreInfo score_info[] = { + {SCORE_VEHICLES, 120, 100}, + {SCORE_STATIONS, 80, 100}, + {SCORE_MIN_PROFIT, 10000, 100}, + {SCORE_MIN_INCOME, 50000, 50}, + {SCORE_MAX_INCOME, 100000, 100}, + {SCORE_DELIVERED, 40000, 400}, + {SCORE_CARGO, 8, 50}, + {SCORE_MONEY, 10000000, 50}, + {SCORE_LOAN, 250000, 50}, + {SCORE_TOTAL} +}; + +int _score_part[MAX_PLAYERS][NUM_SCORE]; + +void UpdateCompanyRatingAndValue(Player *p, bool update); + + VARDEF Subsidy _subsidies[MAX_PLAYERS]; Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode); void DeleteSubsidyWithIndustry(byte index); diff --git a/graph_gui.c b/graph_gui.c index fcb6f81d8..119bea8b4 100644 --- a/graph_gui.c +++ b/graph_gui.c @@ -4,6 +4,7 @@ #include "gui.h" #include "gfx.h" #include "player.h" +#include "economy.h" static uint _legend_showbits; static uint _legend_cargobits; @@ -511,7 +512,227 @@ void ShowDeliveredCargoGraph() InvalidateWindow(WC_GRAPH_LEGEND, 0); _legend_showbits = 0; } -} +} + +/*****************************/ +/* PERFORMANCE RATING DETAIL */ +/*****************************/ + +static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e) +{ + switch(e->event) { + case WE_PAINT: { + int val, needed, score, i; + byte owner, x; + uint16 y=14; + int total_score = 0; + int color_done, color_notdone; + + // Draw standard stuff + DrawWindowWidgets(w); + + // The player of which we check the detail performance rating + owner = FindFirstBit(w->click_state) - 13; + + // Paint the player icons + for (i=0;i<MAX_PLAYERS;i++) { + if (!DEREF_PLAYER(i)->is_active) { + // Check if we have the player as an active player + if (!(w->disabled_state & (1 << (i+13)))) { + // Bah, player gone :( + w->disabled_state += 1 << (i+13); + // Is this player selected? If so, select first player (always save? :s) + if (w->click_state == 1 << (i+13)) + w->click_state = 1 << 13; + // We need a repaint + SetWindowDirty(w); + } + continue; + } + + // Check if we have the player marked as inactive + if ((w->disabled_state & (1 << (i+13)))) { + // New player! Yippie :p + w->disabled_state -= 1 << (i+13); + // We need a repaint + SetWindowDirty(w); + } + + if (i == owner) x = 1; else x = 0; + DrawPlayerIcon(i, i*33+11+x, 16+x); + } + + // The colors used to show how the progress is going + color_done = _color_list[6].window_color_1b; + color_notdone = _color_list[4].window_color_1b; + + // Draw all the score parts + for (i=0;i<NUM_SCORE;i++) { + y += 20; + val = _score_part[owner][i]; + needed = score_info[i].needed; + score = score_info[i].score; + // SCORE_TOTAL has his own rulez ;) + if (i == SCORE_TOTAL) { + needed = total_score; + score = SCORE_MAX; + } else + total_score += score; + + DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0); + + // Draw the score + SET_DPARAM32(0, score); + DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0); + + // Calculate the %-bar + if (val > needed) x = 50; + else if (val == 0) x = 0; + else x = ((val * 50) / needed); + + // SCORE_LOAN is inversed + if (val < 0 && i == SCORE_LOAN) + x = 0; + + // Draw the bar + if (x != 0) + GfxFillRect(112, y-2, x + 112, y+10, color_done); + if (x != 50) + GfxFillRect(x + 112, y-2, 50 + 112, y+10, color_notdone); + + // Calculate the % + if (val > needed) x = 100; + else x = ((val * 100) / needed); + + // SCORE_LOAN is inversed + if (val < 0 && i == SCORE_LOAN) + x = 0; + + // Draw it + SET_DPARAM32(0, x); + DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0); + + // SCORE_LOAN is inversed + if (i == SCORE_LOAN) + val = needed - val; + + // Draw the amount we have against what is needed + // For some of them it is in currency format + SET_DPARAM32(0, val); + SET_DPARAM32(1, needed); + switch (i) { + case SCORE_MIN_PROFIT: + case SCORE_MIN_INCOME: + case SCORE_MAX_INCOME: + case SCORE_MONEY: + case SCORE_LOAN: + DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0); + break; + default: + DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0); + } + } + + break; + } + + case WE_CLICK: + // Check which button is clicked + if (IS_INT_INSIDE(e->click.widget, 13, 21)) { + // Is it no on disable? + if ((w->disabled_state & (1 << e->click.widget)) == 0) { + w->click_state = 1 << e->click.widget; + SetWindowDirty(w); + } + } + break; + + case WE_CREATE: + { + int i; + Player *p2; + w->hidden_state = 0; + w->disabled_state = 0; + + // Hide the player who are not active + for (i=0;i<MAX_PLAYERS;i++) { + if (!DEREF_PLAYER(i)->is_active) { + w->disabled_state += 1 << (i+13); + } + } + // Update all player stats with the current data + // (this is because _score_info is not saved to a savegame) + FOR_ALL_PLAYERS(p2) + if (p2->is_active) + UpdateCompanyRatingAndValue(p2, false); + + w->custom[0] = 74; + w->custom[1] = 5; + + w->click_state = 1 << 13; + + SetWindowDirty(w); + } + break; + case WE_TICK: + { + // Update the player score every 5 days + if (--w->custom[0] == 0) { + w->custom[0] = 74; + if (--w->custom[1] == 0) { + Player *p2; + w->custom[1] = 5; + FOR_ALL_PLAYERS(p2) + // Skip if player is not active + if (p2->is_active) + UpdateCompanyRatingAndValue(p2, false); + SetWindowDirty(w); + } + } + } + break; + } +} + +static const Widget _performance_rating_detail_widgets[] = { +{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, 14, 11, 266, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_IMGBTN, 14, 0, 266, 14, 27, 0x0}, + +{ WWT_IMGBTN, 14, 0, 266, 28, 47, 0x0,STR_PERFORMANCE_DETAIL_VEHICLES_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 48, 67, 0x0,STR_PERFORMANCE_DETAIL_STATIONS_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 68, 87, 0x0,STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 88, 107, 0x0,STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 108, 127, 0x0,STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 128, 147, 0x0,STR_PERFORMANCE_DETAIL_DELIVERED_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 148, 167, 0x0,STR_PERFORMANCE_DETAIL_CARGO_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 168, 187, 0x0,STR_PERFORMANCE_DETAIL_MONEY_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 188, 207, 0x0,STR_PERFORMANCE_DETAIL_LOAN_TIP}, +{ WWT_IMGBTN, 14, 0, 266, 208, 227, 0x0,STR_PERFORMANCE_DETAIL_TOTAL_TIP}, + +{ WWT_IMGBTN, 14, 2, 34, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 35, 67, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 68, 100, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 101, 133, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 134, 166, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 167, 199, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 200, 232, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_IMGBTN, 14, 233, 265, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, +{ WWT_LAST}, +}; + +static const WindowDesc _performance_rating_detail_desc = { + -1, -1, 267, 228, + WC_PERFORMANCE_DETAIL,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, + _performance_rating_detail_widgets, + PerformanceRatingDetailWndProc +}; + +void ShowPerformanceRatingDetail() +{ + AllocateWindowDescFront(&_performance_rating_detail_desc, 0); +} /***********************/ /* PERFORMANCE HISTORY */ @@ -558,14 +779,17 @@ static void PerformanceHistoryWndProc(Window *w, WindowEvent *e) case WE_CLICK: if (e->click.widget == 2) ShowGraphLegend(); + if (e->click.widget == 3) + ShowPerformanceRatingDetail(); break; } } static const Widget _performance_history_widgets[] = { { WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_CAPTION, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, +{ WWT_PUSHTXTBTN, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_IMGBTN, 14, 0, 575, 14, 237, 0x0}, { WWT_LAST}, }; @@ -19,6 +19,7 @@ void ShowPerformanceHistoryGraph(); void ShowCompanyValueGraph(); void ShowCargoPaymentRates(); void ShowCompanyLeagueTable(); +void ShowPerformanceRatingDetail(); /* news_gui.c */ void ShowLastNewsMessage(); diff --git a/lang/english.txt b/lang/english.txt index d999370a8..4ad0a2a2e 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -342,6 +342,7 @@ STR_0157_PERFORMANCE_HISTORY_GRAPH :Performance history graph STR_0158_COMPANY_VALUE_GRAPH :Company value graph STR_0159_CARGO_PAYMENT_RATES :Cargo payment rates STR_015A_COMPANY_LEAGUE_TABLE :Company league table +STR_PERFORMANCE_DETAIL_MENU :Detail performance rating ############ range for menu ends STR_015B_OPENTTD :{WHITE}About OpenTTD @@ -2518,3 +2519,33 @@ STR_B005_COAL_MINE_SUBSIDENCE_LEAVES :{BLACK}{BIGFONT}Coal mine subsidence leave STR_BRIBE_FAILED :{WHITE}Your attempted bribery has been STR_BRIBE_FAILED_2 :{WHITE}discovered by a regional investigator STR_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} + +STR_PERFORMANCE_DETAIL :{WHITE}Detail performance rating +STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detail +STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}{TINYFONT}({CURRCOMPACT}/{CURRCOMPACT}) +STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}{TINYFONT}({INT32}/{INT32}) +STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{INT32}% +SET_PERFORMANCE_DETAIL_INT :{BLACK}{INT32} +############ Those following lines need to be in this order!! +STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vehicles: +STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stations: +STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. profit: +STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. income: +STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. income: +STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Delivered: +STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Cargo: +STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Money: +STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Loan: +STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: +############ End of order list +STR_PERFORMANCE_DETAIL_VEHICLES_TIP :{BLACK}Amount of vehicles. This includes road vehicles, trains, ships and aircraft. +STR_PERFORMANCE_DETAIL_STATIONS_TIP :{BLACK}Amount of station parts. Every part of a station (e.g. train station, bus stop, airport) is counted, even if they are connected to one station. +STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP :{BLACK}The minimum profit of all the vehicles that are more than 2 years old. +STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP :{BLACK}Amount of cash made in the month with the lowest profit of the past 12 quarters +STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP :{BLACK}Amount of cash made in the month with the highest profit of the past 12 quarters +STR_PERFORMANCE_DETAIL_DELIVERED_TIP :{BLACK}Units of cargo delivered in the past four quarters. +STR_PERFORMANCE_DETAIL_CARGO_TIP :{BLACK}Types of cargo delivered in the last quarter. +STR_PERFORMANCE_DETAIL_MONEY_TIP :{BLACK}Amount of cash on hand +STR_PERFORMANCE_DETAIL_LOAN_TIP :{BLACK}Do you have a high loan? +STR_PERFORMANCE_DETAIL_TOTAL_TIP :{BLACK}Total points out of possible points + diff --git a/main_gui.c b/main_gui.c index 9d6c6f5b7..f5eec080b 100644 --- a/main_gui.c +++ b/main_gui.c @@ -202,7 +202,10 @@ void MenuClickGraphs(int index) void MenuClickLeague(int index) { - ShowCompanyLeagueTable(); + switch(index) { + case 0: ShowCompanyLeagueTable(); return; + case 1: ShowPerformanceRatingDetail(); return; + } } void MenuClickIndustry(int index) @@ -648,7 +651,7 @@ static void ToolbarGraphsClick(Window *w) static void ToolbarLeagueClick(Window *w) { - PopupMainToolbMenu(w, 258, 11, STR_015A_COMPANY_LEAGUE_TABLE, 1); + PopupMainToolbMenu(w, 258, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2); } static void ToolbarIndustryClick(Window *w) @@ -601,11 +601,18 @@ void IncreaseDate() /* XXX: check if year 2050 was reached */ } -int FindFirstBit(uint32 x) +int FindFirstBit(uint32 value) { - int i = 0; - assert(x != 0); - for(;!(x&1);i++,x>>=1); + // This is much faster then the one that was before here. + // Created by Darkvater.. blame him if it is wrong ;) + // Btw, the macro FINDFIRSTBIT is better to use when your value is + // not more then 128. + byte i = 0; + if (value & 0xffff0000) { value >>= 16; i += 16; } + if (value & 0x0000ff00) { value >>= 8; i += 8; } + if (value & 0x000000f0) { value >>= 4; i += 4; } + if (value & 0x0000000c) { value >>= 2; i += 2; } + if (value & 0x00000002) { i += 1; } return i; } @@ -705,6 +705,9 @@ void MakeNewEditorWorld() MarkWholeScreenDirty(); } +void StartupPlayers(); +void StartupDisasters(); + void StartScenario() { _game_mode = GM_NORMAL; @@ -393,6 +393,7 @@ enum { WC_INDUSTRY_DIRECTORY = 0x43, WC_MESSAGE_HISTORY = 0x44, WC_CHEATS = 0x45, + WC_PERFORMANCE_DETAIL = 0x46, }; @@ -346,6 +346,8 @@ restart:; _last_window++; SetWindowDirty(w); + + CallWindowEventNP(w, WE_CREATE); return w; } @@ -293,6 +293,7 @@ enum WindowEvents { WE_DROPDOWN_SELECT = 16, WE_RCLICK = 17, WE_KEYPRESS = 18, + WE_CREATE = 19, }; |