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