1 /**
2  * convoi_t Class for vehicle associations
3  * Hansj�rg Malthaner
4  */
5 
6 #include <stdlib.h>
7 
8 #include "simdebug.h"
9 #include "simunits.h"
10 #include "simworld.h"
11 #include "simware.h"
12 #include "player/finance.h" // convert_money
13 #include "player/simplay.h"
14 #include "simconvoi.h"
15 #include "simhalt.h"
16 #include "simdepot.h"
17 #include "gui/simwin.h"
18 #include "simmenu.h"
19 #include "simcolor.h"
20 #include "simmesg.h"
21 #include "simintr.h"
22 #include "simlinemgmt.h"
23 #include "simline.h"
24 #include "freight_list_sorter.h"
25 
26 #include "gui/minimap.h"
27 #include "gui/convoi_info_t.h"
28 #include "gui/schedule_gui.h"
29 #include "gui/depot_frame.h"
30 #include "gui/messagebox.h"
31 #include "gui/convoi_detail_t.h"
32 #include "boden/grund.h"
33 #include "boden/wege/schiene.h"	// for railblocks
34 
35 #include "descriptor/vehicle_desc.h"
36 #include "descriptor/roadsign_desc.h"
37 
38 #include "dataobj/schedule.h"
39 #include "dataobj/route.h"
40 #include "dataobj/loadsave.h"
41 #include "dataobj/translator.h"
42 #include "dataobj/environment.h"
43 
44 #include "display/viewport.h"
45 
46 #include "obj/crossing.h"
47 #include "obj/roadsign.h"
48 #include "obj/wayobj.h"
49 
50 #include "vehicle/simvehicle.h"
51 #include "vehicle/overtaker.h"
52 
53 #include "utils/simrandom.h"
54 #include "utils/simstring.h"
55 #include "utils/cbuffer_t.h"
56 
57 
58 /*
59  * Waiting time for loading (ms)
60  * @author Hj- Malthaner
61  */
62 #define WTT_LOADING 2000
63 
64 
65 karte_ptr_t convoi_t::welt;
66 
67 /*
68  * Debugging helper - translate state value to human readable name
69  * @author Hj- Malthaner
70  */
71 static const char * state_names[convoi_t::MAX_STATES] =
72 {
73 	"INITIAL",
74 	"EDIT_SCHEDULE",
75 	"ROUTING_1",
76 	"",
77 	"",
78 	"NO_ROUTE",
79 	"DRIVING",
80 	"LOADING",
81 	"WAITING_FOR_CLEARANCE",
82 	"WAITING_FOR_CLEARANCE_ONE_MONTH",
83 	"CAN_START",
84 	"CAN_START_ONE_MONTH",
85 	"SELF_DESTRUCT",	// self destruct
86 	"WAITING_FOR_CLEARANCE_TWO_MONTHS",
87 	"CAN_START_TWO_MONTHS",
88 	"LEAVING_DEPOT",
89 	"ENTERING_DEPOT"
90 };
91 
92 
93 /**
94  * Calculates speed of slowest vehicle in the given array
95  * @author Hj. Matthaner
96  */
calc_min_top_speed(const array_tpl<vehicle_t * > & fahr,uint8 anz_vehikel)97 static int calc_min_top_speed(const array_tpl<vehicle_t*>& fahr, uint8 anz_vehikel)
98 {
99 	int min_top_speed = SPEED_UNLIMITED;
100 	for(uint8 i=0; i<anz_vehikel; i++) {
101 		min_top_speed = min(min_top_speed, kmh_to_speed( fahr[i]->get_desc()->get_topspeed() ) );
102 	}
103 	return min_top_speed;
104 }
105 
106 
init(player_t * player)107 void convoi_t::init(player_t *player)
108 {
109 	owner = player;
110 
111 	is_electric = false;
112 	sum_gesamtweight = sum_weight = 0;
113 	sum_running_costs = sum_gear_and_power = previous_delta_v = 0;
114 	sum_power = 0;
115 	min_top_speed = SPEED_UNLIMITED;
116 	speedbonus_kmh = SPEED_UNLIMITED; // speed_to_kmh() not needed
117 
118 	schedule = NULL;
119 	schedule_target = koord3d::invalid;
120 	line = linehandle_t();
121 
122 	anz_vehikel = 0;
123 	steps_driven = -1;
124 	withdraw = false;
125 	has_obsolete = false;
126 	no_load = false;
127 	wait_lock = 0;
128 	arrived_time = 0;
129 
130 	jahresgewinn = 0;
131 	total_distance_traveled = 0;
132 
133 	distance_since_last_stop = 0;
134 	sum_speed_limit = 0;
135 	maxspeed_average_count = 0;
136 	next_reservation_index = 0;
137 
138 	alte_richtung = ribi_t::none;
139 	next_wolke = 0;
140 
141 	state = INITIAL;
142 
143 	*name_and_id = 0;
144 	name_offset = 0;
145 
146 	freight_info_resort = true;
147 	freight_info_order = 0;
148 	loading_level = 0;
149 	loading_limit = 0;
150 
151 	speed_limit = SPEED_UNLIMITED;
152 	max_record_speed = 0;
153 	brake_speed_soll = SPEED_UNLIMITED;
154 	akt_speed_soll = 0;            // target speed
155 	akt_speed = 0;                 // current speed
156 	sp_soll = 0;
157 
158 	next_stop_index = 65535;
159 
160 	line_update_pending = linehandle_t();
161 
162 	home_depot = koord3d::invalid;
163 
164 	recalc_data_front = true;
165 	recalc_data = true;
166 	recalc_speed_limit = true;
167 }
168 
169 
convoi_t(loadsave_t * file)170 convoi_t::convoi_t(loadsave_t* file) : fahr(default_vehicle_length, NULL)
171 {
172 	self = convoihandle_t();
173 	init(0);
174 	rdwr(file);
175 }
176 
177 
convoi_t(player_t * player)178 convoi_t::convoi_t(player_t* player) : fahr(default_vehicle_length, NULL)
179 {
180 	self = convoihandle_t(this);
181 	player->book_convoi_number(1);
182 	init(player);
183 	set_name( "Unnamed" );
184 	welt->add_convoi( self );
185 	init_financial_history();
186 }
187 
188 
~convoi_t()189 convoi_t::~convoi_t()
190 {
191 	owner->book_convoi_number( -1);
192 
193 	assert(self.is_bound());
194 	assert(anz_vehikel==0);
195 
196 	// close windows
197 	destroy_win( magic_convoi_info+self.get_id() );
198 
199 DBG_MESSAGE("convoi_t::~convoi_t()", "destroying %d, %p", self.get_id(), this);
200 	// stop following
201 	if(welt->get_viewport()->get_follow_convoi()==self) {
202 		welt->get_viewport()->set_follow_convoi( convoihandle_t() );
203 	}
204 
205 	welt->sync.remove( this );
206 	welt->rem_convoi( self );
207 
208 	// Knightly : if lineless convoy -> unregister from stops
209 	if(  !line.is_bound()  ) {
210 		unregister_stops();
211 	}
212 
213 	// force asynchronous recalculation
214 	if(schedule) {
215 		if(!schedule->is_editing_finished()) {
216 			destroy_win((ptrdiff_t)schedule);
217 		}
218 		if (!schedule->empty() && !line.is_bound()) {
219 			welt->set_schedule_counter();
220 		}
221 		delete schedule;
222 	}
223 
224 	// @author hsiegeln - deregister from line (again) ...
225 	unset_line();
226 
227 	self.detach();
228 }
229 
230 
231 // waypoint: no stop, resp. for airplanes in air (i.e. no air strip below)
is_waypoint(koord3d ziel) const232 bool convoi_t::is_waypoint( koord3d ziel ) const
233 {
234 	if(  fahr[0]->get_waytype() == air_wt  ) {
235 		// separate logic for airplanes, since the can have waypoints over stops etc.
236 		grund_t *gr = welt->lookup_kartenboden(ziel.get_2d());
237 		if(  gr == NULL  ||  gr->get_weg(air_wt) == NULL  ) {
238 			// during flight always a waypoint
239 			return true;
240 		}
241 		else if(  gr->get_depot()  ) {
242 			// but a depot is not a waypoint
243 			return false;
244 		}
245 		// so we are on a taxiway/runway here ...
246 	}
247 	return !haltestelle_t::get_halt(ziel,get_owner()).is_bound();
248 }
249 
250 
251 /**
252  * unreserves the whole remaining route
253  */
unreserve_route()254 void convoi_t::unreserve_route()
255 {
256 	// need a route, vehicles, and vehicles must belong to this convoi
257 	// (otherwise crash during loading when fahr[0]->convoi is not initialized yet
258 	if(  !route.empty()  &&  anz_vehikel>0  &&  fahr[0]->get_convoi() == this  ) {
259 		rail_vehicle_t* lok = dynamic_cast<rail_vehicle_t*>(fahr[0]);
260 		if (lok) {
261 			// free all reserved blocks
262 			uint16 dummy;
263 			lok->block_reserver(get_route(), back()->get_route_index(), dummy, dummy,  100000, false, true);
264 		}
265 	}
266 }
267 
268 
269 /**
270  * reserves route until next_reservation_index
271  */
reserve_route()272 void convoi_t::reserve_route()
273 {
274 	if(  !route.empty()  &&  anz_vehikel>0  &&  (is_waiting()  ||  state==DRIVING  ||  state==LEAVING_DEPOT)  ) {
275 		for(  int idx = back()->get_route_index();  idx < next_reservation_index  /*&&  idx < route.get_count()*/;  idx++  ) {
276 			if(  grund_t *gr = welt->lookup( route.at(idx) )  ) {
277 				if(  schiene_t *sch = (schiene_t *)gr->get_weg( front()->get_waytype() )  ) {
278 					sch->reserve( self, ribi_type( route.at(max(1u,idx)-1u), route.at(min(route.get_count()-1u,idx+1u)) ) );
279 				}
280 			}
281 		}
282 	}
283 }
284 
285 /**
286  * Sets route_index of all vehicles to startindex.
287  * Puts all vehicles on tile at this position in the route.
288  * Convoy stills needs to be pushed that the convoy is right on track.
289  * @returns length of convoy minus last vehicle
290  */
move_to(uint16 const start_index)291 uint32 convoi_t::move_to(uint16 const start_index)
292 {
293 	steps_driven = -1;
294 	koord3d k = route.at(start_index);
295 	grund_t* gr = welt->lookup(k);
296 
297 	uint32 train_length = 0;
298 	for (unsigned i = 0; i != anz_vehikel; ++i) {
299 		vehicle_t& v = *fahr[i];
300 
301 		if(  grund_t const* gr = welt->lookup(v.get_pos())  ) {
302 			v.mark_image_dirty(v.get_image(), 0);
303 			v.leave_tile();
304 			// maybe unreserve this
305 			if(  schiene_t* const rails = obj_cast<schiene_t>(gr->get_weg(v.get_waytype()))  ) {
306 				rails->unreserve(&v);
307 			}
308 		}
309 		// propagate new index to vehicle, will set all movement related variables, in particular pos
310 		v.initialise_journey(start_index, true);
311 		// now put vehicle on the tile
312 		if (gr) {
313 			v.enter_tile(gr);
314 		}
315 
316 		if (i != anz_vehikel - 1U) {
317 			train_length += v.get_desc()->get_length();
318 		}
319 	}
320 	return train_length;
321 }
322 
323 
finish_rd()324 void convoi_t::finish_rd()
325 {
326 	if(schedule==NULL) {
327 		if(  state!=INITIAL  ) {
328 			grund_t *gr = welt->lookup(home_depot);
329 			if(gr  &&  gr->get_depot()) {
330 				dbg->warning( "convoi_t::finish_rd()","No schedule during loading convoi %i: State will be initial!", self.get_id() );
331 				for( uint8 i=0;  i<anz_vehikel;  i++ ) {
332 					fahr[i]->set_pos(home_depot);
333 				}
334 				state = INITIAL;
335 			}
336 			else {
337 				dbg->error( "convoi_t::finish_rd()","No schedule during loading convoi %i: Convoi will be destroyed!", self.get_id() );
338 				for( uint8 i=0;  i<anz_vehikel;  i++ ) {
339 					fahr[i]->set_pos(koord3d::invalid);
340 				}
341 				destroy();
342 				return;
343 			}
344 		}
345 		// anyway reassign convoi pointer ...
346 		for( uint8 i=0;  i<anz_vehikel;  i++ ) {
347 			vehicle_t* v = fahr[i];
348 			v->set_convoi(this);
349 			if(  state!=INITIAL  &&  welt->lookup(v->get_pos())  ) {
350 				// mark vehicle as used
351 				v->set_driven();
352 			}
353 		}
354 		return;
355 	}
356 	else {
357 		// restore next schedule target for non-stop waypoint handling
358 		const koord3d ziel = schedule->get_current_entry().pos;
359 		if(  anz_vehikel>0  &&  is_waypoint(ziel)  ) {
360 			schedule_target = ziel;
361 		}
362 	}
363 
364 	bool realign_position = false;
365 	if(  anz_vehikel>0  ) {
366 DBG_MESSAGE("convoi_t::finish_rd()","state=%s, next_stop_index=%d", state_names[state], next_stop_index );
367 		// only realign convois not leaving depot to avoid jumps through signals
368 		if(  steps_driven!=-1  ) {
369 			for( uint8 i=0;  i<anz_vehikel;  i++ ) {
370 				vehicle_t* v = fahr[i];
371 				v->set_leading( i==0 );
372 				v->set_last( i+1==anz_vehikel );
373 				v->calc_height();
374 				// this sets the convoi and will renew the block reservation, if needed!
375 				v->set_convoi(this);
376 			}
377 		}
378 		else {
379 			// test also for realignment
380 			sint16 step_pos = 0;
381 			koord3d drive_pos;
382 			uint8 const diagonal_vehicle_steps_per_tile = (uint8)(130560U / welt->get_settings().get_pak_diagonal_multiplier());
383 			for( uint8 i=0;  i<anz_vehikel;  i++ ) {
384 				vehicle_t* v = fahr[i];
385 				v->set_leading( i==0 );
386 				v->set_last( i+1==anz_vehikel );
387 				v->calc_height();
388 				// this sets the convoi and will renew the block reservation, if needed!
389 				v->set_convoi(this);
390 
391 				// wrong alignment here => must relocate
392 				if(v->need_realignment()) {
393 					// diagonal => convoi must restart
394 					realign_position |= ribi_t::is_bend(v->get_direction())  &&  (state==DRIVING  ||  is_waiting());
395 				}
396 				// if version is 99.17 or lower, some convois are broken, i.e. had too large gaps between vehicles
397 				if(  !realign_position  &&  state!=INITIAL  &&  state!=LEAVING_DEPOT  ) {
398 					if(  i==0  ) {
399 						step_pos = v->get_steps();
400 					}
401 					else {
402 						if(  drive_pos!=v->get_pos()  ) {
403 							// with long vehicles on diagonals, vehicles need not to be on consecutive tiles
404 							// do some guessing here
405 							uint32 dist = koord_distance(drive_pos, v->get_pos());
406 							if (dist>1) {
407 								step_pos += (dist-1) * diagonal_vehicle_steps_per_tile;
408 							}
409 							step_pos += ribi_t::is_bend(v->get_direction()) ? diagonal_vehicle_steps_per_tile : VEHICLE_STEPS_PER_TILE;
410 						}
411 						dbg->message("convoi_t::finish_rd()", "v: pos(%s) steps(%d) len=%d ribi=%d prev (%s) step(%d)", v->get_pos().get_str(), v->get_steps(), v->get_desc()->get_length()*16, v->get_direction(),  drive_pos.get_2d().get_str(), step_pos);
412 						if(  abs( v->get_steps() - step_pos )>15  ) {
413 							// not where it should be => realign
414 							realign_position = true;
415 							dbg->warning( "convoi_t::finish_rd()", "convoi (%s) is broken => realign", get_name() );
416 						}
417 					}
418 					step_pos -= v->get_desc()->get_length_in_steps();
419 					drive_pos = v->get_pos();
420 				}
421 			}
422 		}
423 DBG_MESSAGE("convoi_t::finish_rd()","next_stop_index=%d", next_stop_index );
424 
425 		linehandle_t new_line  = line;
426 		if(  !new_line.is_bound()  ) {
427 			// if there is a line with id=0 in the savegame try to assign cnv to this line
428 			new_line = get_owner()->simlinemgmt.get_line_with_id_zero();
429 		}
430 		if(  new_line.is_bound()  ) {
431 			if (  !schedule->matches( welt, new_line->get_schedule() )  ) {
432 				// 101 version produced broken line ids => we have to find our line the hard way ...
433 				vector_tpl<linehandle_t> lines;
434 				get_owner()->simlinemgmt.get_lines(schedule->get_type(), &lines);
435 				new_line = linehandle_t();
436 				FOR(vector_tpl<linehandle_t>, const l, lines) {
437 					if(  schedule->matches( welt, l->get_schedule() )  ) {
438 						// if a line is assigned, set line!
439 						new_line = l;
440 						break;
441 					}
442 				}
443 			}
444 			// now the line should match our schedule or else ...
445 			if(new_line.is_bound()) {
446 				line = new_line;
447 				line->add_convoy(self);
448 				DBG_DEBUG("convoi_t::finish_rd()","%s registers for %d", name_and_id, line.get_id());
449 			}
450 			else {
451 				line = linehandle_t();
452 			}
453 		}
454 	}
455 	else {
456 		// no vehicles in this convoi?!?
457 		dbg->error( "convoi_t::finish_rd()","No vehicles in Convoi %i: will be destroyed!", self.get_id() );
458 		destroy();
459 		return;
460 	}
461 	// put convoi again right on track?
462 	if(realign_position  &&  anz_vehikel>1) {
463 		// display just a warning
464 		dbg->warning("convoi_t::finish_rd()","cnv %i is currently too long.",self.get_id());
465 
466 		if (route.empty()) {
467 			// realigning needs a route
468 			state = NO_ROUTE;
469 			owner->report_vehicle_problem( self, koord3d::invalid );
470 			dbg->error( "convoi_t::finish_rd()", "No valid route, but needs realignment at (%s)!", fahr[0]->get_pos().get_str() );
471 		}
472 		else {
473 			// since start may have been changed
474 			uint16 start_index = max(1,fahr[anz_vehikel-1]->get_route_index())-1;
475 			if (start_index > route.get_count()) {
476 				dbg->error( "convoi_t::finish_rd()", "Routeindex of last vehicle of (%s) too large!", get_name() );
477 				start_index = 0;
478 			}
479 
480 			uint32 train_length = move_to(start_index) + 1;
481 			const koord3d last_start = fahr[0]->get_pos();
482 
483 			// now advance all convoi until it is completely on the track
484 			fahr[0]->set_leading(false); // switches off signal checks ...
485 			for(unsigned i=0; i<anz_vehikel; i++) {
486 				vehicle_t* v = fahr[i];
487 
488 				v->get_smoke(false);
489 				fahr[i]->do_drive( (VEHICLE_STEPS_PER_CARUNIT*train_length)<<YARDS_PER_VEHICLE_STEP_SHIFT );
490 				train_length -= v->get_desc()->get_length();
491 				v->get_smoke(true);
492 
493 				// eventually reserve this again
494 				grund_t *gr=welt->lookup(v->get_pos());
495 				// airplanes may have no ground ...
496 				if (schiene_t* const sch0 = obj_cast<schiene_t>(gr->get_weg(fahr[i]->get_waytype()))) {
497 					sch0->reserve(self,ribi_t::none);
498 				}
499 			}
500 			fahr[0]->set_leading(true);
501 			if(  state != INITIAL  &&  state != EDIT_SCHEDULE  &&  fahr[0]->get_pos() != last_start  ) {
502 				state = WAITING_FOR_CLEARANCE;
503 			}
504 		}
505 	}
506 	if(  state==LOADING  ) {
507 		// the fully the shorter => register again as older convoi
508 		wait_lock = 2000-loading_level*20;
509 	}
510 	// when saving with open window, this can happen
511 	if(  state==EDIT_SCHEDULE  ) {
512 		if (env_t::networkmode) {
513 			wait_lock = 30000; // 60s to drive on, if the client in question had left
514 		}
515 		schedule->finish_editing();
516 	}
517 	// remove wrong freight
518 	check_freight();
519 	// some convois had wrong old direction in them
520 	if(  state<DRIVING  ||  state==LOADING  ) {
521 		alte_richtung = fahr[0]->get_direction();
522 	}
523 	// Knightly : if lineless convoy -> register itself with stops
524 	if(  !line.is_bound()  ) {
525 		register_stops();
526 	}
527 
528 	calc_speedbonus_kmh();
529 }
530 
531 
532 // since now convoi states go via tool_t
call_convoi_tool(const char function,const char * extra) const533 void convoi_t::call_convoi_tool( const char function, const char *extra ) const
534 {
535 	tool_t *tmp_tool = create_tool( TOOL_CHANGE_CONVOI | SIMPLE_TOOL );
536 	cbuffer_t param;
537 	param.printf("%c,%u", function, self.get_id());
538 	if(  extra  &&  *extra  ) {
539 		param.printf(",%s", extra);
540 	}
541 	tmp_tool->set_default_param(param);
542 	welt->set_tool( tmp_tool, get_owner() );
543 	// since init always returns false, it is safe to delete immediately
544 	delete tmp_tool;
545 }
546 
547 
rotate90(const sint16 y_size)548 void convoi_t::rotate90( const sint16 y_size )
549 {
550 	record_pos.rotate90( y_size );
551 	home_depot.rotate90( y_size );
552 	route.rotate90( y_size );
553 	if(  schedule_target!=koord3d::invalid  ) {
554 		schedule_target.rotate90( y_size );
555 	}
556 	if(schedule) {
557 		schedule->rotate90( y_size );
558 	}
559 	for(  int i=0;  i<anz_vehikel;  i++  ) {
560 		fahr[i]->rotate90_freight_destinations( y_size );
561 	}
562 	// eventually correct freight destinations (and remove all stale freight)
563 	check_freight();
564 }
565 
566 
567 /**
568  * Return the convoi position.
569  * @return Convoi position
570  * @author Hj. Malthaner
571  */
get_pos() const572 koord3d convoi_t::get_pos() const
573 {
574 	if(anz_vehikel > 0 && fahr[0]) {
575 		return state==INITIAL ? home_depot : fahr[0]->get_pos();
576 	}
577 	else {
578 		return koord3d::invalid;
579 	}
580 }
581 
582 
583 /**
584  * Sets the name. Creates a copy of name.
585  * @author Hj. Malthaner
586  */
set_name(const char * name,bool with_new_id)587 void convoi_t::set_name(const char *name, bool with_new_id)
588 {
589 	if(  with_new_id  ) {
590 		char buf[128];
591 		name_offset = sprintf(buf,"(%i) ",self.get_id() );
592 		tstrncpy(buf + name_offset, translator::translate(name, welt->get_settings().get_name_language_id()), lengthof(buf) - name_offset);
593 		tstrncpy(name_and_id, buf, lengthof(name_and_id));
594 	}
595 	else {
596 		char buf[128];
597 		// check if there is a id in the name string
598 		name_offset = sprintf(buf,"(%i) ",self.get_id() );
599 		if(  strlen(name) < name_offset  ||  strncmp(buf,name,name_offset)!=0) {
600 			name_offset = 0;
601 		}
602 		tstrncpy(buf+name_offset, name+name_offset, sizeof(buf)-name_offset);
603 		tstrncpy(name_and_id, buf, lengthof(name_and_id));
604 	}
605 	// now tell the windows that we were renamed
606 	convoi_info_t *info = dynamic_cast<convoi_info_t*>(win_get_magic( magic_convoi_info+self.get_id()));
607 	if (info) {
608 		info->update_data();
609 	}
610 	if(  in_depot()  ) {
611 		const grund_t *const ground = welt->lookup( get_home_depot() );
612 		if(  ground  ) {
613 			const depot_t *const depot = ground->get_depot();
614 			if(  depot  ) {
615 				depot_frame_t *const frame = dynamic_cast<depot_frame_t *>( win_get_magic( (ptrdiff_t)depot ) );
616 				if(  frame  ) {
617 					frame->update_data();
618 				}
619 			}
620 		}
621 	}
622 }
623 
624 
625 // length of convoi (16 is one tile)
get_length() const626 uint32 convoi_t::get_length() const
627 {
628 	uint32 len = 0;
629 	for( uint8 i=0; i<anz_vehikel; i++ ) {
630 		len += fahr[i]->get_desc()->get_length();
631 	}
632 	return len;
633 }
634 
635 
636 /**
637  * convoi add their running cost for traveling one tile
638  * @author Hj. Malthaner
639  */
add_running_cost(const weg_t * weg)640 void convoi_t::add_running_cost( const weg_t *weg )
641 {
642 	jahresgewinn += sum_running_costs;
643 
644 	if(  weg  &&  weg->get_owner()!=get_owner()  &&  weg->get_owner()!=NULL  ) {
645 		// running on non-public way costs toll (since running costs are positive => invert)
646 		sint32 toll = -(sum_running_costs*welt->get_settings().get_way_toll_runningcost_percentage())/100l;
647 		if(  welt->get_settings().get_way_toll_waycost_percentage()  ) {
648 			if(  weg->is_electrified()  &&  needs_electrification()  ) {
649 				// toll for using electricity
650 				grund_t *gr = welt->lookup(weg->get_pos());
651 				for(  int i=1;  i<gr->get_top();  i++  ) {
652 					obj_t *d=gr->obj_bei(i);
653 					if(  wayobj_t const* const wo = obj_cast<wayobj_t>(d)  )  {
654 						if(  wo->get_waytype()==weg->get_waytype()  ) {
655 							toll += (wo->get_desc()->get_maintenance()*welt->get_settings().get_way_toll_waycost_percentage())/100l;
656 							break;
657 						}
658 					}
659 				}
660 			}
661 			// now add normal way toll be maintenance
662 			toll += (weg->get_desc()->get_maintenance()*welt->get_settings().get_way_toll_waycost_percentage())/100l;
663 		}
664 		weg->get_owner()->book_toll_received( toll, get_schedule()->get_waytype() );
665 		get_owner()->book_toll_paid(         -toll, get_schedule()->get_waytype() );
666 		book( -toll, CONVOI_WAYTOLL);
667 		book( -toll, CONVOI_PROFIT);
668 	}
669 	get_owner()->book_running_costs( sum_running_costs, get_schedule()->get_waytype());
670 
671 	book( sum_running_costs, CONVOI_OPERATIONS );
672 	book( sum_running_costs, CONVOI_PROFIT );
673 
674 	total_distance_traveled ++;
675 	distance_since_last_stop++;
676 
677 	sum_speed_limit += speed_to_kmh( min( min_top_speed, speed_limit ));
678 	book( 1, CONVOI_DISTANCE );
679 }
680 
681 
682 /**
683  * Returns residual power given power, weight, and current speed.
684  * @param speed (in internal speed unit)
685  * @param total_power sum of power times gear (see calculation of sum_gear_and_power)
686  * @param friction_weight weight including friction of the convoy
687  * @param total_weight weight of the convoy
688  * @returns residual power
689  */
res_power(sint64 speed,sint32 total_power,sint64 friction_weight,sint64 total_weight)690 static inline sint32 res_power(sint64 speed, sint32 total_power, sint64 friction_weight, sint64 total_weight)
691 {
692 	sint32 res = total_power - (sint32)( ( (sint64)speed * ( (friction_weight * (sint64)speed ) / 3125ll + 1ll) ) / 2048ll + (total_weight * 64ll) / 1000ll);
693 	return res;
694 }
695 
696 /* Calculates (and sets) new akt_speed
697  * needed for driving, entering and leaving a depot)
698  */
calc_acceleration(uint32 delta_t)699 void convoi_t::calc_acceleration(uint32 delta_t)
700 {
701 	if(  !recalc_data  &&  !recalc_speed_limit  &&  !recalc_data_front  &&  (
702 		(sum_friction_weight == sum_gesamtweight  &&  akt_speed_soll <= akt_speed  &&  akt_speed_soll+24 >= akt_speed)  ||
703 		(sum_friction_weight > sum_gesamtweight  &&  akt_speed_soll == akt_speed)  )
704 		) {
705 		// at max speed => go with max speed and finish calculation here
706 		// at slopes/curves, only do this if there is absolutely now change
707 		akt_speed = akt_speed_soll;
708 		return;
709 	}
710 
711 	// Dwachs: only compute this if a vehicle in the convoi hopped
712 	if(  recalc_data  ||  recalc_speed_limit  ) {
713 		// calculate total friction and lowest speed limit
714 		const vehicle_t* v = front();
715 		speed_limit = min( min_top_speed, v->get_speed_limit() );
716 		if (recalc_data) {
717 			sum_gesamtweight   = v->get_total_weight();
718 			sum_friction_weight = v->get_frictionfactor() * sum_gesamtweight;
719 		}
720 
721 		for(  unsigned i=1; i<anz_vehikel; i++  ) {
722 			const vehicle_t* v = fahr[i];
723 			speed_limit = min( speed_limit, v->get_speed_limit() );
724 
725 			if (recalc_data) {
726 				int total_vehicle_weight = v->get_total_weight();
727 				sum_friction_weight += v->get_frictionfactor() * total_vehicle_weight;
728 				sum_gesamtweight += total_vehicle_weight;
729 			}
730 		}
731 		recalc_data = recalc_speed_limit = false;
732 		akt_speed_soll = min( speed_limit, brake_speed_soll );
733 	}
734 
735 	if(  recalc_data_front  ) {
736 		// brake at the end of stations/in front of signals and crossings
737 		const uint32 tiles_left = 1 + get_next_stop_index() - front()->get_route_index();
738 		brake_speed_soll = SPEED_UNLIMITED;
739 		if(  tiles_left < 4  ) {
740 			static sint32 brake_speed_countdown[4] = {
741 				kmh_to_speed(25),
742 				kmh_to_speed(50),
743 				kmh_to_speed(100),
744 				kmh_to_speed(200)
745 			};
746 			brake_speed_soll = brake_speed_countdown[tiles_left];
747 		}
748 		akt_speed_soll = min( speed_limit, brake_speed_soll );
749 		recalc_data_front = false;
750 	}
751 
752 	// Prissi: more pleasant and a little more "physical" model *
753 
754 	// try to simulate quadratic friction
755 	if(sum_gesamtweight != 0) {
756 		/*
757 			* The parameter consist of two parts (optimized for good looking):
758 			*  - every vehicle in a convoi has a the friction of its weight
759 			*  - the dynamic friction is calculated that way, that v^2*weight*frictionfactor = 200 kW
760 			* => heavier loaded and faster traveling => less power for acceleration is available!
761 			* since delta_t can have any value, we have to scale the step size by this value.
762 			* however, there is a quadratic friction term => if delta_t is too large the calculation may get weird results
763 			* @author prissi
764 			*/
765 
766 		/* but for integer, we have to use the order below and calculate actually 64*deccel, like the sum_gear_and_power
767 			* since akt_speed=10/128 km/h and we want 64*200kW=(100km/h)^2*100t, we must multiply by (128*2)/100
768 			* But since the acceleration was too fast, we just decelerate 4x more => >>6 instead >>8 */
769 		//sint32 deccel = ( ( (akt_speed*sum_friction_weight)>>6 )*(akt_speed>>2) ) / 25 + (sum_gesamtweight*64);	// this order is needed to prevent overflows!
770 		//sint32 deccel = (sint32)( ( (sint64)akt_speed * (sint64)sum_friction_weight * (sint64)akt_speed ) / (25ll*256ll) + sum_gesamtweight * 64ll) / 1000ll; // intermediate still overflows so sint64
771 		//sint32 deccel = (sint32)( ( (sint64)akt_speed * ( (sum_friction_weight * (sint64)akt_speed ) / 3125ll + 1ll) ) / 2048ll + (sum_gesamtweight * 64ll) / 1000ll);
772 
773 		// prissi: integer sucks with planes => using floats ...
774 		// turfit: result can overflow sint32 and double so onto sint64. planes ok.
775 		//sint32 delta_v =  (sint32)( ( (double)( (akt_speed>akt_speed_soll?0l:sum_gear_and_power) - deccel)*(double)delta_t)/(double)sum_gesamtweight);
776 
777 		sint64 residual_power = res_power(akt_speed, akt_speed>akt_speed_soll? 0l : sum_gear_and_power, sum_friction_weight, sum_gesamtweight);
778 
779 		// we normalize delta_t to 1/64th and check for speed limit */
780 		//sint32 delta_v = ( ( (akt_speed>akt_speed_soll?0l:sum_gear_and_power) - deccel) * delta_t)/sum_gesamtweight;
781 		sint64 delta_v = ( residual_power * (sint64)delta_t * 1000ll) / (sint64)sum_gesamtweight;
782 
783 		// we need more accurate arithmetic, so we store the previous value
784 		delta_v += previous_delta_v;
785 		previous_delta_v = (sint32)(delta_v & 0x00000FFFll);
786 		// and finally calculate new speed
787 		akt_speed = max(akt_speed_soll>>4, akt_speed+(sint32)(delta_v>>12l) );
788 	}
789 	else {
790 		// very old vehicle ...
791 		akt_speed += 16;
792 	}
793 
794 	// obey speed maximum with additional const brake ...
795 	if(akt_speed > akt_speed_soll) {
796 		if (akt_speed > akt_speed_soll + 24) {
797 			akt_speed -= 24;
798 			if(akt_speed > akt_speed_soll+kmh_to_speed(20)) {
799 				akt_speed = akt_speed_soll+kmh_to_speed(20);
800 			}
801 		}
802 		else {
803 			akt_speed = akt_speed_soll;
804 		}
805 	}
806 
807 	// new record?
808 	if(akt_speed > max_record_speed) {
809 		max_record_speed = akt_speed;
810 		record_pos = fahr[0]->get_pos().get_2d();
811 	}
812 }
813 
814 
815 /**
816  * Calculates maximal possible speed.
817  * Uses iterative technique to take care of integer arithmetic.
818  */
calc_max_speed(uint64 total_power,uint64 total_weight,sint32 speed_limit)819 sint32 convoi_t::calc_max_speed(uint64 total_power, uint64 total_weight, sint32 speed_limit)
820 {
821 	// precision is 0.5 km/h
822 	const sint32 tol = kmh_to_speed(1)/2;
823 	// bisection to find max speed
824 	sint32 pl,pr,pm;
825 	sint64 sl,sr,sm;
826 
827 	// test speed_limit
828 	sr = speed_limit;
829 	pr = res_power(sr, (sint32)total_power, total_weight, total_weight);
830 	if (pr >= 0) {
831 		return (sint32)sr; // convoy can travel at speed given by speed_limit
832 	}
833 	sl = 1;
834 	pl = res_power(sl, (sint32)total_power, total_weight, total_weight);
835 	if (pl <= 0) {
836 		return 0; // no power to move at all
837 	}
838 
839 	// bisection algorithm to find speed for which residual power is zero
840 	while (sr - sl > tol) {
841 		sm = (sl + sr)/2;
842 		if (sm == sl) break;
843 
844 		pm = res_power(sm, (sint32)total_power, total_weight, total_weight);
845 
846 		if (((sint64)pl)*pm <= 0) {
847 			pr = pm;
848 			sr = sm;
849 		}
850 		else {
851 			pl = pm;
852 			sl = sm;
853 		}
854 	}
855 	return (sint32)sl;
856 }
857 
858 
get_vehicle_at_length(uint16 length)859 int convoi_t::get_vehicle_at_length(uint16 length)
860 {
861 	int current_length = 0;
862 	for( int i=0;  i<anz_vehikel;  i++  ) {
863 		current_length += fahr[i]->get_desc()->get_length();
864 		if(length<current_length) {
865 			return i;
866 		}
867 	}
868 	return anz_vehikel;
869 }
870 
871 
872 // moves all vehicles of a convoi
sync_step(uint32 delta_t)873 sync_result convoi_t::sync_step(uint32 delta_t)
874 {
875 	// still have to wait before next action?
876 	wait_lock -= delta_t;
877 	if(wait_lock > 0) {
878 		return SYNC_OK;
879 	}
880 	wait_lock = 0;
881 
882 	switch(state) {
883 		case INITIAL:
884 			// in depot, should not be in sync list, remove
885 			return SYNC_REMOVE;
886 
887 		case EDIT_SCHEDULE:
888 		case ROUTING_1:
889 		case DUMMY4:
890 		case DUMMY5:
891 		case NO_ROUTE:
892 		case CAN_START:
893 		case CAN_START_ONE_MONTH:
894 		case CAN_START_TWO_MONTHS:
895 			// Hajo: this is an async task, see step()
896 			break;
897 
898 		case ENTERING_DEPOT:
899 			break;
900 
901 		case LEAVING_DEPOT:
902 			{
903 				// ok, so we will accelerate
904 				akt_speed_soll = max( akt_speed_soll, kmh_to_speed(30) );
905 				calc_acceleration(delta_t);
906 				sp_soll += (akt_speed*delta_t);
907 
908 				// now actually move the units
909 				while(sp_soll>>12) {
910 					// Attempt to move one step.
911 					uint32 sp_hat = fahr[0]->do_drive(1<<YARDS_PER_VEHICLE_STEP_SHIFT);
912 					int v_nr = get_vehicle_at_length((++steps_driven)>>4);
913 					// stop when depot reached
914 					if (state==INITIAL) {
915 						return SYNC_REMOVE;
916 					}
917 					if (state==ROUTING_1) {
918 						break;
919 					}
920 					// until all are moving or something went wrong (sp_hat==0)
921 					if(sp_hat==0  ||  v_nr==anz_vehikel) {
922 						steps_driven = -1;
923 						state = DRIVING;
924 						return SYNC_OK;
925 					}
926 					// now only the right numbers
927 					for(int i=1; i<=v_nr; i++) {
928 						fahr[i]->do_drive(sp_hat);
929 					}
930 					sp_soll -= sp_hat;
931 				}
932 				// smoke for the engines
933 				next_wolke += delta_t;
934 				if(next_wolke>500) {
935 					next_wolke = 0;
936 					for(int i=0;  i<anz_vehikel;  i++  ) {
937 						fahr[i]->make_smoke();
938 					}
939 				}
940 			}
941 			break;	// LEAVING_DEPOT
942 
943 		case DRIVING:
944 			{
945 				calc_acceleration(delta_t);
946 
947 				// now actually move the units
948 				sp_soll += (akt_speed*delta_t);
949 				uint32 sp_hat = fahr[0]->do_drive(sp_soll);
950 				// stop when depot reached ...
951 				if(state==INITIAL) {
952 					return SYNC_REMOVE;
953 				}
954 				// now move the rest (so all vehikel are moving synchronously)
955 				for(unsigned i=1; i<anz_vehikel; i++) {
956 					fahr[i]->do_drive(sp_hat);
957 				}
958 				// maybe we have been stopped be something => avoid wide jumps
959 				sp_soll = (sp_soll-sp_hat) & 0x0FFF;
960 
961 				// smoke for the engines
962 				next_wolke += delta_t;
963 				if(next_wolke>500) {
964 					next_wolke = 0;
965 					for(int i=0;  i<anz_vehikel;  i++  ) {
966 						fahr[i]->make_smoke();
967 					}
968 				}
969 			}
970 			break;	// DRIVING
971 
972 		case LOADING:
973 			// Hajo: loading is an async task, see laden()
974 			break;
975 
976 		case WAITING_FOR_CLEARANCE:
977 		case WAITING_FOR_CLEARANCE_ONE_MONTH:
978 		case WAITING_FOR_CLEARANCE_TWO_MONTHS:
979 			// Hajo: waiting is asynchronous => fixed waiting order and route search
980 			break;
981 
982 		case SELF_DESTRUCT:
983 			// see step, since destruction during a screen update may give strange effects
984 			break;
985 
986 		default:
987 			dbg->fatal("convoi_t::sync_step()", "Wrong state %d!\n", state);
988 			break;
989 	}
990 
991 	return SYNC_OK;
992 }
993 
994 
995 /**
996  * Berechne route von Start- zu Zielkoordinate
997  * @author Hanjs�rg Malthaner
998  */
drive_to()999 bool convoi_t::drive_to()
1000 {
1001 	if(  anz_vehikel>0  ) {
1002 
1003 		// unreserve all tiles that are covered by the train but do not contain one of the wagons,
1004 		// otherwise repositioning of the train drive_to may lead to stray reserved tiles
1005 		if (dynamic_cast<rail_vehicle_t*>(fahr[0])!=NULL  &&  anz_vehikel > 1) {
1006 			// route-index points to next position in route
1007 			// it is completely off when convoi leaves depot
1008 			uint16 index0 = min(fahr[0]->get_route_index()-1, route.get_count());
1009 			for(uint8 i=1; i<anz_vehikel; i++) {
1010 				uint16 index1 = fahr[i]->get_route_index();
1011 				for(uint16 j = index1; j<index0; j++) {
1012 					// unreserve track on tiles between wagons
1013 					grund_t *gr = welt->lookup(route.at(j));
1014 					if (schiene_t *track = (schiene_t *)gr->get_weg( front()->get_waytype() ) ) {
1015 						track->unreserve(self);
1016 					}
1017 				}
1018 				index0 = min(index1-1, route.get_count());
1019 			}
1020 		}
1021 
1022 		koord3d start = fahr[0]->get_pos();
1023 		koord3d ziel = schedule->get_current_entry().pos;
1024 
1025 		// avoid stopping mid-halt
1026 		if(  start==ziel  ) {
1027 			halthandle_t halt = haltestelle_t::get_halt(ziel,get_owner());
1028 			if(  halt.is_bound()  &&  route.is_contained(start)  ) {
1029 				for(  uint32 i=route.index_of(start);  i<route.get_count();  i++  ) {
1030 					grund_t *gr = welt->lookup(route.at(i));
1031 					if(  gr  && gr->get_halt()==halt  ) {
1032 						ziel = gr->get_pos();
1033 					}
1034 					else {
1035 						break;
1036 					}
1037 				}
1038 			}
1039 		}
1040 
1041 		if(  !fahr[0]->calc_route( start, ziel, speed_to_kmh(min_top_speed), &route )  ) {
1042 			if(  state != NO_ROUTE  ) {
1043 				state = NO_ROUTE;
1044 				get_owner()->report_vehicle_problem( self, ziel );
1045 			}
1046 			// wait 25s before next attempt
1047 			wait_lock = 25000;
1048 		}
1049 		else {
1050 			bool route_ok = true;
1051 			const uint8 current_stop = schedule->get_current_stop();
1052 			if(  fahr[0]->get_waytype() != water_wt  ) {
1053 				air_vehicle_t *const plane = dynamic_cast<air_vehicle_t *>(fahr[0]);
1054 				uint32 takeoff = 0, search = 0, landing = 0;
1055 				air_vehicle_t::flight_state plane_state = air_vehicle_t::taxiing;
1056 				if(  plane  ) {
1057 					// due to the complex state system of aircrafts, we have to save index and state
1058 					plane->get_event_index( plane_state, takeoff, search, landing );
1059 				}
1060 
1061 				// set next schedule target position if next is a waypoint
1062 				if(  is_waypoint(ziel)  ) {
1063 					schedule_target = ziel;
1064 				}
1065 
1066 				// continue route search until the destination is a station
1067 				while(  is_waypoint(ziel)  ) {
1068 					start = ziel;
1069 					schedule->advance();
1070 					ziel = schedule->get_current_entry().pos;
1071 
1072 					if(  schedule->get_current_stop() == current_stop  ) {
1073 						// looped around without finding a halt => entire schedule is waypoints.
1074 						break;
1075 					}
1076 
1077 					route_t next_segment;
1078 					if(  !fahr[0]->calc_route( start, ziel, speed_to_kmh(min_top_speed), &next_segment )  ) {
1079 						// do we still have a valid route to proceed => then go until there
1080 						if(  route.get_count()>1  ) {
1081 							break;
1082 						}
1083 						// we are stuck on our first routing attempt => give up
1084 						if(  state != NO_ROUTE  ) {
1085 							state = NO_ROUTE;
1086 							get_owner()->report_vehicle_problem( self, ziel );
1087 						}
1088 						// wait 25s before next attempt
1089 						wait_lock = 25000;
1090 						route_ok = false;
1091 						break;
1092 					}
1093 					else {
1094 						bool looped = false;
1095 						if(  fahr[0]->get_waytype() != air_wt  ) {
1096 							 // check if the route circles back on itself (only check the first tile, should be enough)
1097 							looped = route.is_contained(next_segment.at(1));
1098 #if 0
1099 							// this will forbid an eight figure, which might be clever to avoid a problem of reserving one own track
1100 							for(  unsigned i = 1;  i<next_segment.get_count();  i++  ) {
1101 								if(  route.is_contained(next_segment.at(i))  ) {
1102 									looped = true;
1103 									break;
1104 								}
1105 							}
1106 #endif
1107 						}
1108 
1109 						if(  looped  ) {
1110 							// proceed upto the waypoint before the loop. Will pause there for a new route search.
1111 							break;
1112 						}
1113 						else {
1114 							uint32 count_offset = route.get_count()-1;
1115 							route.append( &next_segment);
1116 							if(  plane  ) {
1117 								// maybe we need to restore index
1118 								air_vehicle_t::flight_state dummy1;
1119 								uint32 new_takeoff, new_search, new_landing;
1120 								plane->get_event_index( dummy1, new_takeoff, new_search, new_landing );
1121 								if(  takeoff == 0x7FFFFFFF  &&  new_takeoff != 0x7FFFFFFF  ) {
1122 									takeoff = new_takeoff + count_offset;
1123 								}
1124 								if(  landing == 0x7FFFFFFF  &&  new_landing != 0x7FFFFFFF  ) {
1125 									landing = new_landing + count_offset;
1126 								}
1127 								if(  search == 0x7FFFFFFF  &&  new_search != 0x7FFFFFFF ) {
1128 									search = new_search + count_offset;
1129 								}
1130 							}
1131 						}
1132 					}
1133 				}
1134 
1135 				if(  plane  ) {
1136 					// due to the complex state system of aircrafts, we have to restore index and state
1137 					plane->set_event_index( plane_state, takeoff, search, landing );
1138 				}
1139 			}
1140 
1141 			schedule->set_current_stop(current_stop);
1142 			if(  route_ok  ) {
1143 				vorfahren();
1144 				return true;
1145 			}
1146 		}
1147 	}
1148 	return false;
1149 }
1150 
1151 
1152 /**
1153  * Ein Fahrzeug hat ein Problem erkannt und erzwingt die
1154  * Berechnung einer neuen Route
1155  * @author Hanjs�rg Malthaner
1156  */
suche_neue_route()1157 void convoi_t::suche_neue_route()
1158 {
1159 	state = ROUTING_1;
1160 	wait_lock = 0;
1161 }
1162 
1163 
1164 /**
1165  * Asynchrne step methode des Convois
1166  * @author Hj. Malthaner
1167  */
step()1168 void convoi_t::step()
1169 {
1170 	if(  wait_lock > 0  ) {
1171 		return;
1172 	}
1173 
1174 	// moved check to here, as this will apply the same update
1175 	// logic/constraints convois have for manual schedule manipulation
1176 	if (line_update_pending.is_bound()) {
1177 		check_pending_updates();
1178 	}
1179 
1180 	switch(state) {
1181 
1182 		case LOADING:
1183 			laden();
1184 			break;
1185 
1186 		case DUMMY4:
1187 		case DUMMY5:
1188 			break;
1189 
1190 		case EDIT_SCHEDULE:
1191 			// schedule window closed?
1192 			if(schedule!=NULL  &&  schedule->is_editing_finished()) {
1193 
1194 				set_schedule(schedule);
1195 				schedule_target = koord3d::invalid;
1196 
1197 				if(  schedule->empty()  ) {
1198 					// no entry => no route ...
1199 					state = NO_ROUTE;
1200 					owner->report_vehicle_problem( self, koord3d::invalid );
1201 				}
1202 				else {
1203 					// Schedule changed at station
1204 					// this station? then complete loading task else drive on
1205 					halthandle_t h = haltestelle_t::get_halt( get_pos(), get_owner() );
1206 					if(  h.is_bound()  &&  h==haltestelle_t::get_halt( schedule->get_current_entry().pos, get_owner() )  ) {
1207 						if (route.get_count() > 0) {
1208 							koord3d const& pos = route.back();
1209 							if (h == haltestelle_t::get_halt(pos, get_owner())) {
1210 								state = get_pos() == pos ? LOADING : DRIVING;
1211 								break;
1212 							}
1213 						}
1214 						else {
1215 							if(  drive_to()  ) {
1216 								state = DRIVING;
1217 								break;
1218 							}
1219 						}
1220 					}
1221 
1222 					if(  schedule->get_current_entry().pos==get_pos()  ) {
1223 						// position in depot: waiting
1224 						grund_t *gr = welt->lookup(schedule->get_current_entry().pos);
1225 						if(  gr  &&  gr->get_depot()  ) {
1226 							betrete_depot( gr->get_depot() );
1227 						}
1228 						else {
1229 							state = ROUTING_1;
1230 						}
1231 					}
1232 					else {
1233 						// go to next
1234 						state = ROUTING_1;
1235 					}
1236 				}
1237 			}
1238 			break;
1239 
1240 		case ROUTING_1:
1241 			{
1242 				vehicle_t* v = fahr[0];
1243 
1244 				if(  schedule->empty()  ) {
1245 					state = NO_ROUTE;
1246 					owner->report_vehicle_problem( self, koord3d::invalid );
1247 				}
1248 				else {
1249 					// check first, if we are already there:
1250 					assert( schedule->get_current_stop()<schedule->get_count()  );
1251 					if(  v->get_pos()==schedule->get_current_entry().pos  ) {
1252 						schedule->advance();
1253 					}
1254 					// Hajo: now calculate a new route
1255 					drive_to();
1256 					// finally, was there a record last time?
1257 					if(max_record_speed>welt->get_record_speed(fahr[0]->get_waytype())) {
1258 						welt->notify_record(self, max_record_speed, record_pos);
1259 					}
1260 				}
1261 			}
1262 			break;
1263 
1264 		case NO_ROUTE:
1265 			// stuck vehicles
1266 			if (schedule->empty()) {
1267 				// no entries => no route ...
1268 			}
1269 			else {
1270 				// Hajo: now calculate a new route
1271 				drive_to();
1272 			}
1273 			break;
1274 
1275 		case CAN_START:
1276 		case CAN_START_ONE_MONTH:
1277 		case CAN_START_TWO_MONTHS:
1278 			{
1279 				vehicle_t* v = fahr[0];
1280 
1281 				sint32 restart_speed = -1;
1282 				if(  v->can_enter_tile( restart_speed, 0 )  ) {
1283 					// can reserve new block => drive on
1284 					state = (steps_driven>=0) ? LEAVING_DEPOT : DRIVING;
1285 					if(haltestelle_t::get_halt(v->get_pos(),owner).is_bound()) {
1286 						v->play_sound();
1287 					}
1288 				}
1289 				else if(  steps_driven==0  ) {
1290 					// on rail depot tile, do not reserve this
1291 					if(  grund_t *gr = welt->lookup(fahr[0]->get_pos())  ) {
1292 						if (schiene_t* const sch0 = obj_cast<schiene_t>(gr->get_weg(fahr[0]->get_waytype()))) {
1293 							sch0->unreserve(fahr[0]);
1294 						}
1295 					}
1296 				}
1297 				if(restart_speed>=0) {
1298 					akt_speed = restart_speed;
1299 				}
1300 				if(state==CAN_START  ||  state==CAN_START_ONE_MONTH) {
1301 					set_tiles_overtaking( 0 );
1302 				}
1303 			}
1304 			break;
1305 
1306 		case WAITING_FOR_CLEARANCE_ONE_MONTH:
1307 		case WAITING_FOR_CLEARANCE_TWO_MONTHS:
1308 		case WAITING_FOR_CLEARANCE:
1309 			{
1310 				sint32 restart_speed = -1;
1311 				if(  fahr[0]->can_enter_tile( restart_speed, 0 )  ) {
1312 					state = (steps_driven>=0) ? LEAVING_DEPOT : DRIVING;
1313 				}
1314 				if(restart_speed>=0) {
1315 					akt_speed = restart_speed;
1316 				}
1317 				if(state!=DRIVING) {
1318 					set_tiles_overtaking( 0 );
1319 				}
1320 			}
1321 			break;
1322 
1323 		// must be here; may otherwise confuse window management
1324 		case SELF_DESTRUCT:
1325 			welt->set_dirty();
1326 			destroy();
1327 			return; // must not continue method after deleting this object
1328 
1329 		default:	/* keeps compiler silent*/
1330 			break;
1331 	}
1332 
1333 	// calculate new waiting time
1334 	switch( state ) {
1335 		// handled by routine
1336 		case LOADING:
1337 			break;
1338 
1339 		// immediate action needed
1340 		case SELF_DESTRUCT:
1341 		case LEAVING_DEPOT:
1342 		case ENTERING_DEPOT:
1343 		case DRIVING:
1344 		case DUMMY4:
1345 		case DUMMY5:
1346 			wait_lock = 0;
1347 			break;
1348 
1349 		// just waiting for action here
1350 		case INITIAL:
1351 			welt->sync.remove(this);
1352 			/* FALLTHROUGH */
1353 		case EDIT_SCHEDULE:
1354 		case NO_ROUTE:
1355 			wait_lock = max( wait_lock, 25000 );
1356 			break;
1357 
1358 		// action soon needed
1359 		case ROUTING_1:
1360 		case CAN_START:
1361 		case WAITING_FOR_CLEARANCE:
1362 			wait_lock = max( wait_lock, 500 );
1363 			break;
1364 
1365 		// waiting for free way, not too heavy, not to slow
1366 		case CAN_START_ONE_MONTH:
1367 		case WAITING_FOR_CLEARANCE_ONE_MONTH:
1368 		case CAN_START_TWO_MONTHS:
1369 		case WAITING_FOR_CLEARANCE_TWO_MONTHS:
1370 			wait_lock = 2500;
1371 			break;
1372 		default: ;
1373 	}
1374 }
1375 
1376 
new_year()1377 void convoi_t::new_year()
1378 {
1379     jahresgewinn = 0;
1380 }
1381 
1382 
new_month()1383 void convoi_t::new_month()
1384 {
1385 	// should not happen: leftover convoi without vehicles ...
1386 	if(anz_vehikel==0) {
1387 		DBG_DEBUG("convoi_t::new_month()","no vehicles => self destruct!");
1388 		self_destruct();
1389 		return;
1390 	}
1391 	// update statistics of average speed
1392 	if(  maxspeed_average_count==0  ) {
1393 		financial_history[0][CONVOI_MAXSPEED] = distance_since_last_stop>0 ? get_speedbonus_kmh() : 0;
1394 	}
1395 	maxspeed_average_count = 0;
1396 	// everything normal: update histroy
1397 	for (int j = 0; j<MAX_CONVOI_COST; j++) {
1398 		for (int k = MAX_MONTHS-1; k>0; k--) {
1399 			financial_history[k][j] = financial_history[k-1][j];
1400 		}
1401 		financial_history[0][j] = 0;
1402 	}
1403 	// remind every new month again
1404 	if(  state==NO_ROUTE  ) {
1405 		get_owner()->report_vehicle_problem( self, get_pos() );
1406 	}
1407 	// check for traffic jam
1408 	if(state==WAITING_FOR_CLEARANCE) {
1409 		state = WAITING_FOR_CLEARANCE_ONE_MONTH;
1410 		// check, if now free ...
1411 		// might also reset the state!
1412 		sint32 restart_speed = -1;
1413 		if(  fahr[0]->can_enter_tile( restart_speed, 0 )  ) {
1414 			state = DRIVING;
1415 		}
1416 		if(restart_speed>=0) {
1417 			akt_speed = restart_speed;
1418 		}
1419 	}
1420 	else if(state==WAITING_FOR_CLEARANCE_ONE_MONTH) {
1421 		// make sure, not another vehicle with same line is loading in front
1422 		bool notify = true;
1423 		// check, if we are not waiting for load
1424 		if(  line.is_bound()  &&  loading_level==0  ) {
1425 			for(  uint i=0;  i < line->count_convoys();  i++  ) {
1426 				convoihandle_t cnv = line->get_convoy(i);
1427 				if(  cnv.is_bound()  &&  cnv->get_state()==LOADING  &&  cnv->get_loading_level() < cnv->get_loading_limit()  ) {
1428 					// convoi on this line is waiting for load => assume we are waiting behind
1429 					notify = false;
1430 					break;
1431 				}
1432 			}
1433 		}
1434 		if(  notify  ) {
1435 			get_owner()->report_vehicle_problem( self, koord3d::invalid );
1436 		}
1437 		state = WAITING_FOR_CLEARANCE_TWO_MONTHS;
1438 	}
1439 	// check for traffic jam
1440 	if(state==CAN_START) {
1441 		state = CAN_START_ONE_MONTH;
1442 	}
1443 	else if(state==CAN_START_ONE_MONTH  ||  state==CAN_START_TWO_MONTHS  ) {
1444 		get_owner()->report_vehicle_problem( self, koord3d::invalid );
1445 		state = CAN_START_TWO_MONTHS;
1446 	}
1447 	// check for obsolete vehicles in the convoi
1448 	if(!has_obsolete  &&  welt->use_timeline()) {
1449 		// convoi has obsolete vehicles?
1450 		const int month_now = welt->get_timeline_year_month();
1451 		has_obsolete = false;
1452 		for(unsigned j=0;  j<get_vehicle_count();  j++ ) {
1453 			if (fahr[j]->get_desc()->is_retired(month_now)) {
1454 				has_obsolete = true;
1455 				break;
1456 			}
1457 		}
1458 	}
1459 }
1460 
1461 
betrete_depot(depot_t * dep)1462 void convoi_t::betrete_depot(depot_t *dep)
1463 {
1464 	// first remove reservation, if train is still on track
1465 	unreserve_route();
1466 
1467 	// Hajo: remove vehicles from world data structure
1468 	for(unsigned i=0; i<anz_vehikel; i++) {
1469 		vehicle_t* v = fahr[i];
1470 
1471 		grund_t* gr = welt->lookup(v->get_pos());
1472 		if(gr) {
1473 			// remove from blockstrecke
1474 			v->set_last(true);
1475 			v->leave_tile();
1476 			v->set_flag( obj_t::not_on_map );
1477 		}
1478 	}
1479 
1480 	dep->convoi_arrived(self, get_schedule());
1481 
1482 	destroy_win( magic_convoi_info+self.get_id() );
1483 
1484 	maxspeed_average_count = 0;
1485 	state = INITIAL;
1486 }
1487 
1488 
start()1489 void convoi_t::start()
1490 {
1491 	if(state == INITIAL || state == ROUTING_1) {
1492 
1493 		// set home depot to location of depot convoi is leaving
1494 		if(route.empty()) {
1495 			home_depot = fahr[0]->get_pos();
1496 		}
1497 		else {
1498 			home_depot = route.front();
1499 			fahr[0]->set_pos( home_depot );
1500 		}
1501 		// put the convoi on the depot ground, to get automatic rotation
1502 		// (vorfahren() will remove it anyway again.)
1503 		grund_t *gr = welt->lookup( home_depot );
1504 		assert(gr);
1505 		gr->obj_add( fahr[0] );
1506 
1507 		// put into sync list
1508 		welt->sync.add(this);
1509 
1510 		alte_richtung = ribi_t::none;
1511 		no_load = false;
1512 
1513 		state = ROUTING_1;
1514 
1515 		// recalc weight and image
1516 		// also for any vehicle entered a depot, set_letztes is true! => reset it correctly
1517 		sint64 restwert_delta = 0;
1518 		for(unsigned i=0; i<anz_vehikel; i++) {
1519 			fahr[i]->set_leading( false );
1520 			fahr[i]->set_last( false );
1521 			restwert_delta -= fahr[i]->calc_sale_value();
1522 			fahr[i]->set_driven();
1523 			restwert_delta += fahr[i]->calc_sale_value();
1524 			fahr[i]->clear_flag( obj_t::not_on_map );
1525 		}
1526 		fahr[0]->set_leading( true );
1527 		fahr[anz_vehikel-1]->set_last( true );
1528 		// do not show the vehicle - it will be wrong positioned -vorfahren() will correct this
1529 		fahr[0]->set_image(IMG_EMPTY);
1530 
1531 		// update finances for used vehicle reduction when first driven
1532 		owner->update_assets( restwert_delta, get_schedule()->get_waytype());
1533 
1534 		// calc state for convoi
1535 		calc_loading();
1536 		calc_speedbonus_kmh();
1537 		maxspeed_average_count = 0;
1538 
1539 		if(line.is_bound()) {
1540 			// might have changed the vehicles in this car ...
1541 			line->recalc_catg_index();
1542 		}
1543 		else {
1544 			welt->set_schedule_counter();
1545 		}
1546 		wait_lock = 0;
1547 
1548 		DBG_MESSAGE("convoi_t::start()","Convoi %s wechselt von INITIAL nach ROUTING_1", name_and_id);
1549 	}
1550 	else {
1551 		dbg->warning("convoi_t::start()","called with state=%s\n",state_names[state]);
1552 	}
1553 }
1554 
1555 
1556 /* called, when at a destination
1557  * can be waypoint, depot or a stop
1558  * called from the first vehicle_t of a convoi */
ziel_erreicht()1559 void convoi_t::ziel_erreicht()
1560 {
1561 	const vehicle_t* v = fahr[0];
1562 	alte_richtung = v->get_direction();
1563 
1564 	// check, what is at destination!
1565 	const grund_t *gr = welt->lookup(v->get_pos());
1566 	depot_t *dp = gr->get_depot();
1567 
1568 	if(dp) {
1569 		// ok, we are entering a depot
1570 		cbuffer_t buf;
1571 
1572 		// we still book the money for the trip; however, the freight will be deleted (by the vehicle in the depot itself)
1573 		calc_gewinn();
1574 
1575 		akt_speed = 0;
1576 		buf.printf( translator::translate("%s has entered a depot."), get_name() );
1577 		welt->get_message()->add_message(buf, v->get_pos().get_2d(),message_t::warnings, PLAYER_FLAG|get_owner()->get_player_nr(), IMG_EMPTY);
1578 
1579 		betrete_depot(dp);
1580 	}
1581 	else {
1582 		// no depot reached, check for stop!
1583 		halthandle_t halt = haltestelle_t::get_halt(schedule->get_current_entry().pos,owner);
1584 		if(  halt.is_bound() &&  gr->get_weg_ribi(v->get_waytype())!=0  ) {
1585 			// seems to be a stop, so book the money for the trip
1586 			akt_speed = 0;
1587 			halt->book(1, HALT_CONVOIS_ARRIVED);
1588 			state = LOADING;
1589 			arrived_time = welt->get_ticks();
1590 		}
1591 		else {
1592 			// Neither depot nor station: waypoint
1593 			schedule->advance();
1594 			state = ROUTING_1;
1595 		}
1596 	}
1597 	wait_lock = 0;
1598 }
1599 
1600 
1601 /**
1602  * Wartet bis Fahrzeug 0 freie Fahrt meldet
1603  * @author Hj. Malthaner
1604  */
warten_bis_weg_frei(sint32 restart_speed)1605 void convoi_t::warten_bis_weg_frei(sint32 restart_speed)
1606 {
1607 	if(!is_waiting()) {
1608 		state = WAITING_FOR_CLEARANCE;
1609 		wait_lock = 0;
1610 	}
1611 	if(restart_speed>=0) {
1612 		// langsam anfahren
1613 		akt_speed = restart_speed;
1614 	}
1615 }
1616 
1617 
add_vehikel(vehicle_t * v,bool infront)1618 bool convoi_t::add_vehikel(vehicle_t *v, bool infront)
1619 {
1620 DBG_MESSAGE("convoi_t::add_vehikel()","at pos %i of %i total vehikels.",anz_vehikel,fahr.get_count());
1621 	// extend array if requested
1622 	if(anz_vehikel == fahr.get_count()) {
1623 		fahr.resize(anz_vehikel+1,NULL);
1624 DBG_MESSAGE("convoi_t::add_vehikel()","extend array_tpl to %i totals.",fahr.get_count());
1625 	}
1626 	// now append
1627 	if (anz_vehikel < fahr.get_count()) {
1628 		v->set_convoi(this);
1629 
1630 		if(infront) {
1631 			for(unsigned i = anz_vehikel; i > 0; i--) {
1632 				fahr[i] = fahr[i - 1];
1633 			}
1634 			fahr[0] = v;
1635 		} else {
1636 			fahr[anz_vehikel] = v;
1637 		}
1638 		anz_vehikel ++;
1639 
1640 		const vehicle_desc_t *info = v->get_desc();
1641 		if(info->get_power()) {
1642 			is_electric |= info->get_engine_type()==vehicle_desc_t::electric;
1643 		}
1644 		sum_power += info->get_power();
1645 		sum_gear_and_power += info->get_power()*info->get_gear();
1646 		sum_weight += info->get_weight();
1647 		sum_running_costs -= info->get_running_cost();
1648 		min_top_speed = min( min_top_speed, kmh_to_speed( v->get_desc()->get_topspeed() ) );
1649 		sum_gesamtweight = sum_weight;
1650 		calc_loading();
1651 		freight_info_resort = true;
1652 		// Add good_catg_index:
1653 		if(v->get_cargo_max() != 0) {
1654 			const goods_desc_t *ware=v->get_cargo_type();
1655 			if(ware!=goods_manager_t::none  ) {
1656 				goods_catg_index.append_unique( ware->get_catg_index() );
1657 			}
1658 		}
1659 		// check for obsolete
1660 		if(!has_obsolete  &&  welt->use_timeline()) {
1661 			has_obsolete = info->is_retired( welt->get_timeline_year_month() );
1662 		}
1663 		player_t::add_maintenance( get_owner(), info->get_maintenance(), info->get_waytype() );
1664 	}
1665 	else {
1666 		return false;
1667 	}
1668 
1669 	// der convoi hat jetzt ein neues ende
1670 	set_erstes_letztes();
1671 
1672 DBG_MESSAGE("convoi_t::add_vehikel()","now %i of %i total vehikels.",anz_vehikel,fahr.get_count());
1673 	return true;
1674 }
1675 
1676 
remove_vehikel_bei(uint16 i)1677 vehicle_t *convoi_t::remove_vehikel_bei(uint16 i)
1678 {
1679 	vehicle_t *v = NULL;
1680 	if(i<anz_vehikel) {
1681 		v = fahr[i];
1682 		if(v != NULL) {
1683 			for(unsigned j=i; j<anz_vehikel-1u; j++) {
1684 				fahr[j] = fahr[j + 1];
1685 			}
1686 
1687 			v->set_convoi(NULL);
1688 
1689 			--anz_vehikel;
1690 			fahr[anz_vehikel] = NULL;
1691 
1692 			const vehicle_desc_t *info = v->get_desc();
1693 			sum_power -= info->get_power();
1694 			sum_gear_and_power -= info->get_power()*info->get_gear();
1695 			sum_weight -= info->get_weight();
1696 			sum_running_costs += info->get_running_cost();
1697 			player_t::add_maintenance( get_owner(), -info->get_maintenance(), info->get_waytype() );
1698 		}
1699 		sum_gesamtweight = sum_weight;
1700 		calc_loading();
1701 		freight_info_resort = true;
1702 
1703 		// der convoi hat jetzt ein neues ende
1704 		if(anz_vehikel > 0) {
1705 			set_erstes_letztes();
1706 		}
1707 
1708 		// Hajo: calculate new minimum top speed
1709 		min_top_speed = calc_min_top_speed(fahr, anz_vehikel);
1710 
1711 		// check for obsolete
1712 		if(has_obsolete) {
1713 			has_obsolete = false;
1714 			const int month_now = welt->get_timeline_year_month();
1715 			for(unsigned i=0; i<anz_vehikel; i++) {
1716 				has_obsolete |= fahr[i]->get_desc()->is_retired(month_now);
1717 			}
1718 		}
1719 
1720 		recalc_catg_index();
1721 
1722 		// still requires electrifications?
1723 		if(is_electric) {
1724 			is_electric = false;
1725 			for(unsigned i=0; i<anz_vehikel; i++) {
1726 				if(fahr[i]->get_desc()->get_power()) {
1727 					is_electric |= fahr[i]->get_desc()->get_engine_type()==vehicle_desc_t::electric;
1728 				}
1729 			}
1730 		}
1731 	}
1732 	return v;
1733 }
1734 
1735 
1736 // recalc what good this convoy is moving
recalc_catg_index()1737 void convoi_t::recalc_catg_index()
1738 {
1739 	goods_catg_index.clear();
1740 
1741 	for(  uint8 i = 0;  i < get_vehicle_count();  i++  ) {
1742 		// Only consider vehicles that really transport something
1743 		// this helps against routing errors through passenger
1744 		// trains pulling only freight wagons
1745 		if(get_vehikel(i)->get_cargo_max() == 0) {
1746 			continue;
1747 		}
1748 		const goods_desc_t *ware=get_vehikel(i)->get_cargo_type();
1749 		if(ware!=goods_manager_t::none  ) {
1750 			goods_catg_index.append_unique( ware->get_catg_index() );
1751 		}
1752 	}
1753 	/* since during composition of convois all kinds of composition could happen,
1754 	 * we do not enforce schedule recalculation here; it will be done anyway all times when leaving the INTI state ...
1755 	 */
1756 }
1757 
1758 
set_erstes_letztes()1759 void convoi_t::set_erstes_letztes()
1760 {
1761 	// anz_vehikel muss korrekt init sein
1762 	if(anz_vehikel>0) {
1763 		fahr[0]->set_leading(true);
1764 		for(unsigned i=1; i<anz_vehikel; i++) {
1765 			fahr[i]->set_leading(false);
1766 			fahr[i - 1]->set_last(false);
1767 		}
1768 		fahr[anz_vehikel - 1]->set_last(true);
1769 	}
1770 	else {
1771 		dbg->warning("convoi_t::set_erstes_letzes()", "called with anz_vehikel==0!");
1772 	}
1773 }
1774 
1775 
1776 // remove wrong freight when schedule changes etc.
check_freight()1777 void convoi_t::check_freight()
1778 {
1779 	for(unsigned i=0; i<anz_vehikel; i++) {
1780 		fahr[i]->remove_stale_cargo();
1781 	}
1782 	calc_loading();
1783 	freight_info_resort = true;
1784 }
1785 
1786 
set_schedule(schedule_t * f)1787 bool convoi_t::set_schedule(schedule_t * f)
1788 {
1789 	if(  state==SELF_DESTRUCT  ) {
1790 		return false;
1791 	}
1792 
1793 	DBG_DEBUG("convoi_t::set_schedule()", "new=%p, old=%p", f, schedule);
1794 	assert(f != NULL);
1795 
1796 	// happens to be identical?
1797 	if(schedule!=f) {
1798 		// now check, we we have been bond to a line we are about to lose:
1799 		bool changed = false;
1800 		if(  line.is_bound()  ) {
1801 			if(  !f->matches( welt, line->get_schedule() )  ) {
1802 				// change from line to individual schedule
1803 				//		-> unset line now and register stops from new schedule later
1804 				changed = true;
1805 				unset_line();
1806 			}
1807 		}
1808 		else {
1809 			if(  !f->matches( welt, schedule )  ) {
1810 				// Knightly : merely change schedule and do not involve line
1811 				//				-> unregister stops from old schedule now and register stops from new schedule later
1812 				changed = true;
1813 				unregister_stops();
1814 			}
1815 		}
1816 		// destroy a possibly open schedule window
1817 		if(  schedule  &&  !schedule->is_editing_finished()  ) {
1818 			destroy_win((ptrdiff_t)schedule);
1819 			delete schedule;
1820 		}
1821 		schedule = f;
1822 		if(  changed  ) {
1823 			// Knightly : if line is unset or schedule is changed
1824 			//				-> register stops from new schedule
1825 			register_stops();
1826 			welt->set_schedule_counter();	// must trigger refresh
1827 		}
1828 	}
1829 
1830 	// remove wrong freight
1831 	check_freight();
1832 
1833 	// ok, now we have a schedule
1834 	if(state != INITIAL) {
1835 		state = EDIT_SCHEDULE;
1836 	}
1837 	// to avoid jumping trains
1838 	alte_richtung = fahr[0]->get_direction();
1839 	wait_lock = 0;
1840 	return true;
1841 }
1842 
1843 
create_schedule()1844 schedule_t *convoi_t::create_schedule()
1845 {
1846 	if(schedule == NULL) {
1847 		const vehicle_t* v = fahr[0];
1848 
1849 		if (v != NULL) {
1850 			schedule = v->generate_new_schedule();
1851 			schedule->finish_editing();
1852 		}
1853 	}
1854 
1855 	return schedule;
1856 }
1857 
1858 
1859 /* checks, if we go in the same direction;
1860  * true: convoy prepared
1861  * false: must recalculate position
1862  * on all error we better use the normal starting procedure ...
1863  */
can_go_alte_richtung()1864 bool convoi_t::can_go_alte_richtung()
1865 {
1866 	// invalid route? nothing to test, must start new
1867 	if(route.empty()) {
1868 		return false;
1869 	}
1870 
1871 	// going backwards? then recalculate all
1872 	ribi_t::ribi neue_richtung_rwr = ribi_t::backward(fahr[0]->calc_direction(route.front(), route.at(min(2, route.get_count() - 1))));
1873 //	DBG_MESSAGE("convoi_t::go_alte_richtung()","neu=%i,rwr_neu=%i,alt=%i",neue_richtung_rwr,ribi_t::backward(neue_richtung_rwr),alte_richtung);
1874 	if(neue_richtung_rwr&alte_richtung) {
1875 		akt_speed = 8;
1876 		return false;
1877 	}
1878 
1879 	// now get the actual length and the tile length
1880 	uint16 convoi_length = 15;
1881 	uint16 tile_length = 24;
1882 	unsigned i;	// for visual C++
1883 	const vehicle_t* pred = NULL;
1884 	for(i=0; i<anz_vehikel; i++) {
1885 		const vehicle_t* v = fahr[i];
1886 		grund_t *gr = welt->lookup(v->get_pos());
1887 
1888 		// not last vehicle?
1889 		// the length of last vehicle does not matter when it comes to positioning of vehicles
1890 		if ( i+1 < anz_vehikel) {
1891 			convoi_length += v->get_desc()->get_length();
1892 		}
1893 
1894 		if(gr==NULL  ||  (pred!=NULL  &&  (abs(v->get_pos().x-pred->get_pos().x)>=2  ||  abs(v->get_pos().y-pred->get_pos().y)>=2))  ) {
1895 			// ending here is an error!
1896 			// this is an already broken train => restart
1897 			dbg->warning("convoi_t::go_alte_richtung()","broken convoy (id %i) found => fixing!",self.get_id());
1898 			akt_speed = 8;
1899 			return false;
1900 		}
1901 
1902 		// now check, if ribi is straight and train is not
1903 		ribi_t::ribi weg_ribi = gr->get_weg_ribi_unmasked(v->get_waytype());
1904 		if(ribi_t::is_straight(weg_ribi)  &&  (weg_ribi|v->get_direction())!=weg_ribi) {
1905 			dbg->warning("convoi_t::go_alte_richtung()","convoy with wrong vehicle directions (id %i) found => fixing!",self.get_id());
1906 			akt_speed = 8;
1907 			return false;
1908 		}
1909 
1910 		if(  pred  &&  pred->get_pos()!=v->get_pos()  ) {
1911 			tile_length += (ribi_t::is_straight(welt->lookup(pred->get_pos())->get_weg_ribi_unmasked(pred->get_waytype())) ? 16 : 8192/vehicle_t::get_diagonal_multiplier())*koord_distance(pred->get_pos(),v->get_pos());
1912 		}
1913 
1914 		pred = v;
1915 	}
1916 	// check if convoi is way too short (even for diagonal tracks)
1917 	tile_length += (ribi_t::is_straight(welt->lookup(fahr[anz_vehikel-1]->get_pos())->get_weg_ribi_unmasked(fahr[anz_vehikel-1]->get_waytype())) ? 16 : 8192/vehicle_t::get_diagonal_multiplier());
1918 	if(  convoi_length>tile_length  ) {
1919 		dbg->warning("convoi_t::go_alte_richtung()","convoy too short (id %i) => fixing!",self.get_id());
1920 		akt_speed = 8;
1921 		return false;
1922 	}
1923 
1924 	uint16 length = min((convoi_length/16u)+4u,route.get_count());	// maximum length in tiles to check
1925 
1926 	// we just check, whether we go back (i.e. route tiles other than zero have convoi vehicles on them)
1927 	for( int index=1;  index<length;  index++ ) {
1928 		grund_t *gr=welt->lookup(route.at(index));
1929 		// now check, if we are already here ...
1930 		for(unsigned i=0; i<anz_vehikel; i++) {
1931 			if (gr->obj_ist_da(fahr[i])) {
1932 				// we are turning around => start slowly and rebuilt train
1933 				akt_speed = 8;
1934 				return false;
1935 			}
1936 		}
1937 	}
1938 
1939 //DBG_MESSAGE("convoi_t::go_alte_richtung()","alte=%d, neu_rwr=%d",alte_richtung,neue_richtung_rwr);
1940 
1941 	// we continue our journey; however later cars need also a correct route entry
1942 	// eventually we need to add their positions to the convois route
1943 	koord3d pos = fahr[0]->get_pos();
1944 	assert(pos == route.front());
1945 	if(welt->lookup(pos)->get_depot()) {
1946 		return false;
1947 	}
1948 	else {
1949 		for(i=0; i<anz_vehikel; i++) {
1950 			vehicle_t* v = fahr[i];
1951 			// eventually add current position to the route
1952 			if (route.front() != v->get_pos() && route.at(1) != v->get_pos()) {
1953 				route.insert(v->get_pos());
1954 			}
1955 		}
1956 	}
1957 
1958 	// since we need the route for every vehicle of this convoi,
1959 	// we must set the current route index (instead assuming 1)
1960 	length = min((convoi_length/8u),route.get_count()-1);	// maximum length in tiles to check
1961 	bool ok=false;
1962 	for(i=0; i<anz_vehikel; i++) {
1963 		vehicle_t* v = fahr[i];
1964 
1965 		// this is such awkward, since it takes into account different vehicle length
1966 		const koord3d vehicle_start_pos = v->get_pos();
1967 		for( int idx=0;  idx<=length;  idx++  ) {
1968 			if(route.at(idx)==vehicle_start_pos) {
1969 				// set route index, no recalculations necessary
1970 				v->initialise_journey(idx, false );
1971 				ok = true;
1972 
1973 				// check direction
1974 				uint8 richtung = v->get_direction();
1975 				uint8 neu_richtung = v->calc_direction( route.at(max(idx-1,0)), v->get_pos_next());
1976 				// we need to move to this place ...
1977 				if(neu_richtung!=richtung  &&  (i!=0  ||  anz_vehikel==1  ||  ribi_t::is_bend(neu_richtung)) ) {
1978 					// 90 deg bend!
1979 					return false;
1980 				}
1981 
1982 				break;
1983 			}
1984 		}
1985 		// too short?!? (rather broken then!)
1986 		if(!ok) {
1987 			return false;
1988 		}
1989 	}
1990 
1991 	return true;
1992 }
1993 
1994 
1995 // put the convoi on its way
vorfahren()1996 void convoi_t::vorfahren()
1997 {
1998 	// Hajo: init speed settings
1999 	sp_soll = 0;
2000 	set_tiles_overtaking( 0 );
2001 	recalc_data_front = true;
2002 	recalc_data = true;
2003 
2004 	koord3d k0 = route.front();
2005 	grund_t *gr = welt->lookup(k0);
2006 	bool at_dest = false;
2007 	if(gr  &&  gr->get_depot()) {
2008 		// start in depot
2009 		for(unsigned i=0; i<anz_vehikel; i++) {
2010 			vehicle_t* v = fahr[i];
2011 
2012 			// remove from old position
2013 			grund_t* gr = welt->lookup(v->get_pos());
2014 			if(gr) {
2015 				gr->obj_remove(v);
2016 				if(gr->ist_uebergang()) {
2017 					crossing_t *cr = gr->find<crossing_t>(2);
2018 					cr->release_crossing(v);
2019 				}
2020 				// eventually unreserve this
2021 				if(  schiene_t* const sch0 = obj_cast<schiene_t>(gr->get_weg(fahr[i]->get_waytype()))  ) {
2022 					sch0->unreserve(v);
2023 				}
2024 			}
2025 			v->initialise_journey(0, true);
2026 			// set at new position
2027 			gr = welt->lookup(v->get_pos());
2028 			assert(gr);
2029 			v->enter_tile(gr);
2030 		}
2031 
2032 		// just advances the first vehicle
2033 		vehicle_t* v0 = fahr[0];
2034 		v0->set_leading(false); // switches off signal checks ...
2035 		v0->get_smoke(false);
2036 		steps_driven = 0;
2037 		// drive half a tile:
2038 		for(int i=0; i<anz_vehikel; i++) {
2039 			fahr[i]->do_drive( (VEHICLE_STEPS_PER_TILE/2)<<YARDS_PER_VEHICLE_STEP_SHIFT );
2040 		}
2041 		v0->get_smoke(true);
2042 		v0->set_leading(true); // switches on signal checks to reserve the next route
2043 
2044 		// until all other are on the track
2045 		state = CAN_START;
2046 	}
2047 	else {
2048 		// still leaving depot (steps_driven!=0) or going in other direction or misalignment?
2049 		if(  steps_driven>0  ||  !can_go_alte_richtung()  ) {
2050 
2051 			// start route from the beginning at index 0, place everything on start
2052 			uint32 train_length = move_to(0);
2053 
2054 			// move one train length to the start position ...
2055 			// in north/west direction, we leave the vehicle away to start as much back as possible
2056 			ribi_t::ribi neue_richtung = fahr[0]->get_direction();
2057 			if(neue_richtung==ribi_t::south  ||  neue_richtung==ribi_t::east) {
2058 				// drive the convoi to the same position, but do not hop into next tile!
2059 				if(  train_length%16==0  ) {
2060 					// any space we need => just add
2061 					train_length += fahr[anz_vehikel-1]->get_desc()->get_length();
2062 				}
2063 				else {
2064 					// limit train to front of tile
2065 					train_length += min( (train_length%CARUNITS_PER_TILE)-1, fahr[anz_vehikel-1]->get_desc()->get_length() );
2066 				}
2067 			}
2068 			else {
2069 				train_length += 1;
2070 			}
2071 			train_length = max(1,train_length);
2072 
2073 			// now advance all convoi until it is completely on the track
2074 			fahr[0]->set_leading(false); // switches off signal checks ...
2075 			uint32 dist = VEHICLE_STEPS_PER_CARUNIT*train_length<<YARDS_PER_VEHICLE_STEP_SHIFT;
2076 			for(unsigned i=0; i<anz_vehikel; i++) {
2077 				vehicle_t* v = fahr[i];
2078 
2079 				v->get_smoke(false);
2080 				uint32 const driven = fahr[i]->do_drive( dist );
2081 				if (i==0  &&  driven < dist) {
2082 					// we are already at our destination
2083 					at_dest = true;
2084 				}
2085 				// this gives the length in carunits, 1/CARUNITS_PER_TILE of a full tile => all cars closely coupled!
2086 				v->get_smoke(true);
2087 
2088 				uint32 const vlen = ((VEHICLE_STEPS_PER_CARUNIT*v->get_desc()->get_length())<<YARDS_PER_VEHICLE_STEP_SHIFT);
2089 				if (vlen > dist) {
2090 					break;
2091 				}
2092 				dist = driven - vlen;
2093 			}
2094 			fahr[0]->set_leading(true);
2095 		}
2096 		if (!at_dest) {
2097 			state = CAN_START;
2098 
2099 			// to advance more smoothly
2100 			sint32 restart_speed = -1;
2101 			if(  fahr[0]->can_enter_tile( restart_speed, 0 )  ) {
2102 				// can reserve new block => drive on
2103 				if(haltestelle_t::get_halt(k0,owner).is_bound()) {
2104 					fahr[0]->play_sound();
2105 				}
2106 				state = DRIVING;
2107 			}
2108 		}
2109 		else {
2110 			ziel_erreicht();
2111 		}
2112 	}
2113 
2114 	// finally reserve route (if needed)
2115 	if(  fahr[0]->get_waytype()!=air_wt  &&  !at_dest  ) {
2116 		// do not pre-reserve for airplanes
2117 		for(unsigned i=0; i<anz_vehikel; i++) {
2118 			// eventually reserve this
2119 			vehicle_t const& v = *fahr[i];
2120 			if (schiene_t* const sch0 = obj_cast<schiene_t>(welt->lookup(v.get_pos())->get_weg(v.get_waytype()))) {
2121 				sch0->reserve(self,ribi_t::none);
2122 			}
2123 			else {
2124 				break;
2125 			}
2126 		}
2127 	}
2128 
2129 	wait_lock = 0;
2130 	INT_CHECK("simconvoi 711");
2131 }
2132 
2133 
rdwr_convoihandle_t(loadsave_t * file,convoihandle_t & cnv)2134 void convoi_t::rdwr_convoihandle_t(loadsave_t *file, convoihandle_t &cnv)
2135 {
2136 	if(  file->is_version_atleast(112, 3)  ) {
2137 		uint16 id = (file->is_saving()  &&  cnv.is_bound()) ? cnv.get_id() : 0;
2138 		file->rdwr_short( id );
2139 		if (file->is_loading()) {
2140 			cnv.set_id( id );
2141 		}
2142 	}
2143 }
2144 
2145 
rdwr(loadsave_t * file)2146 void convoi_t::rdwr(loadsave_t *file)
2147 {
2148 	xml_tag_t t( file, "convoi_t" );
2149 
2150 	sint32 dummy;
2151 	sint32 owner_n = welt->sp2num(owner);
2152 
2153 	if(file->is_saving()) {
2154 		if(  file->is_version_less(101, 0)  ) {
2155 			file->wr_obj_id("Convoi");
2156 			// the matching read is in karte_t::laden(loadsave*)...
2157 		}
2158 	}
2159 
2160 	// do the update, otherwise we might lose the line after save & reload
2161 	if(file->is_saving()  &&  line_update_pending.is_bound()) {
2162 		check_pending_updates();
2163 	}
2164 
2165 	simline_t::rdwr_linehandle_t(file, line);
2166 
2167 	// we want persistent convoihandles so we can keep dialogues open in network games
2168 	if(  file->is_loading()  ) {
2169 		if(  file->is_version_less(112, 3)  ) {
2170 			self = convoihandle_t( this );
2171 		}
2172 		else {
2173 			uint16 id;
2174 			file->rdwr_short( id );
2175 			self = convoihandle_t( this, id );
2176 		}
2177 	}
2178 	else if(  file->is_version_atleast(112, 3)  ) {
2179 		uint16 id = self.get_id();
2180 		file->rdwr_short( id );
2181 	}
2182 
2183 	dummy = anz_vehikel;
2184 	file->rdwr_long(dummy);
2185 	anz_vehikel = (uint8)dummy;
2186 
2187 	if(file->is_version_less(99, 14)) {
2188 		// was anz_ready
2189 		file->rdwr_long(dummy);
2190 	}
2191 
2192 	file->rdwr_long(wait_lock);
2193 	// some versions may produce broken safegames apparently
2194 	if(wait_lock > 60000) {
2195 		dbg->warning("convoi_t::sync_prepre()","Convoi %d: wait lock out of bounds: wait_lock = %d, setting to 60000",self.get_id(), wait_lock);
2196 		wait_lock = 60000;
2197 	}
2198 
2199 	bool dummy_bool=false;
2200 	file->rdwr_bool(dummy_bool);
2201 	file->rdwr_long(owner_n);
2202 	file->rdwr_long(akt_speed);
2203 	file->rdwr_long(akt_speed_soll);
2204 	file->rdwr_long(sp_soll);
2205 	file->rdwr_enum(state);
2206 	file->rdwr_enum(alte_richtung);
2207 
2208 	// read the yearly income (which has since then become a 64 bit value)
2209 	// will be recalculated later directly from the history
2210 	if(file->is_version_less(89, 4)) {
2211 		file->rdwr_long(dummy);
2212 	}
2213 
2214 	route.rdwr(file);
2215 
2216 	if(file->is_loading()) {
2217 		// extend array if requested (only needed for trains)
2218 		if(anz_vehikel > fahr.get_count()) {
2219 			fahr.resize(anz_vehikel, NULL);
2220 		}
2221 		owner = welt->get_player( owner_n );
2222 
2223 		// Hajo: sanity check for values ... plus correction
2224 		if(sp_soll < 0) {
2225 			sp_soll = 0;
2226 		}
2227 	}
2228 
2229 	file->rdwr_str(name_and_id + name_offset, lengthof(name_and_id) - name_offset);
2230 	if(file->is_loading()) {
2231 		set_name(name_and_id+name_offset);	// will add id automatically
2232 	}
2233 
2234 	koord3d dummy_pos;
2235 	if(file->is_saving()) {
2236 		for(unsigned i=0; i<anz_vehikel; i++) {
2237 			file->wr_obj_id( fahr[i]->get_typ() );
2238 			fahr[i]->rdwr_from_convoi(file);
2239 		}
2240 	}
2241 	else {
2242 		bool override_monorail = false;
2243 		is_electric = false;
2244 		for(  uint8 i=0;  i<anz_vehikel;  i++  ) {
2245 			obj_t::typ typ = (obj_t::typ)file->rd_obj_id();
2246 			vehicle_t *v = 0;
2247 
2248 			const bool first = (i==0);
2249 			const bool last = (i==anz_vehikel-1u);
2250 			if(override_monorail) {
2251 				// ignore type for ancient monorails
2252 				v = new monorail_vehicle_t(file, first, last);
2253 			}
2254 			else {
2255 				switch(typ) {
2256 					case obj_t::old_automobil:
2257 					case obj_t::road_vehicle: v = new road_vehicle_t(file, first, last);  break;
2258 					case obj_t::old_waggon:
2259 					case obj_t::rail_vehicle:    v = new rail_vehicle_t(file, first, last);     break;
2260 					case obj_t::old_schiff:
2261 					case obj_t::water_vehicle:    v = new water_vehicle_t(file, first, last);     break;
2262 					case obj_t::old_aircraft:
2263 					case obj_t::air_vehicle:    v = new air_vehicle_t(file, first, last);     break;
2264 					case obj_t::old_monorailwaggon:
2265 					case obj_t::monorail_vehicle:    v = new monorail_vehicle_t(file, first, last);     break;
2266 					case obj_t::maglev_vehicle:         v = new maglev_vehicle_t(file, first, last);     break;
2267 					case obj_t::narrowgauge_vehicle:    v = new narrowgauge_vehicle_t(file, first, last);     break;
2268 					default:
2269 						dbg->fatal("convoi_t::convoi_t()","Can't load vehicle type %d", typ);
2270 				}
2271 			}
2272 
2273 			// no matching vehicle found?
2274 			if(v->get_desc()==NULL) {
2275 				// will create orphan object, but better than crashing at deletion ...
2276 				dbg->error("convoi_t::convoi_t()","Can't load vehicle and no replacement found!");
2277 				i --;
2278 				anz_vehikel --;
2279 				continue;
2280 			}
2281 
2282 			// in very old games, monorail was a railway
2283 			// so we need to convert this
2284 			// freight will be lost, but game will be loadable
2285 			if(i==0  &&  v->get_desc()->get_waytype()==monorail_wt  &&  v->get_typ()==obj_t::rail_vehicle) {
2286 				override_monorail = true;
2287 				vehicle_t *v_neu = new monorail_vehicle_t( v->get_pos(), v->get_desc(), v->get_owner(), NULL );
2288 				v->discard_cargo();
2289 				delete v;
2290 				v = v_neu;
2291 			}
2292 
2293 			if(file->is_version_less(99, 4)) {
2294 				dummy_pos.rdwr(file);
2295 			}
2296 
2297 			const vehicle_desc_t *info = v->get_desc();
2298 			assert(info);
2299 
2300 			// Hajo: if we load a game from a file which was saved from a
2301 			// game with a different vehicle.tab, there might be no vehicle
2302 			// info
2303 			if(info) {
2304 				sum_power += info->get_power();
2305 				sum_gear_and_power += info->get_power()*info->get_gear();
2306 				sum_weight += info->get_weight();
2307 				sum_running_costs -= info->get_running_cost();
2308 				is_electric |= info->get_engine_type()==vehicle_desc_t::electric;
2309 				has_obsolete |= welt->use_timeline()  &&  info->is_retired( welt->get_timeline_year_month() );
2310 				player_t::add_maintenance( get_owner(), info->get_maintenance(), info->get_waytype() );
2311 			}
2312 
2313 			// some versions save vehicles after leaving depot with koord3d::invalid
2314 			if(v->get_pos()==koord3d::invalid) {
2315 				state = INITIAL;
2316 			}
2317 
2318 			if(state!=INITIAL) {
2319 				grund_t *gr;
2320 				gr = welt->lookup(v->get_pos());
2321 				if(!gr) {
2322 					gr = welt->lookup_kartenboden(v->get_pos().get_2d());
2323 					if(gr) {
2324 						dbg->error("convoi_t::rdwr()", "invalid position %s for vehicle %s in state %d (setting to %i,%i,%i)", v->get_pos().get_str(), v->get_name(), state, gr->get_pos().x, gr->get_pos().y, gr->get_pos().z );
2325 						v->set_pos( gr->get_pos() );
2326 					}
2327 					else {
2328 						dbg->fatal("convoi_t::rdwr()", "invalid position %s for vehicle %s in state %d", v->get_pos().get_str(), v->get_name(), state);
2329 					}
2330 					state = INITIAL;
2331 				}
2332 				// add to blockstrecke
2333 				if(v->get_waytype()==track_wt  ||  v->get_waytype()==monorail_wt  ||  v->get_waytype()==maglev_wt  ||  v->get_waytype()==narrowgauge_wt) {
2334 					schiene_t* sch = (schiene_t*)gr->get_weg(v->get_waytype());
2335 					if(sch) {
2336 						sch->reserve(self,ribi_t::none);
2337 					}
2338 					// add to crossing
2339 					if(gr->ist_uebergang()) {
2340 						gr->find<crossing_t>()->add_to_crossing(v);
2341 					}
2342 				}
2343 				if(  gr->get_top()>253  ) {
2344 					dbg->warning( "convoi_t::rdwr()", "cannot put vehicle on ground at (%s)", gr->get_pos().get_str() );
2345 				}
2346 				gr->obj_add(v);
2347 				v->clear_flag(obj_t::not_on_map);
2348 			}
2349 			else {
2350 				v->set_flag(obj_t::not_on_map);
2351 			}
2352 
2353 			// add to convoi
2354 			fahr[i] = v;
2355 		}
2356 		sum_gesamtweight = sum_weight;
2357 	}
2358 
2359 	bool has_schedule = (schedule != NULL);
2360 	file->rdwr_bool(has_schedule);
2361 	if(has_schedule) {
2362 		//DBG_MESSAGE("convoi_t::rdwr()","convoi has a schedule, state %s!",state_names[state]);
2363 		const vehicle_t* v = fahr[0];
2364 		if(file->is_loading() && v) {
2365 			schedule = v->generate_new_schedule();
2366 		}
2367 		// Hajo: hack to load corrupted games -> there is a schedule
2368 		// but no vehicle so we can't determine the exact type of
2369 		// schedule needed. This hack is safe because convois
2370 		// without vehicles get deleted right after loading.
2371 		// Since generic schedules are not allowed, we use a train_schedule_t
2372 		if(schedule == 0) {
2373 			schedule = new train_schedule_t();
2374 		}
2375 
2376 		// Hajo: now read the schedule, we have one for sure here
2377 		schedule->rdwr( file );
2378 	}
2379 
2380 	if(file->is_loading()) {
2381 		next_wolke = 0;
2382 		calc_loading();
2383 	}
2384 
2385 	// Hajo: calculate new minimum top speed
2386 	min_top_speed = calc_min_top_speed(fahr, anz_vehikel);
2387 
2388 	// Hajo: since sp_ist became obsolete, sp_soll is used modulo 65536
2389 	sp_soll &= 65535;
2390 
2391 	if(file->is_version_less(88, 4)) {
2392 		// load statistics
2393 		int j;
2394 		for (j = 0; j<3; j++) {
2395 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2396 				file->rdwr_longlong(financial_history[k][j]);
2397 			}
2398 		}
2399 		for (j = 2; j<5; j++) {
2400 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2401 				file->rdwr_longlong(financial_history[k][j]);
2402 			}
2403 		}
2404 		for (size_t k = MAX_MONTHS; k-- != 0;) {
2405 			financial_history[k][CONVOI_DISTANCE] = 0;
2406 			financial_history[k][CONVOI_MAXSPEED] = 0;
2407 			financial_history[k][CONVOI_WAYTOLL] = 0;
2408 		}
2409 	}
2410 	else if(  file->is_version_less(102, 3)  ){
2411 		// load statistics
2412 		for (int j = 0; j<5; j++) {
2413 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2414 				file->rdwr_longlong(financial_history[k][j]);
2415 			}
2416 		}
2417 		for (size_t k = MAX_MONTHS; k-- != 0;) {
2418 			financial_history[k][CONVOI_DISTANCE] = 0;
2419 			financial_history[k][CONVOI_MAXSPEED] = 0;
2420 			financial_history[k][CONVOI_WAYTOLL] = 0;
2421 		}
2422 	}
2423 	else if(  file->is_version_less(111, 1)  ){
2424 		// load statistics
2425 		for (int j = 0; j<6; j++) {
2426 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2427 				file->rdwr_longlong(financial_history[k][j]);
2428 			}
2429 		}
2430 		for (size_t k = MAX_MONTHS; k-- != 0;) {
2431 			financial_history[k][CONVOI_MAXSPEED] = 0;
2432 			financial_history[k][CONVOI_WAYTOLL] = 0;
2433 		}
2434 	}
2435 	else if(  file->is_version_less(112, 8)  ){
2436 		// load statistics
2437 		for (int j = 0; j<7; j++) {
2438 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2439 				file->rdwr_longlong(financial_history[k][j]);
2440 			}
2441 		}
2442 		for (size_t k = MAX_MONTHS; k-- != 0;) {
2443 			financial_history[k][CONVOI_WAYTOLL] = 0;
2444 		}
2445 	}
2446 	else
2447 	{
2448 		// load statistics
2449 		for (int j = 0; j<MAX_CONVOI_COST; j++) {
2450 			for (size_t k = MAX_MONTHS; k-- != 0;) {
2451 				file->rdwr_longlong(financial_history[k][j]);
2452 			}
2453 		}
2454 	}
2455 
2456 	// the convoi odometer
2457 	if(  file->is_version_atleast(102, 3)  ){
2458 		file->rdwr_longlong( total_distance_traveled);
2459 	}
2460 
2461 	// since it was saved as an signed int
2462 	// we recalc it anyhow
2463 	if(file->is_loading()) {
2464 		jahresgewinn = 0;
2465 		for(int i=welt->get_last_month()%12;  i>=0;  i--  ) {
2466 			jahresgewinn += financial_history[i][CONVOI_PROFIT];
2467 		}
2468 	}
2469 
2470 	// save/restore pending line updates
2471 	if(file->is_version_atleast(84, 9)  &&  file->is_version_less(99, 13)) {
2472 		file->rdwr_long(dummy);	// ignore
2473 	}
2474 	if(file->is_loading()) {
2475 		line_update_pending = linehandle_t();
2476 	}
2477 
2478 	if(file->is_version_atleast(84, 10)) {
2479 		home_depot.rdwr(file);
2480 	}
2481 
2482 	// Old versions recorded last_stop_pos in convoi, not in vehicle
2483 	koord3d last_stop_pos_convoi = koord3d(0,0,0);
2484 	if (anz_vehikel !=0) {
2485 		last_stop_pos_convoi = fahr[0]->last_stop_pos;
2486 	}
2487 	if(file->is_version_atleast(87, 1)) {
2488 		last_stop_pos_convoi.rdwr(file);
2489 	}
2490 	else {
2491 		last_stop_pos_convoi =
2492 			!route.empty()   ? route.front()      :
2493 			anz_vehikel != 0 ? fahr[0]->get_pos() :
2494 			koord3d(0, 0, 0);
2495 	}
2496 
2497 	// for leaving the depot routine
2498 	if(file->is_version_less(99, 14)) {
2499 		steps_driven = -1;
2500 	}
2501 	else {
2502 		file->rdwr_short(steps_driven);
2503 	}
2504 
2505 	// waiting time left ...
2506 	if(file->is_version_atleast(99, 17)) {
2507 		if(file->is_saving()) {
2508 			if(  has_schedule  &&  schedule->get_current_entry().waiting_time_shift > 0  ) {
2509 				uint32 diff_ticks = arrived_time + (welt->ticks_per_world_month >> (16 - schedule->get_current_entry().waiting_time_shift)) - welt->get_ticks();
2510 				file->rdwr_long(diff_ticks);
2511 			}
2512 			else {
2513 				uint32 diff_ticks = 0xFFFFFFFFu; // write old WAIT_INFINITE value for backwards compatibility
2514 				file->rdwr_long(diff_ticks);
2515 			}
2516 		}
2517 		else {
2518 			uint32 diff_ticks = 0;
2519 			file->rdwr_long(diff_ticks);
2520 			arrived_time = has_schedule ? welt->get_ticks() - (welt->ticks_per_world_month >> (16 - schedule->get_current_entry().waiting_time_shift)) + diff_ticks : 0;
2521 		}
2522 	}
2523 
2524 	// since 99015, the last stop will be maintained by the vehikels themselves
2525 	if(file->is_version_less(99, 15)) {
2526 		for(unsigned i=0; i<anz_vehikel; i++) {
2527 			fahr[i]->last_stop_pos = last_stop_pos_convoi;
2528 		}
2529 	}
2530 
2531 	// overtaking status
2532 	if(file->is_version_less(100, 1)) {
2533 		set_tiles_overtaking( 0 );
2534 	}
2535 	else {
2536 		file->rdwr_byte(tiles_overtaking);
2537 		set_tiles_overtaking( tiles_overtaking );
2538 	}
2539 	// no_load, withdraw
2540 	if(file->is_version_less(102, 1)) {
2541 		no_load = false;
2542 		withdraw = false;
2543 	}
2544 	else {
2545 		file->rdwr_bool(no_load);
2546 		file->rdwr_bool(withdraw);
2547 	}
2548 
2549 	if(file->is_version_atleast(111, 1)) {
2550 		file->rdwr_long( distance_since_last_stop );
2551 		file->rdwr_long( sum_speed_limit );
2552 	}
2553 
2554 	if(  file->is_version_atleast(111, 2)  ) {
2555 		file->rdwr_long( maxspeed_average_count );
2556 	}
2557 
2558 	if(  file->is_version_atleast(111, 3)  ) {
2559 		file->rdwr_short( next_stop_index );
2560 		file->rdwr_short( next_reservation_index );
2561 	}
2562 
2563 	if(  file->is_loading()  ) {
2564 		reserve_route();
2565 		recalc_catg_index();
2566 	}
2567 }
2568 
2569 
open_info_window()2570 void convoi_t::open_info_window()
2571 {
2572 	if(  in_depot()  ) {
2573 		// Knightly : if ownership matches, we can try to open the depot dialog
2574 		if(  get_owner()==welt->get_active_player()  ) {
2575 			grund_t *const ground = welt->lookup( get_home_depot() );
2576 			if(  ground  ) {
2577 				depot_t *const depot = ground->get_depot();
2578 				if(  depot  ) {
2579 					depot->show_info();
2580 					// try to activate this particular convoy in the depot
2581 					depot_frame_t *const frame = dynamic_cast<depot_frame_t *>( win_get_magic( (ptrdiff_t)depot ) );
2582 					if(  frame  ) {
2583 						frame->activate_convoi(self);
2584 					}
2585 				}
2586 			}
2587 		}
2588 	}
2589 	else {
2590 		if(  env_t::verbose_debug  ) {
2591 			dump();
2592 		}
2593 		create_win( new convoi_info_t(self), w_info, magic_convoi_info+self.get_id() );
2594 	}
2595 }
2596 
2597 
info(cbuffer_t & buf) const2598 void convoi_t::info(cbuffer_t & buf) const
2599 {
2600 	const vehicle_t* v = fahr[0];
2601 	if (v != NULL) {
2602 		char tmp[128];
2603 
2604 		buf.printf("\n %d/%dkm/h (%1.2f$/km)\n", speed_to_kmh(min_top_speed), v->get_desc()->get_topspeed(), get_running_cost() / 100.0);
2605 		buf.printf(" %s: %ikW\n", translator::translate("Leistung"), sum_power);
2606 		buf.printf(" %s: %i (%i) t\n", translator::translate("Gewicht"), sum_weight, sum_gesamtweight - sum_weight);
2607 		buf.printf(" %s: ", translator::translate("Gewinn"));
2608 		money_to_string(tmp, (double)jahresgewinn);
2609 		buf.append(tmp);
2610 		buf.append("\n");
2611 	}
2612 }
2613 
2614 
2615 // sort order of convoi
set_sortby(uint8 sort_order)2616 void convoi_t::set_sortby(uint8 sort_order)
2617 {
2618 	freight_info_order = sort_order;
2619 	freight_info_resort = true;
2620 }
2621 
2622 
2623 // caches the last info; resorts only when needed
get_freight_info(cbuffer_t & buf)2624 void convoi_t::get_freight_info(cbuffer_t & buf)
2625 {
2626 	if(freight_info_resort) {
2627 		freight_info_resort = false;
2628 		// rebuilt the list with goods ...
2629 		vector_tpl<ware_t> total_fracht;
2630 
2631 		size_t const n = goods_manager_t::get_count();
2632 		ALLOCA(uint32, max_loaded_waren, n);
2633 		MEMZERON(max_loaded_waren, n);
2634 
2635 		for(  uint32 i = 0;  i != anz_vehikel;  ++i  ) {
2636 			const vehicle_t* v = fahr[i];
2637 
2638 			// first add to capacity indicator
2639 			const goods_desc_t* ware_desc = v->get_desc()->get_freight_type();
2640 			const uint16 menge = v->get_desc()->get_capacity();
2641 			if(menge>0  &&  ware_desc!=goods_manager_t::none) {
2642 				max_loaded_waren[ware_desc->get_index()] += menge;
2643 			}
2644 
2645 			// then add the actual load
2646 			FOR(slist_tpl<ware_t>, ware, v->get_cargo()) {
2647 				FOR(vector_tpl<ware_t>, & tmp, total_fracht) {
2648 					// could this be joined with existing freight?
2649 
2650 					// for pax: join according next stop
2651 					// for all others we *must* use target coordinates
2652 					if( ware.same_destination(tmp) ) {
2653 						tmp.menge += ware.menge;
2654 						ware.menge = 0;
2655 						break;
2656 					}
2657 				}
2658 
2659 				// if != 0 we could not join it to existing => load it
2660 				if(ware.menge != 0) {
2661 					total_fracht.append(ware);
2662 				}
2663 			}
2664 
2665 			INT_CHECK("simconvoi 2643");
2666 		}
2667 		buf.clear();
2668 
2669 		// apend info on total capacity
2670 		slist_tpl <ware_t>capacity;
2671 		for (size_t i = 0; i != n; ++i) {
2672 			if(max_loaded_waren[i]>0  &&  i!=goods_manager_t::INDEX_NONE) {
2673 				ware_t ware(goods_manager_t::get_info(i));
2674 				ware.menge = max_loaded_waren[i];
2675 				// append to category?
2676 				slist_tpl<ware_t>::iterator j   = capacity.begin();
2677 				slist_tpl<ware_t>::iterator end = capacity.end();
2678 				while (j != end && j->get_desc()->get_catg_index() < ware.get_desc()->get_catg_index()) ++j;
2679 				if (j != end && j->get_desc()->get_catg_index() == ware.get_desc()->get_catg_index()) {
2680 					j->menge += max_loaded_waren[i];
2681 				} else {
2682 					// not yet there
2683 					capacity.insert(j, ware);
2684 				}
2685 			}
2686 		}
2687 
2688 		// show new info
2689 		freight_list_sorter_t::sort_freight(total_fracht, buf, (freight_list_sorter_t::sort_mode_t)freight_info_order, &capacity, "loaded");
2690 	}
2691 }
2692 
2693 
open_schedule_window(bool show)2694 void convoi_t::open_schedule_window( bool show )
2695 {
2696 	DBG_MESSAGE("convoi_t::open_schedule_window()","Id = %ld, State = %d, Lock = %d",self.get_id(), state, wait_lock);
2697 
2698 	// manipulation of schedule not allowed while:
2699 	// - just starting
2700 	// - a line update is pending
2701 	if(  (state==EDIT_SCHEDULE  ||  line_update_pending.is_bound())  &&  get_owner()==welt->get_active_player()  ) {
2702 		if (show) {
2703 			create_win( new news_img("Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later!"), w_time_delete, magic_none );
2704 		}
2705 		return;
2706 	}
2707 
2708 	if(state==DRIVING) {
2709 		// book the current value of goods
2710 		calc_gewinn();
2711 	}
2712 
2713 	akt_speed = 0;	// stop the train ...
2714 	if(state!=INITIAL) {
2715 		state = EDIT_SCHEDULE;
2716 	}
2717 	wait_lock = 25000;
2718 	alte_richtung = fahr[0]->get_direction();
2719 
2720 	if(  show  ) {
2721 		// Open schedule dialog
2722 		create_win( new schedule_gui_t(schedule,get_owner(),self), w_info, (ptrdiff_t)schedule );
2723 		// TODO: what happens if no client opens the window??
2724 	}
2725 	schedule->start_editing();
2726 }
2727 
2728 
2729 /**
2730  * Check validity of convoi with respect to vehicle constraints
2731  */
pruefe_alle()2732 bool convoi_t::pruefe_alle()
2733 {
2734 	bool ok = anz_vehikel == 0  ||  fahr[0]->get_desc()->can_follow(NULL);
2735 	unsigned i;
2736 
2737 	const vehicle_t* pred = fahr[0];
2738 	for(i = 1; ok && i < anz_vehikel; i++) {
2739 		const vehicle_t* v = fahr[i];
2740 		ok = pred->get_desc()->can_lead(v->get_desc())  &&
2741 				 v->get_desc()->can_follow(pred->get_desc());
2742 		pred = v;
2743 	}
2744 	if(ok) {
2745 		ok = pred->get_desc()->can_lead(NULL);
2746 	}
2747 
2748 	return ok;
2749 }
2750 
2751 
2752 /**
2753  * Kontrolliert Be- und Entladen
2754  * @author Hj. Malthaner
2755  *
2756  * V.Meyer: minimum_loading is now stored in the object (not returned)
2757  */
laden()2758 void convoi_t::laden()
2759 {
2760 	if(  state == EDIT_SCHEDULE  ) {
2761 		return;
2762 	}
2763 
2764 	// just wait a little longer if this is a non-bound halt
2765 	wait_lock = (WTT_LOADING*2)+(self.get_id())%1024;
2766 
2767 	halthandle_t halt = haltestelle_t::get_halt(schedule->get_current_entry().pos,owner);
2768 	// eigene haltestelle ?
2769 	if(  halt.is_bound()  ) {
2770 		const player_t* halt_owner = halt->get_owner();
2771 		if(  halt_owner == get_owner()  ||  halt_owner == welt->get_public_player()  ) {
2772 			// loading/unloading ...
2773 			halt->request_loading( self );
2774 		}
2775 	}
2776 }
2777 
2778 
2779 /**
2780  * calculate income for last hop
2781  * @author Hj. Malthaner
2782  */
calc_gewinn()2783 void convoi_t::calc_gewinn()
2784 {
2785 	sint64 gewinn = 0;
2786 
2787 	for(unsigned i=0; i<anz_vehikel; i++) {
2788 		vehicle_t* v = fahr[i];
2789 		sint64 tmp;
2790 		gewinn += tmp = v->calc_revenue(v->last_stop_pos, v->get_pos() );
2791 		// get_schedule is needed as v->get_waytype() returns track_wt for trams (instead of tram_wt
2792 		owner->book_revenue(tmp, fahr[0]->get_pos().get_2d(), get_schedule()->get_waytype(), v->get_cargo_type()->get_index() );
2793 		v->last_stop_pos = v->get_pos();
2794 	}
2795 
2796 	// update statistics of average speed
2797 	if(  distance_since_last_stop  ) {
2798 		financial_history[0][CONVOI_MAXSPEED] *= maxspeed_average_count;
2799 		financial_history[0][CONVOI_MAXSPEED] += get_speedbonus_kmh();
2800 		maxspeed_average_count ++;
2801 		financial_history[0][CONVOI_MAXSPEED] /= maxspeed_average_count;
2802 	}
2803 	distance_since_last_stop = 0;
2804 	sum_speed_limit = 0;
2805 
2806 	if(gewinn) {
2807 		jahresgewinn += gewinn;
2808 
2809 		book(gewinn, CONVOI_PROFIT);
2810 		book(gewinn, CONVOI_REVENUE);
2811 	}
2812 }
2813 
2814 
2815 /**
2816  * convoi an haltestelle anhalten
2817  * @author Hj. Malthaner
2818  *
2819  * V.Meyer: minimum_loading is now stored in the object (not returned)
2820  */
hat_gehalten(halthandle_t halt)2821 void convoi_t::hat_gehalten(halthandle_t halt)
2822 {
2823 	grund_t *gr=welt->lookup(fahr[0]->get_pos());
2824 
2825 	// now find out station length
2826 	uint16 vehicles_loading = 0;
2827 	if(  gr->is_water()  ) {
2828 		// harbour has any size
2829 		vehicles_loading = anz_vehikel;
2830 	}
2831 	else {
2832 		// calculate real station length
2833 		// and numbers of vehicles that can be (un)loaded
2834 		koord zv = koord( ribi_t::backward(fahr[0]->get_direction()) );
2835 		koord3d pos = fahr[0]->get_pos();
2836 		// start on bridge?
2837 		pos.z += gr->get_weg_yoff() / TILE_HEIGHT_STEP;
2838 		// difference between actual station length and vehicle lenghts
2839 		sint16 station_length = -fahr[vehicles_loading]->get_desc()->get_length();
2840 		do {
2841 			// advance one station tile
2842 			station_length += CARUNITS_PER_TILE;
2843 
2844 			while(station_length >= 0) {
2845 				vehicles_loading++;
2846 				if (vehicles_loading < anz_vehikel) {
2847 					station_length -= fahr[vehicles_loading]->get_desc()->get_length();
2848 				}
2849 				else {
2850 					// all vehicles fit into station
2851 					goto station_tile_search_ready;
2852 				}
2853 			}
2854 
2855 			// search for next station tile
2856 			pos += zv;
2857 			gr = welt->lookup(pos);
2858 			if (gr == NULL) {
2859 				gr = welt->lookup(pos-koord3d(0,0,1));
2860 				if (gr == NULL) {
2861 					gr = welt->lookup(pos-koord3d(0,0,2));
2862 				}
2863 				if (gr  &&  (pos.z != gr->get_hoehe() + gr->get_weg_yoff()/TILE_HEIGHT_STEP) ) {
2864 					// not end/start of bridge
2865 					break;
2866 				}
2867 			}
2868 
2869 		}  while(  gr  &&  gr->get_halt() == halt  );
2870 		// finished
2871 station_tile_search_ready: ;
2872 	}
2873 
2874 	// prepare a list of all destination halts in the schedule
2875 	vector_tpl<halthandle_t> destination_halts(schedule->get_count());
2876 	if (!no_load) {
2877 		const uint8 count = schedule->get_count();
2878 		for(  uint8 i=1;  i<count;  i++  ) {
2879 			const uint8 wrap_i = (i + schedule->get_current_stop()) % count;
2880 
2881 			const halthandle_t plan_halt = haltestelle_t::get_halt(schedule->entries[wrap_i].pos, owner);
2882 			if(plan_halt == halt) {
2883 				// we will come later here again ...
2884 				break;
2885 			}
2886 			else if(  !plan_halt.is_bound()  ) {
2887 				if(  grund_t *gr = welt->lookup( schedule->entries[wrap_i].pos )  ) {
2888 					if(  gr->get_depot()  ) {
2889 						// do not load for stops after a depot
2890 						break;
2891 					}
2892 				}
2893 				continue;
2894 			}
2895 			destination_halts.append(plan_halt);
2896 		}
2897 	}
2898 
2899 	// only load vehicles in station
2900 	// don't load when vehicle is being withdrawn
2901 	bool changed_loading_level = false;
2902 	uint32 time = WTT_LOADING;	// min time for loading/unloading
2903 	sint64 gewinn = 0;
2904 
2905 	// cargo type of previous vehicle that could not be filled
2906 	const goods_desc_t* cargo_type_prev = NULL;
2907 
2908 	for(unsigned i=0; i<vehicles_loading; i++) {
2909 		vehicle_t* v = fahr[i];
2910 
2911 		// we need not to call this on the same position
2912 		if(  v->last_stop_pos != v->get_pos()  ) {
2913 			sint64 tmp;
2914 			// calc_revenue
2915 			gewinn += tmp = v->calc_revenue(v->last_stop_pos, v->get_pos() );
2916 			owner->book_revenue(tmp, fahr[0]->get_pos().get_2d(), get_schedule()->get_waytype(), v->get_cargo_type()->get_index());
2917 			v->last_stop_pos = v->get_pos();
2918 		}
2919 
2920 		const grund_t *gr = welt->lookup( schedule->entries[(schedule->get_current_stop()+1)%schedule->get_count()].pos );
2921 		const bool next_depot = gr  &&  gr->get_depot();
2922 		uint16 amount = v->unload_cargo(halt, next_depot  );
2923 
2924 		if(  !no_load  &&  !next_depot  &&  v->get_total_cargo() < v->get_cargo_max()  ) {
2925 			// load if: unloaded something (might go back) or previous non-filled car requested different cargo type
2926 			if (amount>0  ||  cargo_type_prev==NULL  ||  !cargo_type_prev->is_interchangeable(v->get_cargo_type())) {
2927 				// load
2928 				amount += v->load_cargo(halt, destination_halts);
2929 			}
2930 			if (v->get_total_cargo() < v->get_cargo_max()) {
2931 				// not full
2932 				cargo_type_prev = v->get_cargo_type();
2933 			}
2934 		}
2935 
2936 		if(  amount  ) {
2937 			time = max( time, (amount*v->get_desc()->get_loading_time()) / max(v->get_cargo_max(), 1) );
2938 			v->mark_image_dirty(v->get_image(), 0);
2939 			v->calc_image();
2940 			changed_loading_level = true;
2941 		}
2942 	}
2943 	freight_info_resort |= changed_loading_level;
2944 	if(  changed_loading_level  ) {
2945 		halt->recalc_status();
2946 	}
2947 
2948 	// any unloading/loading went on?
2949 	if(  changed_loading_level  ) {
2950 		calc_loading();
2951 	}
2952 	loading_limit = schedule->get_current_entry().minimum_loading;
2953 
2954 	// update statistics of average speed
2955 	if(  distance_since_last_stop  ) {
2956 		financial_history[0][CONVOI_MAXSPEED] *= maxspeed_average_count;
2957 		financial_history[0][CONVOI_MAXSPEED] += get_speedbonus_kmh();
2958 		maxspeed_average_count ++;
2959 		financial_history[0][CONVOI_MAXSPEED] /= maxspeed_average_count;
2960 	}
2961 	distance_since_last_stop = 0;
2962 	sum_speed_limit = 0;
2963 
2964 	if(gewinn) {
2965 		jahresgewinn += gewinn;
2966 
2967 		book(gewinn, CONVOI_PROFIT);
2968 		book(gewinn, CONVOI_REVENUE);
2969 	}
2970 
2971 	// loading is finished => maybe drive on
2972 	if(  loading_level >= loading_limit  ||  no_load
2973 		||  (schedule->get_current_entry().waiting_time_shift > 0  &&  welt->get_ticks() - arrived_time > (welt->ticks_per_world_month >> (16 - schedule->get_current_entry().waiting_time_shift)) ) ) {
2974 
2975 		if(  withdraw  &&  (loading_level == 0  ||  goods_catg_index.empty())  ) {
2976 			// destroy when empty
2977 			self_destruct();
2978 			return;
2979 		}
2980 
2981 		calc_speedbonus_kmh();
2982 
2983 		// add available capacity after loading(!) to statistics
2984 		for (unsigned i = 0; i<anz_vehikel; i++) {
2985 			book(get_vehikel(i)->get_cargo_max()-get_vehikel(i)->get_total_cargo(), CONVOI_CAPACITY);
2986 		}
2987 
2988 		// Advance schedule
2989 		schedule->advance();
2990 		state = ROUTING_1;
2991 		loading_limit = 0;
2992 	}
2993 
2994 	INT_CHECK( "convoi_t::hat_gehalten" );
2995 
2996 	// at least wait the minimum time for loading
2997 	wait_lock = time;
2998 }
2999 
3000 
calc_restwert() const3001 sint64 convoi_t::calc_restwert() const
3002 {
3003 	sint64 result = 0;
3004 
3005 	for(uint i=0; i<anz_vehikel; i++) {
3006 		result += fahr[i]->calc_sale_value();
3007 	}
3008 	return result;
3009 }
3010 
3011 
3012 /**
3013  * Calculate loading_level and loading_limit. This depends on current state (loading or not).
3014  * @author Volker Meyer
3015  * @date  20.06.2003
3016  */
calc_loading()3017 void convoi_t::calc_loading()
3018 {
3019 	int fracht_max = 0;
3020 	int fracht_menge = 0;
3021 	for(unsigned i=0; i<anz_vehikel; i++) {
3022 		const vehicle_t* v = fahr[i];
3023 		fracht_max += v->get_cargo_max();
3024 		fracht_menge += v->get_total_cargo();
3025 	}
3026 	loading_level = fracht_max > 0 ? (fracht_menge*100)/fracht_max : 100;
3027 	loading_limit = 0;	// will be set correctly from hat_gehalten() routine
3028 
3029 	// since weight has changed
3030 	recalc_data=true;
3031 }
3032 
3033 
calc_speedbonus_kmh()3034 void convoi_t::calc_speedbonus_kmh()
3035 {
3036 	// init with default
3037 	const sint32 cnv_min_top_kmh = speed_to_kmh( min_top_speed );
3038 	speedbonus_kmh = cnv_min_top_kmh;
3039 	// flying aircraft have 0 friction --> speed not limited by power, so just use top_speed
3040 	if(  front()!=NULL  &&  front()->get_waytype() != air_wt  ) {
3041 		sint32 total_max_weight = 0;
3042 		sint32 total_weight = 0;
3043 		for(  unsigned i=0;  i<anz_vehikel;  i++  ) {
3044 			const vehicle_desc_t* const desc = fahr[i]->get_desc();
3045 			total_max_weight += desc->get_weight();
3046 			total_weight += fahr[i]->get_total_weight(); // convoi_t::sum_gesamweight may not be updated yet when this method is called...
3047 			if(  desc->get_freight_type() == goods_manager_t::none  ) {
3048 				; // nothing
3049 			}
3050 			else if(  desc->get_freight_type()->get_catg() == 0  ) {
3051 				// use full weight for passengers, mail, and special goods
3052 				total_max_weight += desc->get_freight_type()->get_weight_per_unit() * desc->get_capacity();
3053 			}
3054 			else {
3055 				// use actual weight for regular goods
3056 				total_max_weight += fahr[i]->get_cargo_weight();
3057 			}
3058 		}
3059 		// very old vehicles have zero weight ...
3060 		if(  total_weight>0  ) {
3061 
3062 			speedbonus_kmh = speed_to_kmh( calc_max_speed(sum_gear_and_power, total_max_weight, min_top_speed) );
3063 
3064 			// convoi overtakers use current actual weight for achievable speed
3065 			if(  front()->get_overtaker()  ) {
3066 				max_power_speed = calc_max_speed(sum_gear_and_power, total_weight, min_top_speed);
3067 			}
3068 		}
3069 	}
3070 }
3071 
3072 
3073 // return the current bonus speed
get_speedbonus_kmh() const3074 sint32 convoi_t::get_speedbonus_kmh() const
3075 {
3076 	if(  distance_since_last_stop > 0  &&  front()!=NULL  &&  front()->get_waytype() != air_wt  ) {
3077 		return min( speedbonus_kmh, (sint32)(sum_speed_limit / distance_since_last_stop) );
3078 	}
3079 	return speedbonus_kmh;
3080 }
3081 
3082 
3083 // return the current bonus speed
get_average_kmh() const3084 uint32 convoi_t::get_average_kmh() const
3085 {
3086 	if(  distance_since_last_stop > 0  ) {
3087 		return sum_speed_limit / distance_since_last_stop;
3088 	}
3089 	return speedbonus_kmh;
3090 }
3091 
3092 
3093 /**
3094  * Schedule convois for self destruction. Will be executed
3095  * upon next sync step
3096  * @author Hj. Malthaner
3097  */
self_destruct()3098 void convoi_t::self_destruct()
3099 {
3100 	line_update_pending = linehandle_t();	// does not bother to add it to a new line anyway ...
3101 	// convois in depot are not contained in the map array!
3102 	if(state==INITIAL) {
3103 		destroy();
3104 	}
3105 	else {
3106 		state = SELF_DESTRUCT;
3107 		wait_lock = 0;
3108 	}
3109 }
3110 
3111 
3112 /**
3113  * Helper method to remove convois from the map that cannot
3114  * removed normally (i.e. by sending to a depot) anymore.
3115  * This is a workaround for bugs in the game.
3116  * @author Hj. Malthaner
3117  * @date  12-Jul-03
3118  */
destroy()3119 void convoi_t::destroy()
3120 {
3121 	// can be only done here, with a valid convoihandle ...
3122 	if(fahr[0]) {
3123 		fahr[0]->set_convoi(NULL);
3124 	}
3125 
3126 	if(  state == INITIAL  ) {
3127 		// in depot => not on map
3128 		for(  uint8 i = anz_vehikel;  i-- != 0;  ) {
3129 			fahr[i]->set_flag( obj_t::not_on_map );
3130 		}
3131 	}
3132 	state = SELF_DESTRUCT;
3133 
3134 	if(schedule!=NULL  &&  !schedule->is_editing_finished()) {
3135 		destroy_win((ptrdiff_t)schedule);
3136 	}
3137 
3138 	if(  line.is_bound()  ) {
3139 		// needs to be done here to remove correctly ware catg from lines
3140 		unset_line();
3141 		delete schedule;
3142 		schedule = NULL;
3143 	}
3144 
3145 	// pay the current value
3146 	owner->book_new_vehicle( calc_restwert(), get_pos().get_2d(), fahr[0] ? fahr[0]->get_desc()->get_waytype() : ignore_wt );
3147 
3148 	for(  uint8 i = anz_vehikel;  i-- != 0;  ) {
3149 		if(  !fahr[i]->get_flag( obj_t::not_on_map )  ) {
3150 			// remove from rails/roads/crossings
3151 			grund_t *gr = welt->lookup(fahr[i]->get_pos());
3152 			fahr[i]->set_last( true );
3153 			fahr[i]->leave_tile();
3154 			if(  gr  &&  gr->ist_uebergang()  ) {
3155 				gr->find<crossing_t>()->release_crossing(fahr[i]);
3156 			}
3157 			fahr[i]->set_flag( obj_t::not_on_map );
3158 
3159 		}
3160 		player_t::add_maintenance( owner, -fahr[i]->get_desc()->get_maintenance(), fahr[i]->get_desc()->get_waytype() );
3161 
3162 		fahr[i]->discard_cargo();
3163 		fahr[i]->cleanup(owner);
3164 		delete fahr[i];
3165 	}
3166 	anz_vehikel = 0;
3167 
3168 	delete this;
3169 }
3170 
3171 
3172 /**
3173  * Debug info nach stderr
3174  * @author Hj. Malthaner
3175  * @date 04-Sep-03
3176  */
dump() const3177 void convoi_t::dump() const
3178 {
3179 	dbg->debug("convoi::dump()",
3180 		"\nanz_vehikel = %d\n"
3181 		"wait_lock = %d\n"
3182 		"owner_n = %d\n"
3183 		"akt_speed = %d\n"
3184 		"akt_speed_soll = %d\n"
3185 		"sp_soll = %d\n"
3186 		"state = %d\n"
3187 		"statename = %s\n"
3188 		"alte_richtung = %d\n"
3189 		"jahresgewinn = %ld\n"	// %lld crashes mingw now, cast gewinn to long ...
3190 		"name = '%s'\n"
3191 		"line_id = '%d'\n"
3192 		"schedule = '%p'",
3193 		(int)anz_vehikel,
3194 		(int)wait_lock,
3195 		(int)welt->sp2num(owner),
3196 		(int)akt_speed,
3197 		(int)akt_speed_soll,
3198 		(int)sp_soll,
3199 		(int)state,
3200 		(const char *)(state_names[state]),
3201 		(int)alte_richtung,
3202 		(long)(jahresgewinn/100),
3203 		(const char *)name_and_id,
3204 		line.is_bound() ? line.get_id() : 0,
3205 		(const void *)schedule );
3206 }
3207 
3208 
book(sint64 amount,int cost_type)3209 void convoi_t::book(sint64 amount, int cost_type)
3210 {
3211 	assert(  cost_type<MAX_CONVOI_COST);
3212 
3213 	financial_history[0][cost_type] += amount;
3214 	if (line.is_bound()) {
3215 		line->book( amount, simline_t::convoi_to_line_catgory(cost_type) );
3216 	}
3217 }
3218 
3219 
init_financial_history()3220 void convoi_t::init_financial_history()
3221 {
3222 	for (int j = 0; j<MAX_CONVOI_COST; j++) {
3223 		for (size_t k = MAX_MONTHS; k-- != 0;) {
3224 			financial_history[k][j] = 0;
3225 		}
3226 	}
3227 }
3228 
3229 
get_fix_cost() const3230 sint32 convoi_t::get_fix_cost() const
3231 {
3232 	sint32 running_cost = 0;
3233 	for(  unsigned i = 0;  i < get_vehicle_count();  i++  ) {
3234 		running_cost += fahr[i]->get_desc()->get_maintenance();
3235 	}
3236 	return running_cost;
3237 }
3238 
3239 
get_running_cost() const3240 sint32 convoi_t::get_running_cost() const
3241 {
3242 	sint32 running_cost = 0;
3243 	for(  unsigned i = 0;  i < get_vehicle_count();  i++  ) {
3244 		running_cost += fahr[i]->get_operating_cost();
3245 	}
3246 	return running_cost;
3247 }
3248 
3249 
get_purchase_cost() const3250 sint64 convoi_t::get_purchase_cost() const
3251 {
3252 	sint64 purchase_cost = 0;
3253 	for(  unsigned i = 0;  i < get_vehicle_count();  i++  ) {
3254 		purchase_cost += fahr[i]->get_desc()->get_price();
3255 	}
3256 	return purchase_cost;
3257 }
3258 
3259 
3260 /**
3261 * set line
3262 * since convoys must operate on a copy of the route's schedule, we apply a fresh copy
3263 * @author hsiegeln
3264 */
set_line(linehandle_t org_line)3265 void convoi_t::set_line(linehandle_t org_line)
3266 {
3267 	// to remove a convoi from a line, call unset_line(); passing a NULL is not allowed!
3268 	if(!org_line.is_bound()) {
3269 		return;
3270 	}
3271 	if(  line.is_bound()  ) {
3272 		unset_line();
3273 	}
3274 	else {
3275 		// Knightly : originally a lineless convoy -> unregister itself from stops as it now belongs to a line
3276 		unregister_stops();
3277 		// must trigger refresh if old schedule was not empty
3278 		if (schedule  &&  !schedule->empty()) {
3279 			welt->set_schedule_counter();
3280 		}
3281 	}
3282 	line_update_pending = org_line;
3283 	check_pending_updates();
3284 }
3285 
3286 
3287 /**
3288 * unset line
3289 * removes convoy from route without destroying its schedule
3290 * => no need to recalculate connections!
3291 * @author hsiegeln
3292 */
unset_line()3293 void convoi_t::unset_line()
3294 {
3295 	if(  line.is_bound()  ) {
3296 DBG_DEBUG("convoi_t::unset_line()", "removing old destinations from line=%d, schedule=%p",line.get_id(),schedule);
3297 		line->remove_convoy(self);
3298 		line = linehandle_t();
3299 		line_update_pending = linehandle_t();
3300 	}
3301 }
3302 
3303 
3304 // matches two halts; if the pos is not identical, maybe the halt still is the same
matches_halt(const koord3d pos1,const koord3d pos2)3305 bool convoi_t::matches_halt( const koord3d pos1, const koord3d pos2 )
3306 {
3307 	halthandle_t halt1 = haltestelle_t::get_halt(pos1, owner );
3308 	return pos1==pos2  ||  (halt1.is_bound()  &&  halt1==haltestelle_t::get_halt( pos2, owner ));
3309 }
3310 
3311 
3312 // updates a line schedule and tries to find the best next station to go
check_pending_updates()3313 void convoi_t::check_pending_updates()
3314 {
3315 	if(  line_update_pending.is_bound()  ) {
3316 		// create dummy schedule
3317 		if(  schedule==NULL  ) {
3318 			schedule = create_schedule();
3319 		}
3320 		schedule_t* new_schedule = line_update_pending->get_schedule();
3321 		int current_stop = schedule->get_current_stop(); // save current position of schedule
3322 		bool is_same = false;
3323 		bool is_depot = false;
3324 		koord3d current = koord3d::invalid, depot = koord3d::invalid;
3325 
3326 		if (schedule->empty() || new_schedule->empty()) {
3327 			// was no entry or is no entry => goto  1st stop
3328 			current_stop = 0;
3329 		}
3330 		else {
3331 			// something to check for ...
3332 			current = schedule->get_current_entry().pos;
3333 
3334 			if(  current_stop<new_schedule->get_count() &&  current==new_schedule->entries[current_stop].pos  ) {
3335 				// next pos is the same => keep the convoi state
3336 				is_same = true;
3337 			}
3338 			else {
3339 				// check depot first (must also keept this state)
3340 				is_depot = (welt->lookup(current)  &&  welt->lookup(current)->get_depot() != NULL);
3341 
3342 				if(is_depot) {
3343 					// depot => current_stop+1 (depot will be restore later before this)
3344 					depot = current;
3345 					schedule->remove();
3346 					current = schedule->get_current_entry().pos;
3347 				}
3348 
3349 				/* there could be only one entry that matches best:
3350 				 * we try first same sequence as in old schedule;
3351 				 * if not found, we try for same nextnext station
3352 				 * (To detect also places, where only the platform
3353 				 *  changed, we also compare the halthandle)
3354 				 */
3355 				const koord3d next = schedule->entries[(current_stop+1)%schedule->get_count()].pos;
3356 				const koord3d nextnext = schedule->entries[(current_stop+2)%schedule->get_count()].pos;
3357 				const koord3d nextnextnext = schedule->entries[(current_stop+3)%schedule->get_count()].pos;
3358 				int how_good_matching = 0;
3359 				const uint8 new_count = new_schedule->get_count();
3360 
3361 				for(  uint8 i=0;  i<new_count;  i++  ) {
3362 					int quality =
3363 						matches_halt(current,new_schedule->entries[i].pos)*3 +
3364 						matches_halt(next,new_schedule->entries[(i+1)%new_count].pos)*4 +
3365 						matches_halt(nextnext,new_schedule->entries[(i+2)%new_count].pos)*2 +
3366 						matches_halt(nextnextnext,new_schedule->entries[(i+3)%new_count].pos);
3367 					if(  quality>how_good_matching  ) {
3368 						// better match than previous: but depending of distance, the next number will be different
3369 						if(  matches_halt(current,new_schedule->entries[i].pos)  ) {
3370 							current_stop = i;
3371 						}
3372 						else if(  matches_halt(next,new_schedule->entries[(i+1)%new_count].pos)  ) {
3373 							current_stop = i+1;
3374 						}
3375 						else if(  matches_halt(nextnext,new_schedule->entries[(i+2)%new_count].pos)  ) {
3376 							current_stop = i+2;
3377 						}
3378 						else if(  matches_halt(nextnextnext,new_schedule->entries[(i+3)%new_count].pos)  ) {
3379 							current_stop = i+3;
3380 						}
3381 						current_stop %= new_count;
3382 						how_good_matching = quality;
3383 					}
3384 				}
3385 
3386 				if(how_good_matching==0) {
3387 					// nothing matches => take the one from the line
3388 					current_stop = new_schedule->get_current_stop();
3389 				}
3390 				// if we go to same, then we do not need route recalculation ...
3391 				is_same = matches_halt(current,new_schedule->entries[current_stop].pos);
3392 			}
3393 		}
3394 
3395 		// we may need to update the line and connection tables
3396 		if(  !line.is_bound()  ) {
3397 			line_update_pending->add_convoy(self);
3398 		}
3399 		line = line_update_pending;
3400 		line_update_pending = linehandle_t();
3401 
3402 		// destroy old schedule and all related windows
3403 		if(!schedule->is_editing_finished()) {
3404 			schedule->copy_from( new_schedule );
3405 			schedule->set_current_stop(current_stop); // set new schedule current position to best match
3406 			schedule->start_editing();
3407 		}
3408 		else {
3409 			schedule->copy_from( new_schedule );
3410 			schedule->set_current_stop(current_stop); // set new schedule current position to one before best match
3411 		}
3412 
3413 		if(is_depot) {
3414 			// next was depot. restore it
3415 			schedule->insert(welt->lookup(depot));
3416 			schedule->set_current_stop( (schedule->get_current_stop()+schedule->get_count()-1)%schedule->get_count() );
3417 		}
3418 
3419 		if (state != INITIAL) {
3420 			// remove wrong freight
3421 			check_freight();
3422 
3423 			if(is_same  ||  is_depot) {
3424 				/* same destination
3425 				 * We are already there => keep current state
3426 				 */
3427 			}
3428 			else {
3429 				// need re-routing
3430 				state = EDIT_SCHEDULE;
3431 			}
3432 			// make this change immediately
3433 			if(  state!=LOADING  ) {
3434 				wait_lock = 0;
3435 			}
3436 		}
3437 	}
3438 }
3439 
3440 
3441 /**
3442  * Register the convoy with the stops in the schedule
3443  * @author Knightly
3444  */
register_stops()3445 void convoi_t::register_stops()
3446 {
3447 	if(  schedule  ) {
3448 		FOR(minivec_tpl<schedule_entry_t>, const& i, schedule->entries) {
3449 			halthandle_t const halt = haltestelle_t::get_halt(i.pos, get_owner());
3450 			if(  halt.is_bound()  ) {
3451 				halt->add_convoy(self);
3452 			}
3453 		}
3454 	}
3455 }
3456 
3457 
3458 /**
3459  * Unregister the convoy from the stops in the schedule
3460  * @author Knightly
3461  */
unregister_stops()3462 void convoi_t::unregister_stops()
3463 {
3464 	if(  schedule  ) {
3465 		FOR(minivec_tpl<schedule_entry_t>, const& i, schedule->entries) {
3466 			halthandle_t const halt = haltestelle_t::get_halt(i.pos, get_owner());
3467 			if(  halt.is_bound()  ) {
3468 				halt->remove_convoy(self);
3469 			}
3470 		}
3471 	}
3472 }
3473 
3474 
3475 // set next stop before breaking will occur (or route search etc.)
3476 // currently only used for tracks
set_next_stop_index(uint16 n)3477 void convoi_t::set_next_stop_index(uint16 n)
3478 {
3479 	// stop at station or signals, not at waypoints
3480 	if(  n==INVALID_INDEX  ) {
3481 		// find out if stop or waypoint, waypoint: do not brake at waypoints
3482 		grund_t const* const gr = welt->lookup(route.back());
3483 		if(  gr  &&  gr->is_halt()  ) {
3484 			n = route.get_count()-1-1; // extra -1 to brake 1 tile earlier when entering station
3485 		}
3486 	}
3487 	next_stop_index = n+1;
3488 }
3489 
3490 
3491 /* including this route_index, the route was reserved the last time
3492  * currently only used for tracks
3493  */
set_next_reservation_index(uint16 n)3494 void convoi_t::set_next_reservation_index(uint16 n)
3495 {
3496 	// stop at station or signals, not at waypoints
3497 	if(  n==INVALID_INDEX  ) {
3498 		n = route.get_count()-1;
3499 	}
3500 	next_reservation_index = n;
3501 }
3502 
3503 
3504 /*
3505  * the current state saved as color
3506  * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete)
3507  */
get_status_color() const3508 PIXVAL convoi_t::get_status_color() const
3509 {
3510 	if(state==INITIAL) {
3511 		// in depot/under assembly
3512 		return SYSCOL_TEXT_HIGHLIGHT;
3513 	}
3514 	else if (state == WAITING_FOR_CLEARANCE_ONE_MONTH || state == CAN_START_ONE_MONTH || get_state() == NO_ROUTE) {
3515 		// stuck or no route
3516 		return color_idx_to_rgb(COL_ORANGE);
3517 	}
3518 	else if(financial_history[0][CONVOI_PROFIT]+financial_history[1][CONVOI_PROFIT]<0) {
3519 		// ok, not performing best
3520 		return MONEY_MINUS;
3521 	}
3522 	else if((financial_history[0][CONVOI_OPERATIONS]|financial_history[1][CONVOI_OPERATIONS])==0) {
3523 		// nothing moved
3524 		return SYSCOL_TEXT_UNUSED;
3525 	}
3526 	else if(has_obsolete) {
3527 		return color_idx_to_rgb(COL_BLUE);
3528 	}
3529 	// normal state
3530 	return SYSCOL_TEXT;
3531 }
3532 
3533 
3534 // returns tiles needed for this convoi
get_tile_length() const3535 uint16 convoi_t::get_tile_length() const
3536 {
3537 	uint16 carunits=0;
3538 	for(uint8 i=0;  i<anz_vehikel-1;  i++) {
3539 		carunits += fahr[i]->get_desc()->get_length();
3540 	}
3541 	// the last vehicle counts differently in stations and for reserving track
3542 	// (1) add 8 = 127/256 tile to account for the driving in stations in north/west direction
3543 	//     see at the end of vehicle_t::hop()
3544 	// (2) for length of convoi for loading in stations the length of the last vehicle matters
3545 	//     see convoi_t::hat_gehalten
3546 	carunits += max(CARUNITS_PER_TILE/2, fahr[anz_vehikel-1]->get_desc()->get_length());
3547 
3548 	uint16 tiles = (carunits + CARUNITS_PER_TILE - 1) / CARUNITS_PER_TILE;
3549 	return tiles;
3550 }
3551 
3552 
3553 // if withdraw and empty, then self destruct
set_withdraw(bool new_withdraw)3554 void convoi_t::set_withdraw(bool new_withdraw)
3555 {
3556 	withdraw = new_withdraw;
3557 	if(  withdraw  &&  (loading_level==0  ||  goods_catg_index.empty())) {
3558 		// test if convoi in depot and not driving
3559 		grund_t *gr = welt->lookup( get_pos());
3560 		if(  gr  &&  gr->get_depot()  &&  state == INITIAL  ) {
3561 #if 1
3562 			// do not touch line bound convois in depots
3563 			withdraw = false;
3564 			no_load = false;
3565 #else
3566 			// disassemble also line bound convois in depots
3567 			gr->get_depot()->disassemble_convoi(self, true);
3568 #endif
3569 		}
3570 		else {
3571 			self_destruct();
3572 		}
3573 	}
3574 }
3575 
3576 
3577 /**
3578  * conditions for a city car to overtake another overtaker.
3579  * The city car is not overtaking/being overtaken.
3580  * @author isidoro
3581  */
can_overtake(overtaker_t * other_overtaker,sint32 other_speed,sint16 steps_other)3582 bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other)
3583 {
3584 	if(fahr[0]->get_waytype()!=road_wt) {
3585 		return false;
3586 	}
3587 
3588 	if (!other_overtaker->can_be_overtaken()) {
3589 		return false;
3590 	}
3591 
3592 	if(  other_speed == 0  ) {
3593 		/* overtaking a loading convoi
3594 		 * => we can do a lazy check, since halts are always straight
3595 		 */
3596 		grund_t *gr = welt->lookup(get_pos());
3597 		if(  gr==NULL  ) {
3598 			// should never happen, since there is a vehicle in front of us ...
3599 			return false;
3600 		}
3601 		weg_t *str = gr->get_weg(road_wt);
3602 		if(  str==0  ) {
3603 			// also this is not possible, since a car loads in front of is!?!
3604 			return false;
3605 		}
3606 
3607 		uint16 idx = fahr[0]->get_route_index();
3608 		const sint32 tiles = other_speed == 0 ? 2 : (steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) + get_tile_length() + 1;
3609 		if(  tiles > 0  &&  idx+(uint32)tiles >= route.get_count()  ) {
3610 			// needs more space than there
3611 			return false;
3612 		}
3613 
3614 		for(  sint32 i=0;  i<tiles;  i++  ) {
3615 			grund_t *gr = welt->lookup( route.at( idx+i ) );
3616 			if(  gr==NULL  ) {
3617 				return false;
3618 			}
3619 			weg_t *str = gr->get_weg(road_wt);
3620 			if(  str==0  ) {
3621 				return false;
3622 			}
3623 			// not overtaking on railroad crossings or normal crossings ...
3624 			if(  str->is_crossing() ) {
3625 				return false;
3626 			}
3627 			if(  ribi_t::is_threeway(str->get_ribi())  ) {
3628 				return false;
3629 			}
3630 			// Check for other vehicles on the next tile
3631 			const uint8 top = gr->get_top();
3632 			for(  uint8 j=1;  j<top;  j++  ) {
3633 				if(  vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j))  ) {
3634 					// check for other traffic on the road
3635 					const overtaker_t *ov = v->get_overtaker();
3636 					if(ov) {
3637 						if(this!=ov  &&  other_overtaker!=ov) {
3638 							return false;
3639 						}
3640 					}
3641 					else if(  v->get_waytype()==road_wt  &&  v->get_typ()!=obj_t::pedestrian  ) {
3642 						return false;
3643 					}
3644 				}
3645 			}
3646 		}
3647 		set_tiles_overtaking( tiles );
3648 		return true;
3649 	}
3650 
3651 	int diff_speed = akt_speed - other_speed;
3652 	if(  diff_speed < kmh_to_speed(5)  ) {
3653 		return false;
3654 	}
3655 
3656 	// Number of tiles overtaking will take
3657 	int n_tiles = 0;
3658 
3659 	// Distance it takes overtaking (unit: vehicle_steps) = my_speed * time_overtaking
3660 	// time_overtaking = tiles_to_overtake/diff_speed
3661 	// tiles_to_overtake = convoi_length + current pos within tile + (pos_other_convoi within tile + length of other convoi) - one tile
3662 	int distance = akt_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed;
3663 	int time_overtaking = 0;
3664 
3665 	// Conditions for overtaking:
3666 	// Flat tiles, with no stops, no crossings, no signs, no change of road speed limit
3667 	// First phase: no traffic except me and my overtaken car in the dangerous zone
3668 	unsigned int route_index = fahr[0]->get_route_index()+1;
3669 	koord3d pos = fahr[0]->get_pos();
3670 	koord3d pos_prev = route_index > 2 ? route.at(route_index-2) : pos;
3671 	koord3d pos_next;
3672 
3673 	while( distance > 0 ) {
3674 
3675 		if(  route_index >= route.get_count()  ) {
3676 			return false;
3677 		}
3678 
3679 		pos_next = route.at(route_index++);
3680 		grund_t *gr = welt->lookup(pos);
3681 		// no ground, or slope => about
3682 		if(  gr==NULL  ||  gr->get_weg_hang()!=slope_t::flat  ) {
3683 			return false;
3684 		}
3685 
3686 		weg_t *str = gr->get_weg(road_wt);
3687 		if(  str==NULL  ) {
3688 			return false;
3689 		}
3690 		// the only roadsign we must account for are choose points and traffic lights
3691 		if(  str->has_sign()  ) {
3692 			const roadsign_t *rs = gr->find<roadsign_t>(1);
3693 			if(rs) {
3694 				const roadsign_desc_t *rb = rs->get_desc();
3695 				if(rb->is_choose_sign()  ||  rb->is_traffic_light()  ) {
3696 					// because we need to stop here ...
3697 					return false;
3698 				}
3699 			}
3700 		}
3701 		// not overtaking on railroad crossings or on normal crossings ...
3702 		if(  str->is_crossing()  ||  ribi_t::is_threeway(str->get_ribi())  ) {
3703 			return false;
3704 		}
3705 		// street gets too slow (TODO: should be able to be correctly accounted for)
3706 		if(  akt_speed > kmh_to_speed(str->get_max_speed())  ) {
3707 			return false;
3708 		}
3709 
3710 		int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : vehicle_base_t::get_diagonal_vehicle_steps_per_tile();
3711 		distance -= d;
3712 		time_overtaking += d;
3713 
3714 		// Check for other vehicles
3715 		const uint8 top = gr->get_top();
3716 		for(  uint8 j=1;  j<top;  j++ ) {
3717 			if (vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j))) {
3718 				// check for other traffic on the road
3719 				const overtaker_t *ov = v->get_overtaker();
3720 				if(ov) {
3721 					if(this!=ov  &&  other_overtaker!=ov) {
3722 						return false;
3723 					}
3724 				}
3725 				else if(  v->get_waytype()==road_wt  &&  v->get_typ()!=obj_t::pedestrian  ) {
3726 					// sheeps etc.
3727 					return false;
3728 				}
3729 			}
3730 		}
3731 		n_tiles++;
3732 		pos_prev = pos;
3733 		pos = pos_next;
3734 	}
3735 
3736 	// Second phase: only facing traffic is forbidden
3737 	//   Since street speed can change, we do the calculation with time.
3738 	//   Each empty tile will subtract tile_dimension/max_street_speed.
3739 	//   If time is exhausted, we are guaranteed that no facing traffic will
3740 	//   invade the dangerous zone.
3741 	// Conditions for the street are milder: e.g. if no street, no facing traffic
3742 	time_overtaking = (time_overtaking << 16)/akt_speed;
3743 	while(  time_overtaking > 0  ) {
3744 
3745 		if(  route_index >= route.get_count()  ) {
3746 			return false;
3747 		}
3748 
3749 		pos_next = route.at(route_index++);
3750 		grund_t *gr= welt->lookup(pos);
3751 		if(  gr==NULL  ) {
3752 			// will cause a route search, but is ok
3753 			break;
3754 		}
3755 
3756 		weg_t *str = gr->get_weg(road_wt);
3757 		if(  str==NULL  ) {
3758 			break;
3759 		}
3760 		// cannot check for oncoming traffic over crossings
3761 		if(  ribi_t::is_threeway(str->get_ribi()) ) {
3762 			return false;
3763 		}
3764 
3765 		if(  ribi_t::is_straight(str->get_ribi())  ) {
3766 			time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed());
3767 		}
3768 		else {
3769 			time_overtaking -= (vehicle_base_t::get_diagonal_vehicle_steps_per_tile()<<16) / kmh_to_speed(str->get_max_speed());
3770 		}
3771 
3772 		// Check for other vehicles in facing direction
3773 		ribi_t::ribi their_direction = ribi_t::backward( fahr[0]->calc_direction(pos_prev, pos_next) );
3774 		const uint8 top = gr->get_top();
3775 		for(  uint8 j=1;  j<top;  j++ ) {
3776 			vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j));
3777 			if (v && v->get_direction() == their_direction && v->get_overtaker()) {
3778 				return false;
3779 			}
3780 		}
3781 		pos_prev = pos;
3782 		pos = pos_next;
3783 	}
3784 
3785 	set_tiles_overtaking( 1+n_tiles );
3786 	other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed );
3787 	return true;
3788 }
3789 
3790 
get_stat_converted(int month,int cost_type) const3791 sint64 convoi_t::get_stat_converted(int month, int cost_type) const
3792 {
3793 	sint64 value = financial_history[month][cost_type];
3794 	switch(cost_type) {
3795 		case CONVOI_REVENUE:
3796 		case CONVOI_OPERATIONS:
3797 		case CONVOI_PROFIT:
3798 		case CONVOI_WAYTOLL:
3799 			value = convert_money(value);
3800 			break;
3801 		default: ;
3802 	}
3803 	return value;
3804 }
3805 
3806 
send_to_depot(bool local)3807 const char* convoi_t::send_to_depot(bool local)
3808 {
3809 	// iterate over all depots and try to find shortest route
3810 	route_t *shortest_route = new route_t();
3811 	route_t *route = new route_t();
3812 	koord3d home = koord3d::invalid;
3813 	vehicle_t *v = front();
3814 	FOR(slist_tpl<depot_t*>, const depot, depot_t::get_depot_list()) {
3815 		if (depot->get_waytype() != v->get_desc()->get_waytype()  ||  depot->get_owner() != get_owner()) {
3816 			continue;
3817 		}
3818 		koord3d pos = depot->get_pos();
3819 
3820 		if(!shortest_route->empty()  &&  koord_distance(pos, get_pos()) >= shortest_route->get_count()-1) {
3821 			// the current route is already shorter, no need to search further
3822 			continue;
3823 		}
3824 		if (v->calc_route(get_pos(), pos, 50, route)) { // do not care about speed
3825 			if(  route->get_count() < shortest_route->get_count()  ||  shortest_route->empty()  ) {
3826 				// just swap the pointers
3827 				sim::swap(shortest_route, route);
3828 				home = pos;
3829 			}
3830 		}
3831 	}
3832 	delete route;
3833 	DBG_MESSAGE("shortest route has ", "%i hops", shortest_route->get_count()-1);
3834 
3835 	if (local) {
3836 		if (convoi_info_t *info = dynamic_cast<convoi_info_t*>(win_get_magic( magic_convoi_info+self.get_id()))) {
3837 			info->route_search_finished();
3838 		}
3839 	}
3840 	// if route to a depot has been found, update the convoi's schedule
3841 	const char *txt;
3842 	if(  !shortest_route->empty()  ) {
3843 		schedule_t *schedule = get_schedule()->copy();
3844 		schedule->insert(welt->lookup(home));
3845 		schedule->set_current_stop( (schedule->get_current_stop()+schedule->get_count()-1)%schedule->get_count() );
3846 		set_schedule(schedule);
3847 		txt = "Convoi has been sent\nto the nearest depot\nof appropriate type.\n";
3848 	}
3849 	else {
3850 		txt = "Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually.";
3851 	}
3852 	delete shortest_route;
3853 
3854 	return txt;
3855 }
3856