(svn r117) Feature: Performance details window in company league menu (TrueLight)
authordominik
Mon, 23 Aug 2004 10:59:03 +0000
changeset 116 ca4332a9ec1d
parent 115 3a3c64e7be82
child 117 c7bbddbaf1da
(svn r117) Feature: Performance details window in company league menu (TrueLight)
economy.c
economy.h
graph_gui.c
gui.h
lang/english.txt
main_gui.c
misc.c
ttd.c
ttd.h
window.c
window.h
--- a/economy.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/economy.c	Mon Aug 23 10:59:03 2004 +0000
@@ -80,10 +80,14 @@
 	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 @@
 					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 @@
 				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 @@
 			} 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 @@
 				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 @@
 			if (p->num_valid_stat_ent != 24)
 				p->num_valid_stat_ent++;
 
-			UpdateCompanyRatingAndValue(p);
+			UpdateCompanyRatingAndValue(p, true);
 			PlayersCheckBankrupt(p);
 
 			if (p->block_preview != 0)
--- a/economy.h	Mon Aug 23 08:59:36 2004 +0000
+++ b/economy.h	Mon Aug 23 10:59:03 2004 +0000
@@ -23,6 +23,48 @@
 } 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);
--- a/graph_gui.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/graph_gui.c	Mon Aug 23 10:59:03 2004 +0000
@@ -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 @@
 		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 @@
 	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},
 };
--- a/gui.h	Mon Aug 23 08:59:36 2004 +0000
+++ b/gui.h	Mon Aug 23 10:59:03 2004 +0000
@@ -19,6 +19,7 @@
 void ShowCompanyValueGraph();
 void ShowCargoPaymentRates();
 void ShowCompanyLeagueTable();
+void ShowPerformanceRatingDetail();
 
 /* news_gui.c */
 void ShowLastNewsMessage();
--- a/lang/english.txt	Mon Aug 23 08:59:36 2004 +0000
+++ b/lang/english.txt	Mon Aug 23 10:59:03 2004 +0000
@@ -342,6 +342,7 @@
 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_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
+
--- a/main_gui.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/main_gui.c	Mon Aug 23 10:59:03 2004 +0000
@@ -202,7 +202,10 @@
 
 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 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)
--- a/misc.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/misc.c	Mon Aug 23 10:59:03 2004 +0000
@@ -601,11 +601,18 @@
 	/* 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;
 }
 
--- a/ttd.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/ttd.c	Mon Aug 23 10:59:03 2004 +0000
@@ -705,6 +705,9 @@
 	MarkWholeScreenDirty();
 }
 
+void StartupPlayers();
+void StartupDisasters();
+
 void StartScenario()
 {
 	_game_mode = GM_NORMAL;
--- a/ttd.h	Mon Aug 23 08:59:36 2004 +0000
+++ b/ttd.h	Mon Aug 23 10:59:03 2004 +0000
@@ -393,6 +393,7 @@
 	WC_INDUSTRY_DIRECTORY = 0x43,
 	WC_MESSAGE_HISTORY = 0x44,
 	WC_CHEATS = 0x45,
+	WC_PERFORMANCE_DETAIL = 0x46,
 };
 
 
--- a/window.c	Mon Aug 23 08:59:36 2004 +0000
+++ b/window.c	Mon Aug 23 10:59:03 2004 +0000
@@ -346,6 +346,8 @@
 	_last_window++;
 
 	SetWindowDirty(w);
+	
+	CallWindowEventNP(w, WE_CREATE);
 
 	return w;
 }
--- a/window.h	Mon Aug 23 08:59:36 2004 +0000
+++ b/window.h	Mon Aug 23 10:59:03 2004 +0000
@@ -293,6 +293,7 @@
 	WE_DROPDOWN_SELECT = 16,
 	WE_RCLICK = 17,
 	WE_KEYPRESS = 18,
+	WE_CREATE = 19,
 };