1 /*
2  * Copyright (c) 1997 - 2002 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic licence.
5  * (see licence.txt)
6  */
7 
8 #include <algorithm>
9 #include "../vehicle/simvehicle.h"
10 #include "../player/simplay.h"
11 #include "../simdebug.h"
12 #include "../utils/simrandom.h"
13 #include "../simtypes.h"
14 
15 #include "../dataobj/environment.h"
16 #include "../dataobj/tabfile.h"
17 #include "../dataobj/loadsave.h"
18 #include "../dataobj/translator.h"
19 
20 #include "../descriptor/vehicle_desc.h"
21 #include "../gui/depot_frame.h"
22 
23 #include "vehikelbauer.h"
24 
25 #include "../tpl/stringhashtable_tpl.h"
26 
27 
28 static stringhashtable_tpl<const vehicle_desc_t*> name_fahrzeuge;
29 
30 // index 0 aur, 1...8 at normal waytype index
31 #define GET_WAYTYPE_INDEX(wt) ((int)(wt)>8 ? 0 : (wt))
32 static slist_tpl<const vehicle_desc_t*> typ_fahrzeuge[depot_frame_t::sb_length][9];
33 static uint8 tmp_sort_idx;
34 
35 class bonus_record_t {
36 public:
37 	sint32 year;
38 	sint32 speed;
bonus_record_t(sint32 y=0,sint32 kmh=0)39 	bonus_record_t( sint32 y=0, sint32 kmh=0 ) {
40 		year = y*12;
41 		speed = kmh;
42 	};
rdwr(loadsave_t * file)43 	void rdwr(loadsave_t *file) {
44 		file->rdwr_long(year);
45 		file->rdwr_long(speed);
46 	}
47 };
48 
49 // speed bonus
50 static vector_tpl<bonus_record_t>speedbonus[8];
51 
52 static sint32 default_speedbonus[8] =
53 {
54 	60,	// road
55 	80,	// track
56 	35,	// water
57 	350,	// air
58 	80,	// monorail
59 	200,	// maglev
60 	60,	// tram
61 	60	// narrowgauge
62 };
63 
speedbonus_init(const std::string & objfilename)64 bool vehicle_builder_t::speedbonus_init(const std::string &objfilename)
65 {
66 	tabfile_t bonusconf;
67 	// first take user data, then user global data
68 	if (!bonusconf.open((objfilename+"config/speedbonus.tab").c_str())) {
69 		dbg->warning("vehicle_builder_t::speedbonus_init()", "Can't read speedbonus.tab" );
70 		return false;
71 	}
72 
73 	tabfileobj_t contents;
74 	bonusconf.read(contents);
75 
76 	/* init the values from line with the form year, speed, year, speed
77 	 * must be increasing order!
78 	 */
79 	for(  int j=0;  j<8;  j++  ) {
80 		int *tracks = contents.get_ints(weg_t::waytype_to_string(j==3?air_wt:(waytype_t)(j+1)));
81 		if((tracks[0]&1)==1) {
82 			dbg->warning( "vehicle_builder_t::speedbonus_init()", "Ill formed line in speedbonus.tab\nFormat is year,speed[,year,speed]!" );
83 			tracks[0]--;
84 		}
85 		speedbonus[j].resize( tracks[0]/2 );
86 		for(  int i=1;  i<tracks[0];  i+=2  ) {
87 			bonus_record_t b( tracks[i], tracks[i+1] );
88 			speedbonus[j].append( b );
89 		}
90 		delete [] tracks;
91 	}
92 
93 	return true;
94 }
95 
96 
get_speedbonus(sint32 monthyear,waytype_t wt)97 sint32 vehicle_builder_t::get_speedbonus( sint32 monthyear, waytype_t wt )
98 {
99 	const int typ = wt==air_wt ? 3 : (wt-1)&7;
100 
101 	if(  monthyear==0  ) {
102 		return default_speedbonus[typ];
103 	}
104 
105 	// ok, now lets see if we have data for this
106 	vector_tpl<bonus_record_t> const& b = speedbonus[typ];
107 	if (!b.empty()) {
108 		uint i=0;
109 		while (i < b.get_count() && monthyear >= b[i].year) {
110 			i++;
111 		}
112 		if (i == b.get_count()) {
113 			// maxspeed already?
114 			return b[i - 1].speed;
115 		}
116 		else if(i==0) {
117 			// minspeed below
118 			return b[0].speed;
119 		}
120 		else {
121 			// interpolate linear
122 			sint32 const delta_speed = b[i].speed - b[i - 1].speed;
123 			sint32 const delta_years = b[i].year  - b[i - 1].year;
124 			return delta_speed * (monthyear - b[i - 1].year) / delta_years + b[i - 1].speed;
125 		}
126 	}
127 	else {
128 		sint32 speed_sum = 0;
129 		sint32 num_averages = 0;
130 		// needs to do it the old way => iterate over all vehicles with this type ...
131 		FOR(slist_tpl<vehicle_desc_t const*>, const info, typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) {
132 			if(  info->get_power()>0  &&  info->is_available(monthyear)  ) {
133 				speed_sum += info->get_topspeed();
134 				num_averages ++;
135 			}
136 		}
137 		if(  num_averages>0  ) {
138 			return speed_sum / num_averages;
139 		}
140 	}
141 
142 	// no vehicles => return default
143 	return default_speedbonus[typ];
144 }
145 
146 
rdwr_speedbonus(loadsave_t * file)147 void vehicle_builder_t::rdwr_speedbonus(loadsave_t *file)
148 {
149 	for(  int j=0;  j<8;  j++  ) {
150 		uint32 count = speedbonus[j].get_count();
151 		file->rdwr_long(count);
152 		if (file->is_loading()) {
153 			speedbonus[j].clear();
154 			speedbonus[j].resize(count);
155 		}
156 		for(uint32 i=0; i<count; i++) {
157 			if (file->is_loading()) {
158 				speedbonus[j].append(bonus_record_t());
159 			}
160 			speedbonus[j][i].rdwr(file);
161 		}
162 	}
163 }
164 
165 
build(koord3d k,player_t * player,convoi_t * cnv,const vehicle_desc_t * vb)166 vehicle_t* vehicle_builder_t::build(koord3d k, player_t* player, convoi_t* cnv, const vehicle_desc_t* vb )
167 {
168 	vehicle_t* v;
169 	switch (vb->get_waytype()) {
170 		case road_wt:     v = new road_vehicle_t(      k, vb, player, cnv); break;
171 		case monorail_wt: v = new monorail_vehicle_t(k, vb, player, cnv); break;
172 		case track_wt:
173 		case tram_wt:     v = new rail_vehicle_t(         k, vb, player, cnv); break;
174 		case water_wt:    v = new water_vehicle_t(         k, vb, player, cnv); break;
175 		case air_wt:      v = new air_vehicle_t(       k, vb, player, cnv); break;
176 		case maglev_wt:   v = new maglev_vehicle_t(  k, vb, player, cnv); break;
177 		case narrowgauge_wt:v = new narrowgauge_vehicle_t(k, vb, player, cnv); break;
178 
179 		default:
180 			dbg->fatal("vehicle_builder_t::build()", "cannot built a vehicle with waytype %i", vb->get_waytype());
181 	}
182 
183 	player->book_new_vehicle(-(sint64)vb->get_price(), k.get_2d(), vb->get_waytype() );
184 
185 	return v;
186 }
187 
188 
189 
register_desc(const vehicle_desc_t * desc)190 bool vehicle_builder_t::register_desc(const vehicle_desc_t *desc)
191 {
192 	// register waytype list
193 	const int wt_idx = GET_WAYTYPE_INDEX( desc->get_waytype() );
194 
195 	// first hashtable
196 	vehicle_desc_t const *old_desc = name_fahrzeuge.get( desc->get_name() );
197 	if(  old_desc  ) {
198 		dbg->doubled( "vehicle", desc->get_name() );
199 		name_fahrzeuge.remove( desc->get_name() );
200 	}
201 	name_fahrzeuge.put(desc->get_name(), desc);
202 
203 	// now add it to sorter (may be more than once!)
204 	for(  int sort_idx = 0;  sort_idx < depot_frame_t::sb_length;  sort_idx++  ) {
205 		if(  old_desc  ) {
206 			typ_fahrzeuge[sort_idx][wt_idx].remove(old_desc);
207 		}
208 		typ_fahrzeuge[sort_idx][wt_idx].append(desc);
209 	}
210 
211 	return true;
212 }
213 
214 
215 
216 // compare funcions to sort vehicle in the list
compare_freight(const vehicle_desc_t * a,const vehicle_desc_t * b)217 static int compare_freight(const vehicle_desc_t* a, const vehicle_desc_t* b)
218 {
219 	int cmp = a->get_freight_type()->get_catg() - b->get_freight_type()->get_catg();
220 	if (cmp != 0) return cmp;
221 	if (a->get_freight_type()->get_catg() == 0) {
222 		cmp = a->get_freight_type()->get_index() - b->get_freight_type()->get_index();
223 	}
224 	return cmp;
225 }
compare_capacity(const vehicle_desc_t * a,const vehicle_desc_t * b)226 static int compare_capacity(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_capacity() - b->get_capacity(); }
compare_engine(const vehicle_desc_t * a,const vehicle_desc_t * b)227 static int compare_engine(const vehicle_desc_t* a, const vehicle_desc_t* b) {
228 	return (a->get_capacity() + a->get_power() == 0 ? (uint8)vehicle_desc_t::steam : a->get_engine_type()) - (b->get_capacity() + b->get_power() == 0 ? (uint8)vehicle_desc_t::steam : b->get_engine_type());
229 }
compare_price(const vehicle_desc_t * a,const vehicle_desc_t * b)230 static int compare_price(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_price() - b->get_price(); }
compare_cost(const vehicle_desc_t * a,const vehicle_desc_t * b)231 static int compare_cost(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_running_cost() - b->get_running_cost(); }
compare_cost_per_unit(const vehicle_desc_t * a,const vehicle_desc_t * b)232 static int compare_cost_per_unit(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_running_cost()*b->get_capacity() - b->get_running_cost()*a->get_capacity(); }
compare_topspeed(const vehicle_desc_t * a,const vehicle_desc_t * b)233 static int compare_topspeed(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_topspeed() - b->get_topspeed();}
compare_power(const vehicle_desc_t * a,const vehicle_desc_t * b)234 static int compare_power(const vehicle_desc_t* a, const vehicle_desc_t* b)	{return (a->get_power() == 0 ? 0x7FFFFFF : a->get_power()) - (b->get_power() == 0 ? 0x7FFFFFF : b->get_power());}
compare_weight(const vehicle_desc_t * a,const vehicle_desc_t * b)235 static int compare_weight(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_weight() - b->get_weight();}
compare_intro_year_month(const vehicle_desc_t * a,const vehicle_desc_t * b)236 static int compare_intro_year_month(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_intro_year_month() - b->get_intro_year_month();}
compare_retire_year_month(const vehicle_desc_t * a,const vehicle_desc_t * b)237 static int compare_retire_year_month(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_retire_year_month() - b->get_retire_year_month();}
238 
239 
240 
241 // default compare function
compare_vehicles(const vehicle_desc_t * a,const vehicle_desc_t * b)242 static bool compare_vehicles(const vehicle_desc_t* a, const vehicle_desc_t* b)
243 {
244 	int cmp = compare_freight(a, b);
245 	if (cmp != 0) return cmp < 0;
246 	switch (tmp_sort_idx) {
247 		case depot_frame_t::sb_name:
248 			cmp = strcmp(translator::translate(a->get_name()), translator::translate(b->get_name()));
249 			if (cmp != 0) return cmp < 0;
250 			break;
251 		case depot_frame_t::sb_price:
252 			cmp = compare_price(a, b);
253 			if (cmp != 0) return cmp < 0;
254 		case depot_frame_t::sb_cost:
255 			cmp = compare_cost(a, b);
256 			if (cmp != 0) return cmp < 0;
257 			cmp = compare_price(a, b);
258 			if (cmp != 0) return cmp < 0;
259 			break;
260 		case depot_frame_t::sb_cost_per_unit:
261 			cmp = compare_cost_per_unit(a,b);
262 			if (cmp != 0) return cmp < 0;
263 			break;
264 		case depot_frame_t::sb_speed:
265 			cmp = compare_topspeed(a, b);
266 			if (cmp != 0) return cmp < 0;
267 			break;
268 		case depot_frame_t::sb_weight:
269 			cmp = compare_weight(a, b);
270 			if (cmp != 0) return cmp < 0;
271 			break;
272 		case depot_frame_t::sb_power:
273 			cmp = compare_power(a, b);
274 			if (cmp != 0) return cmp < 0;
275 			break;
276 		case depot_frame_t::sb_intro_date:
277 			cmp = compare_intro_year_month(a, b);
278 			if (cmp != 0) return cmp < 0;
279 		case depot_frame_t::sb_retire_date:
280 			cmp = compare_retire_year_month(a, b);
281 			if (cmp != 0) return cmp < 0;
282 			cmp = compare_intro_year_month(a, b);
283 			if (cmp != 0) return cmp < 0;
284 			break;
285 	}
286 	// Sort by:
287 	//  1. cargo category
288 	//  2. cargo (if special freight)
289 	//  3. engine_type
290 	//  4. speed
291 	//  5. power
292 	//  6. intro date
293 	//  7. name
294 	cmp = compare_capacity(a, b);
295 	if (cmp != 0) return cmp < 0;
296 	cmp = compare_engine(a, b);
297 	if (cmp != 0) return cmp < 0;
298 	cmp = compare_topspeed(a, b);
299 	if (cmp != 0) return cmp < 0;
300 	cmp = compare_power(a, b);
301 	if (cmp != 0) return cmp < 0;
302 	cmp = compare_intro_year_month(a, b);
303 	if (cmp != 0) return cmp < 0;
304 	cmp = strcmp(translator::translate(a->get_name()), translator::translate(b->get_name()));
305 	return cmp < 0;
306 }
307 
308 
309 
successfully_loaded()310 bool vehicle_builder_t::successfully_loaded()
311 {
312 	// first: check for bonus tables
313 	DBG_MESSAGE("vehicle_builder_t::sort_lists()","called");
314 	for (  int sort_idx = 0; sort_idx < depot_frame_t::sb_length; sort_idx++  ) {
315 		for(  int wt_idx=0;  wt_idx<9;  wt_idx++  ) {
316 			tmp_sort_idx = sort_idx;
317 			slist_tpl<const vehicle_desc_t*>& typ_liste = typ_fahrzeuge[sort_idx][wt_idx];
318 			uint count = typ_liste.get_count();
319 			if (count == 0) {
320 				continue;
321 			}
322 			const vehicle_desc_t** const tmp     = new const vehicle_desc_t*[count];
323 			const vehicle_desc_t** const tmp_end = tmp + count;
324 			for(  const vehicle_desc_t** tmpptr = tmp;  tmpptr != tmp_end;  tmpptr++  ) {
325 				*tmpptr = typ_liste.remove_first();
326 			}
327 			std::sort(tmp, tmp_end, compare_vehicles);
328 			for(  const vehicle_desc_t** tmpptr = tmp;  tmpptr != tmp_end;  tmpptr++  ) {
329 				typ_liste.append(*tmpptr);
330 			}
331 			delete [] tmp;
332 		}
333 	}
334 	return true;
335 }
336 
337 
338 
get_info(const char * name)339 const vehicle_desc_t *vehicle_builder_t::get_info(const char *name)
340 {
341 	return name_fahrzeuge.get(name);
342 }
343 
344 
get_info(waytype_t const typ,uint8 sortkey)345 slist_tpl<vehicle_desc_t const*> const & vehicle_builder_t::get_info(waytype_t const typ, uint8 sortkey)
346 {
347 	return typ_fahrzeuge[sortkey][GET_WAYTYPE_INDEX(typ)];
348 }
349 
350 
351 /* extended search for vehicles for KI *
352  * checks also timeline and constraints
353  * tries to get best with but adds a little random action
354  * @author prissi
355  */
vehikel_search(waytype_t wt,const uint16 month_now,const uint32 target_weight,const sint32 target_speed,const goods_desc_t * target_freight,bool include_electric,bool not_obsolete)356 const vehicle_desc_t *vehicle_builder_t::vehikel_search( waytype_t wt, const uint16 month_now, const uint32 target_weight, const sint32 target_speed, const goods_desc_t * target_freight, bool include_electric, bool not_obsolete )
357 {
358 	const vehicle_desc_t *desc = NULL;
359 	sint32 desc_index = -100000;
360 
361 	if(  target_freight==NULL  &&  target_weight==0  ) {
362 		// no power, no freight => no vehicle to search
363 		return NULL;
364 	}
365 
366 	FOR(slist_tpl<vehicle_desc_t const*>, const test_desc, typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) {
367 		// no constricts allow for rail vehicles concerning following engines
368 		if(wt==track_wt  &&  !test_desc->can_follow_any()  ) {
369 			continue;
370 		}
371 		// do not buy incomplete vehicles
372 		if(wt==road_wt && !test_desc->can_lead(NULL)) {
373 			continue;
374 		}
375 
376 		// engine, but not allowed to lead a convoi, or no power at all or no electrics allowed
377 		if(target_weight) {
378 			if(test_desc->get_power()==0  ||  !test_desc->can_follow(NULL)  ||  (!include_electric  &&  test_desc->get_engine_type()==vehicle_desc_t::electric) ) {
379 				continue;
380 			}
381 		}
382 
383 		// check for waytype too
384 		if(test_desc->get_waytype()!=wt  ||  test_desc->is_future(month_now)  ) {
385 			continue;
386 		}
387 
388 		if(  not_obsolete  &&  test_desc->is_retired(month_now)  ) {
389 			// not using vintage cars here!
390 			continue;
391 		}
392 
393 		uint32 power = (test_desc->get_power()*test_desc->get_gear())/64;
394 		if(target_freight) {
395 			// this is either a railcar/trailer or a truck/boat/plane
396 			if(  test_desc->get_capacity()==0  ||  !test_desc->get_freight_type()->is_interchangeable(target_freight)  ) {
397 				continue;
398 			}
399 
400 			sint32 difference=0;	// smaller is better
401 			// assign this vehicle if we have not found one yet, or we only found one too weak
402 			if(  desc!=NULL  ) {
403 				// is it cheaper to run? (this is most important)
404 				difference += (desc->get_capacity()*1000)/(1+desc->get_running_cost()) < (test_desc->get_capacity()*1000)/(1+test_desc->get_running_cost()) ? -20 : 20;
405 				if(  target_weight>0  ) {
406 					// is it stronger?
407 					difference += (desc->get_power()*desc->get_gear())/64 < power ? -10 : 10;
408 				}
409 				// is it faster? (although we support only up to 120km/h for goods)
410 				difference += (desc->get_topspeed() < test_desc->get_topspeed())? -10 : 10;
411 				// is it cheaper? (not so important)
412 				difference += (desc->get_price() > test_desc->get_price())? -5 : 5;
413 				// add some malus for obsolete vehicles
414 				if(test_desc->is_retired(month_now)) {
415 					difference += 5;
416 				}
417 			}
418 			// ok, final check
419 			if(  desc==NULL  ||  difference<(int)simrand(25)    ) {
420 				// then we want this vehicle!
421 				desc = test_desc;
422 				DBG_MESSAGE( "vehicle_builder_t::vehikel_search","Found car %s",desc->get_name());
423 			}
424 		}
425 
426 		else {
427 			// engine/tugboat/truck for trailer
428 			if(  test_desc->get_capacity()!=0  ||  !test_desc->can_follow(NULL)  ) {
429 				continue;
430 			}
431 			// finally, we might be able to use this vehicle
432 			sint32 speed = test_desc->get_topspeed();
433 			uint32 max_weight = power/( (speed*speed)/2500 + 1 );
434 
435 			// we found a useful engine
436 			sint32 current_index = (power * 100) / (1 + test_desc->get_running_cost()) + test_desc->get_topspeed() - test_desc->get_weight() / 1000 - (sint32)(test_desc->get_price() / 25000);
437 			// too slow?
438 			if(speed < target_speed) {
439 				current_index -= 250;
440 			}
441 			// too weak to reach full speed?
442 			if(  max_weight < target_weight+test_desc->get_weight()/1000  ) {
443 				current_index += max_weight - (sint32)(target_weight+test_desc->get_weight()/1000);
444 			}
445 			current_index += simrand(100);
446 			if(  current_index > desc_index  ) {
447 				// then we want this vehicle!
448 				desc = test_desc;
449 				desc_index = current_index;
450 				DBG_MESSAGE( "vehicle_builder_t::vehikel_search","Found engine %s",desc->get_name());
451 			}
452 		}
453 	}
454 	// no vehicle found!
455 	if(  desc==NULL  ) {
456 		DBG_MESSAGE( "vehicle_builder_t::vehikel_search()","could not find a suitable vehicle! (speed %i, weight %i)",target_speed,target_weight);
457 	}
458 	return desc;
459 }
460 
461 
462 
463 /* extended search for vehicles for replacement on load time
464  * tries to get best match (no random action)
465  * if prev_desc==NULL, then the convoi must be able to lead a convoi
466  * @author prissi
467  */
get_best_matching(waytype_t wt,const uint16 month_now,const uint32 target_weight,const uint32 target_power,const sint32 target_speed,const goods_desc_t * target_freight,bool not_obsolete,const vehicle_desc_t * prev_veh,bool is_last)468 const vehicle_desc_t *vehicle_builder_t::get_best_matching( waytype_t wt, const uint16 month_now, const uint32 target_weight, const uint32 target_power, const sint32 target_speed, const goods_desc_t * target_freight, bool not_obsolete, const vehicle_desc_t *prev_veh, bool is_last )
469 {
470 	const vehicle_desc_t *desc = NULL;
471 	sint32 desc_index = -100000;
472 
473 	FOR(slist_tpl<vehicle_desc_t const*>, const test_desc, typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) {
474 		if(target_power>0  &&  test_desc->get_power()==0) {
475 			continue;
476 		}
477 
478 		// will test for first (prev_veh==NULL) or matching following vehicle
479 		if(!test_desc->can_follow(prev_veh)) {
480 			continue;
481 		}
482 
483 		// not allowed as last vehicle
484 		if(is_last  &&  test_desc->get_trailer_count()>0  &&  test_desc->get_trailer(0)!=NULL  ) {
485 			continue;
486 		}
487 
488 		// not allowed as non-last vehicle
489 		if(!is_last  &&  test_desc->get_trailer_count()==1  &&  test_desc->get_trailer(0)==NULL  ) {
490 			continue;
491 		}
492 
493 		// check for waytype too
494 		if(test_desc->get_waytype()!=wt  ||  test_desc->is_future(month_now)  ) {
495 			continue;
496 		}
497 
498 		// ignore vehicles that need electrification
499 		if(test_desc->get_power()>0  &&  test_desc->get_engine_type()==vehicle_desc_t::electric) {
500 			continue;
501 		}
502 
503 		// likely tender => replace with some engine ...
504 		if(target_freight==0  &&  target_weight==0) {
505 			if(  test_desc->get_capacity()!=0  ) {
506 				continue;
507 			}
508 		}
509 
510 		if(  not_obsolete  &&  test_desc->is_retired(month_now)  ) {
511 			// not using vintage cars here!
512 			continue;
513 		}
514 
515 		uint32 power = (test_desc->get_power()*test_desc->get_gear())/64;
516 		if(target_freight) {
517 			// this is either a railcar/trailer or a truck/boat/plane
518 			if(  test_desc->get_capacity()==0  ||  !test_desc->get_freight_type()->is_interchangeable(target_freight)  ) {
519 				continue;
520 			}
521 
522 			sint32 difference=0;	// smaller is better
523 			// assign this vehicle if we have not found one yet, or we only found one too weak
524 			if(  desc!=NULL  ) {
525 				// is it cheaper to run? (this is most important)
526 				difference += (desc->get_capacity()*1000)/(1+desc->get_running_cost()) < (test_desc->get_capacity()*1000)/(1+test_desc->get_running_cost()) ? -20 : 20;
527 				if(  target_weight>0  ) {
528 					// is it stronger?
529 					difference += (desc->get_power()*desc->get_gear())/64 < power ? -10 : 10;
530 				}
531 				// is it faster? (although we support only up to 120km/h for goods)
532 				difference += (desc->get_topspeed() < test_desc->get_topspeed())? -10 : 10;
533 				// is it cheaper? (not so important)
534 				difference += (desc->get_price() > test_desc->get_price())? -5 : 5;
535 				// add some malus for obsolete vehicles
536 				if(test_desc->is_retired(month_now)) {
537 					difference += 5;
538 				}
539 			}
540 			// ok, final check
541 			if(  desc==NULL  ||  difference<12    ) {
542 				// then we want this vehicle!
543 				desc = test_desc;
544 				DBG_MESSAGE( "vehicle_builder_t::get_best_matching","Found car %s",desc->get_name());
545 			}
546 		}
547 		else {
548 			// finally, we might be able to use this vehicle
549 			sint32 speed = test_desc->get_topspeed();
550 			uint32 max_weight = power/( (speed*speed)/2500 + 1 );
551 
552 			// we found a useful engine
553 			sint32 current_index = (power * 100) / (1 + test_desc->get_running_cost()) + test_desc->get_topspeed() - (sint16)test_desc->get_weight() / 1000 - (sint32)(test_desc->get_price() / 25000);
554 			// too slow?
555 			if(speed < target_speed) {
556 				current_index -= 250;
557 			}
558 			// too weak to reach full speed?
559 			if(  max_weight < target_weight+test_desc->get_weight()/1000  ) {
560 				current_index += max_weight - (sint32)(target_weight+test_desc->get_weight()/1000);
561 			}
562 			current_index += 50;
563 			if(  current_index > desc_index  ) {
564 				// then we want this vehicle!
565 				desc = test_desc;
566 				desc_index = current_index;
567 				DBG_MESSAGE( "vehicle_builder_t::get_best_matching","Found engine %s",desc->get_name());
568 			}
569 		}
570 	}
571 	// no vehicle found!
572 	if(  desc==NULL  ) {
573 		DBG_MESSAGE( "vehicle_builder_t::get_best_matching()","could not find a suitable vehicle! (speed %i, weight %i)",target_speed,target_weight);
574 	}
575 	return desc;
576 }
577 
get_fastest_vehicle_speed(waytype_t wt,uint16 const month_now,bool const use_timeline,bool const allow_obsolete)578 sint32 vehicle_builder_t::get_fastest_vehicle_speed(waytype_t wt, uint16 const month_now, bool const use_timeline, bool const allow_obsolete)
579 {
580 	sint32 fastest_speed = 0;
581 
582 	FOR(slist_tpl<vehicle_desc_t const*>, const vehicle_descriptor, typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) {
583 		if (vehicle_descriptor->get_power() == 0 ||
584 			use_timeline && (
585 				vehicle_descriptor->is_future(month_now) ||
586 				!allow_obsolete && vehicle_descriptor->is_retired(month_now))) {
587 			continue;
588 		}
589 
590 		sint32 const speed = vehicle_descriptor->get_topspeed();
591 		if (fastest_speed < speed) {
592 			fastest_speed = speed;
593 		}
594 	}
595 
596 	return fastest_speed;
597 }
598