1 /*
2  * Copyright (c) 1997 - 2001 Hj. Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic license.
5  * (see license.txt)
6  *
7  * All moving stuff (vehicle_base_t) and all player vehicle (derived from vehicle_t)
8  *
9  * 01.11.99  Moved from simobj.cc
10  *
11  * Hansjoerg Malthaner, Nov. 1999
12  */
13 
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <math.h>
18 
19 #include "../boden/grund.h"
20 #include "../boden/wege/runway.h"
21 #include "../boden/wege/kanal.h"
22 #include "../boden/wege/schiene.h"
23 #include "../boden/wege/monorail.h"
24 #include "../boden/wege/strasse.h"
25 
26 #include "../bauer/goods_manager.h"
27 
28 #include "../simworld.h"
29 #include "../simdebug.h"
30 #include "../simdepot.h"
31 #include "../simconvoi.h"
32 #include "../simunits.h"
33 
34 #include "../player/simplay.h"
35 #include "../simfab.h"
36 #include "../simware.h"
37 #include "../simhalt.h"
38 #include "../simsound.h"
39 
40 #include "../display/simimg.h"
41 #include "../simmesg.h"
42 #include "../simcolor.h"
43 #include "../display/simgraph.h"
44 
45 #include "../simline.h"
46 
47 #include "../simintr.h"
48 
49 #include "../obj/wolke.h"
50 #include "../obj/signal.h"
51 #include "../obj/roadsign.h"
52 #include "../obj/crossing.h"
53 #include "../obj/zeiger.h"
54 
55 #include "../gui/minimap.h"
56 
57 #include "../descriptor/citycar_desc.h"
58 #include "../descriptor/goods_desc.h"
59 #include "../descriptor/skin_desc.h"
60 #include "../descriptor/roadsign_desc.h"
61 
62 #include "../dataobj/schedule.h"
63 #include "../dataobj/translator.h"
64 #include "../dataobj/loadsave.h"
65 #include "../dataobj/environment.h"
66 
67 #include "../utils/simstring.h"
68 #include "../utils/cbuffer_t.h"
69 
70 #include "../bauer/vehikelbauer.h"
71 
72 #include "simvehicle.h"
73 #include "simroadtraffic.h"
74 
75 
76 /* get dx and dy from dir (just to remind you)
77  * any vehicle (including city cars and pedestrians)
78  * will go this distance per sync step.
79  * (however, the real dirs are only calculated during display, these are the old ones)
80  */
81 sint8 vehicle_base_t::dxdy[ 8*2 ] = {
82 	-2, 1,	// s
83 	-2, -1,	// w
84 	-4, 0,	// sw
85 	0, 2,	//se
86 	2, -1,	// n
87 	2, 1,	// e
88 	4, 0,	// ne
89 	0, -2	// nw
90 };
91 
92 
93 // Constants
94 uint8 vehicle_base_t::old_diagonal_vehicle_steps_per_tile = 128;
95 uint8 vehicle_base_t::diagonal_vehicle_steps_per_tile = 181;
96 uint16 vehicle_base_t::diagonal_multiplier = 724;
97 
98 
99 // set only once, before loading!
set_diagonal_multiplier(uint32 multiplier,uint32 old_diagonal_multiplier)100 void vehicle_base_t::set_diagonal_multiplier( uint32 multiplier, uint32 old_diagonal_multiplier )
101 {
102 	diagonal_multiplier = (uint16)multiplier;
103 	diagonal_vehicle_steps_per_tile = (uint8)(130560u/diagonal_multiplier) + 1;
104 	old_diagonal_vehicle_steps_per_tile = (uint8)(130560u/old_diagonal_multiplier) + 1;
105 }
106 
107 
108 // if true, convoi, must restart!
need_realignment() const109 bool vehicle_base_t::need_realignment() const
110 {
111 	return old_diagonal_vehicle_steps_per_tile!=diagonal_vehicle_steps_per_tile  &&  ribi_t::is_bend(direction);
112 }
113 
114 // [0]=xoff [1]=yoff
115 sint8 vehicle_base_t::driveleft_base_offsets[8][2] =
116 {
117 	{ 12, 6 },
118 	{ -12, 6 },
119 	{ 0, 6 },
120 	{ 12, 0 },
121 	{ -12, -6 },
122 	{ 12, -6 },
123 	{ 0, -6 },
124 	{ -12, 0 }
125 //	{ 12, -12, 0, 12, -12, 12, 0 -12 },
126 //	{ 6, 6, 6, 0, -6, -6, -6, 0 }
127 };
128 
129 // [0]=xoff [1]=yoff
130 sint8 vehicle_base_t::overtaking_base_offsets[8][2];
131 
132 // recalc offsets for overtaking
set_overtaking_offsets(bool driving_on_the_left)133 void vehicle_base_t::set_overtaking_offsets( bool driving_on_the_left )
134 {
135 	sint8 sign = driving_on_the_left ? -1 : 1;
136 	// a tile has the internal size of
137 	const sint8 XOFF=12;
138 	const sint8 YOFF=6;
139 
140 	overtaking_base_offsets[0][0] = sign * XOFF;
141 	overtaking_base_offsets[1][0] = -sign * XOFF;
142 	overtaking_base_offsets[2][0] = 0;
143 	overtaking_base_offsets[3][0] = sign * XOFF;
144 	overtaking_base_offsets[4][0] = -sign * XOFF;
145 	overtaking_base_offsets[5][0] = sign * XOFF;
146 	overtaking_base_offsets[6][0] = 0;
147 	overtaking_base_offsets[7][0] = sign * (-XOFF-YOFF);
148 
149 	overtaking_base_offsets[0][1] = sign * YOFF;
150 	overtaking_base_offsets[1][1] = sign * YOFF;
151 	overtaking_base_offsets[2][1] = sign * YOFF;
152 	overtaking_base_offsets[3][1] = 0;
153 	overtaking_base_offsets[4][1] = -sign * YOFF;
154 	overtaking_base_offsets[5][1] = -sign * YOFF;
155 	overtaking_base_offsets[6][1] = -sign * YOFF;
156 	overtaking_base_offsets[7][1] = 0;
157 }
158 
159 
160 /**
161  * Checks if this vehicle must change the square upon next move
162  * THIS IS ONLY THERE FOR LOADING OLD SAVES!
163  * @author Hj. Malthaner
164  */
is_about_to_hop(const sint8 neu_xoff,const sint8 neu_yoff) const165 bool vehicle_base_t::is_about_to_hop( const sint8 neu_xoff, const sint8 neu_yoff ) const
166 {
167 	const sint8 y_off_2 = 2*neu_yoff;
168 	const sint8 c_plus  = y_off_2 + neu_xoff;
169 	const sint8 c_minus = y_off_2 - neu_xoff;
170 
171 	return ! (c_plus < OBJECT_OFFSET_STEPS*2  &&  c_minus < OBJECT_OFFSET_STEPS*2  &&  c_plus > -OBJECT_OFFSET_STEPS*2  &&  c_minus > -OBJECT_OFFSET_STEPS*2);
172 }
173 
174 
vehicle_base_t()175 vehicle_base_t::vehicle_base_t():
176 	obj_t()
177 {
178 	image = IMG_EMPTY;
179 	set_flag( obj_t::is_vehicle );
180 	steps = 0;
181 	steps_next = VEHICLE_STEPS_PER_TILE - 1;
182 	use_calc_height = true;
183 	dx = 0;
184 	dy = 0;
185 	zoff_start = zoff_end = 0;
186 	disp_lane = 2;
187 }
188 
189 
vehicle_base_t(koord3d pos)190 vehicle_base_t::vehicle_base_t(koord3d pos):
191 	obj_t(pos)
192 {
193 	image = IMG_EMPTY;
194 	set_flag( obj_t::is_vehicle );
195 	pos_next = pos;
196 	steps = 0;
197 	steps_next = VEHICLE_STEPS_PER_TILE - 1;
198 	use_calc_height = true;
199 	dx = 0;
200 	dy = 0;
201 	zoff_start = zoff_end = 0;
202 	disp_lane = 2;
203 }
204 
205 
rotate90()206 void vehicle_base_t::rotate90()
207 {
208 	koord3d pos_cur = get_pos();
209 	pos_cur.rotate90( welt->get_size().y-1 );
210 	set_pos( pos_cur );
211 	// directions are counterclockwise to ribis!
212 	direction = ribi_t::rotate90( direction );
213 	pos_next.rotate90( welt->get_size().y-1 );
214 	// new offsets: very tricky ...
215 	sint8 new_dx = -dy*2;
216 	dy = dx/2;
217 	dx = new_dx;
218 	// new pos + step offsets (only possible, since we know the height!
219 	sint8 neu_yoff = get_xoff()/2;
220 	set_xoff( -get_yoff()*2 );
221 	set_yoff( neu_yoff );
222 	// adjust disp_lane individually
223 }
224 
225 
leave_tile()226 void vehicle_base_t::leave_tile()
227 {
228 	// first: release crossing
229 	grund_t *gr = welt->lookup(get_pos());
230 	if(  gr  &&  gr->ist_uebergang()  ) {
231 		crossing_t *cr = gr->find<crossing_t>(2);
232 		grund_t *gr2 = welt->lookup(pos_next);
233 		if(  gr2==NULL  ||  gr2==gr  ||  !gr2->ist_uebergang()  ||  cr->get_logic()!=gr2->find<crossing_t>(2)->get_logic()  ) {
234 			cr->release_crossing(this);
235 		}
236 	}
237 
238 	// then remove from ground (or search whole map, if failed)
239 	if(!get_flag(not_on_map)  &&  (gr==NULL  ||  !gr->obj_remove(this)) ) {
240 
241 		// was not removed (not found?)
242 		dbg->error("vehicle_base_t::leave_tile()","'typ %i' %p could not be removed from %d %d", get_typ(), this, get_pos().x, get_pos().y);
243 		DBG_MESSAGE("vehicle_base_t::leave_tile()","checking all plan squares");
244 
245 		// check, whether it is on another height ...
246 		const planquadrat_t *pl = welt->access( get_pos().get_2d() );
247 		if(  pl  ) {
248 			gr = pl->get_boden_von_obj(this);
249 			if(  gr  ) {
250 				gr->obj_remove(this);
251 				dbg->warning("vehicle_base_t::leave_tile()","removed vehicle typ %i (%p) from %d %d",get_typ(), this, get_pos().x, get_pos().y);
252 			}
253 			return;
254 		}
255 
256 		koord k;
257 		bool ok = false;
258 
259 		for(k.y=0; k.y<welt->get_size().y; k.y++) {
260 			for(k.x=0; k.x<welt->get_size().x; k.x++) {
261 				grund_t *gr = welt->access( k )->get_boden_von_obj(this);
262 				if(gr && gr->obj_remove(this)) {
263 					dbg->warning("vehicle_base_t::leave_tile()","removed vehicle typ %i (%p) from %d %d",get_name(), this, k.x, k.y);
264 					ok = true;
265 				}
266 			}
267 		}
268 
269 		if(!ok) {
270 			dbg->error("vehicle_base_t::leave_tile()","'%s' %p was not found on any map square!",get_name(), this);
271 		}
272 	}
273 }
274 
275 
enter_tile(grund_t * gr)276 void vehicle_base_t::enter_tile(grund_t* gr)
277 {
278 	if(!gr) {
279 		dbg->error("vehicle_base_t::enter_tile()","'%s' new position (%i,%i,%i)!",get_name(), get_pos().x, get_pos().y, get_pos().z );
280 		gr = welt->lookup_kartenboden(get_pos().get_2d());
281 		set_pos( gr->get_pos() );
282 	}
283 	gr->obj_add(this);
284 }
285 
286 
287 /* THE routine for moving vehicles
288  * it will drive on as log as it can
289  * @return the distance actually traveled
290  */
do_drive(uint32 distance)291 uint32 vehicle_base_t::do_drive(uint32 distance)
292 {
293 
294 	uint32 steps_to_do = distance >> YARDS_PER_VEHICLE_STEP_SHIFT;
295 
296 	if(  steps_to_do == 0  ) {
297 		// ok, we will not move in this steps
298 		return 0;
299 	}
300 	// ok, so moving ...
301 	if(  !get_flag(obj_t::dirty)  ) {
302 		mark_image_dirty( image, 0 );
303 		set_flag( obj_t::dirty );
304 	}
305 
306 	grund_t *gr = NULL; // if hopped, then this is new position
307 
308 	uint32 steps_target = steps_to_do + steps;
309 
310 	uint32 distance_travelled; // Return value
311 
312 	if(  steps_target > steps_next  ) {
313 		// We are going far enough to hop.
314 
315 		// We'll be adding steps_next+1 for each hop, as if we
316 		// started at the beginning of this tile, so for an accurate
317 		// count of steps done we must subtract the location we started with.
318 		sint32 steps_done = -steps;
319 
320 		// Hop as many times as possible.
321 		while(  steps_target > steps_next  &&  (gr = hop_check())  ) {
322 			// now do the update for hopping
323 			steps_target -= steps_next+1;
324 			steps_done += steps_next+1;
325 			koord pos_prev(get_pos().get_2d());
326 			hop(gr);
327 			use_calc_height = true;
328 
329 			// set offsets
330 			set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS );
331 			set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 );
332 			if(dx*dy==0) {
333 				if(dx==0) {
334 					if(dy>0) {
335 						set_xoff( pos_prev.x!=get_pos().x ? -OBJECT_OFFSET_STEPS : OBJECT_OFFSET_STEPS );
336 					}
337 					else {
338 						set_xoff( pos_prev.x!=get_pos().x ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS );
339 					}
340 				}
341 				else {
342 					if(dx>0) {
343 						set_yoff( pos_prev.y!=get_pos().y ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 );
344 					}
345 					else {
346 						set_yoff( pos_prev.y!=get_pos().y ? -OBJECT_OFFSET_STEPS/2 : OBJECT_OFFSET_STEPS/2 );
347 					}
348 				}
349 			}
350 		}
351 
352 		if(  steps_next == 0  ) {
353 			// only needed for aircrafts, which can turn on the same tile
354 			// the indicate the turn with this here
355 			steps_next = VEHICLE_STEPS_PER_TILE - 1;
356 			steps_target = VEHICLE_STEPS_PER_TILE - 1;
357 			steps_done -= VEHICLE_STEPS_PER_TILE - 1;
358 		}
359 
360 		// Update internal status, how far we got within the tile.
361 		if(  steps_target <= steps_next  ) {
362 			steps = steps_target;
363 		}
364 		else {
365 			// could not go as far as we wanted (hop_check failed) => stop at end of tile
366 			steps = steps_next;
367 		}
368 
369 		steps_done += steps;
370 		distance_travelled = steps_done << YARDS_PER_VEHICLE_STEP_SHIFT;
371 
372 	}
373 	else {
374 		// Just travel to target, it's on same tile
375 		steps = steps_target;
376 		distance_travelled = distance & YARDS_VEHICLE_STEP_MASK; // round down to nearest step
377 	}
378 
379 	if(use_calc_height) {
380 		calc_height(gr);
381 	}
382 	// remaining steps
383 	return distance_travelled;
384 }
385 
386 
387 // to make smaller steps than the tile granularity, we have to use this trick
get_screen_offset(int & xoff,int & yoff,const sint16 raster_width) const388 void vehicle_base_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const
389 {
390 	// vehicles needs finer steps to appear smoother
391 	sint32 display_steps = (uint32)steps*(uint16)raster_width;
392 	if(dx && dy) {
393 		display_steps &= 0xFFFFFC00;
394 	}
395 	else {
396 		display_steps = (display_steps*diagonal_multiplier)>>10;
397 	}
398 	xoff += (display_steps*dx) >> 10;
399 	yoff += ((display_steps*dy) >> 10) + (get_hoff(raster_width))/(4*16);
400 }
401 
402 
403 // calcs new direction and applies it to the vehicles
calc_set_direction(const koord3d & start,const koord3d & ende)404 ribi_t::ribi vehicle_base_t::calc_set_direction(const koord3d& start, const koord3d& ende)
405 {
406 	ribi_t::ribi direction = ribi_t::none;
407 
408 	const sint8 di = ende.x - start.x;
409 	const sint8 dj = ende.y - start.y;
410 
411 	if(dj < 0 && di == 0) {
412 		direction = ribi_t::north;
413 		dx = 2;
414 		dy = -1;
415 		steps_next = VEHICLE_STEPS_PER_TILE - 1;
416 	} else if(dj > 0 && di == 0) {
417 		direction = ribi_t::south;
418 		dx = -2;
419 		dy = 1;
420 		steps_next = VEHICLE_STEPS_PER_TILE - 1;
421 	} else if(di < 0 && dj == 0) {
422 		direction = ribi_t::west;
423 		dx = -2;
424 		dy = -1;
425 		steps_next = VEHICLE_STEPS_PER_TILE - 1;
426 	} else if(di >0 && dj == 0) {
427 		direction = ribi_t::east;
428 		dx = 2;
429 		dy = 1;
430 		steps_next = VEHICLE_STEPS_PER_TILE - 1;
431 	} else if(di > 0 && dj > 0) {
432 		direction = ribi_t::southeast;
433 		dx = 0;
434 		dy = 2;
435 		steps_next = diagonal_vehicle_steps_per_tile - 1;
436 	} else if(di < 0 && dj < 0) {
437 		direction = ribi_t::northwest;
438 		dx = 0;
439 		dy = -2;
440 		steps_next = diagonal_vehicle_steps_per_tile - 1;
441 	} else if(di > 0 && dj < 0) {
442 		direction = ribi_t::northeast;
443 		dx = 4;
444 		dy = 0;
445 		steps_next = diagonal_vehicle_steps_per_tile - 1;
446 	} else {
447 		direction = ribi_t::southwest;
448 		dx = -4;
449 		dy = 0;
450 		steps_next = diagonal_vehicle_steps_per_tile - 1;
451 	}
452 	// we could artificially make diagonals shorter: but this would break existing game behaviour
453 	return direction;
454 }
455 
456 
457 // this routine calculates the new height
458 // beware of bridges, tunnels, slopes, ...
calc_height(grund_t * gr)459 void vehicle_base_t::calc_height(grund_t *gr)
460 {
461 	use_calc_height = false;	// assume, we are only needed after next hop
462 	zoff_start = zoff_end = 0;    // assume flat way
463 
464 	if(gr==NULL) {
465 		gr = welt->lookup(get_pos());
466 	}
467 	if(gr==NULL) {
468 		// slope changed below a moving thing?!?
469 		return;
470 	}
471 	else if(  gr->ist_tunnel()  &&  gr->ist_karten_boden()  &&  !is_flying() ) {
472 		use_calc_height = true; // to avoid errors if underground mode is switched
473 		if(  grund_t::underground_mode == grund_t::ugm_none  ||
474 			(grund_t::underground_mode == grund_t::ugm_level  &&  gr->get_hoehe() < grund_t::underground_level)
475 		) {
476 			// need hiding? One of the few uses of XOR: not half driven XOR exiting => not hide!
477 			ribi_t::ribi hang_ribi = ribi_type( gr->get_grund_hang() );
478 			if((steps<(steps_next/2))  ^  ((hang_ribi&direction)!=0)  ) {
479 				set_image(IMG_EMPTY);
480 			}
481 			else {
482 				calc_image();
483 			}
484 		}
485 	}
486 	else {
487 		// force a valid image above ground, with special handling of tunnel entraces
488 		if(  get_image()==IMG_EMPTY  ) {
489 			if(  !gr->ist_tunnel()  &&  gr->ist_karten_boden()  ) {
490 				calc_image();
491 			}
492 		}
493 
494 		// will not work great with ways, but is very short!
495 		slope_t::type hang = gr->get_weg_hang();
496 		if(  hang  ) {
497 			const uint slope_height = (hang & 7) ? 1 : 2;
498 			ribi_t::ribi hang_ribi = ribi_type(hang);
499 			if(  ribi_t::doubles(hang_ribi)  ==  ribi_t::doubles(direction)) {
500 				zoff_start = hang_ribi & direction                      ? 2*slope_height : 0;  // 0 .. 4
501 				zoff_end   = hang_ribi & ribi_t::backward(direction) ? 2*slope_height : 0;  // 0 .. 4
502 			}
503 			else {
504 				// only for shadows and movingobjs ...
505 				zoff_start = hang_ribi & direction                      ? slope_height+1 : 0;  // 0 .. 3
506 				zoff_end   = hang_ribi & ribi_t::backward(direction) ? slope_height+1 : 0;  // 0 .. 3
507 			}
508 		}
509 		else {
510 			zoff_start = (gr->get_weg_yoff() * 2) / TILE_HEIGHT_STEP;
511 			zoff_end = zoff_start;
512 		}
513 	}
514 }
515 
516 
get_hoff(const sint16 raster_width) const517 sint16 vehicle_base_t::get_hoff(const sint16 raster_width) const
518 {
519 	sint16 h_start = -(sint8)TILE_HEIGHT_STEP * (sint8)zoff_start;
520 	sint16 h_end   = -(sint8)TILE_HEIGHT_STEP * (sint8)zoff_end;
521 	return ((h_start*steps + h_end*(256-steps))*raster_width) >> 9;
522 }
523 
524 
525 /* true, if one could pass through this field
526  * also used for citycars, thus defined here
527  */
no_cars_blocking(const grund_t * gr,const convoi_t * cnv,const uint8 current_direction,const uint8 next_direction,const uint8 next_90direction)528 vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convoi_t *cnv, const uint8 current_direction, const uint8 next_direction, const uint8 next_90direction )
529 {
530 	// Search vehicle
531 	for(  uint8 pos=1;  pos<(uint8)gr->get_top();  pos++  ) {
532 		if(  vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(pos))  ) {
533 			if(  v->get_typ()==obj_t::pedestrian  ) {
534 				continue;
535 			}
536 
537 			// check for car
538 			uint8 other_direction=255;
539 			bool other_moving = false;
540 			if(  road_vehicle_t const* const at = obj_cast<road_vehicle_t>(v)  ) {
541 				// ignore ourself
542 				if(  cnv == at->get_convoi()  ) {
543 					continue;
544 				}
545 				other_direction = at->get_direction();
546 				other_moving = at->get_convoi()->get_akt_speed() > kmh_to_speed(1);
547 			}
548 			// check for city car
549 			else if(  v->get_waytype() == road_wt  ) {
550 				other_direction = v->get_direction();
551 				if(  private_car_t const* const sa = obj_cast<private_car_t>(v)  ){
552 					other_moving = sa->get_current_speed() > 1;
553 				}
554 			}
555 
556 			// ok, there is another car ...
557 			if(  other_direction != 255  ) {
558 				if(  next_direction == other_direction  &&  !ribi_t::is_threeway(gr->get_weg_ribi(road_wt))  ) {
559 					// cars going in the same direction and no crossing => that mean blocking ...
560 					return v;
561 				}
562 
563 				const ribi_t::ribi other_90direction = (gr->get_pos().get_2d() == v->get_pos_next().get_2d()) ? other_direction : calc_direction(gr->get_pos(), v->get_pos_next());
564 				if(  other_90direction == next_90direction  ) {
565 					// Want to exit in same as other   ~50% of the time
566 					return v;
567 				}
568 
569 				const bool drives_on_left = welt->get_settings().is_drive_left();
570 				const bool across = next_direction == (drives_on_left ? ribi_t::rotate45l(next_90direction) : ribi_t::rotate45(next_90direction)); // turning across the opposite directions lane
571 				const bool other_across = other_direction == (drives_on_left ? ribi_t::rotate45l(other_90direction) : ribi_t::rotate45(other_90direction)); // other is turning across the opposite directions lane
572 				if(  other_direction == next_direction  &&  !(other_across || across)  ) {
573 					// entering same straight waypoint as other ~18%
574 					return v;
575 				}
576 
577 				const bool straight = next_direction == next_90direction; // driving straight
578 				const ribi_t::ribi current_90direction = straight ? ribi_t::backward(next_90direction) : (~(next_direction|ribi_t::backward(next_90direction)))&0x0F;
579 				const bool other_straight = other_direction == other_90direction; // other is driving straight
580 				const bool other_exit_same_side = current_90direction == other_90direction; // other is exiting same side as we're entering
581 				const bool other_exit_opposite_side = ribi_t::backward(current_90direction) == other_90direction; // other is exiting side across from where we're entering
582 				if(  across  &&  ((ribi_t::is_perpendicular(current_90direction,other_direction)  &&  other_moving)  ||  (other_across  &&  other_exit_opposite_side)  ||  ((other_across  ||  other_straight)  &&  other_exit_same_side  &&  other_moving) ) )  {
583 					// other turning across in front of us from orth entry dir'n   ~4%
584 					return v;
585 				}
586 
587 				const bool headon = ribi_t::backward(current_direction) == other_direction; // we're meeting the other headon
588 				const bool other_exit_across = (drives_on_left ? ribi_t::rotate90l(next_90direction) : ribi_t::rotate90(next_90direction)) == other_90direction; // other is exiting by turning across the opposite directions lane
589 				if(  straight  &&  (ribi_t::is_perpendicular(current_90direction,other_direction)  ||  (other_across  &&  other_moving  &&  (other_exit_across  ||  (other_exit_same_side  &&  !headon))) ) ) {
590 					// other turning across in front of us, but allow if other is stopped - duplicating historic behaviour   ~2%
591 					return v;
592 				}
593 				else if(  other_direction == current_direction  &&  current_90direction == ribi_t::none  ) {
594 					// entering same diagonal waypoint as other   ~1%
595 					return v;
596 				}
597 
598 				// else other car is not blocking   ~25%
599 			}
600 		}
601 	}
602 
603 	// way is free
604 	return NULL;
605 }
606 
607 
rotate90()608 void vehicle_t::rotate90()
609 {
610 	vehicle_base_t::rotate90();
611 	previous_direction = ribi_t::rotate90( previous_direction );
612 	last_stop_pos.rotate90( welt->get_size().y-1 );
613 }
614 
615 
rotate90_freight_destinations(const sint16 y_size)616 void vehicle_t::rotate90_freight_destinations(const sint16 y_size)
617 {
618 	// now rotate the freight
619 	FOR(slist_tpl<ware_t>, & tmp, fracht) {
620 		tmp.rotate90(y_size );
621 	}
622 }
623 
624 
set_convoi(convoi_t * c)625 void vehicle_t::set_convoi(convoi_t *c)
626 {
627 	/* cnv can have three values:
628 	 * NULL: not previously assigned
629 	 * 1 (only during loading): convoi wants to reserve the whole route
630 	 * other: previous convoi (in this case, currently always c==cnv)
631 	 *
632 	 * if c is NULL, then the vehicle is removed from the convoi
633 	 * (the rail_vehicle_t::set_convoi etc. routines must then remove a
634 	 *  possibly pending reservation of stops/tracks)
635 	 */
636 	assert(  c==NULL  ||  cnv==NULL  ||  cnv==(convoi_t *)1  ||  c==cnv);
637 	cnv = c;
638 	if(cnv) {
639 		// we need to re-establish the finish flag after loading
640 		if(leading) {
641 			route_t const& r = *cnv->get_route();
642 			check_for_finish = r.empty() || route_index >= r.get_count() || get_pos() == r.at(route_index);
643 		}
644 		if(  pos_next != koord3d::invalid  ) {
645 			route_t const& r = *cnv->get_route();
646 			if (!r.empty() && route_index < r.get_count() - 1) {
647 				grund_t const* const gr = welt->lookup(pos_next);
648 				if (!gr || !gr->get_weg(get_waytype())) {
649 					if (!(water_wt == get_waytype()  &&  gr->is_water())) { // ships on the open sea are valid
650 						pos_next = r.at(route_index + 1U);
651 					}
652 				}
653 			}
654 		}
655 		// just correct freight destinations
656 		FOR(slist_tpl<ware_t>, & c, fracht) {
657 			c.finish_rd(welt);
658 		}
659 	}
660 }
661 
662 
663 /**
664  * Unload freight to halt
665  * @return sum of unloaded goods
666  * @author Hj. Malthaner
667  */
unload_cargo(halthandle_t halt,bool unload_all)668 uint16 vehicle_t::unload_cargo(halthandle_t halt, bool unload_all )
669 {
670 	uint16 sum_menge = 0, sum_delivered = 0, index = 0;
671 	if(  !halt.is_bound()  ) {
672 		return 0;
673 	}
674 
675 	if(  halt->is_enabled( get_cargo_type() )  ) {
676 		if(  !fracht.empty()  ) {
677 
678 			for(  slist_tpl<ware_t>::iterator i = fracht.begin(), end = fracht.end();  i != end;  ) {
679 				const ware_t& tmp = *i;
680 
681 				halthandle_t end_halt = tmp.get_ziel();
682 				halthandle_t via_halt = tmp.get_zwischenziel();
683 
684 				// check if destination or transfer is still valid
685 				if(  !end_halt.is_bound() || !via_halt.is_bound()  ) {
686 					// target halt no longer there => delete and remove from fab in transit
687 					fabrik_t::update_transit( &tmp, false );
688 					DBG_MESSAGE("vehicle_t::unload_freight()", "destination of %d %s is no longer reachable",tmp.menge,translator::translate(tmp.get_name()));
689 					total_freight -= tmp.menge;
690 					sum_weight -= tmp.menge * tmp.get_desc()->get_weight_per_unit();
691 					i = fracht.erase( i );
692 				}
693 				else if(  end_halt == halt || via_halt == halt  ||  unload_all  ) {
694 
695 					//		    printf("Liefere %d %s nach %s via %s an %s\n",
696 					//                           tmp->menge,
697 					//			   tmp->name(),
698 					//			   end_halt->get_name(),
699 					//			   via_halt->get_name(),
700 					//			   halt->get_name());
701 
702 					// here, only ordinary goods should be processed
703 					int menge = halt->liefere_an(tmp);
704 					sum_menge += menge;
705 					total_freight -= menge;
706 					sum_weight -= tmp.menge * tmp.get_desc()->get_weight_per_unit();
707 
708 					index = tmp.get_index();
709 
710 					if(end_halt==halt) {
711 						sum_delivered += menge;
712 					}
713 
714 					i = fracht.erase( i );
715 				}
716 				else {
717 					++i;
718 				}
719 			}
720 		}
721 	}
722 
723 	if(  sum_menge  ) {
724 		// book transported goods
725 		get_owner()->book_transported( sum_menge, get_desc()->get_waytype(), index );
726 
727 		if(  sum_delivered  ) {
728 			// book delivered goods to destination
729 			get_owner()->book_delivered( sum_delivered, get_desc()->get_waytype(), index );
730 		}
731 
732 		// add delivered goods to statistics
733 		cnv->book( sum_menge, convoi_t::CONVOI_TRANSPORTED_GOODS );
734 
735 		// add delivered goods to halt's statistics
736 		halt->book( sum_menge, HALT_ARRIVED );
737 	}
738 	return sum_menge;
739 }
740 
741 
742 /**
743  * Load freight from halt
744  * @return amount loaded
745  * @author Hj. Malthaner
746  */
load_cargo(halthandle_t halt,const vector_tpl<halthandle_t> & destination_halts)747 uint16 vehicle_t::load_cargo(halthandle_t halt, const vector_tpl<halthandle_t>& destination_halts)
748 {
749 	if(  !halt.is_bound()  ||  !halt->gibt_ab(desc->get_freight_type())  ) {
750 		return 0;
751 	}
752 
753 	const uint16 total_freight_start = total_freight;
754 	const uint16 capacity_left = desc->get_capacity() - total_freight;
755 	if (capacity_left > 0) {
756 
757 		slist_tpl<ware_t> freight_add;
758 		halt->fetch_goods( freight_add, desc->get_freight_type(), capacity_left, destination_halts);
759 
760 		if(  freight_add.empty()  ) {
761 			// now empty, but usually, we can get it here ...
762 			return 0;
763 		}
764 
765 		for(  slist_tpl<ware_t>::iterator iter_z = freight_add.begin();  iter_z != freight_add.end();  ) {
766 			ware_t &ware = *iter_z;
767 
768 			total_freight += ware.menge;
769 			sum_weight += ware.menge * ware.get_desc()->get_weight_per_unit();
770 
771 			// could this be joined with existing freight?
772 			FOR( slist_tpl<ware_t>, & tmp, fracht ) {
773 				// for pax: join according next stop
774 				// for all others we *must* use target coordinates
775 				if(  ware.same_destination(tmp)  ) {
776 					tmp.menge += ware.menge;
777 					ware.menge = 0;
778 					break;
779 				}
780 			}
781 
782 			// if != 0 we could not join it to existing => load it
783 			if(  ware.menge != 0  ) {
784 				++iter_z;
785 				// we add list directly
786 			}
787 			else {
788 				iter_z = freight_add.erase(iter_z);
789 			}
790 		}
791 
792 		if(  !freight_add.empty()  ) {
793 			fracht.append_list(freight_add);
794 		}
795 	}
796 	return total_freight - total_freight_start;
797 }
798 
799 
800 /**
801  * Remove freight that no longer can reach it's destination
802  * i.e. because of a changed schedule
803  * @author Hj. Malthaner
804  */
remove_stale_cargo()805 void vehicle_t::remove_stale_cargo()
806 {
807 	DBG_DEBUG("vehicle_t::remove_stale_cargo()", "called");
808 
809 	// and now check every piece of ware on board,
810 	// if its target is somewhere on
811 	// the new schedule, if not -> remove
812 	slist_tpl<ware_t> kill_queue;
813 	total_freight = 0;
814 
815 	if (!fracht.empty()) {
816 		FOR(slist_tpl<ware_t>, & tmp, fracht) {
817 			bool found = false;
818 
819 			if(  tmp.get_zwischenziel().is_bound()  ) {
820 				// the original halt exists, but does we still go there?
821 				FOR(minivec_tpl<schedule_entry_t>, const& i, cnv->get_schedule()->entries) {
822 					if(  haltestelle_t::get_halt( i.pos, cnv->get_owner()) == tmp.get_zwischenziel()  ) {
823 						found = true;
824 						break;
825 					}
826 				}
827 			}
828 			if(  !found  ) {
829 				// the target halt may have been joined or there is a closer one now, thus our original target is no longer valid
830 				const int offset = cnv->get_schedule()->get_current_stop();
831 				const int max_count = cnv->get_schedule()->entries.get_count();
832 				for(  int i=0;  i<max_count;  i++  ) {
833 					// try to unload on next stop
834 					halthandle_t halt = haltestelle_t::get_halt( cnv->get_schedule()->entries[ (i+offset)%max_count ].pos, cnv->get_owner() );
835 					if(  halt.is_bound()  ) {
836 						if(  halt->is_enabled(tmp.get_index())  ) {
837 							// ok, lets change here, since goods are accepted here
838 							tmp.access_zwischenziel() = halt;
839 							if (!tmp.get_ziel().is_bound()) {
840 								// set target, to prevent that unload_freight drops cargo
841 								tmp.set_ziel( halt );
842 							}
843 							found = true;
844 							break;
845 						}
846 					}
847 				}
848 			}
849 
850 			if(  !found  ) {
851 				kill_queue.insert(tmp);
852 			}
853 			else {
854 				// since we need to point at factory (0,0), we recheck this too
855 				koord k = tmp.get_zielpos();
856 				fabrik_t *fab = fabrik_t::get_fab( k );
857 				tmp.set_zielpos( fab ? fab->get_pos().get_2d() : k );
858 
859 				total_freight += tmp.menge;
860 			}
861 		}
862 
863 		FOR(slist_tpl<ware_t>, const& c, kill_queue) {
864 			fabrik_t::update_transit( &c, false );
865 			fracht.remove(c);
866 		}
867 	}
868 	sum_weight =  get_cargo_weight() + desc->get_weight();
869 }
870 
871 
play_sound() const872 void vehicle_t::play_sound() const
873 {
874 	if(  desc->get_sound() >= 0  &&  !welt->is_fast_forward()  ) {
875 		welt->play_sound_area_clipped(get_pos().get_2d(), desc->get_sound());
876 	}
877 }
878 
879 
880 /**
881  * Prepare vehicle for new ride.
882  * Sets route_index, pos_next, steps_next.
883  * If @p recalc is true this sets position and recalculates/resets movement parameters.
884  * @author Hj. Malthaner
885  */
initialise_journey(uint16 start_route_index,bool recalc)886 void vehicle_t::initialise_journey(uint16 start_route_index, bool recalc)
887 {
888 	route_index = start_route_index+1;
889 	check_for_finish = false;
890 	use_calc_height = true;
891 
892 	if(welt->is_within_limits(get_pos().get_2d())) {
893 		mark_image_dirty( get_image(), 0 );
894 	}
895 
896 	route_t const& r = *cnv->get_route();
897 	if(!recalc) {
898 		// always set pos_next
899 		pos_next = r.at(route_index);
900 		assert(get_pos() == r.at(start_route_index));
901 	}
902 	else {
903 		// set pos_next
904 		if (route_index < r.get_count()) {
905 			pos_next = r.at(route_index);
906 		}
907 		else {
908 			// already at end of route
909 			check_for_finish = true;
910 		}
911 		set_pos(r.at(start_route_index));
912 
913 		// recalc directions
914 		previous_direction = direction;
915 		direction = calc_set_direction( get_pos(), pos_next );
916 
917 		zoff_start = zoff_end = 0;
918 		steps = 0;
919 
920 		set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS );
921 		set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 );
922 
923 		calc_image();
924 	}
925 	if ( ribi_t::is_single(direction) ) {
926 		steps_next = VEHICLE_STEPS_PER_TILE - 1;
927 	}
928 	else {
929 		steps_next = diagonal_vehicle_steps_per_tile - 1;
930 	}
931 }
932 
933 
vehicle_t(koord3d pos,const vehicle_desc_t * desc,player_t * player)934 vehicle_t::vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player) :
935 	vehicle_base_t(pos)
936 {
937 	this->desc = desc;
938 
939 	set_owner( player );
940 	purchase_time = welt->get_current_month();
941 	cnv = NULL;
942 	speed_limit = SPEED_UNLIMITED;
943 
944 	route_index = 1;
945 
946 	smoke = true;
947 	direction = ribi_t::none;
948 
949 	current_friction = 4;
950 	total_freight = 0;
951 	sum_weight = desc->get_weight();
952 
953 	leading = last = false;
954 	check_for_finish = false;
955 	use_calc_height = true;
956 	has_driven = false;
957 
958 	previous_direction = direction = ribi_t::none;
959 	target_halt = halthandle_t();
960 }
961 
962 
vehicle_t()963 vehicle_t::vehicle_t() :
964 	vehicle_base_t()
965 {
966 	smoke = true;
967 
968 	desc = NULL;
969 	cnv = NULL;
970 
971 	route_index = 1;
972 	current_friction = 4;
973 	sum_weight = 10;
974 	total_freight = 0;
975 
976 	leading = last = false;
977 	check_for_finish = false;
978 	use_calc_height = true;
979 
980 	previous_direction = direction = ribi_t::none;
981 }
982 
983 
calc_route(koord3d start,koord3d ziel,sint32 max_speed,route_t * route)984 bool vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route)
985 {
986 	return route->calc_route(welt, start, ziel, this, max_speed, 0 );
987 }
988 
989 
hop_check()990 grund_t* vehicle_t::hop_check()
991 {
992 	// the leading vehicle will do all the checks
993 	if(leading) {
994 		if(check_for_finish) {
995 			// so we are there yet?
996 			cnv->ziel_erreicht();
997 			if(cnv->get_state()==convoi_t::INITIAL) {
998 				// to avoid crashes with airplanes
999 				use_calc_height = false;
1000 			}
1001 			return NULL;
1002 		}
1003 
1004 		// now check, if we can go here
1005 		grund_t *bd = welt->lookup(pos_next);
1006 		if(bd==NULL  ||  !check_next_tile(bd)  ||  cnv->get_route()->empty()) {
1007 			// way (weg) not existent (likely destroyed) or no route ...
1008 			cnv->suche_neue_route();
1009 			return NULL;
1010 		}
1011 
1012 		// check for one-way sign etc.
1013 		const waytype_t wt = get_waytype();
1014 		if(  air_wt != wt  &&  route_index < cnv->get_route()->get_count()-1  ) {
1015 			uint8 dir = get_ribi(bd);
1016 			koord3d nextnext_pos = cnv->get_route()->at(route_index+1);
1017 			if ( nextnext_pos == get_pos() ) {
1018 				dbg->error("vehicle_t::hop_check", "route contains point (%s) twice for %s", nextnext_pos.get_str(), cnv->get_name());
1019 			}
1020 			uint8 new_dir = ribi_type(nextnext_pos - pos_next);
1021 			if((dir&new_dir)==0) {
1022 				// new one way sign here?
1023 				cnv->suche_neue_route();
1024 				return NULL;
1025 			}
1026 			// check for recently built bridges/tunnels or reverse branches (really slows down the game, so we do this only on slopes)
1027 			if(  bd->get_weg_hang()  ) {
1028 				grund_t *from;
1029 				if(  !bd->get_neighbour( from, get_waytype(), ribi_type( get_pos(), pos_next ) )  ) {
1030 					// way likely destroyed or altered => reroute
1031 					cnv->suche_neue_route();
1032 					return NULL;
1033 				}
1034 			}
1035 		}
1036 
1037 		sint32 restart_speed = -1;
1038 		// ist_weg_frei() berechnet auch die Geschwindigkeit
1039 		// mit der spaeter weitergefahren wird
1040 		if(  !can_enter_tile( bd, restart_speed, 0 )  ) {
1041 			// stop convoi, when the way is not free
1042 			cnv->warten_bis_weg_frei(restart_speed);
1043 
1044 			// don't continue
1045 			return NULL;
1046 		}
1047 		// we cache it here, hop() will use it to save calls to karte_t::lookup
1048 		return bd;
1049 	}
1050 	else {
1051 		// this is needed since in convoi_t::vorfahren the flag 'leading' is set to null
1052 		if(check_for_finish) {
1053 			return NULL;
1054 		}
1055 	}
1056 	return welt->lookup(pos_next);
1057 }
1058 
1059 
can_enter_tile(sint32 & restart_speed,uint8 second_check_count)1060 bool vehicle_t::can_enter_tile(sint32 &restart_speed, uint8 second_check_count)
1061 {
1062 	grund_t *gr = welt->lookup( pos_next );
1063 	if(  gr  ) {
1064 		return can_enter_tile( gr, restart_speed, second_check_count );
1065 	}
1066 	else {
1067 		if(  !second_check_count  ) {
1068 			cnv->suche_neue_route();
1069 		}
1070 		return false;
1071 	}
1072 }
1073 
1074 
leave_tile()1075 void vehicle_t::leave_tile()
1076 {
1077 	vehicle_base_t::leave_tile();
1078 #ifndef DEBUG_ROUTES
1079 	if(last  &&  minimap_t::is_visible) {
1080 			minimap_t::get_instance()->calc_map_pixel(get_pos().get_2d());
1081 	}
1082 #endif
1083 }
1084 
1085 
1086 /* this routine add a vehicle to a tile and will insert it in the correct sort order to prevent overlaps
1087  * @author prissi
1088  */
enter_tile(grund_t * gr)1089 void vehicle_t::enter_tile(grund_t* gr)
1090 {
1091 	vehicle_base_t::enter_tile(gr);
1092 
1093 	if(leading  &&  minimap_t::is_visible  ) {
1094 		minimap_t::get_instance()->calc_map_pixel( get_pos().get_2d() );
1095 	}
1096 }
1097 
1098 
hop(grund_t * gr)1099 void vehicle_t::hop(grund_t* gr)
1100 {
1101 	leave_tile();
1102 
1103 	koord3d pos_prev = get_pos();
1104 	set_pos( pos_next );  // next field
1105 	if(route_index<cnv->get_route()->get_count()-1) {
1106 		route_index ++;
1107 		pos_next = cnv->get_route()->at(route_index);
1108 	}
1109 	else {
1110 		route_index ++;
1111 		check_for_finish = true;
1112 	}
1113 	previous_direction = direction;
1114 
1115 	// check if arrived at waypoint, and update schedule to next destination
1116 	// route search through the waypoint is already complete
1117 	if(  get_pos()==cnv->get_schedule_target()  ) {
1118 		if(  route_index >= cnv->get_route()->get_count()  ) {
1119 			// we end up here after loading a game or when a waypoint is reached which crosses next itself
1120 			cnv->set_schedule_target( koord3d::invalid );
1121 		}
1122 		else {
1123 			cnv->get_schedule()->advance();
1124 			const koord3d ziel = cnv->get_schedule()->get_current_entry().pos;
1125 			cnv->set_schedule_target( cnv->is_waypoint(ziel) ? ziel : koord3d::invalid );
1126 		}
1127 	}
1128 
1129 	// this is a required hack for aircrafts! Aircrafts can turn on a single square, and this confuses the previous calculation!
1130 	// author: hsiegeln
1131 	if(!check_for_finish  &&  pos_prev==pos_next) {
1132 		direction = calc_set_direction( get_pos(), pos_next);
1133 		steps_next = 0;
1134 	}
1135 	else {
1136 		if(  pos_next!=get_pos()  ) {
1137 			direction = calc_set_direction( pos_prev, pos_next );
1138 		}
1139 		else if(  (  check_for_finish  &&  welt->lookup(pos_next)  &&  ribi_t::is_straight(welt->lookup(pos_next)->get_weg_ribi_unmasked(get_waytype()))  )  ||  welt->lookup(pos_next)->is_halt()) {
1140 			// allow diagonal stops at waypoints on diagonal tracks but avoid them on halts and at straight tracks...
1141 			direction = calc_set_direction( pos_prev, pos_next );
1142 		}
1143 	}
1144 
1145 	// change image if direction changes
1146 	if (previous_direction != direction) {
1147 		calc_image();
1148 	}
1149 	sint32 old_speed_limit = speed_limit;
1150 
1151 	enter_tile(gr);
1152 	const weg_t *weg = gr->get_weg(get_waytype());
1153 	if(  weg  ) {
1154 		speed_limit = kmh_to_speed( weg->get_max_speed() );
1155 		if(  weg->is_crossing()  ) {
1156 			gr->find<crossing_t>(2)->add_to_crossing(this);
1157 		}
1158 	}
1159 	else {
1160 		speed_limit = SPEED_UNLIMITED;
1161 	}
1162 
1163 	if(  leading  ) {
1164 		if(  check_for_finish  &&  (direction==ribi_t::north  ||  direction==ribi_t::west)  ) {
1165 			steps_next = (steps_next/2)+1;
1166 		}
1167 		cnv->add_running_cost( weg );
1168 		cnv->must_recalc_data_front();
1169 	}
1170 
1171 	// update friction and friction weight of convoy
1172 	sint16 old_friction = current_friction;
1173 	calc_friction(gr);
1174 
1175 	if (old_friction != current_friction) {
1176 		cnv->update_friction_weight( (current_friction-old_friction) * (sint64)sum_weight);
1177 	}
1178 
1179 	// if speed limit changed, then cnv must recalc
1180 	if (speed_limit != old_speed_limit) {
1181 		if (speed_limit < old_speed_limit) {
1182 			if (speed_limit < cnv->get_speed_limit()) {
1183 				// update
1184 				cnv->set_speed_limit(speed_limit);
1185 			}
1186 		}
1187 		else {
1188 			if (old_speed_limit == cnv->get_speed_limit()) {
1189 				// convoy's speed limit may be larger now
1190 				cnv->must_recalc_speed_limit();
1191 			}
1192 		}
1193 	}
1194 }
1195 
1196 
1197 /* calculates the current friction coefficient based on the current track
1198  * flat, slope, curve ...
1199  * @author prissi, HJ, Dwachs
1200  */
calc_friction(const grund_t * gr)1201 void vehicle_t::calc_friction(const grund_t *gr)
1202 {
1203 
1204 	// assume straight flat track
1205 	current_friction = 1;
1206 
1207 	// curve: higher friction
1208 	if(previous_direction != direction) {
1209 		current_friction = 8;
1210 	}
1211 
1212 	// or a hill?
1213 	const slope_t::type hang = gr->get_weg_hang();
1214 	if(  hang != slope_t::flat  ) {
1215 		const uint slope_height = (hang & 7) ? 1 : 2;
1216 		if(  ribi_type(hang) == direction  ) {
1217 			// hill up, since height offsets are negative: heavy decelerate
1218 			current_friction += 15 * slope_height * slope_height;
1219 		}
1220 		else {
1221 			// hill down: accelerate
1222 			current_friction += -7 * slope_height * slope_height;
1223 		}
1224 	}
1225 }
1226 
1227 
make_smoke() const1228 void vehicle_t::make_smoke() const
1229 {
1230 	// does it smoke at all?
1231 	if(  smoke  &&  desc->get_smoke()  ) {
1232 		// Hajo: only produce smoke when heavily accelerating or steam engine
1233 		if(  cnv->get_akt_speed() < (sint32)((cnv->get_speed_limit() * 7u) >> 3)  ||  desc->get_engine_type() == vehicle_desc_t::steam  ) {
1234 			grund_t* const gr = welt->lookup( get_pos() );
1235 			if(  gr  ) {
1236 				wolke_t* const abgas =  new wolke_t( get_pos(), get_xoff() + ((dx * (sint16)((uint16)steps * OBJECT_OFFSET_STEPS)) >> 8), get_yoff() + ((dy * (sint16)((uint16)steps * OBJECT_OFFSET_STEPS)) >> 8) + get_hoff(), desc->get_smoke() );
1237 				if(  !gr->obj_add( abgas )  ) {
1238 					abgas->set_flag( obj_t::not_on_map );
1239 					delete abgas;
1240 				}
1241 				else {
1242 					welt->sync_way_eyecandy.add( abgas );
1243 				}
1244 			}
1245 		}
1246 	}
1247 }
1248 
1249 
1250 /**
1251  * Payment is done per hop. It iterates all goods and calculates
1252  * the income for the last hop. This method must be called upon
1253  * every stop.
1254  * @return income total for last hop
1255  * @author Hj. Malthaner
1256  */
calc_revenue(const koord3d & start,const koord3d & end) const1257 sint64 vehicle_t::calc_revenue(const koord3d& start, const koord3d& end) const
1258 {
1259 	// may happen when waiting in station
1260 	if (start == end || fracht.empty()) {
1261 		return 0;
1262 	}
1263 
1264 	// cnv_kmh = lesser of min_top_speed, power limited top speed, and average way speed limits on trip, except aircraft which are not power limited and don't have speed limits
1265 	sint32 cnv_kmh = cnv->get_speedbonus_kmh();
1266 
1267 	sint64 value = 0;
1268 
1269 	// cache speedbonus price
1270 	const goods_desc_t* last_freight = NULL;
1271 	sint64 freight_revenue = 0;
1272 
1273 	sint32 dist = 0;
1274 	if(  welt->get_settings().get_pay_for_total_distance_mode() == settings_t::TO_PREVIOUS  ) {
1275 		// pay distance traveled
1276 		dist = koord_distance( start, end );
1277 	}
1278 
1279 	FOR(slist_tpl<ware_t>, const& ware, fracht) {
1280 		if(  ware.menge==0  ) {
1281 			continue;
1282 		}
1283 		// which distance will be paid?
1284 		switch(welt->get_settings().get_pay_for_total_distance_mode()) {
1285 			case settings_t::TO_TRANSFER: {
1286 				// pay distance traveled to next transfer stop
1287 
1288 				// now only use the real gain in difference for the revenue (may as well be negative!)
1289 				if (ware.get_zwischenziel().is_bound()) {
1290 					const koord &zwpos = ware.get_zwischenziel()->get_basis_pos();
1291 					// cast of koord_distance to sint32 is necessary otherwise the r-value would be interpreted as unsigned, leading to overflows
1292 					dist = (sint32)koord_distance( zwpos, start ) - (sint32)koord_distance( end, zwpos );
1293 				}
1294 				else {
1295 					dist = koord_distance( end, start );
1296 				}
1297 				break;
1298 			}
1299 			case settings_t::TO_DESTINATION: {
1300 				// pay only the distance, we get closer to our destination
1301 
1302 				// now only use the real gain in difference for the revenue (may as well be negative!)
1303 				const koord &zwpos = ware.get_zielpos();
1304 				// cast of koord_distance to sint32 is necessary otherwise the r-value would be interpreted as unsigned, leading to overflows
1305 				dist = (sint32)koord_distance( zwpos, start ) - (sint32)koord_distance( end, zwpos );
1306 				break;
1307 			}
1308 			default: ; // no need to recompute
1309 		}
1310 
1311 		// calculate freight revenue incl. speed-bonus
1312 		if (ware.get_desc() != last_freight) {
1313 			freight_revenue = ware_t::calc_revenue(ware.get_desc(), get_desc()->get_waytype(), cnv_kmh);
1314 			last_freight = ware.get_desc();
1315 		}
1316 		const sint64 price = freight_revenue * (sint64)dist * (sint64)ware.menge;
1317 
1318 		// sum up new price
1319 		value += price;
1320 	}
1321 
1322 	// Hajo: Rounded value, in cents
1323 	return (value+1500ll)/3000ll;
1324 }
1325 
1326 
get_cargo_mass() const1327 const char *vehicle_t::get_cargo_mass() const
1328 {
1329 	return get_cargo_type()->get_mass();
1330 }
1331 
1332 
1333 /**
1334  * Calculate transported cargo total weight in KG
1335  * @author Hj. Malthaner
1336  */
get_cargo_weight() const1337 uint32 vehicle_t::get_cargo_weight() const
1338 {
1339 	uint32 weight = 0;
1340 
1341 	FOR(slist_tpl<ware_t>, const& c, fracht) {
1342 		weight += c.menge * c.get_desc()->get_weight_per_unit();
1343 	}
1344 	return weight;
1345 }
1346 
1347 
get_cargo_info(cbuffer_t & buf) const1348 void vehicle_t::get_cargo_info(cbuffer_t & buf) const
1349 {
1350 	if (fracht.empty()) {
1351 		buf.append("  ");
1352 		buf.append(translator::translate("leer"));
1353 		buf.append("\n");
1354 	} else {
1355 		FOR(slist_tpl<ware_t>, const& ware, fracht) {
1356 			const char * name = "Error in Routing";
1357 
1358 			halthandle_t halt = ware.get_ziel();
1359 			if(halt.is_bound()) {
1360 				name = halt->get_name();
1361 			}
1362 
1363 			buf.printf("   %u%s %s > %s\n", ware.menge, translator::translate(ware.get_mass()), translator::translate(ware.get_name()), name);
1364 		}
1365 	}
1366 }
1367 
1368 
1369 /**
1370  * Delete all vehicle load
1371  * @author Hj. Malthaner
1372  */
discard_cargo()1373 void vehicle_t::discard_cargo()
1374 {
1375 	FOR(  slist_tpl<ware_t>, w, fracht ) {
1376 		fabrik_t::update_transit( &w, false );
1377 	}
1378 	fracht.clear();
1379 	sum_weight =  desc->get_weight();
1380 }
1381 
1382 
calc_image()1383 void vehicle_t::calc_image()
1384 {
1385 	image_id old_image=get_image();
1386 	if (fracht.empty()) {
1387 		set_image(desc->get_image_id(ribi_t::get_dir(get_direction()),NULL));
1388 	}
1389 	else {
1390 		set_image(desc->get_image_id(ribi_t::get_dir(get_direction()), fracht.front().get_desc()));
1391 	}
1392 	if(old_image!=get_image()) {
1393 		set_flag(obj_t::dirty);
1394 	}
1395 }
1396 
1397 
get_loaded_image() const1398 image_id vehicle_t::get_loaded_image() const
1399 {
1400 	return desc->get_image_id(ribi_t::dir_south, fracht.empty() ?  NULL  : fracht.front().get_desc());
1401 }
1402 
1403 
1404 // true, if this vehicle did not moved for some time
is_stuck()1405 bool vehicle_t::is_stuck()
1406 {
1407 	return cnv==NULL  ||  cnv->is_waiting();
1408 }
1409 
1410 
rdwr(loadsave_t * file)1411 void vehicle_t::rdwr(loadsave_t *file)
1412 {
1413 	// this is only called from objlist => we save nothing ...
1414 	assert(  file->is_saving()  ); (void)file;
1415 }
1416 
1417 
rdwr_from_convoi(loadsave_t * file)1418 void vehicle_t::rdwr_from_convoi(loadsave_t *file)
1419 {
1420 	xml_tag_t r( file, "vehikel_t" );
1421 
1422 	sint32 fracht_count = 0;
1423 
1424 	if(file->is_saving()) {
1425 		fracht_count = fracht.get_count();
1426 		// we try to have one freight count to guess the right freight
1427 		// when no desc is given
1428 		if(fracht_count==0  &&  desc->get_freight_type()!=goods_manager_t::none  &&  desc->get_capacity()>0) {
1429 			fracht_count = 1;
1430 		}
1431 	}
1432 
1433 	obj_t::rdwr(file);
1434 
1435 	// since obj_t does no longer save positions
1436 	if(  file->is_version_atleast(101, 0)  ) {
1437 		koord3d pos = get_pos();
1438 		pos.rdwr(file);
1439 		set_pos(pos);
1440 	}
1441 
1442 
1443 	sint8 hoff = file->is_saving() ? get_hoff() : 0;
1444 
1445 	if(file->is_version_less(86, 6)) {
1446 		sint32 l;
1447 		file->rdwr_long(purchase_time);
1448 		file->rdwr_long(l);
1449 		dx = (sint8)l;
1450 		file->rdwr_long(l);
1451 		dy = (sint8)l;
1452 		file->rdwr_long(l);
1453 		hoff = (sint8)(l*TILE_HEIGHT_STEP/16);
1454 		file->rdwr_long(speed_limit);
1455 		file->rdwr_enum(direction);
1456 		file->rdwr_enum(previous_direction);
1457 		file->rdwr_long(fracht_count);
1458 		file->rdwr_long(l);
1459 		route_index = (uint16)l;
1460 		purchase_time = (purchase_time >> welt->ticks_per_world_month_shift) + welt->get_settings().get_starting_year();
1461 DBG_MESSAGE("vehicle_t::rdwr_from_convoi()","bought at %i/%i.",(purchase_time%12)+1,purchase_time/12);
1462 	}
1463 	else {
1464 		// prissi: changed several data types to save runtime memory
1465 		file->rdwr_long(purchase_time);
1466 		if(file->is_version_less(99, 18)) {
1467 			file->rdwr_byte(dx);
1468 			file->rdwr_byte(dy);
1469 		}
1470 		else {
1471 			file->rdwr_byte(steps);
1472 			file->rdwr_byte(steps_next);
1473 			if(steps_next==old_diagonal_vehicle_steps_per_tile - 1  &&  file->is_loading()) {
1474 				// reset diagonal length (convoi will be reset anyway, if game diagonal is different)
1475 				steps_next = diagonal_vehicle_steps_per_tile - 1;
1476 			}
1477 		}
1478 		sint16 dummy16 = ((16*(sint16)hoff)/TILE_HEIGHT_STEP);
1479 		file->rdwr_short(dummy16);
1480 		hoff = (sint8)((TILE_HEIGHT_STEP*(sint16)dummy16)/16);
1481 		file->rdwr_long(speed_limit);
1482 		file->rdwr_enum(direction);
1483 		file->rdwr_enum(previous_direction);
1484 		file->rdwr_long(fracht_count);
1485 		file->rdwr_short(route_index);
1486 		// restore dxdy information
1487 		dx = dxdy[ ribi_t::get_dir(direction)*2];
1488 		dy = dxdy[ ribi_t::get_dir(direction)*2+1];
1489 	}
1490 
1491 	// convert steps to position
1492 	if(file->is_version_less(99, 18)) {
1493 		sint8 ddx=get_xoff(), ddy=get_yoff()-hoff;
1494 		sint8 i=1;
1495 		dx = dxdy[ ribi_t::get_dir(direction)*2];
1496 		dy = dxdy[ ribi_t::get_dir(direction)*2+1];
1497 
1498 		while(  !is_about_to_hop(ddx+dx*i,ddy+dy*i )  &&  i<16 ) {
1499 			i++;
1500 		}
1501 		i--;
1502 		set_xoff( ddx-(16-i)*dx );
1503 		set_yoff( ddy-(16-i)*dy );
1504 		if(file->is_loading()) {
1505 			if(dx && dy) {
1506 				steps = min( VEHICLE_STEPS_PER_TILE - 1, VEHICLE_STEPS_PER_TILE - 1-(i*16) );
1507 				steps_next = VEHICLE_STEPS_PER_TILE - 1;
1508 			}
1509 			else {
1510 				// will be corrected anyway, if in a convoi
1511 				steps = min( diagonal_vehicle_steps_per_tile - 1, diagonal_vehicle_steps_per_tile - 1-(uint8)(((uint16)i*(uint16)(diagonal_vehicle_steps_per_tile - 1))/8) );
1512 				steps_next = diagonal_vehicle_steps_per_tile - 1;
1513 			}
1514 		}
1515 	}
1516 
1517 	// information about the target halt
1518 	if(file->is_version_atleast(88, 7)) {
1519 		bool target_info;
1520 		if(file->is_loading()) {
1521 			file->rdwr_bool(target_info);
1522 			cnv = (convoi_t *)target_info;	// will be checked during convoi reassignment
1523 		}
1524 		else {
1525 			target_info = target_halt.is_bound();
1526 			file->rdwr_bool(target_info);
1527 		}
1528 	}
1529 	else {
1530 		if(file->is_loading()) {
1531 			cnv = NULL;	// no reservation too
1532 		}
1533 	}
1534 	if(file->is_version_less(112, 9)) {
1535 		koord3d pos_prev(koord3d::invalid);
1536 		pos_prev.rdwr(file);
1537 	}
1538 
1539 	if(file->is_version_less(99, 5)) {
1540 		koord3d dummy;
1541 		dummy.rdwr(file);	// current pos (is already saved as ding => ignore)
1542 	}
1543 	pos_next.rdwr(file);
1544 
1545 	if(file->is_saving()) {
1546 		const char *s = desc->get_name();
1547 		file->rdwr_str(s);
1548 	}
1549 	else {
1550 		char s[256];
1551 		file->rdwr_str(s, lengthof(s));
1552 		desc = vehicle_builder_t::get_info(s);
1553 		if(desc==NULL) {
1554 			desc = vehicle_builder_t::get_info(translator::compatibility_name(s));
1555 		}
1556 		if(desc==NULL) {
1557 			welt->add_missing_paks( s, karte_t::MISSING_VEHICLE );
1558 			dbg->warning("vehicle_t::rdwr_from_convoi()","no vehicle pak for '%s' search for something similar", s);
1559 		}
1560 	}
1561 
1562 	if(file->is_saving()) {
1563 		if (fracht.empty()  &&  fracht_count>0) {
1564 			// create dummy freight for savegame compatibility
1565 			ware_t ware( desc->get_freight_type() );
1566 			ware.menge = 0;
1567 			ware.set_ziel( halthandle_t() );
1568 			ware.set_zwischenziel( halthandle_t() );
1569 			ware.set_zielpos( get_pos().get_2d() );
1570 			ware.rdwr(file);
1571 		}
1572 		else {
1573 			FOR(slist_tpl<ware_t>, ware, fracht) {
1574 				ware.rdwr(file);
1575 			}
1576 		}
1577 	}
1578 	else {
1579 		for(int i=0; i<fracht_count; i++) {
1580 			ware_t ware(file);
1581 			if(  (desc==NULL  ||  ware.menge>0)  &&  welt->is_within_limits(ware.get_zielpos())  &&  ware.get_desc()  ) {
1582 				// also add, of the desc is unknown to find matching replacement
1583 				fracht.insert(ware);
1584 #ifdef CACHE_TRANSIT
1585 				if(  file->is_version_less(112, 1)  )
1586 #endif
1587 					// restore in-transit information
1588 					fabrik_t::update_transit( &ware, true );
1589 			}
1590 			else if(  ware.menge>0  ) {
1591 				if(  ware.get_desc()  ) {
1592 					dbg->error( "vehicle_t::rdwr_from_convoi()", "%i of %s to %s ignored!", ware.menge, ware.get_name(), ware.get_zielpos().get_str() );
1593 				}
1594 				else {
1595 					dbg->error( "vehicle_t::rdwr_from_convoi()", "%i of unknown to %s ignored!", ware.menge, ware.get_zielpos().get_str() );
1596 				}
1597 			}
1598 		}
1599 	}
1600 
1601 	// skip first last info (the convoi will know this better than we!)
1602 	if(file->is_version_less(88, 7)) {
1603 		bool dummy = 0;
1604 		file->rdwr_bool(dummy);
1605 		file->rdwr_bool(dummy);
1606 	}
1607 
1608 	// koordinate of the last stop
1609 	if(file->is_version_atleast(99, 15)) {
1610 		// This used to be 2d, now it's 3d.
1611 		if(file->is_version_less(112, 8)) {
1612 			if(file->is_saving()) {
1613 				koord last_stop_pos_2d = last_stop_pos.get_2d();
1614 				last_stop_pos_2d.rdwr(file);
1615 			}
1616 			else {
1617 				// loading.  Assume ground level stop (could be wrong, but how would we know?)
1618 				koord last_stop_pos_2d = koord::invalid;
1619 				last_stop_pos_2d.rdwr(file);
1620 				const grund_t* gr = welt->lookup_kartenboden(last_stop_pos_2d);
1621 				if (gr) {
1622 					last_stop_pos = koord3d(last_stop_pos_2d, gr->get_hoehe());
1623 				}
1624 				else {
1625 					// no ground?!?
1626 					last_stop_pos = koord3d::invalid;
1627 				}
1628 			}
1629 		}
1630 		else {
1631 			// current version, 3d
1632 			last_stop_pos.rdwr(file);
1633 		}
1634 	}
1635 
1636 	if(file->is_loading()) {
1637 		leading = last = false;	// dummy, will be set by convoi afterwards
1638 		if(desc) {
1639 			calc_image();
1640 
1641 			// full weight after loading
1642 			sum_weight =  get_cargo_weight() + desc->get_weight();
1643 		}
1644 		// recalc total freight
1645 		total_freight = 0;
1646 		FOR(slist_tpl<ware_t>, const& c, fracht) {
1647 			total_freight += c.menge;
1648 		}
1649 	}
1650 
1651 	if(  file->is_version_atleast(110, 0)  ) {
1652 		bool hd = has_driven;
1653 		file->rdwr_bool( hd );
1654 		has_driven = hd;
1655 	}
1656 	else {
1657 		if (file->is_loading()) {
1658 			has_driven = false;
1659 		}
1660 	}
1661 }
1662 
1663 
calc_sale_value() const1664 uint32 vehicle_t::calc_sale_value() const
1665 {
1666 	// if already used, there is a general price reduction
1667 	double value = (double)desc->get_price();
1668 	if(  has_driven  ) {
1669 		value *= (1000 - welt->get_settings().get_used_vehicle_reduction()) / 1000.0;
1670 	}
1671 	// after 20 year, it has only half value
1672 	return (uint32)( value * pow(0.997, (int)(welt->get_current_month() - get_purchase_time())));
1673 }
1674 
1675 
show_info()1676 void vehicle_t::show_info()
1677 {
1678 	if(  cnv != NULL  ) {
1679 		cnv->open_info_window();
1680 	} else {
1681 		dbg->warning("vehicle_t::show_info()","cnv is null, can't open convoi window!");
1682 	}
1683 }
1684 
1685 
info(cbuffer_t & buf) const1686 void vehicle_t::info(cbuffer_t & buf) const
1687 {
1688 	if(cnv) {
1689 		cnv->info(buf);
1690 	}
1691 }
1692 
1693 
is_deletable(const player_t *)1694 const char *vehicle_t::is_deletable(const player_t *)
1695 {
1696 	return "Fahrzeuge koennen so nicht entfernt werden";
1697 }
1698 
1699 
~vehicle_t()1700 vehicle_t::~vehicle_t()
1701 {
1702 	// remove vehicle's marker from the minimap
1703 	minimap_t::get_instance()->calc_map_pixel(get_pos().get_2d());
1704 }
1705 
1706 
1707 #ifdef MULTI_THREAD
display_overlay(int xpos,int ypos) const1708 void vehicle_t::display_overlay(int xpos, int ypos) const
1709 {
1710 	if(  cnv  &&  leading  ) {
1711 #else
1712 void vehicle_t::display_after(int xpos, int ypos, bool is_global) const
1713 {
1714 	if(  is_global  &&  cnv  &&  leading  ) {
1715 #endif
1716 		PIXVAL color = 0; // not used, but stop compiler warning about uninitialized
1717 		char tooltip_text[1024];
1718 		tooltip_text[0] = 0;
1719 		uint8 state = env_t::show_vehicle_states;
1720 		if(  state==1  ) {
1721 			// only show when mouse over vehicle
1722 			if(  welt->get_zeiger()->get_pos()==get_pos()  ) {
1723 				state = 2;
1724 			}
1725 			else {
1726 				state = 0;
1727 			}
1728 		}
1729 
1730 		// now find out what has happened
1731 		switch(cnv->get_state()) {
1732 			case convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH:
1733 			case convoi_t::WAITING_FOR_CLEARANCE:
1734 			case convoi_t::CAN_START:
1735 			case convoi_t::CAN_START_ONE_MONTH:
1736 				if(  state>=2  ) {
1737 					snprintf( tooltip_text, lengthof(tooltip_text), "%s (%s)", translator::translate("Waiting for clearance!"), cnv->get_schedule()->get_current_entry().pos.get_str() );
1738 					color = color_idx_to_rgb(COL_YELLOW);
1739 				}
1740 				break;
1741 
1742 			case convoi_t::LOADING:
1743 				if(  state>=1  ) {
1744 					sprintf( tooltip_text, translator::translate("Loading (%i->%i%%)!"), cnv->get_loading_level(), cnv->get_loading_limit() );
1745 					color = color_idx_to_rgb(COL_YELLOW);
1746 				}
1747 				break;
1748 
1749 			case convoi_t::EDIT_SCHEDULE:
1750 //			case convoi_t::ROUTING_1:
1751 				if(  state>=2  ) {
1752 					tstrncpy( tooltip_text, translator::translate("Schedule changing!"), lengthof(tooltip_text) );
1753 					color = color_idx_to_rgb(COL_YELLOW);
1754 				}
1755 				break;
1756 
1757 			case convoi_t::DRIVING:
1758 				if(  state>=1  ) {
1759 					grund_t const* const gr = welt->lookup(cnv->get_route()->back());
1760 					if(  gr  &&  gr->get_depot()  ) {
1761 						tstrncpy( tooltip_text, translator::translate("go home"), lengthof(tooltip_text) );
1762 						color = color_idx_to_rgb(COL_GREEN);
1763 					}
1764 					else if(  cnv->get_no_load()  ) {
1765 						tstrncpy( tooltip_text, translator::translate("no load"), lengthof(tooltip_text) );
1766 						color = color_idx_to_rgb(COL_GREEN);
1767 					}
1768 				}
1769 				break;
1770 
1771 			case convoi_t::LEAVING_DEPOT:
1772 				if(  state>=2  ) {
1773 					tstrncpy( tooltip_text, translator::translate("Leaving depot!"), lengthof(tooltip_text) );
1774 					color = color_idx_to_rgb(COL_GREEN);
1775 				}
1776 				break;
1777 
1778 			case convoi_t::WAITING_FOR_CLEARANCE_TWO_MONTHS:
1779 			case convoi_t::CAN_START_TWO_MONTHS:
1780 				snprintf( tooltip_text, lengthof(tooltip_text), "%s (%s)", translator::translate("clf_chk_stucked"), cnv->get_schedule()->get_current_entry().pos.get_str() );
1781 				color = color_idx_to_rgb(COL_ORANGE);
1782 				break;
1783 
1784 			case convoi_t::NO_ROUTE:
1785 				tstrncpy( tooltip_text, translator::translate("clf_chk_noroute"), lengthof(tooltip_text) );
1786 				color = color_idx_to_rgb(COL_RED);
1787 				break;
1788 		}
1789 
1790 		// something to show?
1791 		if(  tooltip_text[0]  ) {
1792 			const int width = proportional_string_width(tooltip_text)+7;
1793 			const int raster_width = get_current_tile_raster_width();
1794 			get_screen_offset( xpos, ypos, raster_width );
1795 			xpos += tile_raster_scale_x(get_xoff(), raster_width);
1796 			ypos += tile_raster_scale_y(get_yoff(), raster_width)+14;
1797 			if(ypos>LINESPACE+32  &&  ypos+LINESPACE<display_get_clip_wh().yy) {
1798 				display_ddd_proportional_clip( xpos, ypos, width, 0, color, color_idx_to_rgb(COL_BLACK), tooltip_text, true );
1799 			}
1800 		}
1801 	}
1802 }
1803 
1804 
1805 
1806 road_vehicle_t::road_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) :
1807 	vehicle_t(pos, desc, player)
1808 {
1809 	cnv = cn;
1810 }
1811 
1812 
1813 road_vehicle_t::road_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t()
1814 {
1815 	rdwr_from_convoi(file);
1816 
1817 	if(  file->is_loading()  ) {
1818 		static const vehicle_desc_t *last_desc = NULL;
1819 
1820 		if(is_first) {
1821 			last_desc = NULL;
1822 		}
1823 		// try to find a matching vehicle
1824 		if(desc==NULL) {
1825 			const goods_desc_t* w = (!fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers);
1826 			dbg->warning("road_vehicle_t::road_vehicle_t()","try to find a fitting vehicle for %s.",  w->get_name() );
1827 			desc = vehicle_builder_t::get_best_matching(road_wt, 0, (fracht.empty() ? 0 : 50), is_first?50:0, speed_to_kmh(speed_limit), w, true, last_desc, is_last );
1828 			if(desc) {
1829 				DBG_MESSAGE("road_vehicle_t::road_vehicle_t()","replaced by %s",desc->get_name());
1830 				// still wrong load ...
1831 				calc_image();
1832 			}
1833 			if(!fracht.empty()  &&  fracht.front().menge == 0) {
1834 				// this was only there to find a matching vehicle
1835 				fracht.remove_first();
1836 			}
1837 		}
1838 		if(  desc  ) {
1839 			last_desc = desc;
1840 		}
1841 		calc_disp_lane();
1842 	}
1843 }
1844 
1845 
1846 void road_vehicle_t::rotate90()
1847 {
1848 	vehicle_t::rotate90();
1849 	calc_disp_lane();
1850 }
1851 
1852 
1853 void road_vehicle_t::calc_disp_lane()
1854 {
1855 	// driving in the back or the front
1856 	ribi_t::ribi test_dir = welt->get_settings().is_drive_left() ? ribi_t::northeast : ribi_t::southwest;
1857 	disp_lane = get_direction() & test_dir ? 1 : 3;
1858 }
1859 
1860 // need to reset halt reservation (if there was one)
1861 bool road_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route)
1862 {
1863 	assert(cnv);
1864 	// free target reservation
1865 	if(leading   &&  previous_direction!=ribi_t::none  &&  cnv  &&  target_halt.is_bound() ) {
1866 		// now reserve our choice (beware: might be longer than one tile!)
1867 		for(  uint32 length=0;  length<cnv->get_tile_length()  &&  length+1<cnv->get_route()->get_count();  length++  ) {
1868 			target_halt->unreserve_position( welt->lookup( cnv->get_route()->at( cnv->get_route()->get_count()-length-1) ), cnv->self );
1869 		}
1870 	}
1871 	target_halt = halthandle_t();	// no block reserved
1872 	route_t::route_result_t r = route->calc_route(welt, start, ziel, this, max_speed, cnv->get_tile_length() );
1873 	if(  r == route_t::valid_route_halt_too_short  ) {
1874 		cbuffer_t buf;
1875 		buf.printf( translator::translate("Vehicle %s cannot choose because stop too short!"), cnv->get_name());
1876 		welt->get_message()->add_message( (const char *)buf, ziel.get_2d(), message_t::traffic_jams, PLAYER_FLAG | cnv->get_owner()->get_player_nr(), cnv->front()->get_base_image() );
1877 	}
1878 	return r;
1879 }
1880 
1881 
1882 bool road_vehicle_t::check_next_tile(const grund_t *bd) const
1883 {
1884 	strasse_t *str=(strasse_t *)bd->get_weg(road_wt);
1885 	if(str==NULL  ||  str->get_max_speed()==0) {
1886 		return false;
1887 	}
1888 	bool electric = cnv!=NULL  ?  cnv->needs_electrification() : desc->get_engine_type()==vehicle_desc_t::electric;
1889 	if(electric  &&  !str->is_electrified()) {
1890 		return false;
1891 	}
1892 	// check for signs
1893 	if(str->has_sign()) {
1894 		const roadsign_t* rs = bd->find<roadsign_t>();
1895 		if(rs!=NULL) {
1896 			if(  rs->get_desc()->get_min_speed()>0  &&  rs->get_desc()->get_min_speed()>kmh_to_speed(get_desc()->get_topspeed())  ) {
1897 				return false;
1898 			}
1899 			if(  rs->get_desc()->is_private_way()  &&  (rs->get_player_mask() & (1<<get_player_nr()) ) == 0  ) {
1900 				// private road
1901 				return false;
1902 			}
1903 			// do not search further for a free stop beyond here
1904 			if(target_halt.is_bound()  &&  cnv->is_waiting()  &&  rs->get_desc()->get_flags()&roadsign_desc_t::END_OF_CHOOSE_AREA) {
1905 				return false;
1906 			}
1907 		}
1908 	}
1909 	return true;
1910 }
1911 
1912 
1913 // how expensive to go here (for way search)
1914 // author prissi
1915 int road_vehicle_t::get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const
1916 {
1917 	// first favor faster ways
1918 	if(!w) {
1919 		return 0xFFFF;
1920 	}
1921 
1922 	// max_speed?
1923 	sint32 max_tile_speed = w->get_max_speed();
1924 
1925 	// add cost for going (with maximum speed, cost is 1)
1926 	int costs = (max_speed<=max_tile_speed) ? 1 : 4-(3*max_tile_speed)/max_speed;
1927 
1928 	// assume all traffic is not good ... (otherwise even smoke counts ... )
1929 	costs += (w->get_statistics(WAY_STAT_CONVOIS)  >  ( 2 << (welt->get_settings().get_bits_per_month()-16) )  );
1930 
1931 	// effect of slope
1932 	if(  gr->get_weg_hang()!=0  ) {
1933 		// Knightly : check if the slope is upwards, relative to the previous tile
1934 		// 15 hardcoded, see get_cost_upslope()
1935 		costs += 15 * get_sloping_upwards( gr->get_weg_hang(), from );
1936 	}
1937 	return costs;
1938 }
1939 
1940 
1941 // this routine is called by find_route, to determined if we reached a destination
1942 bool road_vehicle_t::is_target(const grund_t *gr, const grund_t *prev_gr) const
1943 {
1944 	//  just check, if we reached a free stop position of this halt
1945 	if(gr->is_halt()  &&  gr->get_halt()==target_halt  &&  target_halt->is_reservable(gr,cnv->self)) {
1946 		// now we must check the predecessor => try to advance as much as possible
1947 		if(prev_gr!=NULL) {
1948 			const koord dir=gr->get_pos().get_2d()-prev_gr->get_pos().get_2d();
1949 			ribi_t::ribi ribi = ribi_type(dir);
1950 			if(  gr->get_weg(get_waytype())->get_ribi_maske() & ribi  ) {
1951 				// one way sign wrong direction
1952 				return false;
1953 			}
1954 			grund_t *to;
1955 			if(  !gr->get_neighbour(to,road_wt,ribi)  ||  !(to->get_halt()==target_halt)  ||  (gr->get_weg(get_waytype())->get_ribi_maske() & ribi_type(dir))!=0  ||  !target_halt->is_reservable(to,cnv->self)  ) {
1956 				// end of stop: Is it long enough?
1957 				uint16 tiles = cnv->get_tile_length();
1958 				while(  tiles>1  ) {
1959 					if(  !gr->get_neighbour(to,get_waytype(),ribi_t::backward(ribi))  ||  !(to->get_halt()==target_halt)  ||  !target_halt->is_reservable(to,cnv->self)  ) {
1960 						return false;
1961 					}
1962 					gr = to;
1963 					tiles --;
1964 				}
1965 				return true;
1966 			}
1967 			// can advance more
1968 			return false;
1969 		}
1970 //DBG_MESSAGE("is_target()","success at %i,%i",gr->get_pos().x,gr->get_pos().y);
1971 //		return true;
1972 	}
1973 	return false;
1974 }
1975 
1976 
1977 // to make smaller steps than the tile granularity, we have to use this trick
1978 void road_vehicle_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const
1979 {
1980 	vehicle_base_t::get_screen_offset( xoff, yoff, raster_width );
1981 
1982 	if(  welt->get_settings().is_drive_left()  ) {
1983 		const int drive_left_dir = ribi_t::get_dir(get_direction());
1984 		xoff += tile_raster_scale_x( driveleft_base_offsets[drive_left_dir][0], raster_width );
1985 		yoff += tile_raster_scale_y( driveleft_base_offsets[drive_left_dir][1], raster_width );
1986 	}
1987 
1988 	// eventually shift position to take care of overtaking
1989 	if(cnv) {
1990 		if(  cnv->is_overtaking()  ) {
1991 			xoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width);
1992 			yoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width);
1993 		}
1994 		else if(  cnv->is_overtaken()  ) {
1995 			xoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width)/5;
1996 			yoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width)/5;
1997 		}
1998 	}
1999 }
2000 
2001 
2002 // chooses a route at a choose sign; returns true on success
2003 bool road_vehicle_t::choose_route(sint32 &restart_speed, ribi_t::ribi start_direction, uint16 index)
2004 {
2005 	if(  cnv->get_schedule_target()!=koord3d::invalid  ) {
2006 		// destination is a waypoint!
2007 		return true;
2008 	}
2009 
2010 	// are we heading to a target?
2011 	route_t *rt = cnv->access_route();
2012 	target_halt = haltestelle_t::get_halt( rt->back(), get_owner() );
2013 	if(  target_halt.is_bound()  ) {
2014 
2015 		// since convois can long than one tile, check is more difficult
2016 		bool can_go_there = true;
2017 		bool original_route = (rt->back() == cnv->get_schedule()->get_current_entry().pos);
2018 		for(  uint32 length=0;  can_go_there  &&  length<cnv->get_tile_length()  &&  length+1<rt->get_count();  length++  ) {
2019 			if(  grund_t *gr = welt->lookup( rt->at( rt->get_count()-length-1) )  ) {
2020 				if (gr->get_halt().is_bound()) {
2021 					can_go_there &= target_halt->is_reservable( gr, cnv->self );
2022 				}
2023 				else {
2024 					// if this is the original stop, it is too short!
2025 					can_go_there |= original_route;
2026 				}
2027 			}
2028 		}
2029 		if(  can_go_there  ) {
2030 			// then reserve it ...
2031 			for(  uint32 length=0;  length<cnv->get_tile_length()  &&  length+1<rt->get_count();  length++  ) {
2032 				target_halt->reserve_position( welt->lookup( rt->at( rt->get_count()-length-1) ), cnv->self );
2033 			}
2034 		}
2035 		else {
2036 			// cannot go there => need slot search
2037 
2038 			// if we fail, we will wait in a step, much more simulation friendly
2039 			if(!cnv->is_waiting()) {
2040 				restart_speed = -1;
2041 				target_halt = halthandle_t();
2042 				return false;
2043 			}
2044 
2045 			// check if there is a free position
2046 			// this is much faster than waysearch
2047 			if(  !target_halt->find_free_position(road_wt,cnv->self,obj_t::road_vehicle  )) {
2048 				restart_speed = 0;
2049 				target_halt = halthandle_t();
2050 				return false;
2051 			}
2052 
2053 			// now it make sense to search a route
2054 			route_t target_rt;
2055 			koord3d next3d = rt->at(index);
2056 			if(  !target_rt.find_route( welt, next3d, this, speed_to_kmh(cnv->get_min_top_speed()), start_direction, welt->get_settings().get_max_choose_route_steps() )  ) {
2057 				// nothing empty or not route with less than 33 tiles
2058 				target_halt = halthandle_t();
2059 				restart_speed = 0;
2060 				return false;
2061 			}
2062 
2063 			// now reserve our choice (beware: might be longer than one tile!)
2064 			for(  uint32 length=0;  length<cnv->get_tile_length()  &&  length+1<target_rt.get_count();  length++  ) {
2065 				target_halt->reserve_position( welt->lookup( target_rt.at( target_rt.get_count()-length-1) ), cnv->self );
2066 			}
2067 			rt->remove_koord_from( index );
2068 			rt->append( &target_rt );
2069 		}
2070 	}
2071 	return true;
2072 }
2073 
2074 
2075 bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8 second_check_count)
2076 {
2077 	// check for traffic lights (only relevant for the first car in a convoi)
2078 	if(  leading  ) {
2079 		// no further check, when already entered a crossing (to allow leaving it)
2080 		if(  !second_check_count  ) {
2081 			const grund_t *gr_current = welt->lookup(get_pos());
2082 			if(  gr_current  &&  gr_current->ist_uebergang()  ) {
2083 				return true;
2084 			}
2085 		}
2086 
2087 		assert(gr);
2088 
2089 		const strasse_t *str = (strasse_t *)gr->get_weg(road_wt);
2090 		if(  !str  ||  gr->get_top() > 250  ) {
2091 			// too many cars here or no street
2092 			return false;
2093 		}
2094 
2095 		// first: check roadsigns
2096 		const roadsign_t *rs = NULL;
2097 		if(  str->has_sign()  ) {
2098 			rs = gr->find<roadsign_t>();
2099 			route_t const& r = *cnv->get_route();
2100 
2101 			if(  rs  &&  (route_index + 1u < r.get_count())  ) {
2102 				// since at the corner, our direction may be diagonal, we make it straight
2103 				uint8 direction90 = ribi_type(get_pos(), pos_next);
2104 
2105 				if(  rs->get_desc()->is_traffic_light()  &&  (rs->get_dir()&direction90) == 0  ) {
2106 					// wait here
2107 					restart_speed = 16;
2108 					return false;
2109 				}
2110 				// check, if we reached a choose point
2111 				else {
2112 					// route position after road sign
2113 					const koord pos_next_next = r.at(route_index + 1u).get_2d();
2114 					// since at the corner, our direction may be diagonal, we make it straight
2115 					direction90 = ribi_type( pos_next, pos_next_next );
2116 
2117 					if(  rs->is_free_route(direction90)  &&  !target_halt.is_bound()  ) {
2118 						if(  second_check_count  ) {
2119 							return false;
2120 						}
2121 						if(  !choose_route( restart_speed, direction90, route_index )  ) {
2122 							return false;
2123 						}
2124 					}
2125 				}
2126 			}
2127 		}
2128 
2129 		vehicle_base_t *obj = NULL;
2130 		uint32 test_index = route_index + 1u;
2131 
2132 		// way should be clear for overtaking: we checked previously
2133 		if(  !cnv->is_overtaking()  ) {
2134 			// calculate new direction
2135 			route_t const& r = *cnv->get_route();
2136 			koord3d next = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next;
2137 			ribi_t::ribi curr_direction   = get_direction();
2138 			ribi_t::ribi curr_90direction = calc_direction(get_pos(), pos_next);
2139 			ribi_t::ribi next_direction   = calc_direction(get_pos(), next);
2140 			ribi_t::ribi next_90direction = calc_direction(pos_next, next);
2141 			obj = no_cars_blocking( gr, cnv, curr_direction, next_direction, next_90direction );
2142 
2143 			// do not block intersections
2144 			const bool drives_on_left = welt->get_settings().is_drive_left();
2145 			bool int_block = ribi_t::is_threeway(str->get_ribi_unmasked())  &&  (((drives_on_left ? ribi_t::rotate90l(curr_90direction) : ribi_t::rotate90(curr_90direction)) & str->get_ribi_unmasked())  ||  curr_90direction != next_90direction  ||  (rs  &&  rs->get_desc()->is_traffic_light()));
2146 
2147 			// check exit from crossings and intersections, allow to proceed after 4 consecutive
2148 			while(  !obj   &&  (str->is_crossing()  ||  int_block)  &&  test_index < r.get_count()  &&  test_index < route_index + 4u  ) {
2149 				if(  str->is_crossing()  ) {
2150 					crossing_t* cr = gr->find<crossing_t>(2);
2151 					if(  !cr->request_crossing(this)  ) {
2152 						restart_speed = 0;
2153 						return false;
2154 					}
2155 				}
2156 
2157 				// test next position
2158 				gr = welt->lookup(r.at(test_index));
2159 				if(  !gr  ) {
2160 					// way (weg) not existent (likely destroyed)
2161 					if(  !second_check_count  ) {
2162 						cnv->suche_neue_route();
2163 					}
2164 					return false;
2165 				}
2166 
2167 				str = (strasse_t *)gr->get_weg(road_wt);
2168 				if(  !str  ||  gr->get_top() > 250  ) {
2169 					// too many cars here or no street
2170 					if(  !second_check_count  &&  !str) {
2171 						cnv->suche_neue_route();
2172 					}
2173 					return false;
2174 				}
2175 
2176 				// check cars
2177 				curr_direction   = next_direction;
2178 				curr_90direction = next_90direction;
2179 				if(  test_index + 1u < r.get_count()  ) {
2180 					next                 = r.at(test_index + 1u);
2181 					next_direction   = calc_direction(r.at(test_index - 1u), next);
2182 					next_90direction = calc_direction(r.at(test_index),      next);
2183 					obj = no_cars_blocking( gr, cnv, curr_direction, next_direction, next_90direction );
2184 				}
2185 				else {
2186 					next                 = r.at(test_index);
2187 					next_90direction = calc_direction(r.at(test_index - 1u), next);
2188 					if(  curr_direction == next_90direction  ||  !gr->is_halt()  ) {
2189 						// check cars but allow to enter intersection if we are turning even when a car is blocking the halt on the last tile of our route
2190 						// preserves old bus terminal behaviour
2191 						obj = no_cars_blocking( gr, cnv, curr_direction, next_90direction, ribi_t::none );
2192 					}
2193 				}
2194 
2195 				// check roadsigns
2196 				if(  str->has_sign()  ) {
2197 					rs = gr->find<roadsign_t>();
2198 					if(  rs  ) {
2199 						// since at the corner, our direction may be diagonal, we make it straight
2200 						if(  rs->get_desc()->is_traffic_light()  &&  (rs->get_dir() & curr_90direction)==0  ) {
2201 							// wait here
2202 							restart_speed = 16;
2203 							return false;
2204 						}
2205 						// check, if we reached a choose point
2206 
2207 						else if(  rs->is_free_route(curr_90direction)  &&  !target_halt.is_bound()  ) {
2208 							if(  second_check_count  ) {
2209 								return false;
2210 							}
2211 							if(  !choose_route( restart_speed, curr_90direction, test_index )  ) {
2212 								return false;
2213 							}
2214 						}
2215 					}
2216 				}
2217 				else {
2218 					rs = NULL;
2219 				}
2220 
2221 				// check for blocking intersection
2222 				int_block = ribi_t::is_threeway(str->get_ribi_unmasked())  &&  (((drives_on_left ? ribi_t::rotate90l(curr_90direction) : ribi_t::rotate90(curr_90direction)) & str->get_ribi_unmasked())  ||  curr_90direction != next_90direction  ||  (rs  &&  rs->get_desc()->is_traffic_light()));
2223 
2224 				test_index++;
2225 			}
2226 
2227 			if(  obj  &&  test_index > route_index + 1u  &&  !str->is_crossing()  &&  !int_block  ) {
2228 				// found a car blocking us after checking at least 1 intersection or crossing
2229 				// and the car is in a place we could stop. So if it can move, assume it will, so we will too.
2230 				// but check only upto 8 cars ahead to prevent infinite recursion on roundabouts.
2231 				if(  second_check_count >= 8  ) {
2232 					return false;
2233 				}
2234 				if(  road_vehicle_t const* const car = obj_cast<road_vehicle_t>(obj)  ) {
2235 					const convoi_t* const ocnv = car->get_convoi();
2236 					sint32 dummy;
2237 					if(  ocnv->front()->get_route_index() < ocnv->get_route()->get_count()  &&  ocnv->front()->can_enter_tile( dummy, second_check_count + 1 )  ) {
2238 						return true;
2239 					}
2240 				}
2241 			}
2242 		}
2243 
2244 		// stuck message ...
2245 		if(  obj  &&  !second_check_count  ) {
2246 			if(  obj->is_stuck()  ) {
2247 				// end of traffic jam, but no stuck message, because previous vehicle is stuck too
2248 				restart_speed = 0;
2249 				cnv->set_tiles_overtaking(0);
2250 				cnv->reset_waiting();
2251 			}
2252 			else {
2253 				if(  test_index == route_index + 1u  ) {
2254 					// no intersections or crossings, we might be able to overtake this one ...
2255 					overtaker_t *over = obj->get_overtaker();
2256 					if(  over  &&  !over->is_overtaken()  ) {
2257 						if(  over->is_overtaking()  ) {
2258 							// otherwise we would stop every time being overtaken
2259 							return true;
2260 						}
2261 						// not overtaking/being overtake: we need to make a more thought test!
2262 						if(  road_vehicle_t const* const car = obj_cast<road_vehicle_t>(obj)  ) {
2263 							convoi_t* const ocnv = car->get_convoi();
2264 							if(  cnv->can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps())  ) {
2265 								return true;
2266 							}
2267 						}
2268 						else if(  private_car_t* const caut = obj_cast<private_car_t>(obj)  ) {
2269 							if(  cnv->can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE)  ) {
2270 								return true;
2271 							}
2272 						}
2273 					}
2274 				}
2275 				// we have to wait ...
2276 				restart_speed = (cnv->get_akt_speed()*3)/4;
2277 				cnv->set_tiles_overtaking(0);
2278 			}
2279 		}
2280 
2281 		return obj==NULL;
2282 	}
2283 
2284 	return true;
2285 }
2286 
2287 
2288 overtaker_t* road_vehicle_t::get_overtaker()
2289 {
2290 	return cnv;
2291 }
2292 
2293 
2294 void road_vehicle_t::enter_tile(grund_t* gr)
2295 {
2296 	vehicle_t::enter_tile(gr);
2297 	calc_disp_lane();
2298 
2299 	const int cargo = get_total_cargo();
2300 	weg_t *str = gr->get_weg(road_wt);
2301 	str->book(cargo, WAY_STAT_GOODS);
2302 	if (leading)  {
2303 		str->book(1, WAY_STAT_CONVOIS);
2304 		cnv->update_tiles_overtaking();
2305 	}
2306 }
2307 
2308 
2309 schedule_t * road_vehicle_t::generate_new_schedule() const
2310 {
2311   return new truck_schedule_t();
2312 }
2313 
2314 
2315 void road_vehicle_t::set_convoi(convoi_t *c)
2316 {
2317 	DBG_MESSAGE("road_vehicle_t::set_convoi()","%p",c);
2318 	if(c!=NULL) {
2319 		bool target=(bool)cnv;	// only during loadtype: cnv==1 indicates, that the convoi did reserve a stop
2320 		vehicle_t::set_convoi(c);
2321 		if(target  &&  leading  &&  c->get_route()->empty()) {
2322 			// reinitialize the target halt
2323 			const route_t *rt = cnv->get_route();
2324 			target_halt = haltestelle_t::get_halt( rt->back(), get_owner() );
2325 			if(  target_halt.is_bound()  ) {
2326 				for(  uint32 i=0;  i<c->get_tile_length()  &&  i+1<rt->get_count();  i++  ) {
2327 					target_halt->reserve_position( welt->lookup( rt->at(rt->get_count()-i-1) ), cnv->self );
2328 				}
2329 			}
2330 		}
2331 	}
2332 	else {
2333 		if(  cnv  &&  leading  &&  target_halt.is_bound()  ) {
2334 			// now reserve our choice (beware: might be longer than one tile!)
2335 			for(  uint32 length=0;  length<cnv->get_tile_length()  &&  length+1<cnv->get_route()->get_count();  length++  ) {
2336 				target_halt->unreserve_position( welt->lookup( cnv->get_route()->at( cnv->get_route()->get_count()-length-1) ), cnv->self );
2337 			}
2338 			target_halt = halthandle_t();
2339 		}
2340 		cnv = NULL;
2341 	}
2342 }
2343 
2344 
2345 /* from now on rail vehicles (and other vehicles using blocks) */
2346 rail_vehicle_t::rail_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t()
2347 {
2348 	vehicle_t::rdwr_from_convoi(file);
2349 
2350 	if(  file->is_loading()  ) {
2351 		static const vehicle_desc_t *last_desc = NULL;
2352 
2353 		if(is_first) {
2354 			last_desc = NULL;
2355 		}
2356 		// try to find a matching vehicle
2357 		if(desc==NULL) {
2358 			int power = (is_first || fracht.empty() || fracht.front() == goods_manager_t::none) ? 500 : 0;
2359 			const goods_desc_t* w = fracht.empty() ? goods_manager_t::none : fracht.front().get_desc();
2360 			dbg->warning("rail_vehicle_t::rail_vehicle_t()","try to find a fitting vehicle for %s.", power>0 ? "engine": w->get_name() );
2361 			if(last_desc!=NULL  &&  last_desc->can_follow(last_desc)  &&  last_desc->get_freight_type()==w  &&  (!is_last  ||  last_desc->get_trailer(0)==NULL)) {
2362 				// same as previously ...
2363 				desc = last_desc;
2364 			}
2365 			else {
2366 				// we have to search
2367 				desc = vehicle_builder_t::get_best_matching(get_waytype(), 0, w!=goods_manager_t::none?5000:0, power, speed_to_kmh(speed_limit), w, false, last_desc, is_last );
2368 			}
2369 			if(desc) {
2370 DBG_MESSAGE("rail_vehicle_t::rail_vehicle_t()","replaced by %s",desc->get_name());
2371 				calc_image();
2372 			}
2373 			else {
2374 				dbg->error("rail_vehicle_t::rail_vehicle_t()","no matching desc found for %s!",w->get_name());
2375 			}
2376 			if (!fracht.empty() && fracht.front().menge == 0) {
2377 				// this was only there to find a matching vehicle
2378 				fracht.remove_first();
2379 			}
2380 		}
2381 		// update last desc
2382 		if(  desc  ) {
2383 			last_desc = desc;
2384 		}
2385 	}
2386 }
2387 
2388 
2389 rail_vehicle_t::rail_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) :
2390 	vehicle_t(pos, desc, player)
2391 {
2392     cnv = cn;
2393 }
2394 
2395 
2396 rail_vehicle_t::~rail_vehicle_t()
2397 {
2398 	if (cnv && leading) {
2399 		route_t const& r = *cnv->get_route();
2400 		if (!r.empty() && route_index < r.get_count()) {
2401 			// free all reserved blocks
2402 			uint16 dummy;
2403 			block_reserver(&r, cnv->back()->get_route_index(), dummy, dummy, target_halt.is_bound() ? 100000 : 1, false, false);
2404 		}
2405 	}
2406 	grund_t *gr = welt->lookup(get_pos());
2407 	if(gr) {
2408 		schiene_t * sch = (schiene_t *)gr->get_weg(get_waytype());
2409 		if(sch) {
2410 			sch->unreserve(this);
2411 		}
2412 	}
2413 }
2414 
2415 
2416 void rail_vehicle_t::set_convoi(convoi_t *c)
2417 {
2418 	if(c!=cnv) {
2419 		DBG_MESSAGE("rail_vehicle_t::set_convoi()","new=%p old=%p",c,cnv);
2420 		if(leading) {
2421 			if(cnv!=NULL  &&  cnv!=(convoi_t *)1) {
2422 				// free route from old convoi
2423 				route_t const& r = *cnv->get_route();
2424 				if(  !r.empty()  &&  route_index + 1U < r.get_count() - 1  ) {
2425 					uint16 dummy;
2426 					block_reserver(&r, cnv->back()->get_route_index(), dummy, dummy, 100000, false, false);
2427 					target_halt = halthandle_t();
2428 				}
2429 			}
2430 			else if(  c->get_next_reservation_index()==0  ) {
2431 				assert(c!=NULL);
2432 				// eventually search new route
2433 				route_t const& r = *c->get_route();
2434 				if(  (r.get_count()<=route_index  ||  r.empty()  ||  get_pos()==r.back())  &&  c->get_state()!=convoi_t::INITIAL  &&  c->get_state()!=convoi_t::LOADING  &&  c->get_state()!=convoi_t::SELF_DESTRUCT  ) {
2435 					check_for_finish = true;
2436 					dbg->warning("rail_vehicle_t::set_convoi()", "convoi %i had a too high route index! (%i of max %i)", c->self.get_id(), route_index, r.get_count() - 1);
2437 				}
2438 				// set default next stop index
2439 				c->set_next_stop_index( max(route_index,1)-1 );
2440 				// need to reserve new route?
2441 				if(  !check_for_finish  &&  c->get_state()!=convoi_t::SELF_DESTRUCT  &&  (c->get_state()==convoi_t::DRIVING  ||  c->get_state()>=convoi_t::LEAVING_DEPOT)  ) {
2442 					sint32 num_index = cnv==(convoi_t *)1 ? 1001 : 0; 	// only during loadtype: cnv==1 indicates, that the convoi did reserve a stop
2443 					uint16 next_signal, next_crossing;
2444 					cnv = c;
2445 					if(  block_reserver(&r, max(route_index,1)-1, next_signal, next_crossing, num_index, true, false)  ) {
2446 						c->set_next_stop_index( next_signal>next_crossing ? next_crossing : next_signal );
2447 					}
2448 				}
2449 			}
2450 		}
2451 		vehicle_t::set_convoi(c);
2452 	}
2453 }
2454 
2455 
2456 // need to reset halt reservation (if there was one)
2457 bool rail_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route)
2458 {
2459 	if(leading  &&  route_index<cnv->get_route()->get_count()) {
2460 		// free all reserved blocks
2461 		uint16 dummy;
2462 		block_reserver(cnv->get_route(), cnv->back()->get_route_index(), dummy, dummy, target_halt.is_bound() ? 100000 : 1, false, true);
2463 	}
2464 	cnv->set_next_reservation_index( 0 );	// nothing to reserve
2465 	target_halt = halthandle_t();	// no block reserved
2466 	// use length 8888 tiles to advance to the end of all stations
2467 	return route->calc_route(welt, start, ziel, this, max_speed, 8888 /*cnv->get_tile_length()*/ );
2468 }
2469 
2470 
2471 bool rail_vehicle_t::check_next_tile(const grund_t *bd) const
2472 {
2473 	schiene_t const* const sch = obj_cast<schiene_t>(bd->get_weg(get_waytype()));
2474 	if(  !sch  ) {
2475 		return false;
2476 	}
2477 
2478 	// Hajo: diesel and steam engines can use electrified track as well.
2479 	// also allow driving on foreign tracks ...
2480 	const bool needs_no_electric = !(cnv!=NULL ? cnv->needs_electrification() : desc->get_engine_type()==vehicle_desc_t::electric);
2481 	if(  (!needs_no_electric  &&  !sch->is_electrified())  ||  sch->get_max_speed() == 0  ) {
2482 		return false;
2483 	}
2484 
2485 	if (depot_t *depot = bd->get_depot()) {
2486 		if (depot->get_waytype() != desc->get_waytype()  ||  depot->get_owner() != get_owner()) {
2487 			return false;
2488 		}
2489 	}
2490 	// now check for special signs
2491 	if(sch->has_sign()) {
2492 		const roadsign_t* rs = bd->find<roadsign_t>();
2493 		if(  rs->get_desc()->get_wtyp()==get_waytype()  ) {
2494 			if(  cnv != NULL  &&  rs->get_desc()->get_min_speed() > 0  &&  rs->get_desc()->get_min_speed() > cnv->get_min_top_speed()  ) {
2495 				// below speed limit
2496 				return false;
2497 			}
2498 			if(  rs->get_desc()->is_private_way()  &&  (rs->get_player_mask() & (1<<get_player_nr()) ) == 0  ) {
2499 				// private road
2500 				return false;
2501 			}
2502 		}
2503 	}
2504 
2505 	if(  target_halt.is_bound()  &&  cnv->is_waiting()  ) {
2506 		// we are searching a stop here:
2507 		// ok, we can go where we already are ...
2508 		if(bd->get_pos()==get_pos()) {
2509 			return true;
2510 		}
2511 		// we cannot pass an end of choose area
2512 		if(sch->has_sign()) {
2513 			const roadsign_t* rs = bd->find<roadsign_t>();
2514 			if(  rs->get_desc()->get_wtyp()==get_waytype()  ) {
2515 				if(  rs->get_desc()->get_flags() & roadsign_desc_t::END_OF_CHOOSE_AREA  ) {
2516 					return false;
2517 				}
2518 			}
2519 		}
2520 		// but we can only use empty blocks ...
2521 		// now check, if we could enter here
2522 		return sch->can_reserve(cnv->self);
2523 	}
2524 
2525 	return true;
2526 }
2527 
2528 
2529 // how expensive to go here (for way search)
2530 // author prissi
2531 int rail_vehicle_t::get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const
2532 {
2533 	// first favor faster ways
2534 	if(  w==NULL  ) {
2535 		// only occurs when deletion during way search
2536 		return 999;
2537 	}
2538 
2539 	// add cost for going (with maximum speed, cost is 1)
2540 	const sint32 max_tile_speed = w->get_max_speed();
2541 	int costs = (max_speed<=max_tile_speed) ? 1 : 4-(3*max_tile_speed)/max_speed;
2542 
2543 	// effect of slope
2544 	if(  gr->get_weg_hang()!=0  ) {
2545 		// Knightly : check if the slope is upwards, relative to the previous tile
2546 		// 25 hardcoded, see get_cost_upslope()
2547 		costs += 25 * get_sloping_upwards( gr->get_weg_hang(), from );
2548 	}
2549 
2550 	return costs;
2551 }
2552 
2553 
2554 // this routine is called by find_route, to determined if we reached a destination
2555 bool rail_vehicle_t::is_target(const grund_t *gr,const grund_t *prev_gr) const
2556 {
2557 	const schiene_t * sch1 = (const schiene_t *) gr->get_weg(get_waytype());
2558 	// first check blocks, if we can go there
2559 	if(  sch1->can_reserve(cnv->self)  ) {
2560 		//  just check, if we reached a free stop position of this halt
2561 		if(  gr->is_halt()  &&  gr->get_halt()==target_halt  ) {
2562 			// now we must check the predecessor ...
2563 			if(  prev_gr!=NULL  ) {
2564 				const koord dir=gr->get_pos().get_2d()-prev_gr->get_pos().get_2d();
2565 				const ribi_t::ribi ribi = ribi_type(dir);
2566 				if(  gr->get_weg(get_waytype())->get_ribi_maske() & ribi  ) {
2567 					// signal/one way sign wrong direction
2568 					return false;
2569 				}
2570 				grund_t *to;
2571 				if(  !gr->get_neighbour(to,get_waytype(),ribi)  ||  !(to->get_halt()==target_halt)  ||  (to->get_weg(get_waytype())->get_ribi_maske() & ribi_type(dir))!=0  ) {
2572 					// end of stop: Is it long enough?
2573 					// end of stop could be also signal!
2574 					uint16 tiles = cnv->get_tile_length();
2575 					while(  tiles>1  ) {
2576 						if(  gr->get_weg(get_waytype())->get_ribi_maske() & ribi  ||  !gr->get_neighbour(to,get_waytype(),ribi_t::backward(ribi))  ||  !(to->get_halt()==target_halt)  ) {
2577 							return false;
2578 						}
2579 						gr = to;
2580 						tiles --;
2581 					}
2582 					return true;
2583 				}
2584 			}
2585 		}
2586 	}
2587 	return false;
2588 }
2589 
2590 
2591 bool rail_vehicle_t::is_longblock_signal_clear(signal_t *sig, uint16 next_block, sint32 &restart_speed)
2592 {
2593 	// longblock signal: first check, whether there is a signal coming up on the route => just like normal signal
2594 	uint16 next_signal, next_crossing;
2595 	if(  !block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false )  ) {
2596 		// not even the "Normal" signal route part is free => no bother checking further on
2597 		sig->set_state( roadsign_t::rot );
2598 		restart_speed = 0;
2599 		return false;
2600 	}
2601 
2602 	if(  next_signal != INVALID_INDEX  ) {
2603 		// success, and there is a signal before end of route => finished
2604 		sig->set_state( roadsign_t::gruen );
2605 		cnv->set_next_stop_index( min( next_crossing, next_signal ) );
2606 		return true;
2607 	}
2608 
2609 	// no signal before end_of_route => need to do route search in a step
2610 	if(  !cnv->is_waiting()  ) {
2611 		restart_speed = -1;
2612 		return false;
2613 	}
2614 
2615 	// now we can use the route search array
2616 	// (route until end is already reserved at this point!)
2617 	uint8 schedule_index = cnv->get_schedule()->get_current_stop()+1;
2618 	route_t target_rt;
2619 	koord3d cur_pos = cnv->get_route()->back();
2620 	uint16 dummy, next_next_signal;
2621 	if(schedule_index >= cnv->get_schedule()->get_count()) {
2622 		schedule_index = 0;
2623 	}
2624 	while(  schedule_index != cnv->get_schedule()->get_current_stop()  ) {
2625 		// now search
2626 		// search for route
2627 		bool success = target_rt.calc_route( welt, cur_pos, cnv->get_schedule()->entries[schedule_index].pos, this, speed_to_kmh(cnv->get_min_top_speed()), 8888 /*cnv->get_tile_length()*/ );
2628 		if(  target_rt.is_contained(get_pos())  ) {
2629 			// do not reserve route going through my current stop&
2630 			break;
2631 		}
2632 		if(  success  ) {
2633 			success = block_reserver( &target_rt, 1, next_next_signal, dummy, 0, true, false );
2634 			block_reserver( &target_rt, 1, dummy, dummy, 0, false, false );
2635 		}
2636 
2637 		if(  success  ) {
2638 			// ok, would be free
2639 			if(  next_next_signal<target_rt.get_count()  ) {
2640 				// and here is a signal => finished
2641 				// (however, if it is this signal, we need to renew reservation ...
2642 				if(  target_rt.at(next_next_signal) == cnv->get_route()->at( next_block )  ) {
2643 					block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false );
2644 				}
2645 				sig->set_state( roadsign_t::gruen );
2646 				cnv->set_next_stop_index( min( min( next_crossing, next_signal ), cnv->get_route()->get_count() ) );
2647 				return true;
2648 			}
2649 		}
2650 
2651 		if(  !success  ) {
2652 			block_reserver( cnv->get_route(), next_block+1, next_next_signal, dummy, 0, false, false );
2653 			sig->set_state( roadsign_t::rot );
2654 			restart_speed = 0;
2655 			return false;
2656 		}
2657 		// prepare for next leg of schedule
2658 		cur_pos = target_rt.back();
2659 		schedule_index ++;
2660 		if(schedule_index >= cnv->get_schedule()->get_count()) {
2661 			schedule_index = 0;
2662 		}
2663 	}
2664 	if(  cnv->get_next_stop_index()-1 <= route_index  ) {
2665 		cnv->set_next_stop_index( cnv->get_route()->get_count()-1 );
2666 	}
2667 	return true;
2668 }
2669 
2670 
2671 bool rail_vehicle_t::is_choose_signal_clear(signal_t *sig, const uint16 start_block, sint32 &restart_speed)
2672 {
2673 	bool choose_ok = false;
2674 	target_halt = halthandle_t();
2675 
2676 	uint16 next_signal, next_crossing;
2677 	grund_t const* const target = welt->lookup(cnv->get_route()->back());
2678 
2679 	if(  cnv->get_schedule_target()!=koord3d::invalid  ) {
2680 		// destination is a waypoint!
2681 		goto skip_choose;
2682 	}
2683 
2684 	if(  target==NULL  ) {
2685 		cnv->suche_neue_route();
2686 		return false;
2687 	}
2688 
2689 	// first check, if we are not heading to a waypoint
2690 	if(  !target->get_halt().is_bound()  ) {
2691 		goto skip_choose;
2692 	}
2693 
2694 	// now we might choose something at least
2695 	choose_ok = true;
2696 
2697 	// check, if there is another choose signal or end_of_choose on the route
2698 	for(  uint32 idx=start_block+1;  choose_ok  &&  idx<cnv->get_route()->get_count();  idx++  ) {
2699 		grund_t *gr = welt->lookup(cnv->get_route()->at(idx));
2700 		if(  gr==0  ) {
2701 			choose_ok = false;
2702 			break;
2703 		}
2704 		if(  gr->get_halt()==target->get_halt()  ) {
2705 			target_halt = gr->get_halt();
2706 			break;
2707 		}
2708 		weg_t *way = gr->get_weg(get_waytype());
2709 		if(  way==0  ) {
2710 			choose_ok = false;
2711 			break;
2712 		}
2713 		if(  way->has_sign()  ) {
2714 			roadsign_t *rs = gr->find<roadsign_t>(1);
2715 			if(  rs  &&  rs->get_desc()->get_wtyp()==get_waytype()  ) {
2716 				if(  rs->get_desc()->get_flags() & roadsign_desc_t::END_OF_CHOOSE_AREA  ) {
2717 					// end of choose on route => not choosing here
2718 					choose_ok = false;
2719 				}
2720 			}
2721 		}
2722 		if(  way->has_signal()  ) {
2723 			signal_t *sig = gr->find<signal_t>(1);
2724 			if(  sig  &&  sig->get_desc()->is_choose_sign()  ) {
2725 				// second choose signal on route => not choosing here
2726 				choose_ok = false;
2727 			}
2728 		}
2729 	}
2730 
2731 skip_choose:
2732 	if(  !choose_ok  ) {
2733 		// just act as normal signal
2734 		if(  block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 0, true, false )  ) {
2735 			sig->set_state(  roadsign_t::gruen );
2736 			cnv->set_next_stop_index( min( next_crossing, next_signal ) );
2737 			return true;
2738 		}
2739 		// not free => wait here if directly in front
2740 		sig->set_state(  roadsign_t::rot );
2741 		restart_speed = 0;
2742 		return false;
2743 	}
2744 
2745 	target_halt = target->get_halt();
2746 	if(  !block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 100000, true, false )  ) {
2747 		// no free route to target!
2748 		// note: any old reservations should be invalid after the block reserver call.
2749 		// => We can now start freshly all over
2750 
2751 		if(!cnv->is_waiting()) {
2752 			restart_speed = -1;
2753 			target_halt = halthandle_t();
2754 			return false;
2755 		}
2756 		// now we are in a step and can use the route search array
2757 
2758 		// now it we are in a step and can use the route search
2759 		route_t target_rt;
2760 		const int richtung = ribi_type(get_pos(), pos_next);	// to avoid confusion at diagonals
2761 		if(  !target_rt.find_route( welt, cnv->get_route()->at(start_block), this, speed_to_kmh(cnv->get_min_top_speed()), richtung, welt->get_settings().get_max_choose_route_steps() )  ) {
2762 			// nothing empty or not route with less than get_max_choose_route_steps() tiles
2763 			target_halt = halthandle_t();
2764 			sig->set_state(  roadsign_t::rot );
2765 			restart_speed = 0;
2766 			return false;
2767 		}
2768 		else {
2769 			// try to alloc the whole route
2770 			cnv->access_route()->remove_koord_from(start_block);
2771 			cnv->access_route()->append( &target_rt );
2772 			if(  !block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 100000, true, false )  ) {
2773 				dbg->error( "rail_vehicle_t::is_choose_signal_clear()", "could not reserved route after find_route!" );
2774 				target_halt = halthandle_t();
2775 				sig->set_state(  roadsign_t::rot );
2776 				restart_speed = 0;
2777 				return false;
2778 			}
2779 		}
2780 		// reserved route to target
2781 	}
2782 	sig->set_state(  roadsign_t::gruen );
2783 	cnv->set_next_stop_index( min( next_crossing, next_signal ) );
2784 	return true;
2785 }
2786 
2787 
2788 bool rail_vehicle_t::is_pre_signal_clear(signal_t *sig, uint16 next_block, sint32 &restart_speed)
2789 {
2790 	// parse to next signal; if needed recurse, since we allow cascading
2791 	uint16 next_signal, next_crossing;
2792 	if(  block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false )  ) {
2793 		if(  next_signal == INVALID_INDEX  ||  cnv->get_route()->at(next_signal) == cnv->get_route()->back()  ||  is_signal_clear( next_signal, restart_speed )  ) {
2794 			// ok, end of route => we can go
2795 			sig->set_state( roadsign_t::gruen );
2796 			cnv->set_next_stop_index( min( next_signal, next_crossing ) );
2797 			return true;
2798 		}
2799 		// when we reached here, the way is apparently not free => release reservation and set state to next free
2800 		sig->set_state( roadsign_t::naechste_rot );
2801 		block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, false, false );
2802 		restart_speed = 0;
2803 		return false;
2804 	}
2805 	// if we end up here, there was not even the next block free
2806 	sig->set_state( roadsign_t::rot );
2807 	restart_speed = 0;
2808 	return false;
2809 }
2810 
2811 
2812 
2813 bool rail_vehicle_t::is_priority_signal_clear(signal_t *sig, uint16 next_block, sint32 &restart_speed)
2814 {
2815 	// parse to next signal; if needed recurse, since we allow cascading
2816 	uint16 next_signal, next_crossing;
2817 
2818 	if(  block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false )  ) {
2819 		if(  next_signal == INVALID_INDEX  ||  cnv->get_route()->at(next_signal) == cnv->get_route()->back()  ||  is_signal_clear( next_signal, restart_speed )  ) {
2820 			// ok, end of route => we can go
2821 			sig->set_state( roadsign_t::gruen );
2822 			cnv->set_next_stop_index( min( next_signal, next_crossing ) );
2823 
2824 			return true;
2825 		}
2826 
2827 		// when we reached here, the way after the last signal is not free though the way before is => we can still go
2828 		if(  cnv->get_next_stop_index()<=next_signal+1  ) {
2829 			// only show third aspect on last signal of cascade
2830 			sig->set_state( roadsign_t::naechste_rot );
2831 		}
2832 		else {
2833 			sig->set_state( roadsign_t::gruen );
2834 		}
2835 		cnv->set_next_stop_index( min( next_signal, next_crossing ) );
2836 
2837 		return false;
2838 	}
2839 
2840 	// if we end up here, there was not even the next block free
2841 	sig->set_state( roadsign_t::rot );
2842 	restart_speed = 0;
2843 
2844 	return false;
2845 }
2846 
2847 
2848 bool rail_vehicle_t::is_signal_clear(uint16 next_block, sint32 &restart_speed)
2849 {
2850 	// called, when there is a signal; will call other signal routines if needed
2851 	grund_t *gr_next_block = welt->lookup(cnv->get_route()->at(next_block));
2852 	signal_t *sig = gr_next_block->find<signal_t>();
2853 	if(  sig==NULL  ) {
2854 		dbg->error( "rail_vehicle_t::is_signal_clear()", "called at %s without a signal!", cnv->get_route()->at(next_block).get_str() );
2855 		return true;
2856 	}
2857 
2858 	// action depend on the next signal
2859 	const roadsign_desc_t *sig_desc=sig->get_desc();
2860 
2861 	// simple signal: fail, if next block is not free
2862 	if(  sig_desc->is_simple_signal()  ) {
2863 
2864 		uint16 next_signal, next_crossing;
2865 		if(  block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false )  ) {
2866 			sig->set_state(  roadsign_t::gruen );
2867 			cnv->set_next_stop_index( min( next_crossing, next_signal ) );
2868 			return true;
2869 		}
2870 		// not free => wait here if directly in front
2871 		sig->set_state(  roadsign_t::rot );
2872 		restart_speed = 0;
2873 		return false;
2874 	}
2875 
2876 	if(  sig_desc->is_pre_signal()  ) {
2877 		return is_pre_signal_clear( sig, next_block, restart_speed );
2878 	}
2879 
2880 	if (  sig_desc->is_priority_signal()  ) {
2881  	return is_priority_signal_clear( sig, next_block, restart_speed );
2882  }
2883 
2884 	if(  sig_desc->is_longblock_signal()  ) {
2885 		return is_longblock_signal_clear( sig, next_block, restart_speed );
2886 	}
2887 
2888 	if(  sig_desc->is_choose_sign()  ) {
2889 		return is_choose_signal_clear( sig, next_block, restart_speed );
2890 	}
2891 
2892 	dbg->error( "rail_vehicle_t::is_signal_clear()", "felt through at signal at %s", cnv->get_route()->at(next_block).get_str() );
2893 	return false;
2894 }
2895 
2896 
2897 bool rail_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8)
2898 {
2899 	assert(leading);
2900 	uint16 next_signal, next_crossing;
2901 	if(  cnv->get_state()==convoi_t::CAN_START  ||  cnv->get_state()==convoi_t::CAN_START_ONE_MONTH  ||  cnv->get_state()==convoi_t::CAN_START_TWO_MONTHS  ) {
2902 		// reserve first block at the start until the next signal
2903 		grund_t *gr_current = welt->lookup( get_pos() );
2904 		weg_t *w = gr_current ? gr_current->get_weg(get_waytype()) : NULL;
2905 		if(  w==NULL  ||  !(w->has_signal()  ||  w->is_crossing())  ) {
2906 			// free track => reserve up to next signal
2907 			if(  !block_reserver(cnv->get_route(), max(route_index,1)-1, next_signal, next_crossing, 0, true, false )  ) {
2908 				restart_speed = 0;
2909 				return false;
2910 			}
2911 			cnv->set_next_stop_index( next_crossing<next_signal ? next_crossing : next_signal );
2912 			return true;
2913 		}
2914 		cnv->set_next_stop_index( max(route_index,1)-1 );
2915 		if(  steps<steps_next  ) {
2916 			// not yet at tile border => can drive to signal safely
2917 			return true;
2918 		}
2919 		// we start with a signal/crossing => use stuff below ...
2920 	}
2921 
2922 	assert(gr);
2923 	if(gr->get_top()>250) {
2924 		// too many objects here
2925 		return false;
2926 	}
2927 
2928 	schiene_t *w = (schiene_t *)gr->get_weg(get_waytype());
2929 	if(w==NULL) {
2930 		return false;
2931 	}
2932 
2933 	/* this should happen only before signals ...
2934 	 * but if it is already reserved, we can save lots of other checks later
2935 	 */
2936 	if(  !w->can_reserve(cnv->self)  ) {
2937 		restart_speed = 0;
2938 		return false;
2939 	}
2940 
2941 	// is there any signal/crossing to be reserved?
2942 	uint16 next_block = cnv->get_next_stop_index()-1;
2943 	if(  next_block >= cnv->get_route()->get_count()  ) {
2944 		// no obstacle in the way => drive on ...
2945 		return true;
2946 	}
2947 
2948 	// signal disappeared, train passes the tile of former signal
2949 	if(  next_block+1 < route_index  ) {
2950 		// we need to reserve the next block even if there is no signal present anymore
2951 		bool ok = block_reserver( cnv->get_route(), route_index, next_signal, next_crossing, 0, true, false );
2952 		if (ok) {
2953 			cnv->set_next_stop_index( min( next_crossing, next_signal ) );
2954 		}
2955 		return ok;
2956 		// if reservation was not possible the train will wait on the track until block is free
2957 	}
2958 
2959 	if(  next_block <= route_index+3  ) {
2960 		koord3d block_pos=cnv->get_route()->at(next_block);
2961 		grund_t *gr_next_block = welt->lookup(block_pos);
2962 		const schiene_t *sch1 = gr_next_block ? (const schiene_t *)gr_next_block->get_weg(get_waytype()) : NULL;
2963 		if(sch1==NULL) {
2964 			// way (weg) not existent (likely destroyed)
2965 			cnv->suche_neue_route();
2966 			return false;
2967 		}
2968 
2969 		// Is a crossing?
2970 		// note: crossing and signal might exist on same tile
2971 		// so first check crossing
2972 		if(  sch1->is_crossing()  ) {
2973 			if(  crossing_t* cr = gr_next_block->find<crossing_t>(2)  ) {
2974 				// ok, here is a draw/turnbridge ...
2975 				bool ok = cr->request_crossing(this);
2976 				if(!ok) {
2977 					// cannot cross => wait here
2978 					restart_speed = 0;
2979 					return cnv->get_next_stop_index()>route_index+1;
2980 				}
2981 				else if(  !sch1->has_signal()  ) {
2982 					// can reserve: find next place to do something and drive on
2983 					if(  block_pos == cnv->get_route()->back()  ) {
2984 						// is also last tile => go on ...
2985 						cnv->set_next_stop_index( INVALID_INDEX );
2986 						return true;
2987 					}
2988 					else if(  !block_reserver( cnv->get_route(), cnv->get_next_stop_index(), next_signal, next_crossing, 0, true, false )  ) {
2989 						dbg->error( "rail_vehicle_t::can_enter_tile()", "block not free but was reserved!" );
2990 						return false;
2991 					}
2992 					cnv->set_next_stop_index( next_crossing<next_signal ? next_crossing : next_signal );
2993 				}
2994 			}
2995 		}
2996 
2997 		// next check for signal
2998 		if(  sch1->has_signal()  ) {
2999 			if(  !is_signal_clear( next_block, restart_speed )  ) {
3000 				// only return false, if we are directly in front of the signal
3001 				return cnv->get_next_stop_index()>route_index;
3002 			}
3003 		}
3004 	}
3005 	return true;
3006 }
3007 
3008 
3009 /*
3010  * reserves or un-reserves all blocks and returns the handle to the next block (if there)
3011  * if count is larger than 1, (and defined) maximum MAX_CHOOSE_BLOCK_TILES tiles will be checked
3012  * (freeing or reserving a choose signal path)
3013  * if (!reserve && force_unreserve) then un-reserve everything till the end of the route
3014  * return the last checked block
3015  * @author prissi
3016  */
3017 bool rail_vehicle_t::block_reserver(const route_t *route, uint16 start_index, uint16 &next_signal_index, uint16 &next_crossing_index, int count, bool reserve, bool force_unreserve  ) const
3018 {
3019 	bool success=true;
3020 #ifdef MAX_CHOOSE_BLOCK_TILES
3021 	int max_tiles=2*MAX_CHOOSE_BLOCK_TILES; // max tiles to check for choosesignals
3022 #endif
3023 	slist_tpl<grund_t *> signs;	// switch all signals on their way too ...
3024 
3025 	if(start_index>=route->get_count()) {
3026 		cnv->set_next_reservation_index( max(route->get_count(),1)-1 );
3027 		return 0;
3028 	}
3029 
3030 	if(route->at(start_index)==get_pos()  &&  reserve) {
3031 		start_index++;
3032 	}
3033 
3034 	if(  !reserve  ) {
3035 		cnv->set_next_reservation_index( start_index );
3036 	}
3037 
3038 	// find next block segment en route
3039 	uint16 i=start_index;
3040 	next_signal_index=INVALID_INDEX;
3041 	next_crossing_index=INVALID_INDEX;
3042 	bool unreserve_now = false;
3043 	for ( ; success  &&  count>=0  &&  i<route->get_count(); i++) {
3044 
3045 		koord3d pos = route->at(i);
3046 		grund_t *gr = welt->lookup(pos);
3047 		schiene_t * sch1 = gr ? (schiene_t *)gr->get_weg(get_waytype()) : NULL;
3048 		if(sch1==NULL  &&  reserve) {
3049 			// reserve until the end of track
3050 			break;
3051 		}
3052 		// we un-reserve also nonexistent tiles! (may happen during deletion)
3053 
3054 #ifdef MAX_CHOOSE_BLOCK_TILES
3055 		max_tiles--;
3056 		if(max_tiles<0  &&   count>1) {
3057 			break;
3058 		}
3059 #endif
3060 		if(reserve) {
3061 			if(  sch1->has_signal()  &&  i<route->get_count()-1  ) {
3062 				if(count) {
3063 					signs.append(gr);
3064 				}
3065 				count --;
3066 				next_signal_index = i;
3067 			}
3068 			if(  !sch1->reserve( cnv->self, ribi_type( route->at(max(1u,i)-1u), route->at(min(route->get_count()-1u,i+1u)) ) )  ) {
3069 				success = false;
3070 			}
3071 			if(next_crossing_index==INVALID_INDEX  &&  sch1->is_crossing()) {
3072 				next_crossing_index = i;
3073 			}
3074 		}
3075 		else if(sch1) {
3076 			if(!sch1->unreserve(cnv->self)) {
3077 				if(unreserve_now) {
3078 					// reached an reserved or free track => finished
3079 					return false;
3080 				}
3081 			}
3082 			else {
3083 				// un-reserve from here (used during sale, since there might be reserved tiles not freed)
3084 				unreserve_now = !force_unreserve;
3085 			}
3086 			if(sch1->has_signal()) {
3087 				signal_t* signal = gr->find<signal_t>();
3088 				if(signal) {
3089 					signal->set_state(roadsign_t::rot);
3090 				}
3091 			}
3092 			if(sch1->is_crossing()) {
3093 				gr->find<crossing_t>()->release_crossing(this);
3094 			}
3095 		}
3096 	}
3097 
3098 	if(!reserve) {
3099 		return false;
3100 	}
3101 	// here we go only with reserve
3102 
3103 //DBG_MESSAGE("block_reserver()","signals at %i, success=%d",next_signal_index,success);
3104 
3105 	// free, in case of un-reserve or no success in reservation
3106 	if(!success) {
3107 		// free reservation
3108 		for ( int j=start_index; j<i; j++) {
3109 			schiene_t * sch1 = (schiene_t *)welt->lookup( route->at(j))->get_weg(get_waytype());
3110 			sch1->unreserve(cnv->self);
3111 		}
3112 		cnv->set_next_reservation_index( start_index );
3113 		return false;
3114 	}
3115 
3116 	// ok, switch everything green ...
3117 	FOR(slist_tpl<grund_t*>, const g, signs) {
3118 		if (signal_t* const signal = g->find<signal_t>()) {
3119 			signal->set_state(roadsign_t::gruen);
3120 		}
3121 	}
3122 	cnv->set_next_reservation_index( i );
3123 
3124 	return true;
3125 }
3126 
3127 
3128 /* beware: we must un-reserve rail blocks... */
3129 void rail_vehicle_t::leave_tile()
3130 {
3131 	vehicle_t::leave_tile();
3132 	// fix counters
3133 	if(last) {
3134 		grund_t *gr = welt->lookup( get_pos() );
3135 		if(gr) {
3136 			schiene_t *sch0 = (schiene_t *) gr->get_weg(get_waytype());
3137 			if(sch0) {
3138 				sch0->unreserve(this);
3139 				// tell next signal?
3140 				// and switch to red
3141 				if(sch0->has_signal()) {
3142 					signal_t* sig = gr->find<signal_t>();
3143 					if(sig) {
3144 						sig->set_state(roadsign_t::rot);
3145 					}
3146 				}
3147 			}
3148 		}
3149 	}
3150 }
3151 
3152 
3153 void rail_vehicle_t::enter_tile(grund_t* gr)
3154 {
3155 	vehicle_t::enter_tile(gr);
3156 
3157 	if(  schiene_t *sch0 = (schiene_t *) gr->get_weg(get_waytype())  ) {
3158 		// way statistics
3159 		const int cargo = get_total_cargo();
3160 		sch0->book(cargo, WAY_STAT_GOODS);
3161 		if(leading) {
3162 			sch0->book(1, WAY_STAT_CONVOIS);
3163 			sch0->reserve( cnv->self, get_direction() );
3164 		}
3165 	}
3166 }
3167 
3168 
3169 schedule_t * rail_vehicle_t::generate_new_schedule() const
3170 {
3171 	return desc->get_waytype()==tram_wt ? new tram_schedule_t() : new train_schedule_t();
3172 }
3173 
3174 
3175 schedule_t * monorail_vehicle_t::generate_new_schedule() const
3176 {
3177 	return new monorail_schedule_t();
3178 }
3179 
3180 
3181 schedule_t * maglev_vehicle_t::generate_new_schedule() const
3182 {
3183 	return new maglev_schedule_t();
3184 }
3185 
3186 
3187 schedule_t * narrowgauge_vehicle_t::generate_new_schedule() const
3188 {
3189 	return new narrowgauge_schedule_t();
3190 }
3191 
3192 
3193 water_vehicle_t::water_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) :
3194 	vehicle_t(pos, desc, player)
3195 {
3196 	cnv = cn;
3197 }
3198 
3199 
3200 water_vehicle_t::water_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t()
3201 {
3202 	vehicle_t::rdwr_from_convoi(file);
3203 
3204 	if(  file->is_loading()  ) {
3205 		static const vehicle_desc_t *last_desc = NULL;
3206 
3207 		if(is_first) {
3208 			last_desc = NULL;
3209 		}
3210 		// try to find a matching vehicle
3211 		if(desc==NULL) {
3212 			dbg->warning("water_vehicle_t::water_vehicle_t()", "try to find a fitting vehicle for %s.", !fracht.empty() ? fracht.front().get_name() : "passengers");
3213 			desc = vehicle_builder_t::get_best_matching(water_wt, 0, fracht.empty() ? 0 : 30, 100, 40, !fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers, true, last_desc, is_last );
3214 			if(desc) {
3215 				calc_image();
3216 			}
3217 		}
3218 		// update last desc
3219 		if(  desc  ) {
3220 			last_desc = desc;
3221 		}
3222 	}
3223 }
3224 
3225 
3226 void water_vehicle_t::enter_tile(grund_t* gr)
3227 {
3228 	vehicle_t::enter_tile(gr);
3229 
3230 	if(  weg_t *ch = gr->get_weg(water_wt)  ) {
3231 		// we are in a channel, so book statistics
3232 		ch->book(get_total_cargo(), WAY_STAT_GOODS);
3233 		if (leading)  {
3234 			ch->book(1, WAY_STAT_CONVOIS);
3235 		}
3236 	}
3237 }
3238 
3239 
3240 bool water_vehicle_t::check_next_tile(const grund_t *bd) const
3241 {
3242 	if(  bd->is_water()  ) {
3243 		return true;
3244 	}
3245 	// channel can have more stuff to check
3246 	const weg_t *w = bd->get_weg(water_wt);
3247 #if ENABLE_WATERWAY_SIGNS
3248 	if(  w  &&  w->has_sign()  ) {
3249 		const roadsign_t* rs = bd->find<roadsign_t>();
3250 		if(  rs->get_desc()->get_wtyp()==get_waytype()  ) {
3251 			if(  cnv !=NULL  &&  rs->get_desc()->get_min_speed() > 0  &&  rs->get_desc()->get_min_speed() > cnv->get_min_top_speed()  ) {
3252 				// below speed limit
3253 				return false;
3254 			}
3255 			if(  rs->get_desc()->is_private_way()  &&  (rs->get_player_mask() & (1<<get_player_nr()) ) == 0  ) {
3256 				// private road
3257 				return false;
3258 			}
3259 		}
3260 	}
3261 #endif
3262 	return (w  &&  w->get_max_speed()>0);
3263 }
3264 
3265 
3266 /* Since slopes are handled different for ships
3267  * @author prissi
3268  */
3269 void water_vehicle_t::calc_friction(const grund_t *gr)
3270 {
3271 	// or a hill?
3272 	if(gr->get_weg_hang()) {
3273 		// hill up or down => in lock => decelerate
3274 		current_friction = 16;
3275 	}
3276 	else {
3277 		// flat track
3278 		current_friction = 1;
3279 	}
3280 
3281 	if(previous_direction != direction) {
3282 		// curve: higher friction
3283 		current_friction *= 2;
3284 	}
3285 }
3286 
3287 
3288 bool water_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8)
3289 {
3290 	restart_speed = -1;
3291 
3292 	if(leading) {
3293 
3294 		assert(gr);
3295 		if(  gr->get_top()>251  ) {
3296 			// too many ships already here ..
3297 			return false;
3298 		}
3299 		weg_t *w = gr->get_weg(water_wt);
3300 		if(w  &&  w->is_crossing()) {
3301 			// ok, here is a draw/turn-bridge ...
3302 			crossing_t* cr = gr->find<crossing_t>();
3303 			if(!cr->request_crossing(this)) {
3304 				restart_speed = 0;
3305 				return false;
3306 			}
3307 		}
3308 	}
3309 	return true;
3310 }
3311 
3312 
3313 schedule_t * water_vehicle_t::generate_new_schedule() const
3314 {
3315   return new ship_schedule_t();
3316 }
3317 
3318 
3319 /**** from here on planes ***/
3320 
3321 
3322 // for flying things, everywhere is good ...
3323 // another function only called during route searching
3324 ribi_t::ribi air_vehicle_t::get_ribi(const grund_t *gr) const
3325 {
3326 	switch(state) {
3327 		case taxiing:
3328 		case looking_for_parking:
3329 			return gr->get_weg_ribi(air_wt);
3330 
3331 		case taxiing_to_halt:
3332 		{
3333 			// we must invert all one way signs here, since we start from the target position here!
3334 			weg_t *w = gr->get_weg(air_wt);
3335 			if(w) {
3336 				ribi_t::ribi r = w->get_ribi_unmasked();
3337 				if(  ribi_t::ribi mask = w->get_ribi_maske()  ) {
3338 					r &= mask;
3339 				}
3340 				return r;
3341 			}
3342 			return ribi_t::none;
3343 		}
3344 
3345 		case landing:
3346 		case departing:
3347 		{
3348 			ribi_t::ribi dir = gr->get_weg_ribi(air_wt);
3349 			if(dir==0) {
3350 				return ribi_t::all;
3351 			}
3352 			return dir;
3353 		}
3354 
3355 		case flying:
3356 		case circling:
3357 			return ribi_t::all;
3358 	}
3359 	return ribi_t::none;
3360 }
3361 
3362 
3363 // how expensive to go here (for way search)
3364 // author prissi
3365 int air_vehicle_t::get_cost(const grund_t *, const weg_t *w, const sint32, ribi_t::ribi) const
3366 {
3367 	// first favor faster ways
3368 	int costs = 0;
3369 
3370 	if(state==flying) {
3371 		if(w==NULL) {
3372 			costs += 1;
3373 		}
3374 		else {
3375 			if(w->get_desc()->get_styp()==type_flat) {
3376 				costs += 25;
3377 			}
3378 		}
3379 	}
3380 	else {
3381 		// only, if not flying ...
3382 		const runway_t *rw =(const runway_t *)w;
3383 		// if we are on a runway, then take into account how many convois are already going there
3384 		if(  rw->get_desc()->get_styp()==1  ) {
3385 			costs += rw->get_reservation_count()*9;	// encourage detours even during take off
3386 		}
3387 		if(w->get_desc()->get_styp()==type_flat) {
3388 			costs += 3;
3389 		}
3390 		else {
3391 			costs += 2;
3392 		}
3393 	}
3394 
3395 	return costs;
3396 }
3397 
3398 
3399 // whether the ground is drivable or not depends on the current state of the airplane
3400 bool air_vehicle_t::check_next_tile(const grund_t *bd) const
3401 {
3402 	switch (state) {
3403 		case taxiing:
3404 		case taxiing_to_halt:
3405 		case looking_for_parking:
3406 //DBG_MESSAGE("check_next_tile()","at %i,%i",bd->get_pos().x,bd->get_pos().y);
3407 			return (bd->hat_weg(air_wt)  &&  bd->get_weg(air_wt)->get_max_speed()>0);
3408 
3409 		case landing:
3410 		case departing:
3411 		case flying:
3412 		case circling:
3413 		{
3414 //DBG_MESSAGE("air_vehicle_t::check_next_tile()","(cnv %i) in idx %i",cnv->self.get_id(),route_index );
3415 			// prissi: here a height check could avoid too high mountains
3416 			return true;
3417 		}
3418 	}
3419 	return false;
3420 }
3421 
3422 
3423 // this routine is called by find_route, to determined if we reached a destination
3424 bool air_vehicle_t::is_target(const grund_t *gr,const grund_t *) const
3425 {
3426 	if(state!=looking_for_parking  ||  !target_halt.is_bound()) {
3427 		// search for the end of the runway
3428 		const weg_t *w=gr->get_weg(air_wt);
3429 		if(w  &&  w->get_desc()->get_styp()==type_runway) {
3430 			// ok here is a runway
3431 			ribi_t::ribi ribi= w->get_ribi_unmasked();
3432 			if(ribi_t::is_single(ribi)  &&  (ribi&approach_dir)!=0) {
3433 				// pointing in our direction
3434 				// here we should check for length, but we assume everything is ok
3435 				return true;
3436 			}
3437 		}
3438 	}
3439 	else {
3440 		// otherwise we just check, if we reached a free stop position of this halt
3441 		if(gr->get_halt()==target_halt  &&  target_halt->is_reservable(gr,cnv->self)) {
3442 			return true;
3443 		}
3444 	}
3445 	return false;
3446 }
3447 
3448 
3449 /* finds a free stop, calculates a route and reserve the position
3450  * else return false
3451  */
3452 bool air_vehicle_t::find_route_to_stop_position()
3453 {
3454 	if(target_halt.is_bound()) {
3455 //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","bound! (cnv %i)",cnv->self.get_id());
3456 		return true;	// already searched with success
3457 	}
3458 
3459 	// check for skipping circle
3460 	route_t *rt=cnv->access_route();
3461 
3462 //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","can approach? (cnv %i)",cnv->self.get_id());
3463 
3464 	grund_t const* const last = welt->lookup(rt->back());
3465 	target_halt = last ? last->get_halt() : halthandle_t();
3466 	if(!target_halt.is_bound()) {
3467 		return true;	// no halt to search
3468 	}
3469 
3470 	// then: check if the search point is still on a runway (otherwise just proceed)
3471 	grund_t const* const target = welt->lookup(rt->at(search_for_stop));
3472 	if(target==NULL  ||  !target->hat_weg(air_wt)) {
3473 		target_halt = halthandle_t();
3474 		DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","no runway found at (%s)",rt->at(search_for_stop).get_str());
3475 		return true;	// no runway any more ...
3476 	}
3477 
3478 	// is our target occupied?
3479 //	DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","state %i",state);
3480 	if(!target_halt->find_free_position(air_wt,cnv->self,obj_t::air_vehicle)  ) {
3481 		target_halt = halthandle_t();
3482 		DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","no free position found!");
3483 		return false;
3484 	}
3485 	else {
3486 		// calculate route to free position:
3487 
3488 		// if we fail, we will wait in a step, much more simulation friendly
3489 		// and the route finder is not re-entrant!
3490 		if(!cnv->is_waiting()) {
3491 			target_halt = halthandle_t();
3492 			return false;
3493 		}
3494 
3495 		// now search a route
3496 //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","some free: find route from index %i",suchen);
3497 		route_t target_rt;
3498 		flight_state prev_state = state;
3499 		state = looking_for_parking;
3500 		if(!target_rt.find_route( welt, rt->at(search_for_stop), this, 500, ribi_t::all, welt->get_settings().get_max_choose_route_steps() )) {
3501 DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","found no route to free one");
3502 			// circle slowly another round ...
3503 			target_halt = halthandle_t();
3504 			state = prev_state;
3505 			return false;
3506 		}
3507 		state = prev_state;
3508 
3509 		// now reserve our choice ...
3510 		target_halt->reserve_position(welt->lookup(target_rt.back()), cnv->self);
3511 		//DBG_MESSAGE("aircraft_t::find_route_to_stop_position()", "found free stop near %i,%i,%i", target_rt.back().x, target_rt.back().y, target_rt.back().z);
3512 		rt->remove_koord_from(search_for_stop);
3513 		rt->append( &target_rt );
3514 		return true;
3515 	}
3516 }
3517 
3518 
3519 // main routine: searches the new route in up to three steps
3520 // must also take care of stops under traveling and the like
3521 bool air_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route)
3522 {
3523 //DBG_MESSAGE("aircraft_t::calc_route()","search route from %i,%i,%i to %i,%i,%i",start.x,start.y,start.z,ziel.x,ziel.y,ziel.z);
3524 
3525 	if(leading  &&  cnv) {
3526 		// free target reservation
3527 		if(  target_halt.is_bound() ) {
3528 			if (grund_t* const target = welt->lookup(cnv->get_route()->back())) {
3529 				target_halt->unreserve_position(target,cnv->self);
3530 			}
3531 		}
3532 		// free runway reservation
3533 		block_reserver( route_index, route->get_count(), false );
3534 	}
3535 	target_halt = halthandle_t();	// no block reserved
3536 
3537 	const weg_t *w=welt->lookup(start)->get_weg(air_wt);
3538 	bool start_in_the_air = (w==NULL);
3539 	bool end_in_air=false;
3540 
3541 	search_for_stop = takeoff = touchdown = 0x7ffffffful;
3542 	if(!start_in_the_air) {
3543 
3544 		// see, if we find a direct route: We are finished
3545 		state = taxiing;
3546 		if(route->calc_route( welt, start, ziel, this, max_speed, 0 )) {
3547 			// ok, we can taxi to our location
3548 			return true;
3549 		}
3550 	}
3551 
3552 	if(start_in_the_air  ||  (w->get_desc()->get_styp()==type_runway  &&  ribi_t::is_single(w->get_ribi())) ) {
3553 		// we start here, if we are in the air or at the end of a runway
3554 		search_start = start;
3555 		start_in_the_air = true;
3556 		route->clear();
3557 //DBG_MESSAGE("aircraft_t::calc_route()","start in air at %i,%i,%i",search_start.x,search_start.y,search_start.z);
3558 	}
3559 	else {
3560 		// not found and we are not on the takeoff tile (where the route search will fail too) => we try to calculate a complete route, starting with the way to the runway
3561 
3562 		// second: find start runway end
3563 		state = taxiing;
3564 #ifdef USE_DIFFERENT_WIND
3565 		approach_dir = get_approach_ribi( ziel, start );	// reverse
3566 //DBG_MESSAGE("aircraft_t::calc_route()","search runway start near %i,%i,%i with corner in %x",start.x,start.y,start.z, approach_dir);
3567 #else
3568 		approach_dir = ribi_t::northeast;	// reverse
3569 		DBG_MESSAGE("aircraft_t::calc_route()","search runway start near (%s)",start.get_str());
3570 #endif
3571 		if(!route->find_route( welt, start, this, max_speed, ribi_t::all, 100 )) {
3572 			DBG_MESSAGE("aircraft_t::calc_route()","failed");
3573 			return false;
3574 		}
3575 		// save the route
3576 		search_start = route->back();
3577 		//DBG_MESSAGE("aircraft_t::calc_route()","start at ground (%s)",search_start.get_str());
3578 	}
3579 
3580 	// second: find target runway end
3581 
3582 	state = taxiing_to_halt;	// only used for search
3583 
3584 #ifdef USE_DIFFERENT_WIND
3585 	approach_dir = get_approach_ribi( start, ziel );	// reverse
3586 	//DBG_MESSAGE("aircraft_t::calc_route()","search runway target near %i,%i,%i in corners %x",ziel.x,ziel.y,ziel.z,approach_dir);
3587 #else
3588 	approach_dir = ribi_t::southwest;	// reverse
3589 	//DBG_MESSAGE("aircraft_t::calc_route()","search runway target near %i,%i,%i in corners %x",ziel.x,ziel.y,ziel.z);
3590 #endif
3591 	route_t end_route;
3592 
3593 	if(!end_route.find_route( welt, ziel, this, max_speed, ribi_t::all, welt->get_settings().get_max_choose_route_steps() )) {
3594 		// well, probably this is a waypoint
3595 		if(  grund_t *target = welt->lookup(ziel)  ) {
3596 			if(  !target->get_weg(air_wt)  ) {
3597 				end_in_air = true;
3598 				search_end = ziel;
3599 			}
3600 			else {
3601 				// we have a taxiway/illegal runway here we cannot reach
3602 				return false;	// no route!
3603 			}
3604 		}
3605 		else {
3606 			// illegal coordinates?
3607 			return false;
3608 		}
3609 	}
3610 	else {
3611 		// save target route
3612 		search_end = end_route.back();
3613 	}
3614 	//DBG_MESSAGE("aircraft_t::calc_route()","end at ground (%s)",search_end.get_str());
3615 
3616 	// create target route
3617 	if(!start_in_the_air) {
3618 		takeoff = route->get_count()-1;
3619 		koord start_dir(welt->lookup(search_start)->get_weg_ribi(air_wt));
3620 		if(start_dir!=koord(0,0)) {
3621 			// add the start
3622 			ribi_t::ribi start_ribi = ribi_t::backward(ribi_type(start_dir));
3623 			const grund_t *gr=NULL;
3624 			// add the start
3625 			int endi = 1;
3626 			int over = 3;
3627 			// now add all runway + 3 ...
3628 			do {
3629 				if(!welt->is_within_limits(search_start.get_2d()+(start_dir*endi)) ) {
3630 					break;
3631 				}
3632 				gr = welt->lookup_kartenboden(search_start.get_2d()+(start_dir*endi));
3633 				if(over<3  ||  (gr->get_weg_ribi(air_wt)&start_ribi)==0) {
3634 					over --;
3635 				}
3636 				endi ++;
3637 				route->append(gr->get_pos());
3638 			} while(  over>0  );
3639 			// out of map
3640 			if(gr==NULL) {
3641 				dbg->error("aircraft_t::calc_route()","out of map!");
3642 				return false;
3643 			}
3644 			// need some extra step to avoid 180 deg turns
3645 			if( start_dir.x!=0  &&  sgn(start_dir.x)!=sgn(search_end.x-search_start.x)  ) {
3646 				route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord(0,(search_end.y>search_start.y) ? 1 : -1 ) )->get_pos() );
3647 				route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord(0,(search_end.y>search_start.y) ? 2 : -2 ) )->get_pos() );
3648 			}
3649 			else if( start_dir.y!=0  &&  sgn(start_dir.y)!=sgn(search_end.y-search_start.y)  ) {
3650 				route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord((search_end.x>search_start.x) ? 1 : -1 ,0) )->get_pos() );
3651 				route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord((search_end.x>search_start.x) ? 2 : -2 ,0) )->get_pos() );
3652 			}
3653 		}
3654 		else {
3655 			// init with startpos
3656 			dbg->error("aircraft_t::calc_route()","Invalid route calculation: start is on a single direction field ...");
3657 		}
3658 		state = taxiing;
3659 		flying_height = 0;
3660 		target_height = (sint16)get_pos().z*TILE_HEIGHT_STEP;
3661 	}
3662 	else {
3663 		// init with current pos (in air ... )
3664 		route->clear();
3665 		route->append( start );
3666 		state = flying;
3667 		if(flying_height==0) {
3668 			flying_height = 3*TILE_HEIGHT_STEP;
3669 		}
3670 		takeoff = 0;
3671 		target_height = ((sint16)get_pos().z+3)*TILE_HEIGHT_STEP;
3672 	}
3673 
3674 //DBG_MESSAGE("aircraft_t::calc_route()","take off ok");
3675 
3676 	koord3d landing_start=search_end;
3677 	if(!end_in_air) {
3678 		// now find way to start of landing pos
3679 		ribi_t::ribi end_ribi = welt->lookup(search_end)->get_weg_ribi(air_wt);
3680 		koord end_dir(end_ribi);
3681 		end_ribi = ribi_t::backward(end_ribi);
3682 		if(end_dir!=koord(0,0)) {
3683 			// add the start
3684 			const grund_t *gr;
3685 			int endi = 1;
3686 			int over = 3;
3687 			// now add all runway + 3 ...
3688 			do {
3689 				if(!welt->is_within_limits(search_end.get_2d()+(end_dir*endi)) ) {
3690 					break;
3691 				}
3692 				gr = welt->lookup_kartenboden(search_end.get_2d()+(end_dir*endi));
3693 				if(over<3  ||  (gr->get_weg_ribi(air_wt)&end_ribi)==0) {
3694 					over --;
3695 				}
3696 				endi ++;
3697 				landing_start = gr->get_pos();
3698 			} while(  over>0  );
3699 		}
3700 	}
3701 	else {
3702 		search_for_stop = touchdown = 0x7FFFFFFFul;
3703 	}
3704 
3705 	// just some straight routes ...
3706 	if(!route->append_straight_route(welt,landing_start)) {
3707 		// should never fail ...
3708 		dbg->error( "aircraft_t::calc_route()", "No straight route found!" );
3709 		return false;
3710 	}
3711 
3712 	if(!end_in_air) {
3713 
3714 		// find starting direction
3715 		int offset = 0;
3716 		switch(welt->lookup(search_end)->get_weg_ribi(air_wt)) {
3717 			case ribi_t::north: offset = 0; break;
3718 			case ribi_t::west: offset = 4; break;
3719 			case ribi_t::south: offset = 8; break;
3720 			case ribi_t::east: offset = 12; break;
3721 		}
3722 
3723 		// now make a curve
3724 		koord circlepos=landing_start.get_2d();
3725 		static const koord circle_koord[16]={ koord(0,1), koord(0,1), koord(1,0), koord(0,1), koord(1,0), koord(1,0), koord(0,-1), koord(1,0), koord(0,-1), koord(0,-1), koord(-1,0), koord(0,-1), koord(-1,0), koord(-1,0), koord(0,1), koord(-1,0) };
3726 
3727 		// circle to the left
3728 		for(  int  i=0;  i<16;  i++  ) {
3729 			circlepos += circle_koord[(offset+i+16)%16];
3730 			if(welt->is_within_limits(circlepos)) {
3731 				route->append( welt->lookup_kartenboden(circlepos)->get_pos() );
3732 			}
3733 			else {
3734 				// could only happen during loading old savegames;
3735 				// in new versions it should not possible to build a runway here
3736 				route->clear();
3737 				dbg->error("aircraft_t::calc_route()","airport too close to the edge! (Cannot go to %i,%i!)",circlepos.x,circlepos.y);
3738 				return false;
3739 			}
3740 		}
3741 
3742 		touchdown = route->get_count()+2;
3743 		route->append_straight_route(welt,search_end);
3744 
3745 		// now the route reach point (+1, since it will check before entering the tile ...)
3746 		search_for_stop = route->get_count()-1;
3747 
3748 		// now we just append the rest
3749 		for( int i=end_route.get_count()-2;  i>=0;  i--  ) {
3750 			route->append(end_route.at(i));
3751 		}
3752 	}
3753 
3754 //DBG_MESSAGE("aircraft_t::calc_route()","departing=%i  touchdown=%i   suchen=%i   total=%i  state=%i",takeoff, touchdown, suchen, route->get_count()-1, state );
3755 	return true;
3756 }
3757 
3758 
3759 /* reserves runways (reserve true) or removes the reservation
3760  * finishes when reaching end tile or leaving the ground (end of runway)
3761  * @return true if the reservation is successful
3762  */
3763 bool air_vehicle_t::block_reserver( uint32 start, uint32 end, bool reserve ) const
3764 {
3765 	bool start_now = false;
3766 	bool success = true;
3767 
3768 	const route_t *route = cnv->get_route();
3769 	if(route->empty()) {
3770 		return false;
3771 	}
3772 
3773 	for(  uint32 i=start;  success  &&  i<end  &&  i<route->get_count();  i++) {
3774 
3775 		grund_t *gr = welt->lookup(route->at(i));
3776 		runway_t *sch1 = gr ? (runway_t *)gr->get_weg(air_wt) : NULL;
3777 		if(  !sch1  ) {
3778 			if(reserve) {
3779 				if(!start_now) {
3780 					// touched down here
3781 					start = i;
3782 				}
3783 				else {
3784 					// most likely left the ground here ...
3785 					end = i;
3786 					break;
3787 				}
3788 			}
3789 		}
3790 		else {
3791 			// we un-reserve also nonexistent tiles! (may happen during deletion)
3792 			if(reserve) {
3793 				start_now = true;
3794 				sch1->add_convoi_reservation(cnv->self);
3795 				if(  !sch1->reserve(cnv->self,ribi_t::none)  ) {
3796 					// unsuccessful => must un-reserve all
3797 					success = false;
3798 					end = i;
3799 					break;
3800 				}
3801 				// end of runway?
3802 				if(  i > start  &&  (ribi_t::is_single( sch1->get_ribi_unmasked() )  ||  sch1->get_desc()->get_styp() != type_runway)   ) {
3803 					end = i;
3804 					break;
3805 				}
3806 			}
3807 			else {
3808 				// we always unreserve everything
3809 				sch1->unreserve(cnv->self);
3810 			}
3811 		}
3812 	}
3813 
3814 	// un-reserve if not successful
3815 	if(  !success  &&  reserve  ) {
3816 		for(  uint32 i=start;  i<end;  i++  ) {
3817 			grund_t *gr = welt->lookup(route->at(i));
3818 			if (gr) {
3819 				runway_t* sch1 = (runway_t *)gr->get_weg(air_wt);
3820 				if (sch1) {
3821 					sch1->unreserve(cnv->self);
3822 				}
3823 			}
3824 		}
3825 		return false;
3826 	}
3827 
3828 	if(  reserve  &&  end<touchdown  ) {
3829 		// reserve runway for landing for load balancing
3830 		for(  uint32 i=touchdown;  i<route->get_count();  i++  ) {
3831 			if(  grund_t *gr = welt->lookup(route->at(i))  ) {
3832 				if(  runway_t* sch1 = (runway_t *)gr->get_weg(air_wt)  ) {
3833 					if(  sch1->get_desc()->get_styp()!=type_runway  ) {
3834 						break;
3835 					}
3836 					sch1->add_convoi_reservation( cnv->self );
3837 				}
3838 			}
3839 		}
3840 	}
3841 
3842 	return success;
3843 }
3844 
3845 
3846 // handles all the decisions on the ground an in the air
3847 bool air_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8)
3848 {
3849 	restart_speed = -1;
3850 
3851 	assert(gr);
3852 	if(gr->get_top()>250) {
3853 		// too many objects here
3854 		return false;
3855 	}
3856 
3857 	if(  route_index < takeoff  &&  route_index > 1  &&  takeoff<cnv->get_route()->get_count()-1  ) {
3858 		// check, if tile occupied by a plane on ground
3859 		if(  route_index > 1  ) {
3860 			for(  uint8 i = 1;  i<gr->get_top();  i++  ) {
3861 				obj_t *obj = gr->obj_bei(i);
3862 				if(  obj->get_typ()==obj_t::air_vehicle  &&  ((air_vehicle_t *)obj)->is_on_ground()  ) {
3863 					restart_speed = 0;
3864 					return false;
3865 				}
3866 			}
3867 		}
3868 		// need to reserve runway?
3869 		runway_t *rw = (runway_t *)gr->get_weg(air_wt);
3870 		if(rw==NULL) {
3871 			cnv->suche_neue_route();
3872 			return false;
3873 		}
3874 		// next tile a runway => then reserve
3875 		if(rw->get_desc()->get_styp()==type_runway) {
3876 			// try to reserve the runway
3877 			if(!block_reserver(takeoff,takeoff+100,true)) {
3878 				// runway already blocked ...
3879 				restart_speed = 0;
3880 				return false;
3881 			}
3882 		}
3883 		return true;
3884 	}
3885 
3886 	if(  state == taxiing  ) {
3887 		// enforce on ground for taxiing
3888 		flying_height = 0;
3889 		// we may need to unreserve the runway after leaving it
3890 		if(  route_index >= touchdown  ) {
3891 			runway_t *rw = (runway_t *)gr->get_weg(air_wt);
3892 			// next tile a not runway => then unreserve
3893 			if(  rw == NULL  ||  rw->get_desc()->get_styp() != type_runway  ||  gr->is_halt()  ) {
3894 				block_reserver( touchdown, search_for_stop+1, false );
3895 			}
3896 		}
3897 	}
3898 
3899 	if(  route_index == takeoff  &&  state == taxiing  ) {
3900 		// try to reserve the runway if not already done
3901 		if(route_index==2  &&  !block_reserver(takeoff,takeoff+100,true)) {
3902 			// runway blocked, wait at start of runway
3903 			restart_speed = 0;
3904 			return false;
3905 		}
3906 		// stop shortly at the end of the runway
3907 		state = departing;
3908 		restart_speed = 0;
3909 		return false;
3910 	}
3911 
3912 //DBG_MESSAGE("aircraft_t::ist_weg_frei()","index %i<>%i",route_index,touchdown);
3913 
3914 	// check for another circle ...
3915 	if(  route_index==(touchdown-3)  ) {
3916 		if(  !block_reserver( touchdown, search_for_stop+1, true )  ) {
3917 			route_index -= 16;
3918 			return true;
3919 		}
3920 		state = landing;
3921 		return true;
3922 	}
3923 
3924 	if(  route_index==touchdown-16-3  &&  state!=circling  ) {
3925 		// just check, if the end of runway is free; we will wait there
3926 		if(  block_reserver( touchdown, search_for_stop+1, true )  ) {
3927 			route_index += 16;
3928 			// can land => set landing height
3929 			state = landing;
3930 		}
3931 		else {
3932 			// circle slowly next round
3933 			state = circling;
3934 			cnv->must_recalc_data();
3935 			if(  leading  ) {
3936 				cnv->must_recalc_data_front();
3937 			}
3938 		}
3939 	}
3940 
3941 	if(route_index==search_for_stop  &&  state==landing  &&  !target_halt.is_bound()) {
3942 
3943 		// if we fail, we will wait in a step, much more simulation friendly
3944 		// and the route finder is not re-entrant!
3945 		if(!cnv->is_waiting()) {
3946 			return false;
3947 		}
3948 
3949 		// nothing free here?
3950 		if(find_route_to_stop_position()) {
3951 			// stop reservation successful
3952 			state = taxiing;
3953 			return true;
3954 		}
3955 		restart_speed = 0;
3956 		return false;
3957 	}
3958 
3959 	if(state==looking_for_parking) {
3960 		state = taxiing;
3961 	}
3962 
3963 	if(state == taxiing  &&  gr->is_halt()  &&  gr->find<air_vehicle_t>()) {
3964 		// the next step is a parking position. We do not enter, if occupied!
3965 		restart_speed = 0;
3966 		return false;
3967 	}
3968 
3969 	return true;
3970 }
3971 
3972 
3973 // this must also change the internal modes for the calculation
3974 void air_vehicle_t::enter_tile(grund_t* gr)
3975 {
3976 	vehicle_t::enter_tile(gr);
3977 
3978 	if(  this->is_on_ground()  ) {
3979 		runway_t *w=(runway_t *)gr->get_weg(air_wt);
3980 		if(w) {
3981 			const int cargo = get_total_cargo();
3982 			w->book(cargo, WAY_STAT_GOODS);
3983 			if (leading) {
3984 				w->book(1, WAY_STAT_CONVOIS);
3985 			}
3986 		}
3987 	}
3988 }
3989 
3990 
3991 air_vehicle_t::air_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t()
3992 {
3993 	rdwr_from_convoi(file);
3994 
3995 	if(  file->is_loading()  ) {
3996 		static const vehicle_desc_t *last_desc = NULL;
3997 
3998 		if(is_first) {
3999 			last_desc = NULL;
4000 		}
4001 		// try to find a matching vehicle
4002 		if(desc==NULL) {
4003 			dbg->warning("aircraft_t::aircraft_t()", "try to find a fitting vehicle for %s.", !fracht.empty() ? fracht.front().get_name() : "passengers");
4004 			desc = vehicle_builder_t::get_best_matching(air_wt, 0, 101, 1000, 800, !fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers, true, last_desc, is_last );
4005 			if(desc) {
4006 				calc_image();
4007 			}
4008 		}
4009 		// update last desc
4010 		if(  desc  ) {
4011 			last_desc = desc;
4012 		}
4013 	}
4014 }
4015 
4016 
4017 air_vehicle_t::air_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) :
4018 	vehicle_t(pos, desc, player)
4019 {
4020 	cnv = cn;
4021 	state = taxiing;
4022 	flying_height = 0;
4023 	target_height = pos.z;
4024 }
4025 
4026 
4027 air_vehicle_t::~air_vehicle_t()
4028 {
4029 	// mark aircraft (after_image) dirty, since we have no "real" image
4030 	const int raster_width = get_current_tile_raster_width();
4031 	sint16 yoff = tile_raster_scale_y(-flying_height-get_hoff()-2, raster_width);
4032 
4033 	mark_image_dirty( image, yoff);
4034 	mark_image_dirty( image, 0 );
4035 }
4036 
4037 
4038 void air_vehicle_t::set_convoi(convoi_t *c)
4039 {
4040 	DBG_MESSAGE("aircraft_t::set_convoi()","%p",c);
4041 	if(leading  &&  (unsigned long)cnv > 1) {
4042 		// free stop reservation
4043 		route_t const& r = *cnv->get_route();
4044 		if(target_halt.is_bound()) {
4045 			target_halt->unreserve_position(welt->lookup(r.back()), cnv->self);
4046 			target_halt = halthandle_t();
4047 		}
4048 		if (!r.empty()) {
4049 			// free runway reservation
4050 			if(route_index>=takeoff  &&  route_index<touchdown-4  &&  state!=flying) {
4051 				block_reserver( takeoff, takeoff+100, false );
4052 			}
4053 			else if(route_index>=touchdown-1  &&  state!=taxiing) {
4054 				block_reserver( touchdown, search_for_stop+1, false );
4055 			}
4056 		}
4057 	}
4058 	// maybe need to restore state?
4059 	if(c!=NULL) {
4060 		bool target=(bool)cnv;
4061 		vehicle_t::set_convoi(c);
4062 		if(leading) {
4063 			if(target) {
4064 				// reinitialize the target halt
4065 				grund_t* const target=welt->lookup(cnv->get_route()->back());
4066 				target_halt = target->get_halt();
4067 				if(target_halt.is_bound()) {
4068 					target_halt->reserve_position(target,cnv->self);
4069 				}
4070 			}
4071 			// restore reservation
4072 			if(  grund_t *gr = welt->lookup(get_pos())  ) {
4073 				if(  weg_t *weg = gr->get_weg(air_wt)  ) {
4074 					if(  weg->get_desc()->get_styp()==type_runway  ) {
4075 						// but only if we are on a runway ...
4076 						if(  route_index>=takeoff  &&  route_index<touchdown-21  &&  state!=flying  ) {
4077 							block_reserver( takeoff, takeoff+100, true );
4078 						}
4079 						else if(  route_index>=touchdown-1  &&  state!=taxiing  ) {
4080 							block_reserver( touchdown, search_for_stop+1, true );
4081 						}
4082 					}
4083 				}
4084 			}
4085 		}
4086 	}
4087 	else {
4088 		vehicle_t::set_convoi(NULL);
4089 	}
4090 }
4091 
4092 
4093 schedule_t *air_vehicle_t::generate_new_schedule() const
4094 {
4095 	return new airplane_schedule_t();
4096 }
4097 
4098 
4099 void air_vehicle_t::rdwr_from_convoi(loadsave_t *file)
4100 {
4101 	xml_tag_t t( file, "aircraft_t" );
4102 
4103 	// initialize as vehicle_t::rdwr_from_convoi calls get_image()
4104 	if (file->is_loading()) {
4105 		state = taxiing;
4106 		flying_height = 0;
4107 	}
4108 	vehicle_t::rdwr_from_convoi(file);
4109 
4110 	file->rdwr_enum(state);
4111 	file->rdwr_short(flying_height);
4112 	flying_height &= ~(TILE_HEIGHT_STEP-1);
4113 	file->rdwr_short(target_height);
4114 	file->rdwr_long(search_for_stop);
4115 	file->rdwr_long(touchdown);
4116 	file->rdwr_long(takeoff);
4117 }
4118 
4119 
4120 #ifdef USE_DIFFERENT_WIND
4121 // well lots of code to make sure, we have at least two different directions for the runway search
4122 uint8 air_vehicle_t::get_approach_ribi( koord3d start, koord3d ziel )
4123 {
4124 	uint8 dir = ribi_type(start, ziel);	// reverse
4125 	// make sure, there are at last two directions to choose, or you might en up with not route
4126 	if(ribi_t::is_single(dir)) {
4127 		dir |= (dir<<1);
4128 		if(dir>16) {
4129 			dir += 1;
4130 		}
4131 	}
4132 	return dir&0x0F;
4133 }
4134 #endif
4135 
4136 
4137 void air_vehicle_t::hop(grund_t* gr)
4138 {
4139 	sint32 new_speed_limit = SPEED_UNLIMITED;
4140 	sint32 new_friction = 0;
4141 
4142 	// take care of in-flight height ...
4143 	const sint16 h_cur = (sint16)get_pos().z*TILE_HEIGHT_STEP;
4144 	const sint16 h_next = (sint16)pos_next.z*TILE_HEIGHT_STEP;
4145 
4146 	switch(state) {
4147 		case departing: {
4148 			flying_height = 0;
4149 			target_height = h_cur;
4150 			new_friction = max( 1, 28/(1+(route_index-takeoff)*2) ); // 9 5 4 3 2 2 1 1...
4151 
4152 			// take off, when a) end of runway or b) last tile of runway or c) fast enough
4153 			weg_t *weg=welt->lookup(get_pos())->get_weg(air_wt);
4154 			if(  (weg==NULL  ||  // end of runway (broken runway)
4155 				 weg->get_desc()->get_styp()!=type_runway  ||  // end of runway (grass now ... )
4156 				 (route_index>takeoff+1  &&  ribi_t::is_single(weg->get_ribi_unmasked())) )  ||  // single ribi at end of runway
4157 				 cnv->get_akt_speed()>kmh_to_speed(desc->get_topspeed())/3 // fast enough
4158 			) {
4159 				state = flying;
4160 				new_friction = 1;
4161 				block_reserver( takeoff, touchdown-1, false );
4162 				flying_height = h_cur - h_next;
4163 				target_height = h_cur+TILE_HEIGHT_STEP*3;
4164 			}
4165 			break;
4166 		}
4167 		case circling: {
4168 			new_speed_limit = kmh_to_speed(desc->get_topspeed())/3;
4169 			new_friction = 4;
4170 			// do not change height any more while circling
4171 			flying_height += h_cur;
4172 			flying_height -= h_next;
4173 			break;
4174 		}
4175 		case flying: {
4176 			// since we are at a tile border, round up to the nearest value
4177 			flying_height += h_cur;
4178 			if(  flying_height < target_height  ) {
4179 				flying_height = (flying_height+TILE_HEIGHT_STEP) & ~(TILE_HEIGHT_STEP-1);
4180 			}
4181 			else if(  flying_height > target_height  ) {
4182 				flying_height = (flying_height-TILE_HEIGHT_STEP);
4183 			}
4184 			flying_height -= h_next;
4185 			// did we have to change our flight height?
4186 			if(  target_height-h_next > TILE_HEIGHT_STEP*5  ) {
4187 				// Move down
4188 				target_height -= TILE_HEIGHT_STEP*2;
4189 			}
4190 			else if(  target_height-h_next < TILE_HEIGHT_STEP*2  ) {
4191 				// Move up
4192 				target_height += TILE_HEIGHT_STEP*2;
4193 			}
4194 			break;
4195 		}
4196 		case landing: {
4197 			new_speed_limit = kmh_to_speed(desc->get_topspeed())/3; // ==approach speed
4198 			new_friction = 8;
4199 			flying_height += h_cur;
4200 			if(  flying_height < target_height  ) {
4201 				flying_height = (flying_height+TILE_HEIGHT_STEP) & ~(TILE_HEIGHT_STEP-1);
4202 			}
4203 			else if(  flying_height > target_height  ) {
4204 				flying_height = (flying_height-TILE_HEIGHT_STEP);
4205 			}
4206 
4207 			if (route_index >= touchdown)  {
4208 				// come down, now!
4209 				target_height = h_next;
4210 
4211 				// touchdown!
4212 				if (flying_height==h_next) {
4213 					const sint32 taxi_speed = kmh_to_speed( min( 60, desc->get_topspeed()/4 ) );
4214 					if(  cnv->get_akt_speed() <= taxi_speed  ) {
4215 						new_speed_limit = taxi_speed;
4216 						new_friction = 16;
4217 					}
4218 					else {
4219 						const sint32 runway_left = search_for_stop - route_index;
4220 						new_speed_limit = min( new_speed_limit, runway_left*runway_left*taxi_speed ); // ...approach 540 240 60 60
4221 						const sint32 runway_left_fr = max( 0, 6-runway_left );
4222 						new_friction = max( new_friction, min( desc->get_topspeed()/12, 4 + 4*(runway_left_fr*runway_left_fr+1) )); // ...8 8 12 24 44 72 108 152
4223 					}
4224 				}
4225 			}
4226 			else {
4227 				// runway is on this height
4228 				const sint16 runway_height = cnv->get_route()->at(touchdown).z*TILE_HEIGHT_STEP;
4229 
4230 				// we are too low, ascent asap
4231 				if (flying_height < runway_height + TILE_HEIGHT_STEP) {
4232 					target_height = runway_height + TILE_HEIGHT_STEP;
4233 				}
4234 				// too high, descent
4235 				else if (flying_height + h_next - h_cur > runway_height + (sint16)(touchdown-route_index-1)*TILE_HEIGHT_STEP) {
4236 					target_height = runway_height +  (touchdown-route_index-1)*TILE_HEIGHT_STEP;
4237 				}
4238 			}
4239 			flying_height -= h_next;
4240 			break;
4241 		}
4242 		default: {
4243 			new_speed_limit = kmh_to_speed( min( 60, desc->get_topspeed()/4 ) );
4244 			new_friction = 16;
4245 			flying_height = 0;
4246 			target_height = h_next;
4247 			break;
4248 		}
4249 	}
4250 
4251 	// hop to next tile
4252 	vehicle_t::hop(gr);
4253 
4254 	speed_limit = new_speed_limit;
4255 	current_friction = new_friction;
4256 
4257 	// friction factors and speed limit may have changed
4258 	// TODO use the same logic as in vehicle_t::hop
4259 	cnv->must_recalc_data();
4260 }
4261 
4262 
4263 // this routine will display the aircraft (if in flight)
4264 #ifdef MULTI_THREAD
4265 void air_vehicle_t::display_after(int xpos_org, int ypos_org, const sint8 clip_num) const
4266 #else
4267 void air_vehicle_t::display_after(int xpos_org, int ypos_org, bool is_global) const
4268 #endif
4269 {
4270 	if(  image != IMG_EMPTY  &&  !is_on_ground()  ) {
4271 		int xpos = xpos_org, ypos = ypos_org;
4272 
4273 		const int raster_width = get_current_tile_raster_width();
4274 		const sint16 z = get_pos().z;
4275 		if(  z + flying_height/TILE_HEIGHT_STEP - 1 > grund_t::underground_level  ) {
4276 			return;
4277 		}
4278 		const sint16 target = target_height - ((sint16)z*TILE_HEIGHT_STEP);
4279 		sint16 current_flughohe = flying_height;
4280 		if(  current_flughohe < target  ) {
4281 			current_flughohe += (steps*TILE_HEIGHT_STEP) >> 8;
4282 		}
4283 		else if(  current_flughohe > target  ) {
4284 			current_flughohe -= (steps*TILE_HEIGHT_STEP) >> 8;
4285 		}
4286 
4287 		sint8 hoff = get_hoff();
4288 		ypos += tile_raster_scale_y(get_yoff()-current_flughohe-hoff-2, raster_width);
4289 		xpos += tile_raster_scale_x(get_xoff(), raster_width);
4290 		get_screen_offset( xpos, ypos, raster_width );
4291 
4292 		display_swap_clip_wh(CLIP_NUM_VAR);
4293 		// will be dirty
4294 		// the aircraft!!!
4295 		display_color( image, xpos, ypos, get_player_nr(), true, true/*get_flag(obj_t::dirty)*/  CLIP_NUM_PAR);
4296 #ifndef MULTI_THREAD
4297 		vehicle_t::display_after( xpos_org, ypos_org - tile_raster_scale_y( current_flughohe - hoff - 2, raster_width ), is_global );
4298 #endif
4299 		display_swap_clip_wh(CLIP_NUM_VAR);
4300 	}
4301 #ifdef MULTI_THREAD
4302 }
4303 void air_vehicle_t::display_overlay(int xpos_org, int ypos_org) const
4304 {
4305 	if(  image != IMG_EMPTY  &&  !is_on_ground()  ) {
4306 		const int raster_width = get_current_tile_raster_width();
4307 		const sint16 z = get_pos().z;
4308 		if(  z + flying_height/TILE_HEIGHT_STEP - 1 > grund_t::underground_level  ) {
4309 			return;
4310 		}
4311 		const sint16 target = target_height - ((sint16)z*TILE_HEIGHT_STEP);
4312 		sint16 current_flughohe = flying_height;
4313 		if(  current_flughohe < target  ) {
4314 			current_flughohe += (steps*TILE_HEIGHT_STEP) >> 8;
4315 		}
4316 		else if(  current_flughohe > target  ) {
4317 			current_flughohe -= (steps*TILE_HEIGHT_STEP) >> 8;
4318 		}
4319 
4320 		vehicle_t::display_overlay( xpos_org, ypos_org - tile_raster_scale_y( current_flughohe - get_hoff() - 2, raster_width ) );
4321 	}
4322 #endif
4323 	else if(  is_on_ground()  ) {
4324 		// show loading tooltips on ground
4325 #ifdef MULTI_THREAD
4326 		vehicle_t::display_overlay( xpos_org, ypos_org );
4327 #else
4328 		vehicle_t::display_after( xpos_org, ypos_org, is_global );
4329 #endif
4330 	}
4331 }
4332 
4333 
4334 const char *air_vehicle_t::is_deletable(const player_t *player)
4335 {
4336 	if (is_on_ground()) {
4337 		return vehicle_t::is_deletable(player);
4338 	}
4339 	return NULL;
4340 }
4341