aircraft_cmd.c
changeset 0 29654efe3188
child 11 836bc4b37b5b
equal deleted inserted replaced
-1:000000000000 0:29654efe3188
       
     1 #include "stdafx.h"
       
     2 #include "ttd.h"
       
     3 #include "vehicle.h"
       
     4 #include "engine.h"
       
     5 #include "command.h"
       
     6 #include "station.h"
       
     7 #include "news.h"
       
     8 #include "gfx.h"
       
     9 #include "player.h"
       
    10 #include "airport.h"
       
    11 
       
    12 static bool AirportMove(Vehicle *v, const AirportFTAClass *Airport);
       
    13 static bool AirportSetBlocks(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport);
       
    14 static bool AirportHasBlock(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport);
       
    15 static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *Airport);
       
    16 static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *Airport);
       
    17 static void AirportGoToNextPosition(Vehicle *v, const AirportFTAClass *Airport);
       
    18 
       
    19 static void AircraftNextAirportPos_and_Order(Vehicle *v);
       
    20 static byte GetAircraftFlyingAltitude(const Vehicle *v);
       
    21 
       
    22 static const SpriteID _aircraft_sprite[] = {
       
    23 	0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD,
       
    24 	0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5,
       
    25 	0x0EAD, 0x0EE5, 0x0F05, 0x0F0D,
       
    26 	0x0F15, 0x0F1D, 0x0F25, 0x0F2D,
       
    27 	0x0EED, 0x0EF5, 0x0EFD, 0x0F35,
       
    28 	0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5,
       
    29 	0x0EBD, 0x0EC5
       
    30 };
       
    31 
       
    32 int GetAircraftImage(Vehicle *v, byte direction)
       
    33 {
       
    34 	int spritenum = v->spritenum;
       
    35 
       
    36 #ifdef AIRCRAFT_CUSTOM_SPRITES // TODO --pasky
       
    37 	if (is_custom_sprite(spritenum)) {
       
    38 		int sprite = GetCustomVehicleSprite(v, direction);
       
    39 
       
    40 		if (sprite) return sprite;
       
    41 		spritenum = _engine_original_sprites[v->engine_type];
       
    42 	}
       
    43 #endif
       
    44 	return direction + _aircraft_sprite[spritenum];
       
    45 }
       
    46 
       
    47 const byte _aircraft_cost_table[NUM_AIRCRAFT_ENGINES] = {
       
    48 	14, 15, 16, 75, 15, 18, 17, 18,
       
    49 	19, 20, 16, 18, 17, 30, 18, 19,
       
    50 	27, 25, 20, 19, 18, 26, 16, 17,
       
    51 	16, 16, 17, 18, 20, 21, 19, 24,
       
    52 	80, 13, 18, 25, 32, 80, 15, 17,
       
    53 	15
       
    54 };
       
    55 
       
    56 const byte _aircraft_speed[NUM_AIRCRAFT_ENGINES] = {
       
    57 	37, 37, 74, 181, 37, 74, 74, 74,
       
    58 	74, 74, 74, 74, 74, 74, 74, 74,
       
    59 	74, 74, 74, 74, 74, 74, 74, 74,
       
    60 	74, 74, 74, 74, 74, 74, 181, 74,
       
    61 	181, 37, 37, 74, 74, 181, 25, 40,
       
    62 	25
       
    63 };
       
    64 
       
    65 const byte _aircraft_running_cost[NUM_AIRCRAFT_ENGINES] = {
       
    66 	85, 100, 130, 250, 98, 240, 150, 245,
       
    67 	192, 190, 135, 240, 155, 253, 210, 220,
       
    68 	230, 225, 235, 220, 170, 210, 125, 145,
       
    69 	130, 149, 170, 210, 230, 220, 160, 248,
       
    70 	251, 85, 100, 140, 220, 255, 81, 77,
       
    71 	80
       
    72 };
       
    73 
       
    74 const byte _aircraft_num_mail[NUM_AIRCRAFT_ENGINES] = {
       
    75 	 4,  8, 10, 20,  6, 30, 15, 30,
       
    76 	40, 25, 10, 35, 15, 50, 25, 25,
       
    77 	40, 35, 30, 25, 20, 20, 10, 10,
       
    78 	10, 10, 18, 25, 60, 65, 45, 80,
       
    79 	45,  5,  9, 12, 40, 30, 15, 20,
       
    80 	10
       
    81 };
       
    82 
       
    83 const uint16 _aircraft_num_pass[NUM_AIRCRAFT_ENGINES] = {
       
    84 	 25, 65, 90,100, 30,200,100,150,
       
    85 	220,230, 95,170,110,300,200,240,
       
    86 	260,240,260,210,160,220, 80, 85,
       
    87 	 75, 85, 65,110,180,150, 85,400,
       
    88 	130, 25, 60, 90,200,100, 40, 55,
       
    89 	 40
       
    90 };
       
    91 
       
    92 const byte _aircraft_sounds[NUM_AIRCRAFT_ENGINES] = {
       
    93 	 6,  6,  7, 59,  6,  7,  7,  7,
       
    94 	 7,  7,  7,  7,  7, 61,  7,  7,
       
    95 	 7,  7,  7,  7,  7,  7,  7,  7,
       
    96 	 7,  7,  7,  7,  7,  7,  7, 61,
       
    97 	59, 69, 70,  7, 61, 59,  7,  7,
       
    98 	 7
       
    99 };
       
   100 
       
   101 const byte _aircraft_table_3[NUM_AIRCRAFT_ENGINES] = {
       
   102 	 1,  0,  2,  8,  5,  6,  2,  2,
       
   103 	 3,  3,  2,  2,  4,  7,  4,  4,
       
   104 	 4,  3,  4,  4,  4,  4,  6,  2,
       
   105 	11, 10, 15, 12, 13, 14, 16, 17,
       
   106 	18, 20, 21, 22, 23, 24,  9, 19,
       
   107 	25
       
   108 };
       
   109 
       
   110 // &1 = regular aircraft
       
   111 // &2 = crashes easily on small airports
       
   112 const byte _aircraft_subtype[NUM_AIRCRAFT_ENGINES] = {
       
   113 	1,  1,  3,  3,  1,  3,  1,  3,
       
   114 	3,  3,  3,  3,  3,  3,  3,  3,
       
   115 	3,  3,  3,  3,  3,  3,  1,  1,
       
   116 	3,  3,  3,  3,  3,  3,  3,  3,
       
   117 	3,  1,  1,  1,  3,  3,  0,  0,
       
   118 	0
       
   119 };
       
   120 
       
   121 const byte _aircraft_acceleration[NUM_AIRCRAFT_ENGINES] = {
       
   122 	18, 20, 35, 50, 20, 40, 35, 40,
       
   123 	40, 40, 35, 40, 40, 40, 40, 40,
       
   124 	40, 40, 40, 40, 40, 40, 50, 40,
       
   125 	40, 40, 40, 40, 40, 40, 40, 40,
       
   126 	50, 18, 20, 40, 40, 50, 20, 20,
       
   127 	20,
       
   128 };
       
   129 
       
   130 void DrawAircraftEngine(int x, int y, int engine, uint32 image_ormod)
       
   131 {
       
   132 	DrawSprite((6 + _aircraft_sprite[_aircraft_table_3[engine - AIRCRAFT_ENGINES_INDEX]]) | image_ormod, x, y);
       
   133 
       
   134 	if ((_aircraft_subtype[engine - AIRCRAFT_ENGINES_INDEX]&1) == 0)
       
   135 		DrawSprite(0xF3D, x, y-5);
       
   136 }
       
   137 
       
   138 void DrawAircraftEngineInfo(int engine, int x, int y, int maxw)
       
   139 {
       
   140 	engine -= AIRCRAFT_ENGINES_INDEX;
       
   141 
       
   142 	SET_DPARAM32(0, ((_price.aircraft_base >> 3) * _aircraft_cost_table[engine]) >> 5);
       
   143 	SET_DPARAM16(1, _aircraft_speed[engine] << 3);
       
   144 	SET_DPARAM16(2, _aircraft_num_pass[engine]);
       
   145 	SET_DPARAM16(3, _aircraft_num_mail[engine]);
       
   146 	SET_DPARAM32(4, _aircraft_running_cost[engine] * _price.aircraft_running >> 8);
       
   147 
       
   148 	DrawStringMultiCenter(x, y, STR_A02E_COST_MAX_SPEED_CAPACITY, maxw);
       
   149 }
       
   150 
       
   151 /* Allocate many vehicles */
       
   152 bool AllocateVehicles(Vehicle **vl, int num)
       
   153 {
       
   154 	int i;
       
   155 	Vehicle *v;
       
   156 	bool success = true;
       
   157 
       
   158 	for(i=0; i!=num; i++) {
       
   159 		vl[i] = v = AllocateVehicle();
       
   160 		if (v == NULL) {
       
   161 			success = false;
       
   162 			break;
       
   163 		}
       
   164 		v->type = 1;
       
   165 	}
       
   166 
       
   167 	while (--i >= 0) {
       
   168 		vl[i]->type = 0;
       
   169 	}
       
   170 
       
   171 	return success;
       
   172 }
       
   173 
       
   174 static int32 EstimateAircraftCost(uint16 engine_type)
       
   175 {
       
   176 	return _aircraft_cost_table[engine_type - AIRCRAFT_ENGINES_INDEX] * (_price.aircraft_base>>3)>>5;
       
   177 }
       
   178 
       
   179 
       
   180 /* p1 = engine */
       
   181 int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   182 {
       
   183 	int32 value;
       
   184 	Vehicle *vl[3], *v, *u, *w;
       
   185 	byte unit_num;
       
   186 	uint tile = TILE_FROM_XY(x,y);
       
   187 	Engine *e;
       
   188 
       
   189 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
       
   190 
       
   191 	value = EstimateAircraftCost(p1);
       
   192 
       
   193 	if (flags & DC_QUERY_COST)
       
   194 		return value;
       
   195 
       
   196 	// allocate 2 or 3 vehicle structs, depending on type
       
   197 	if (!AllocateVehicles(vl, (_aircraft_subtype[p1 - AIRCRAFT_ENGINES_INDEX]&1) == 0 ? 3 : 2) ||
       
   198 			_ptr_to_next_order >= endof(_order_array))
       
   199 					return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
       
   200 
       
   201 	unit_num = GetFreeUnitNumber(VEH_Aircraft);
       
   202 	if (unit_num > _patches.max_aircraft)
       
   203 		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
       
   204 
       
   205 	if (flags & DC_EXEC) {
       
   206 		v = vl[0];
       
   207 		u = vl[1];
       
   208 
       
   209 		v->unitnumber = unit_num;
       
   210 		v->type = u->type = VEH_Aircraft;
       
   211 		v->direction = 3;
       
   212 
       
   213 		v->owner = u->owner = _current_player;
       
   214 
       
   215 		v->tile = tile;
       
   216 //		u->tile = 0;
       
   217 
       
   218 		x = GET_TILE_X(tile)*16 + 5;
       
   219 		y = GET_TILE_Y(tile)*16 + 3;
       
   220 
       
   221 		v->x_pos = u->x_pos = x;
       
   222 		v->y_pos = u->y_pos = y;
       
   223 
       
   224 		u->z_pos = GetSlopeZ(x, y);
       
   225 		v->z_pos = u->z_pos + 1;
       
   226 
       
   227 		v->x_offs = v->y_offs = -1;
       
   228 //		u->delta_x = u->delta_y = 0;
       
   229 
       
   230 		v->sprite_width = v->sprite_height = 2;
       
   231 		v->z_height = 5;
       
   232 
       
   233 		u->sprite_width = u->sprite_height = 2;
       
   234 		u->z_height = 1;
       
   235 
       
   236 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
       
   237 		u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_DISASTER;
       
   238 
       
   239 		v->spritenum = _aircraft_table_3[p1 - AIRCRAFT_ENGINES_INDEX];
       
   240 //		v->cargo_count = u->number_of_pieces = 0;
       
   241 
       
   242 		v->cargo_cap = _aircraft_num_pass[p1 - AIRCRAFT_ENGINES_INDEX];
       
   243 		u->cargo_cap = _aircraft_num_mail[p1 - AIRCRAFT_ENGINES_INDEX];
       
   244 
       
   245 		v->cargo_type = CT_PASSENGERS;
       
   246 		u->cargo_type = CT_MAIL;
       
   247 
       
   248 		v->string_id = STR_SV_AIRCRAFT_NAME;
       
   249 //		v->next_order_param = v->next_order = 0;
       
   250 
       
   251 //		v->load_unload_time_rem = 0;
       
   252 //		v->progress = 0;
       
   253 		v->last_station_visited = 0xFF;
       
   254 //		v->destination_coords = 0;
       
   255 
       
   256 		v->max_speed = _aircraft_speed[p1 - AIRCRAFT_ENGINES_INDEX];
       
   257 		v->acceleration = _aircraft_acceleration[p1 - AIRCRAFT_ENGINES_INDEX];
       
   258 		v->engine_type = (byte)p1;
       
   259 
       
   260 		v->subtype = (_aircraft_subtype[p1 - AIRCRAFT_ENGINES_INDEX]&1) == 0 ? 0 : 2;
       
   261 		v->value = value;
       
   262 
       
   263 		u->subtype = 4;
       
   264 
       
   265 		e = &_engines[p1];
       
   266 		v->reliability = e->reliability;
       
   267 		v->reliability_spd_dec = e->reliability_spd_dec;
       
   268 		v->max_age = e->lifelength * 366;
       
   269 
       
   270 		_new_aircraft_id = v->index;
       
   271 
       
   272 		*(v->schedule_ptr = _ptr_to_next_order++) = 0;
       
   273 		// the AI doesn't click on a tile to build airplanes, so the below code will
       
   274 		// never work. Therefore just assume the AI's planes always come from Hangar0
       
   275 		v->u.air.pos = (_is_ai_player) ? 0:MAX_ELEMENTS;
       
   276 
       
   277 		/* When we click on hangar we know the tile (it is in var 'tile')it is on. By that we know 
       
   278 			its position in the array of depots the airport has.....we can search 
       
   279 			->layout for #th position of depot. Since layout must start with depots, it is simple
       
   280 		*/
       
   281 		{
       
   282 			Station *st;
       
   283 			const AirportFTAClass *Airport;
       
   284 			const uint16 *cur_depot;
       
   285 			byte i = 0;
       
   286 			st = DEREF_STATION(_map2[tile]);
       
   287 			Airport = GetAirport(st->airport_type);
       
   288 			// first element of depot array contains #of depots on the airport
       
   289 			for (cur_depot=&Airport->airport_depots[1]; i != Airport->airport_depots[0]; cur_depot++) {
       
   290 				if ((uint)(st->airport_tile + *cur_depot) == tile) {
       
   291 					assert(Airport->layout[i].heading == HANGAR);
       
   292 					v->u.air.pos = Airport->layout[i].position;
       
   293 					break;
       
   294 				}
       
   295 				i++;
       
   296 			}
       
   297 			// to ensure v->u.air.pos has been given a value
       
   298 			assert(v->u.air.pos != MAX_ELEMENTS);
       
   299 		}
       
   300 
       
   301 		v->u.air.state = HANGAR;
       
   302 		v->u.air.previous_pos = v->u.air.pos;
       
   303 		v->u.air.targetairport = _map2[tile];
       
   304 		v->next = u;
       
   305 
       
   306 		v->service_interval = _patches.servint_aircraft;
       
   307 
       
   308 		v->date_of_last_service = _date;
       
   309 		v->build_year = _cur_year;
       
   310 
       
   311 		v->cur_image = u->cur_image = 0xEA0;
       
   312 
       
   313 		VehiclePositionChanged(v);
       
   314 		VehiclePositionChanged(u);
       
   315 
       
   316 		// Aircraft with 3 vehicles?
       
   317 		if (v->subtype == 0) {
       
   318 			w = vl[2];
       
   319 
       
   320 			u->next = w;
       
   321 
       
   322 			w->type = VEH_Aircraft;
       
   323 			w->direction = 0;
       
   324 			w->owner = _current_player;
       
   325 			w->x_pos = v->x_pos;
       
   326 			w->y_pos = v->y_pos;
       
   327 			w->z_pos = v->z_pos + 5;
       
   328 			w->x_offs = w->y_offs = -1;
       
   329 			w->sprite_width = w->sprite_height = 2;
       
   330 			w->z_height = 1;
       
   331 			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
       
   332 			w->subtype = 6;
       
   333 			w->cur_image = 0xF3D;
       
   334 			VehiclePositionChanged(w);
       
   335 		}
       
   336 
       
   337 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   338 		InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
       
   339 		InvalidateWindow(WC_COMPANY, v->owner);
       
   340 	}
       
   341 
       
   342 	return value;
       
   343 }
       
   344 
       
   345 bool IsAircraftHangarTile(TileIndex tile)
       
   346 {
       
   347 	// 0x56 - hangar facing other way international airport (86)
       
   348 	// 0x20 - hangar large airport (32)
       
   349 	// 0x41 - hangar small airport (65)
       
   350 	return IS_TILETYPE(tile, MP_STATION) &&
       
   351 				(_map5[tile] == 32 || _map5[tile] == 65 || _map5[tile] == 86);
       
   352 }
       
   353 
       
   354 static bool CheckStoppedInHangar(Vehicle *v)
       
   355 {
       
   356 	if (!(v->vehstatus&VS_STOPPED) ||
       
   357 			!IsAircraftHangarTile(v->tile)) {
       
   358 		_error_message = STR_A01B_AIRCRAFT_MUST_BE_STOPPED;
       
   359 		return false;
       
   360 	}
       
   361 
       
   362 	return true;
       
   363 }
       
   364 
       
   365 
       
   366 void DoDeleteAircraft(Vehicle *v)
       
   367 {
       
   368 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
       
   369 	InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
       
   370 	InvalidateWindow(WC_COMPANY, v->owner);
       
   371 	DeleteVehicleChain(v);
       
   372 }
       
   373 
       
   374 // p1 = vehicle
       
   375 int32 CmdSellAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   376 {
       
   377 	Vehicle *v;
       
   378 
       
   379 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
       
   380 
       
   381 	v = &_vehicles[p1];
       
   382 
       
   383 	if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v))
       
   384 		return CMD_ERROR;
       
   385 
       
   386 	if (flags & DC_EXEC) {
       
   387 		// Invalidate depot
       
   388 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   389 
       
   390 		DoDeleteAircraft(v);
       
   391 
       
   392 	}
       
   393 
       
   394 	return -(int32)v->value;
       
   395 }
       
   396 
       
   397 // p1 = vehicle
       
   398 int32 CmdStartStopAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   399 {
       
   400 	Vehicle *v;
       
   401 
       
   402 	v = &_vehicles[p1];
       
   403 
       
   404 	if (!CheckOwnership(v->owner))
       
   405 		return CMD_ERROR;
       
   406 
       
   407 	// cannot stop airplane when in flight, or when taking off / landing
       
   408 	if (v->u.air.state >= STARTTAKEOFF) {
       
   409 		return_cmd_error(STR_A017_AIRCRAFT_IS_IN_FLIGHT);
       
   410 	}
       
   411 
       
   412 	if (flags & DC_EXEC) {
       
   413 		v->vehstatus ^= VS_STOPPED;
       
   414 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   415 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   416 	}
       
   417 
       
   418 	return 0;
       
   419 }
       
   420 
       
   421 // p1 = vehicle
       
   422 int32 CmdSendAircraftToHangar(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   423 {
       
   424 	Vehicle *v;
       
   425 	Station *st;
       
   426 
       
   427 	v = &_vehicles[p1];
       
   428 
       
   429 	if (!CheckOwnership(v->owner))
       
   430 		return CMD_ERROR;
       
   431 
       
   432 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) {
       
   433 		if (flags & DC_EXEC) {
       
   434  			if (v->next_order&OF_UNLOAD)
       
   435  				{ v->cur_order_index++; }
       
   436 			v->next_order = OT_DUMMY;
       
   437 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   438 		}
       
   439 	} else {
       
   440 		st = DEREF_STATION(v->u.air.targetairport);
       
   441 		// If an airport doesn't have terminals (so no landing space for airports),
       
   442 		// it surely doesn't have any hangars
       
   443 		if (st->xy == 0 || st->airport_tile == 0 || GetAirport(st->airport_type)->nofterminals == 0)
       
   444 					return CMD_ERROR;
       
   445 
       
   446 		if (flags & DC_EXEC) {
       
   447 			v->next_order = OF_NON_STOP | OF_FULL_LOAD | OT_GOTO_DEPOT;
       
   448 			v->next_order_param = v->u.air.targetairport;
       
   449 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   450 		}
       
   451 	}
       
   452 
       
   453 	return 0;
       
   454 }
       
   455 
       
   456 // p1 = vehicle
       
   457 // p2 = new service int
       
   458 int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   459 {
       
   460 	Vehicle *v;
       
   461 
       
   462 	v = &_vehicles[p1];
       
   463 
       
   464 	if (!CheckOwnership(v->owner))
       
   465 		return CMD_ERROR;
       
   466 
       
   467 	if (flags & DC_EXEC) {
       
   468 		v->service_interval = (uint16)p2;
       
   469 		InvalidateWindowWidget(WC_VEHICLE_DETAILS, v->index, 7);
       
   470 	}
       
   471 
       
   472 	return 0;
       
   473 }
       
   474 
       
   475 // p1 = vehicle
       
   476 // p2 = new cargo type
       
   477 int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   478 {
       
   479 	Vehicle *v,*u;
       
   480 	int pass, mail;
       
   481 	int32 cost;
       
   482 
       
   483 	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN);
       
   484 
       
   485 	v = &_vehicles[p1];
       
   486 	if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v))
       
   487 		return CMD_ERROR;
       
   488 
       
   489 	pass = _aircraft_num_pass[v->engine_type - AIRCRAFT_ENGINES_INDEX];
       
   490 	if (p2 != 0) {
       
   491 		pass >>= 1;
       
   492 		if (p2 != 5)
       
   493 			pass >>= 1;
       
   494 	}
       
   495 	_aircraft_refit_capacity = pass;
       
   496 
       
   497 	cost = 0;
       
   498 	if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) {
       
   499 		cost = _price.aircraft_base >> 7;
       
   500 	}
       
   501 
       
   502 	if (flags & DC_EXEC) {
       
   503 		v->cargo_cap = pass;
       
   504 
       
   505 		u = v->next;
       
   506 		mail = _aircraft_num_mail[v->engine_type - AIRCRAFT_ENGINES_INDEX];
       
   507 		if (p2 != 0) {
       
   508 			mail = 0;
       
   509 		}
       
   510 		u->cargo_cap = mail;
       
   511 		v->cargo_count = u->cargo_count = 0;
       
   512 		v->cargo_type = (byte)p2;
       
   513 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   514 	}
       
   515 
       
   516 	return cost;
       
   517 }
       
   518 
       
   519 void HandleClickOnAircraft(Vehicle *v)
       
   520 {
       
   521 	ShowAircraftViewWindow(v);
       
   522 }
       
   523 
       
   524 static void CheckIfAircraftNeedsService(Vehicle *v)
       
   525 {
       
   526 	Station *st;
       
   527 
       
   528 	if (v->date_of_last_service + v->service_interval > _date)
       
   529 		return;
       
   530 
       
   531 	if (v->vehstatus & VS_STOPPED)
       
   532 		return;
       
   533 
       
   534 	if ((v->next_order & (OT_MASK | OF_FULL_LOAD)) == (OT_GOTO_DEPOT | OF_FULL_LOAD))
       
   535 		return;
       
   536 
       
   537  	if (_patches.gotodepot && IS_HUMAN_PLAYER(v->owner) && ScheduleHasDepotOrders(v->schedule_ptr))
       
   538  		return;
       
   539  
       
   540 	st = DEREF_STATION(v->next_order_param);
       
   541 	// only goto depot if the target airport has terminals (eg. it is airport)
       
   542 	if (st->xy != 0 && st->airport_tile != 0 && GetAirport(st->airport_type)->nofterminals != 0) {
       
   543 //		printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index);
       
   544 //		v->u.air.targetairport = st->index;
       
   545 		v->next_order = OF_NON_STOP | OT_GOTO_DEPOT;
       
   546 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   547 	} else if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) {
       
   548 		v->next_order = OT_DUMMY;
       
   549 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   550 	}
       
   551 }
       
   552 
       
   553 void OnNewDay_Aircraft(Vehicle *v)
       
   554 {
       
   555 	int32 cost;
       
   556 
       
   557 	if (v->subtype > 2)
       
   558 		return;
       
   559 
       
   560 	if ((++v->day_counter & 7) == 0)
       
   561 		DecreaseVehicleValue(v);
       
   562 
       
   563 	CheckVehicleBreakdown(v);
       
   564 	AgeVehicle(v);
       
   565 	CheckIfAircraftNeedsService(v);
       
   566 
       
   567 	if (v->vehstatus & VS_STOPPED)
       
   568 		return;
       
   569 
       
   570 	cost = _aircraft_running_cost[v->engine_type - AIRCRAFT_ENGINES_INDEX] * _price.aircraft_running / 364;
       
   571 
       
   572 	v->profit_this_year -= cost >> 8;
       
   573 
       
   574 	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN);
       
   575 	SubtractMoneyFromPlayerFract(v->owner, cost);
       
   576 
       
   577 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   578 	InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
       
   579 }
       
   580 
       
   581 void AircraftYearlyLoop()
       
   582 {
       
   583 	Vehicle *v;
       
   584 
       
   585 	FOR_ALL_VEHICLES(v) {
       
   586 		if (v->type == VEH_Aircraft && v->subtype <= 2) {
       
   587 			v->profit_last_year = v->profit_this_year;
       
   588 			v->profit_this_year = 0;
       
   589 			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   590 		}
       
   591 	}
       
   592 }
       
   593 
       
   594 static void AgeAircraftCargo(Vehicle *v)
       
   595 {
       
   596 	if (_age_cargo_skip_counter != 0)
       
   597 		return;
       
   598 
       
   599 	do {
       
   600 		if (v->cargo_days != 0xFF)
       
   601 			v->cargo_days++;
       
   602 	} while ( (v=v->next) != NULL );
       
   603 }
       
   604 
       
   605 static void HelicopterTickHandler(Vehicle *v)
       
   606 {
       
   607 	Vehicle *u;
       
   608 	int tick,spd;
       
   609 	uint16 img;
       
   610 
       
   611 	u = v->next->next;
       
   612 
       
   613 	if (u->vehstatus & VS_HIDDEN)
       
   614 		return;
       
   615 
       
   616 	// if true, helicopter rotors do not rotate. This should only be the case if a helicopter is 
       
   617 	// loading/unloading at a terminal or stopped
       
   618 	if ((v->next_order&OT_MASK) == OT_LOADING || (v->vehstatus&VS_STOPPED)) {
       
   619 		if (u->cur_speed != 0) {
       
   620 			u->cur_speed++;
       
   621 			if (u->cur_speed >= 0x80 && u->cur_image == 0xF40) {
       
   622 				u->cur_speed = 0;
       
   623 			}
       
   624 		}
       
   625 	} else {
       
   626 		if (u->cur_speed == 0)
       
   627 			u->cur_speed = 0x70;
       
   628 
       
   629 		if (u->cur_speed >= 0x50)
       
   630 			u->cur_speed--;
       
   631 	}
       
   632 
       
   633 	tick = ++u->tick_counter;
       
   634 	spd = u->cur_speed >> 4;
       
   635 
       
   636 	if (spd == 0) {
       
   637 		img = 0xF3D;
       
   638 		if (u->cur_image == img)
       
   639 			return;
       
   640 	} else if (tick >= spd) {
       
   641 		u->tick_counter = 0;
       
   642 		img = u->cur_image + 1;
       
   643 		if (img > 0xF40)
       
   644 			img = 0xF3E;
       
   645 	} else
       
   646 		return;
       
   647 
       
   648 	u->cur_image=img;
       
   649 
       
   650 	BeginVehicleMove(u);
       
   651 	VehiclePositionChanged(u);
       
   652 	EndVehicleMove(u);
       
   653 }
       
   654 
       
   655 static void SetAircraftPosition(Vehicle *v, int x, int y, int z)
       
   656 {
       
   657 	Vehicle *u;
       
   658 	int yt;
       
   659 
       
   660 	v->x_pos = x;
       
   661 	v->y_pos = y;
       
   662 	v->z_pos = z;
       
   663 
       
   664 	v->cur_image = GetAircraftImage(v, v->direction);
       
   665 
       
   666 	BeginVehicleMove(v);
       
   667 	VehiclePositionChanged(v);
       
   668 	EndVehicleMove(v);
       
   669 
       
   670 	u = v->next;
       
   671 
       
   672 	yt = y - ((v->z_pos-GetSlopeZ(x, y-1)) >> 3);
       
   673 	u->x_pos = x;
       
   674 	u->y_pos = yt;
       
   675 	u->z_pos = GetSlopeZ(x,yt);
       
   676 	u->cur_image = v->cur_image;
       
   677 
       
   678 	BeginVehicleMove(u);
       
   679 	VehiclePositionChanged(u);
       
   680 	EndVehicleMove(u);
       
   681 
       
   682 	if ((u=u->next) != NULL) {
       
   683 		u->x_pos = x;
       
   684 		u->y_pos = y;
       
   685 		u->z_pos = z + 5;
       
   686 
       
   687 		BeginVehicleMove(u);
       
   688 		VehiclePositionChanged(u);
       
   689 		EndVehicleMove(u);
       
   690 	}
       
   691 }
       
   692 
       
   693 static void ServiceAircraft(Vehicle *v)
       
   694 {
       
   695 	Vehicle *u;
       
   696 
       
   697 	v->cur_speed = 0;
       
   698 	v->subspeed = 0;
       
   699 	v->progress = 0;
       
   700 	v->vehstatus |= VS_HIDDEN;
       
   701 
       
   702 	u = v->next;
       
   703 	u->vehstatus |= VS_HIDDEN;
       
   704 	if ((u=u->next) != NULL) {
       
   705 		u->vehstatus |= VS_HIDDEN;
       
   706 		u->cur_speed = 0;
       
   707 	}
       
   708 
       
   709 	SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
       
   710 	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   711 
       
   712 	v->date_of_last_service = _date;
       
   713 	v->breakdowns_since_last_service = 0;
       
   714 	v->reliability = _engines[v->engine_type].reliability;
       
   715 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   716 }
       
   717 
       
   718 static void PlayAircraftSound(Vehicle *v)
       
   719 {
       
   720 	SndPlayVehicleFx(_aircraft_sounds[v->engine_type - AIRCRAFT_ENGINES_INDEX], v);
       
   721 }
       
   722 
       
   723 static bool UpdateAircraftSpeed(Vehicle *v)
       
   724 {
       
   725 	uint spd = v->acceleration * 2;
       
   726 	byte t;
       
   727 
       
   728 	v->subspeed = (t=v->subspeed) + (byte)spd;
       
   729 	spd = min( v->cur_speed + (spd >> 8) + (v->subspeed < t), v->max_speed);
       
   730 		   
       
   731 	// adjust speed for broken vehicles
       
   732 	if(v->vehstatus&VS_AIRCRAFT_BROKEN) spd = min(spd, 27);
       
   733 
       
   734 	//updates statusbar only if speed have changed to save CPU time
       
   735 	if (spd != v->cur_speed) {
       
   736 		v->cur_speed = spd;
       
   737 		if (_patches.vehicle_speed)
       
   738 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
   739 	}
       
   740 
       
   741 	if (!(v->direction & 1)) {
       
   742 		spd = spd * 3 >> 2;
       
   743 	}
       
   744 
       
   745 	if (spd == 0)
       
   746 		return false;
       
   747 
       
   748 	if ((byte)++spd == 0)
       
   749 		return true;
       
   750 
       
   751 	v->progress = (t = v->progress) - (byte)spd;
       
   752 
       
   753 	return (t < v->progress);
       
   754 }
       
   755 
       
   756 // get Aircraft running altitude
       
   757 static byte GetAircraftFlyingAltitude(const Vehicle *v)
       
   758 {
       
   759 	byte maxz = 162;
       
   760 	if (v->max_speed != 37) {
       
   761 		maxz = 171;
       
   762 		if (v->max_speed != 74) {maxz = 180;}
       
   763 	}
       
   764 	return maxz;
       
   765 }
       
   766 
       
   767 static bool Aircraft_5(Vehicle *v)
       
   768 {
       
   769 	Station *st;
       
   770 	const AirportMovingData *amd;
       
   771 	Vehicle *u;
       
   772 	byte z,dirdiff,newdir,maxz,curz;
       
   773 	GetNewVehiclePosResult gp;
       
   774 	uint dist;
       
   775 	int x,y;
       
   776 
       
   777 	st = DEREF_STATION(v->u.air.targetairport);
       
   778 
       
   779 	// prevent going to 0,0 if airport is deleted.
       
   780 	{
       
   781 		uint tile = st->airport_tile;
       
   782 		if (tile == 0) tile = st->xy;
       
   783 		// xy of destination
       
   784 		x = GET_TILE_X(tile)*16;
       
   785 		y = GET_TILE_Y(tile)*16;
       
   786 	}
       
   787 
       
   788 	// get airport moving data
       
   789 	assert(v->u.air.pos < GetAirport(st->airport_type)->nofelements);
       
   790 	amd = &_airport_moving_datas[st->airport_type][v->u.air.pos];
       
   791 
       
   792 	// Helicopter raise
       
   793 	if (amd->flag & AMED_HELI_RAISE) {
       
   794 		u = v->next->next;
       
   795 
       
   796 		// Make sure the rotors don't rotate too fast
       
   797 		if (u->cur_speed > 32) {
       
   798 			v->cur_speed = 0;
       
   799 			if (--u->cur_speed == 32) {
       
   800 				SndPlayVehicleFx(0x16, v);
       
   801 			}
       
   802 		} else {
       
   803 			u->cur_speed = 32;
       
   804 			if (UpdateAircraftSpeed(v)) {
       
   805 				v->tile = 0;
       
   806 
       
   807 				// Reached altitude?
       
   808 				if (v->z_pos >= 184) {
       
   809 					v->cur_speed = 0;
       
   810 					return true;
       
   811 				}
       
   812 				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1);
       
   813 			}
       
   814 		}
       
   815 		return false;
       
   816 	}
       
   817 
       
   818 	// Helicopter landing.
       
   819 	if (amd->flag & AMED_HELI_LOWER) {
       
   820 		if (UpdateAircraftSpeed(v)) {
       
   821 			if (st->airport_tile == 0) {
       
   822 				// FIXME - Aircraft_5 -> if station no longer exists, do not land
       
   823 				// helicopter will circle until sign disappears, then go to next order
       
   824 				// * what to do when it is the only order left, right now it just stays in 1 place
       
   825 				v->u.air.state = FLYING;
       
   826 				AircraftNextAirportPos_and_Order(v);
       
   827 				return false;
       
   828 			}
       
   829 
       
   830 			// Vehicle is now at the airport.
       
   831 			v->tile = st->airport_tile;
       
   832 
       
   833 			// Find altitude of landing position.
       
   834 			z = GetSlopeZ(x, y) + 1;
       
   835 			if (st->airport_type == AT_OILRIG) z += 54;
       
   836 			if (st->airport_type == AT_HELIPORT) z += 60;
       
   837 
       
   838 			if (z == v->z_pos) {
       
   839 				u = v->next->next;
       
   840 
       
   841 				// Increase speed of rotors. When speed is 80, we've landed.
       
   842 				if (u->cur_speed >= 80)
       
   843 					return true;
       
   844 				u->cur_speed+=4;
       
   845 			} else if (v->z_pos > z) {
       
   846 				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1);
       
   847 			} else {
       
   848 				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1);
       
   849 			}
       
   850 		}
       
   851 		return false;
       
   852 	}
       
   853 
       
   854 	// Get distance from destination pos to current pos.
       
   855 	dist = myabs(x + amd->x - v->x_pos) +  myabs(y + amd->y - v->y_pos);
       
   856 
       
   857 	// Need exact position?
       
   858 	if (!(amd->flag & AMED_EXACTPOS) && dist <= (uint)((amd->flag&AMED_SLOWTURN)?8:4))
       
   859 		return true;
       
   860 
       
   861 	// At final pos?
       
   862 	if (dist == 0) {
       
   863 
       
   864 		// Clamp speed to 12.
       
   865 		if (v->cur_speed > 12)
       
   866 			v->cur_speed = 12;
       
   867 
       
   868 		// Change direction smoothly to final direction.
       
   869 		dirdiff = amd->direction - v->direction;
       
   870 		// if distance is 0, and plane points in right direction, no point in calling 
       
   871 		// UpdateAircraftSpeed(). So do it only afterwards
       
   872 		if (dirdiff == 0) {
       
   873 			v->cur_speed = 0;
       
   874 			return true;
       
   875 		}
       
   876 
       
   877 		if (!UpdateAircraftSpeed(v))
       
   878 			return false;
       
   879 
       
   880 		v->direction = (v->direction+((dirdiff&7)<5?1:-1)) & 7;
       
   881 		v->cur_speed >>= 1;
       
   882 
       
   883 		SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
       
   884 		return false;
       
   885 	}
       
   886 
       
   887 	// Clamp speed?
       
   888 	if (!(amd->flag & AMED_NOSPDCLAMP) && v->cur_speed > 12)
       
   889 		v->cur_speed = 12;
       
   890 
       
   891 	if (!UpdateAircraftSpeed(v))
       
   892 		return false;
       
   893 
       
   894 	// Decrease animation counter.
       
   895 	if (v->load_unload_time_rem != 0)
       
   896 		v->load_unload_time_rem--;
       
   897 
       
   898 	// Turn. Do it slowly if in the air.
       
   899 	newdir = GetDirectionTowards(v, x + amd->x, y + amd->y);
       
   900 	if (newdir != v->direction) {
       
   901 		if (amd->flag & AMED_SLOWTURN) {
       
   902 			if (v->load_unload_time_rem == 0) {
       
   903 				v->load_unload_time_rem = 8;
       
   904 				v->direction = newdir;
       
   905 			}
       
   906 		} else {
       
   907 			v->cur_speed >>= 1;
       
   908 			v->direction = newdir;
       
   909 		}
       
   910 	}
       
   911 
       
   912 	// Move vehicle.
       
   913 	GetNewVehiclePos(v, &gp);
       
   914 	v->tile = gp.new_tile;
       
   915 
       
   916 	// If vehicle is in the air, use tile coordinate 0.
       
   917 	if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) {
       
   918 		v->tile = 0;
       
   919 	}
       
   920 
       
   921 	// Adjust Z for land or takeoff?
       
   922 	z = v->z_pos;
       
   923 
       
   924 	if (amd->flag & AMED_TAKEOFF) {
       
   925 		z+=2;
       
   926 		// Determine running altitude
       
   927 		maxz = GetAircraftFlyingAltitude(v);
       
   928 		if (z > maxz)
       
   929 			z = maxz;
       
   930 	}
       
   931 
       
   932 	if (amd->flag & AMED_LAND) {
       
   933 		if (st->airport_tile == 0) {
       
   934 			//FIXME -- FIXED - Aircraft_5 -> if station no longer exists, do not land
       
   935 			// * what to do when it is the only order left, right now it just stays in 1 place?
       
   936 			v->u.air.state = FLYING;
       
   937 			AircraftNextAirportPos_and_Order(v);
       
   938 			// get aircraft back on running altitude
       
   939 			SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
       
   940 			return false;
       
   941 		}
       
   942 
       
   943 		curz = GetSlopeZ(x, y) + 1;
       
   944 
       
   945 		if (curz > z) {
       
   946 			z++;
       
   947 		} else {
       
   948 			int t = max(1, dist-4);
       
   949 
       
   950 			z -= ((z - curz) + t - 1) / t;
       
   951 			if (z < curz) z = curz;
       
   952 		}
       
   953 	}
       
   954 
       
   955 	// We've landed. Decrase speed when we're reaching end of runway.
       
   956 	if (amd->flag & AMED_BRAKE) {
       
   957 		curz = GetSlopeZ(x, y) + 1;
       
   958 
       
   959 		if (z > curz) z--;
       
   960 		else if (z < curz) z++;
       
   961 
       
   962 		if (dist < 64 && v->cur_speed > 12)
       
   963 			v->cur_speed -= 4;
       
   964 	}
       
   965 
       
   966 	SetAircraftPosition(v, gp.x, gp.y, z);
       
   967 	return false;
       
   968 }
       
   969 
       
   970 static const int8 _crashed_aircraft_moddir[4] = {
       
   971 	-1,0,0,1
       
   972 };
       
   973 
       
   974 static void HandleCrashedAircraft(Vehicle *v)
       
   975 {
       
   976 	uint32 r;
       
   977 	Station *st;
       
   978 
       
   979 	v->u.air.crashed_counter++;
       
   980 
       
   981 	if (v->u.air.crashed_counter < 650) {
       
   982 		if (CHANCE16R(1,32,r)) {
       
   983 			v->direction = (v->direction+_crashed_aircraft_moddir[(r >> 16)&3]) & 7;
       
   984 			SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
       
   985 			r = Random();
       
   986 			CreateEffectVehicleRel(v,
       
   987 				4 + (r&0xF),
       
   988 				4 + ((r>>4)&0xF),
       
   989 				((r>>8)&0xF),
       
   990 				EV_DEMOLISH);
       
   991 		}
       
   992 	} else if (v->u.air.crashed_counter >= 10000) {
       
   993 		st = DEREF_STATION(v->u.air.targetairport);
       
   994 		// remove rubble of crashed airplane
       
   995 
       
   996 		// clear runway-in on all airports, set by crashing plane
       
   997 		// small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc.
       
   998 		// but they all share the same number
       
   999 		CLRBITS(st->airport_flags, RUNWAY_IN_block);
       
  1000 
       
  1001 		BeginVehicleMove(v);
       
  1002 		EndVehicleMove(v);
       
  1003 
       
  1004 		DoDeleteAircraft(v);
       
  1005 	}
       
  1006 }
       
  1007 
       
  1008 static void HandleBrokenAircraft(Vehicle *v)
       
  1009 {
       
  1010 	if (v->breakdown_ctr != 1) {
       
  1011 		v->breakdown_ctr = 1;
       
  1012 		v->vehstatus |= VS_AIRCRAFT_BROKEN;
       
  1013 
       
  1014 		if (v->breakdowns_since_last_service != 255)
       
  1015 			v->breakdowns_since_last_service++;
       
  1016 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
  1017 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
  1018 	}
       
  1019 }
       
  1020 
       
  1021 static const int8 _aircraft_smoke_xy[16] = {
       
  1022 	5,6,5,0,-5,-6,-5,0, /* x coordinates */
       
  1023 	5,0,-5,-6,-5,0,5,6, /* y coordinate */
       
  1024 };
       
  1025 
       
  1026 static void HandleAircraftSmoke(Vehicle *v)
       
  1027 {
       
  1028 	if (!(v->vehstatus&VS_AIRCRAFT_BROKEN))
       
  1029 		return;
       
  1030 
       
  1031 	if (v->cur_speed < 10) {
       
  1032 		v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
       
  1033 		v->breakdown_ctr = 0;
       
  1034 		return;
       
  1035 	}
       
  1036 
       
  1037 	if ((v->tick_counter & 0x1F) == 0) {
       
  1038 		CreateEffectVehicleRel(v,
       
  1039 			_aircraft_smoke_xy[v->direction],
       
  1040 			_aircraft_smoke_xy[v->direction + 8],
       
  1041 			2,
       
  1042 			EV_SMOKE_3
       
  1043 		);
       
  1044 	}
       
  1045 }
       
  1046 
       
  1047 static void ProcessAircraftOrder(Vehicle *v)
       
  1048 {
       
  1049 	uint order;
       
  1050 
       
  1051 	// OT_GOTO_DEPOT, OT_LOADING
       
  1052  	if ((v->next_order & OT_MASK) >= OT_GOTO_DEPOT && (v->next_order & OT_MASK) <= OT_LOADING) {
       
  1053  		if ((v->next_order & (OT_MASK|OF_UNLOAD)) != (OT_GOTO_DEPOT|OF_UNLOAD))
       
  1054  			return;
       
  1055  	}
       
  1056  
       
  1057  	if ((v->next_order & (OT_MASK|OF_UNLOAD|OF_FULL_LOAD)) == (OT_GOTO_DEPOT|OF_UNLOAD|OF_FULL_LOAD) &&
       
  1058  		v->date_of_last_service+v->service_interval > _date) {
       
  1059  		v->cur_order_index++;
       
  1060  	}
       
  1061 
       
  1062 	if (v->cur_order_index >= v->num_orders)
       
  1063 		v->cur_order_index = 0;
       
  1064 
       
  1065 	order = v->schedule_ptr[v->cur_order_index];
       
  1066 
       
  1067 	if (order == 0) {
       
  1068 		v->next_order = OT_NOTHING;
       
  1069 		return;
       
  1070 	}
       
  1071 
       
  1072 	if (order == (uint)((v->next_order | (v->next_order_param<<8))))
       
  1073 		return;
       
  1074 
       
  1075 	v->next_order = (byte)order;
       
  1076 	v->next_order_param = (byte)(order >> 8);
       
  1077 
       
  1078 	// orders are changed in flight, ensure going to the right station
       
  1079 	if ((order & OT_MASK) == OT_GOTO_STATION && v->u.air.state == FLYING) {
       
  1080 		AircraftNextAirportPos_and_Order(v);
       
  1081 		v->u.air.targetairport = order >> 8;
       
  1082 	}
       
  1083 
       
  1084 	InvalidateVehicleOrderWidget(v);
       
  1085 }
       
  1086 
       
  1087 static void HandleAircraftLoading(Vehicle *v, int mode)
       
  1088 {
       
  1089 	if (v->next_order == OT_NOTHING)
       
  1090 		return;
       
  1091 
       
  1092 	if (v->next_order != OT_DUMMY) {
       
  1093 		if ((v->next_order&OT_MASK) != OT_LOADING)
       
  1094 			return;
       
  1095 
       
  1096 		if (mode != 0)
       
  1097 			return;
       
  1098 
       
  1099 		if (--v->load_unload_time_rem)
       
  1100 			return;
       
  1101 
       
  1102 		if (v->next_order&OF_FULL_LOAD && CanFillVehicle(v)) {
       
  1103 			SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC);
       
  1104 			LoadUnloadVehicle(v);
       
  1105 			return;
       
  1106 		}
       
  1107 
       
  1108 		{
       
  1109 			byte b = v->next_order;
       
  1110 			v->next_order = OT_NOTHING;
       
  1111 			if (!(b & OF_NON_STOP))
       
  1112 				return;
       
  1113 		}
       
  1114 	}
       
  1115 	v->cur_order_index++;
       
  1116 	InvalidateVehicleOrderWidget(v);
       
  1117 }
       
  1118 
       
  1119 static void MaybeCrashAirplane(Vehicle *v)
       
  1120 {
       
  1121 	Station *st;
       
  1122 	uint16 prob;
       
  1123 	int i;
       
  1124 	uint16 amt;
       
  1125 
       
  1126 	st = DEREF_STATION(v->u.air.targetairport);
       
  1127 
       
  1128 	//FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports
       
  1129 	prob = 0x10000 / 1500;
       
  1130 	if (st->airport_type == AT_SMALL && (_aircraft_subtype[v->engine_type - AIRCRAFT_ENGINES_INDEX]&2)) {
       
  1131 		prob = 0x10000 / 20;
       
  1132 	}
       
  1133 
       
  1134 	if ((uint16)Random() > prob)
       
  1135 		return;
       
  1136 
       
  1137 	// Crash the airplane. Remove all goods stored at the station.
       
  1138 	for(i=0; i!=NUM_CARGO; i++) {
       
  1139 		st->goods[i].rating = 1;
       
  1140 		st->goods[i].waiting_acceptance &= ~0xFFF;
       
  1141 	}
       
  1142 
       
  1143 	v->vehstatus |= VS_CRASHED;
       
  1144 	v->u.air.crashed_counter = 0;
       
  1145 
       
  1146 	CreateEffectVehicleRel(v, 4, 4, 8, EV_CRASHED_SMOKE);
       
  1147 
       
  1148 	InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
  1149 
       
  1150 	amt = 2;
       
  1151 	if (v->cargo_type == CT_PASSENGERS) amt += v->cargo_count;
       
  1152 	SET_DPARAM16(0, amt);
       
  1153 
       
  1154 	v->cargo_count = 0;
       
  1155 	v->next->cargo_count = 0,
       
  1156 
       
  1157 	SET_DPARAM16(1, st->index);
       
  1158 	AddNewsItem(STR_A034_PLANE_CRASH_DIE_IN_FIREBALL,
       
  1159 		NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
       
  1160 		v->index,
       
  1161 		0);
       
  1162 
       
  1163 	ModifyStationRatingAround(TILE_FROM_XY(v->x_pos, v->y_pos), v->owner, -160, 30);
       
  1164 	SndPlayVehicleFx(16, v);
       
  1165 }
       
  1166 
       
  1167 // we've landed and just arrived at a terminal
       
  1168 static void AircraftEntersTerminal(Vehicle *v)
       
  1169 {
       
  1170 	Station *st;
       
  1171 	byte old_order;
       
  1172 
       
  1173 	if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT)
       
  1174 		return;
       
  1175 
       
  1176 	st = DEREF_STATION(v->u.air.targetairport);
       
  1177 	v->last_station_visited = v->u.air.targetairport;
       
  1178 
       
  1179 	/* Check if station was ever visited before */
       
  1180 	if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
       
  1181 		uint32 flags;
       
  1182 
       
  1183 		st->had_vehicle_of_type |= HVOT_AIRCRAFT;
       
  1184 		SET_DPARAM16(0, st->index);
       
  1185 		// show newsitem of celebrating citizens
       
  1186 		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
       
  1187 		AddNewsItem(
       
  1188 			STR_A033_CITIZENS_CELEBRATE_FIRST,
       
  1189 			flags,
       
  1190 			v->index,
       
  1191 			0);
       
  1192 	}
       
  1193 
       
  1194 	old_order = v->next_order;
       
  1195 	v->next_order = OT_LOADING;
       
  1196 
       
  1197 	if ((old_order & OT_MASK) == OT_GOTO_STATION &&
       
  1198 			v->next_order_param == v->last_station_visited) {
       
  1199 		v->next_order = OT_LOADING | (old_order & (OF_UNLOAD|OF_FULL_LOAD)) | OF_NON_STOP;
       
  1200 	}
       
  1201 
       
  1202 	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC);
       
  1203 	LoadUnloadVehicle(v);
       
  1204 	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
       
  1205 }
       
  1206 
       
  1207 static void AircraftEnterHangar(Vehicle *v)
       
  1208 {
       
  1209 	byte old_order;
       
  1210 
       
  1211 	ServiceAircraft(v);
       
  1212 	
       
  1213 	MaybeRenewVehicle(v, EstimateAircraftCost(v->engine_type));
       
  1214 
       
  1215 	if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) {
       
  1216 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
  1217 
       
  1218 		old_order = v->next_order;
       
  1219 		v->next_order = OT_NOTHING;
       
  1220 
       
  1221  			if (old_order & OF_UNLOAD) { v->cur_order_index++; }
       
  1222  
       
  1223  			else if (old_order & OF_FULL_LOAD) { // force depot visit
       
  1224 			v->vehstatus |= VS_STOPPED;
       
  1225 
       
  1226 			if (v->owner == _local_player) {
       
  1227 				SET_DPARAM16(0, v->unitnumber);
       
  1228 				AddNewsItem(
       
  1229 					STR_A014_AIRCRAFT_IS_WAITING_IN,
       
  1230 					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
       
  1231 					v->index,
       
  1232 					0);
       
  1233 			}
       
  1234 		}
       
  1235 	}
       
  1236 }
       
  1237 
       
  1238 static void AircraftLand(Vehicle *v)
       
  1239 {
       
  1240 	v->sprite_width = v->sprite_height = 2;
       
  1241 }
       
  1242 
       
  1243 static void AircraftLandAirplane(Vehicle *v)
       
  1244 {
       
  1245 	AircraftLand(v);
       
  1246 	SndPlayVehicleFx(0x15, v);
       
  1247 	MaybeCrashAirplane(v);
       
  1248 }
       
  1249 
       
  1250 // set the right pos when heading to other airports after takeoff
       
  1251 static void AircraftNextAirportPos_and_Order(Vehicle *v)
       
  1252 {
       
  1253 	Station *st;
       
  1254 	const AirportFTAClass *Airport;
       
  1255 
       
  1256 	if ((v->next_order&OT_MASK) == OT_GOTO_STATION ||
       
  1257 			(v->next_order&OT_MASK) == OT_GOTO_DEPOT)
       
  1258 			v->u.air.targetairport = v->next_order_param;
       
  1259 
       
  1260 	st = DEREF_STATION(v->u.air.targetairport);
       
  1261 	Airport = GetAirport(st->airport_type);
       
  1262 	v->u.air.pos = v->u.air.previous_pos = Airport->entry_point;
       
  1263 }
       
  1264 
       
  1265 static void AircraftLeaveHangar(Vehicle *v)
       
  1266 {
       
  1267 	v->cur_speed = 0;
       
  1268 	v->subspeed = 0;
       
  1269 	v->progress = 0;
       
  1270 	v->direction = 3;
       
  1271 	v->vehstatus &= ~VS_HIDDEN;
       
  1272 	{
       
  1273 		Vehicle *u = v->next;
       
  1274 		u->vehstatus &= ~VS_HIDDEN;
       
  1275 
       
  1276 		// Rotor blades
       
  1277 		if ((u=u->next) != NULL) {
       
  1278 			u->vehstatus &= ~VS_HIDDEN;
       
  1279 			u->cur_speed = 80;
       
  1280 		}
       
  1281 	}
       
  1282 
       
  1283 	SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
       
  1284 	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
  1285 }
       
  1286 
       
  1287 
       
  1288 ////////////////////////////////////////////////////////////////////////////////
       
  1289 ///////////////////   AIRCRAFT MOVEMENT SCHEME  ////////////////////////////////
       
  1290 ////////////////////////////////////////////////////////////////////////////////
       
  1291 static void AircraftEventHandler_EnterTerminal(Vehicle *v, const AirportFTAClass *Airport)
       
  1292 {
       
  1293 	AircraftEntersTerminal(v);
       
  1294 	v->u.air.state = Airport->layout[v->u.air.pos].heading;
       
  1295 }
       
  1296 
       
  1297 static void AircraftEventHandler_EnterHangar(Vehicle *v, const AirportFTAClass *Airport)
       
  1298 {
       
  1299 	AircraftEnterHangar(v);
       
  1300 	v->u.air.state = Airport->layout[v->u.air.pos].heading;
       
  1301 }
       
  1302 
       
  1303 // In an Airport Hangar
       
  1304 static void AircraftEventHandler_InHangar(Vehicle *v, const AirportFTAClass *Airport)
       
  1305 {
       
  1306 	// if we just arrived, execute EnterHangar first
       
  1307 	if (v->u.air.previous_pos != v->u.air.pos) {
       
  1308 		AircraftEventHandler_EnterHangar(v, Airport);
       
  1309 		return;
       
  1310 	}
       
  1311 
       
  1312 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT && (v->vehstatus&VS_STOPPED)) { // if we were sent to the depot, stay there
       
  1313 		v->next_order = OT_NOTHING;
       
  1314 		return;
       
  1315 	}
       
  1316 
       
  1317 	if ((v->next_order&OT_MASK) != OT_GOTO_STATION && (v->next_order&OT_MASK) != OT_GOTO_DEPOT)
       
  1318 		return;
       
  1319 
       
  1320 	// if the block of the next position is busy, stay put
       
  1321 	if (AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;}
       
  1322 
       
  1323 	// We are already at the target airport, we need to find a terminal
       
  1324 	if (v->next_order_param == v->u.air.targetairport) {
       
  1325 		// FindFreeTerminal:
       
  1326 		// 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal
       
  1327 		if (v->subtype != 0) {if(!AirportFindFreeTerminal(v, Airport)) {return;}} // airplane
       
  1328 		else {if(!AirportFindFreeHelipad(v, Airport)) {return;}} // helicopter
       
  1329 	}
       
  1330 	else { // Else prepare for launch.
       
  1331 		// airplane goto state takeoff, helicopter to helitakeoff
       
  1332 		v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF;
       
  1333 	}
       
  1334 	AircraftLeaveHangar(v);
       
  1335 	AirportMove(v, Airport);
       
  1336 }
       
  1337 
       
  1338 // At one of the Airport's Terminals
       
  1339 static void AircraftEventHandler_AtTerminal(Vehicle *v, const AirportFTAClass *Airport)
       
  1340 {
       
  1341 	// if we just arrived, execute EnterTerminal first
       
  1342 	if (v->u.air.previous_pos != v->u.air.pos) {
       
  1343 		AircraftEventHandler_EnterTerminal(v, Airport);
       
  1344 		// on an airport with helipads, a helicopter will always land there
       
  1345 		// and get serviced at the same time - patch setting
       
  1346 		if (_patches.serviceathelipad) {
       
  1347 			if (v->subtype == 0 && Airport->nofhelipads > 0) {
       
  1348 				// an exerpt of ServiceAircraft, without the invisibility stuff
       
  1349 				v->date_of_last_service = _date;
       
  1350 				v->breakdowns_since_last_service = 0;
       
  1351 				v->reliability = _engines[v->engine_type].reliability;
       
  1352 				InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
  1353 			}
       
  1354 		}
       
  1355 		return;
       
  1356 	}
       
  1357 
       
  1358 	// removed &0x1F
       
  1359 	if (v->next_order == OT_NOTHING) {return;}
       
  1360 
       
  1361 	// if the block of the next position is busy, stay put
       
  1362 	if (AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {
       
  1363 		return;
       
  1364 	}
       
  1365 
       
  1366 	// airport-road is free. We either have to go to another airport, or to the hangar
       
  1367 	// ---> start moving
       
  1368 
       
  1369 	switch (v->next_order&OT_MASK) {
       
  1370 		case OT_GOTO_STATION: // ready to fly to another airport
       
  1371 			// airplane goto state takeoff, helicopter to helitakeoff
       
  1372 			v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF;
       
  1373 			break;
       
  1374 		case OT_GOTO_DEPOT:   // visit hangar for serivicing, sale, etc.
       
  1375 			if (v->next_order_param == v->u.air.targetairport)
       
  1376 				v->u.air.state = HANGAR;
       
  1377 			else
       
  1378 				v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF;
       
  1379 			break;
       
  1380 		default:  // orders have been deleted (no orders), goto depot and don't bother us
       
  1381 			v->next_order  = OT_NOTHING;
       
  1382 			v->u.air.state = HANGAR;
       
  1383 	}
       
  1384 	AirportMove(v, Airport);
       
  1385 }
       
  1386 
       
  1387 static void AircraftEventHandler_General(Vehicle *v, const AirportFTAClass *Airport)
       
  1388 {
       
  1389 	printf("OK, you shouldn't be here, check your Airport Scheme!\n");
       
  1390 	assert(1 == v->u.air.state); // when here state is 0, so this always fails
       
  1391 }
       
  1392 
       
  1393 static void AircraftEventHandler_TakeOff(Vehicle *v, const AirportFTAClass *Airport) {
       
  1394 	PlayAircraftSound(v); // play takeoffsound for airplanes
       
  1395 	v->u.air.state = STARTTAKEOFF;
       
  1396 }
       
  1397 
       
  1398 static void AircraftEventHandler_StartTakeOff(Vehicle *v, const AirportFTAClass *Airport)
       
  1399 {
       
  1400 	v->sprite_width = v->sprite_height = 24; // ??? no idea what this is
       
  1401 	v->u.air.state = ENDTAKEOFF;
       
  1402 }
       
  1403 
       
  1404 static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *Airport)
       
  1405 {
       
  1406 	v->u.air.state = FLYING;
       
  1407 	// get the next position to go to, differs per airport
       
  1408 	AircraftNextAirportPos_and_Order(v);
       
  1409 }
       
  1410 
       
  1411 static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *Airport)
       
  1412 {
       
  1413 	v->sprite_width = v->sprite_height = 24; // ??? no idea what this is
       
  1414 	v->u.air.state = FLYING;
       
  1415 	// get the next position to go to, differs per airport
       
  1416 	AircraftNextAirportPos_and_Order(v);
       
  1417 }
       
  1418 
       
  1419 static void AircraftEventHandler_Flying(Vehicle *v, const AirportFTAClass *Airport)
       
  1420 {
       
  1421 	Station *st;
       
  1422 	byte landingtype;
       
  1423 	AirportFTA *current;
       
  1424 	uint16 tcur_speed, tsubspeed;
       
  1425 
       
  1426 	st = DEREF_STATION(v->u.air.targetairport);
       
  1427 	// flying device is accepted at this station
       
  1428 	// small airport --> no helicopters (AIRCRAFT_ONLY)
       
  1429 	// all other airports --> all types of flying devices (ALL)
       
  1430 	// heliport/oilrig, etc --> no airplanes (HELICOPTERS_ONLY)
       
  1431 	// runway busy or not allowed to use this airstation, circle
       
  1432 	if (! (v->subtype == Airport->acc_planes ||
       
  1433 			st->airport_tile == 0 || (st->owner != OWNER_NONE && st->owner != v->owner) )) {
       
  1434 
       
  1435 		// {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
       
  1436 		// if it is an airplane, look for LANDING, for helicopter HELILANDING
       
  1437 		// it is possible to choose from multiple landing runways, so loop until a free one is found
       
  1438 		landingtype = (v->subtype != 0) ? LANDING : HELILANDING;
       
  1439 		current = Airport->layout[v->u.air.pos].next_in_chain;
       
  1440 		while (current != NULL) {
       
  1441 			if (current->heading == landingtype) {
       
  1442 				// save speed before, since if AirportHasBlock is false, it resets them to 0
       
  1443 				// we don't want that for plane in air
       
  1444 				// hack for speed thingie
       
  1445 				tcur_speed = v->cur_speed;
       
  1446 				tsubspeed = v->subspeed;
       
  1447 				if (!AirportHasBlock(v, current, Airport)) {
       
  1448 					v->u.air.state = landingtype; // LANDING / HELILANDING
       
  1449 					// it's a bit dirty, but I need to set position to next position, otherwise
       
  1450 					// if there are multiple runways, plane won't know which one it took (because
       
  1451 					// they all have heading LANDING). And also occupy that block!
       
  1452 					v->u.air.pos = current->next_position;
       
  1453 					SETBITS(st->airport_flags, Airport->layout[v->u.air.pos].block);
       
  1454 					return;
       
  1455 				}
       
  1456 				v->cur_speed = tcur_speed;
       
  1457 				v->subspeed = tsubspeed;
       
  1458 			}
       
  1459 			current = current->next_in_chain;
       
  1460 		}
       
  1461 	}
       
  1462 	v->u.air.state = FLYING;
       
  1463 	v->u.air.pos = Airport->layout[v->u.air.pos].next_position;
       
  1464 }
       
  1465 
       
  1466 static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *Airport)
       
  1467 {
       
  1468 	AircraftLandAirplane(v);  // maybe crash airplane
       
  1469 	v->u.air.state = ENDLANDING;
       
  1470 }
       
  1471 
       
  1472 static void AircraftEventHandler_HeliLanding(Vehicle *v, const AirportFTAClass *Airport)
       
  1473 {
       
  1474 	AircraftLand(v); // helicopters don't crash
       
  1475 	v->u.air.state = HELIENDLANDING;
       
  1476 }
       
  1477 
       
  1478 static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *Airport)
       
  1479 {
       
  1480 	// next block busy, don't do a thing, just wait
       
  1481 	if(AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;}
       
  1482 
       
  1483 	// if going to terminal (OT_GOTO_STATION) choose one
       
  1484 	// 1. in case all terminals are busy AirportFindFreeTerminal() returns false or
       
  1485 	// 2. not going for terminal (but depot, no order),
       
  1486 	// --> get out of the way to the hangar.
       
  1487 	if ((v->next_order&OT_MASK) == OT_GOTO_STATION) {
       
  1488 		if (AirportFindFreeTerminal(v, Airport)) {return;}
       
  1489 	}
       
  1490 	v->u.air.state = HANGAR;
       
  1491 
       
  1492 }
       
  1493 
       
  1494 static void AircraftEventHandler_HeliEndLanding(Vehicle *v, const AirportFTAClass *Airport)
       
  1495 {
       
  1496 	// next block busy, don't do a thing, just wait
       
  1497 	if(AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;}
       
  1498 
       
  1499 	// if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal
       
  1500 	// 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or
       
  1501 	// 2. not going for terminal (but depot, no order),
       
  1502 	// --> get out of the way to the hangar IF there are terminals on the airport.
       
  1503 	// --> else TAKEOFF
       
  1504 	// the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes
       
  1505 	// must go to a hangar.
       
  1506 	if ((v->next_order&OT_MASK) == OT_GOTO_STATION) {
       
  1507 		if (AirportFindFreeHelipad(v, Airport)) {return;}
       
  1508 	}
       
  1509 	v->u.air.state = (Airport->nofterminals != 0) ? HANGAR : HELITAKEOFF;
       
  1510 }
       
  1511 
       
  1512 typedef void AircraftStateHandler(Vehicle *v, const AirportFTAClass *Airport);
       
  1513 static AircraftStateHandler * const _aircraft_state_handlers[] = {
       
  1514 	AircraftEventHandler_General,				// TO_ALL         =  0
       
  1515 	AircraftEventHandler_InHangar,			// HANGAR         =  1
       
  1516 	AircraftEventHandler_AtTerminal,		// TERM1          =  2
       
  1517 	AircraftEventHandler_AtTerminal,		// TERM2          =  3
       
  1518 	AircraftEventHandler_AtTerminal,		// TERM3          =  4
       
  1519 	AircraftEventHandler_AtTerminal,		// TERM4          =  5
       
  1520 	AircraftEventHandler_AtTerminal,		// TERM5          =  6
       
  1521 	AircraftEventHandler_AtTerminal,		// TERM6          =  7
       
  1522 	AircraftEventHandler_AtTerminal,		// HELIPAD1       =  8
       
  1523 	AircraftEventHandler_AtTerminal,		// HELIPAD2       =  9
       
  1524 	AircraftEventHandler_TakeOff,				// TAKEOFF        = 10
       
  1525 	AircraftEventHandler_StartTakeOff,	// STARTTAKEOFF   = 11
       
  1526 	AircraftEventHandler_EndTakeOff,		// ENDTAKEOFF     = 12
       
  1527 	AircraftEventHandler_HeliTakeOff,		// HELITAKEOFF    = 13
       
  1528 	AircraftEventHandler_Flying,				// FLYING         = 14
       
  1529 	AircraftEventHandler_Landing,				// LANDING        = 15
       
  1530 	AircraftEventHandler_EndLanding,		// ENDLANDING     = 16
       
  1531 	AircraftEventHandler_HeliLanding,		// HELILANDING    = 17
       
  1532 	AircraftEventHandler_HeliEndLanding,// HELIENDLANDING = 18
       
  1533 };
       
  1534 
       
  1535 static void AirportClearBlock(Vehicle *v, const AirportFTAClass *Airport)
       
  1536 {
       
  1537 	Station *st;
       
  1538 	// we have left the previous block, and entered the new one. Free the previous block
       
  1539 	if (Airport->layout[v->u.air.previous_pos].block != Airport->layout[v->u.air.pos].block) {
       
  1540 		st = DEREF_STATION(v->u.air.targetairport);
       
  1541 		CLRBITS(st->airport_flags, Airport->layout[v->u.air.previous_pos].block);
       
  1542 	}
       
  1543 }
       
  1544 
       
  1545 static void AirportGoToNextPosition(Vehicle *v, const AirportFTAClass *Airport)
       
  1546 {
       
  1547 	// if aircraft is not in position, wait until it is
       
  1548 	if (!Aircraft_5(v)) {return;}
       
  1549 
       
  1550 	AirportClearBlock(v, Airport);
       
  1551 	AirportMove(v, Airport); // move aircraft to next position
       
  1552 }
       
  1553 
       
  1554 // gets pos from vehicle and next orders
       
  1555 static bool AirportMove(Vehicle *v, const AirportFTAClass *Airport)
       
  1556 {
       
  1557 	AirportFTA *current;
       
  1558 	byte prev_pos;
       
  1559 	bool retval = false;
       
  1560 
       
  1561 	// error handling
       
  1562 	if (v->u.air.pos >= Airport->nofelements) {
       
  1563 		printf("position %d is not valid for current airport. Max position is %d\n", v->u.air.pos, Airport->nofelements-1);
       
  1564 		assert(v->u.air.pos < Airport->nofelements);
       
  1565 	}
       
  1566 
       
  1567 	current = &Airport->layout[v->u.air.pos];
       
  1568 	// we have arrived in an important state (eg terminal, hangar, etc.)
       
  1569 	if (current->heading == v->u.air.state) {
       
  1570 		prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand
       
  1571 		_aircraft_state_handlers[v->u.air.state](v, Airport);
       
  1572 		if (v->u.air.state != FLYING) {v->u.air.previous_pos = prev_pos;}
       
  1573 		return true;
       
  1574 	}
       
  1575 
       
  1576 	v->u.air.previous_pos = v->u.air.pos; // save previous location
       
  1577 
       
  1578 	// there is only one choice to move to
       
  1579 	if (current->next_in_chain == NULL) {
       
  1580 		if (AirportSetBlocks(v, current, Airport)) {
       
  1581 			v->u.air.pos = current->next_position;
       
  1582 		} // move to next position
       
  1583 		return retval;
       
  1584 	}
       
  1585 
       
  1586 	// there are more choices to choose from, choose the one that
       
  1587 	// matches our heading
       
  1588 	do {
       
  1589 		if (v->u.air.state == current->heading || current->heading == TO_ALL) {
       
  1590 					if (AirportSetBlocks(v, current, Airport)) {
       
  1591 						v->u.air.pos = current->next_position;
       
  1592 					} // move to next position
       
  1593 					return retval;
       
  1594 		}
       
  1595 		current = current->next_in_chain;
       
  1596 	} while (current != NULL);
       
  1597 
       
  1598 	printf("Cannot move further on Airport...! pos:%d state:%d\n", v->u.air.pos, v->u.air.state);
       
  1599 	printf("Airport entry point: %d, Vehicle: %d\n", Airport->entry_point, v->index);
       
  1600 	assert(0);
       
  1601 	return false;
       
  1602 }
       
  1603 
       
  1604 // returns true if the road ahead is busy, eg. you must wait before proceeding
       
  1605 static bool AirportHasBlock(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport)
       
  1606 {
       
  1607 	Station *st;
       
  1608 	uint32 airport_flags;
       
  1609 	AirportFTA *next, *reference;
       
  1610 	reference = &Airport->layout[v->u.air.pos];
       
  1611 	next = &Airport->layout[current_pos->next_position];
       
  1612 
       
  1613 	// same block, then of course we can move
       
  1614 	if (Airport->layout[current_pos->position].block != next->block) {
       
  1615 		airport_flags = next->block;
       
  1616 		st = DEREF_STATION(v->u.air.targetairport);
       
  1617 		// check additional possible extra blocks
       
  1618 		if (current_pos != reference && current_pos->block != NOTHING_block) {
       
  1619 			airport_flags |= current_pos->block;
       
  1620 		}
       
  1621 
       
  1622 		if (HASBITS(st->airport_flags, airport_flags)) {
       
  1623 			v->cur_speed = 0;
       
  1624 			v->subspeed = 0;
       
  1625 			return true;
       
  1626 		}
       
  1627 	}
       
  1628 	return false;
       
  1629 }
       
  1630 
       
  1631 // returns true on success. Eg, next block was free and we have occupied it
       
  1632 static bool AirportSetBlocks(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport)
       
  1633 {
       
  1634 	Station *st;
       
  1635 	uint32 airport_flags;
       
  1636 	AirportFTA *current, *reference, *next;
       
  1637 	next = &Airport->layout[current_pos->next_position];
       
  1638 	reference = &Airport->layout[v->u.air.pos];
       
  1639 
       
  1640 	// if the next position is in another block, check it and wait until it is free
       
  1641 	if (Airport->layout[current_pos->position].block != next->block) {
       
  1642 		airport_flags = next->block;
       
  1643 		st = DEREF_STATION(v->u.air.targetairport);
       
  1644 		//search for all all elements in the list with the same state, and blocks != N
       
  1645 		// this means more blocks should be checked/set
       
  1646 		current = current_pos;
       
  1647 		if (current == reference) { current = current->next_in_chain;}
       
  1648 		while (current != NULL) {
       
  1649 			if (current->heading == current_pos->heading && current->block != 0) {
       
  1650 				airport_flags |= current->block;
       
  1651 				break;
       
  1652 			}
       
  1653 			current = current->next_in_chain;
       
  1654 		};
       
  1655 
       
  1656 		// if the block to be checked is in the next position, then exclude that from
       
  1657 		// checking, because it has been set by the airplane before
       
  1658 		if (current_pos->block == next->block) {airport_flags ^= next->block;}
       
  1659 
       
  1660 		if (HASBITS(st->airport_flags, airport_flags)) {
       
  1661 			v->cur_speed = 0;
       
  1662 			v->subspeed = 0;
       
  1663 			return false;
       
  1664 		}
       
  1665 
       
  1666 		if (next->block != NOTHING_block) {
       
  1667 			SETBITS(st->airport_flags, airport_flags); // occupy next block
       
  1668 		}
       
  1669 	}
       
  1670 	return true;
       
  1671 }
       
  1672 
       
  1673 static bool FreeTerminal(Vehicle *v, byte i, byte last_terminal)
       
  1674 {
       
  1675 	Station *st = DEREF_STATION(v->u.air.targetairport);
       
  1676 	for (; i < last_terminal; i++) {
       
  1677 		if (!HASBIT(st->airport_flags, i)) {
       
  1678 			// TERMINAL# HELIPAD#
       
  1679 			v->u.air.state = i + TERM1; // start moving to that terminal/helipad
       
  1680 			SETBIT(st->airport_flags, i); // occupy terminal/helipad
       
  1681 			return true;
       
  1682 		}
       
  1683 	}
       
  1684 	return false;
       
  1685 }
       
  1686 
       
  1687 static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *Airport) 
       
  1688 {
       
  1689 	byte nofterminalspergroup, i;
       
  1690 	AirportFTA *temp;
       
  1691 	Station *st;
       
  1692 
       
  1693 	/* example of more terminalgroups
       
  1694 		{0,HANGAR,NOTHING_block,1}, {0,255,TERM_GROUP1_block,0}, {0,255,TERM_GROUP2_ENTER_block,1}, {0,0,N,1},
       
  1695 		Heading 255 denotes a group. We see 2 groups here:
       
  1696 		1. group 0 -- TERM_GROUP1_block (check block)
       
  1697 		2. group 1 -- TERM_GROUP2_ENTER_block (check block)
       
  1698 		First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it 
       
  1699 		looks	at the corresponding terminals of that group. If no free ones are found, other 
       
  1700 		possible groups are checked	(in this case group 1, since that is after group 0). If that 
       
  1701 		fails, then attempt fails and plane waits
       
  1702 	*/
       
  1703 	if (Airport->nofterminalgroups > 1) {
       
  1704 		st = DEREF_STATION(v->u.air.targetairport);
       
  1705 		nofterminalspergroup = Airport->nofterminals / Airport->nofterminalgroups;
       
  1706 		temp = Airport->layout[v->u.air.pos].next_in_chain;
       
  1707 		while (temp != NULL) {
       
  1708 			if (temp->heading == 255) {
       
  1709 				if (!HASBITS(st->airport_flags, temp->block)) {
       
  1710 					i = temp->next_position * nofterminalspergroup; // next_position denotes the group to check
       
  1711 					// only that group will be checked (eg 6 terms, 2 groups)
       
  1712 					// with i = 0 terms 1 - 3 and
       
  1713 					// with i = 1 terms 4 - 6
       
  1714 					if (FreeTerminal(v, i, i + nofterminalspergroup)) {return true;}
       
  1715 				}
       
  1716 			}
       
  1717 			else {return false;} // once the heading isn't 255, we've exhausted the possible blocks. So we cannot move
       
  1718 			temp = temp->next_in_chain;
       
  1719 		}
       
  1720 	}
       
  1721 
       
  1722 	// if there is only 1 terminalgroup, all terminals are checked (starting from 0 to max)
       
  1723 	return FreeTerminal(v, 0, Airport->nofterminals);
       
  1724 }
       
  1725 
       
  1726 static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *Airport) 
       
  1727 {
       
  1728   Station *st;
       
  1729   byte nofhelipadspergroup,  i;
       
  1730   AirportFTA *temp;
       
  1731 
       
  1732 	// if an airport doesn't have helipads, use terminals
       
  1733 	if (Airport->nofhelipads == 0) {return AirportFindFreeTerminal(v, Airport);}
       
  1734 
       
  1735 	// if there are more helicoptergroups, pick one, just as in AirportFindFreeTerminal()
       
  1736 	if (Airport->nofhelipadgroups > 1) {
       
  1737 		st = DEREF_STATION(v->u.air.targetairport);
       
  1738 		nofhelipadspergroup = Airport->nofhelipads / Airport->nofhelipadgroups;
       
  1739 		temp = Airport->layout[v->u.air.pos].next_in_chain;
       
  1740 		while (temp != NULL) {
       
  1741 			if (temp->heading == 255) {
       
  1742 				if (!HASBITS(st->airport_flags, temp->block)) {
       
  1743 					i = temp->next_position * nofhelipadspergroup; // next position is the group to check
       
  1744 					// heliports start from after TERMINALS, so MAX_TERMINALS needs to be added
       
  1745 					if (FreeTerminal(v, i + MAX_TERMINALS, i + MAX_TERMINALS + nofhelipadspergroup)) {return true;}
       
  1746 				}
       
  1747 			}
       
  1748 			else {return false;} // once the heading isn't 255, we've exhausted the possible blocks. So we cannot move
       
  1749 			temp = temp->next_in_chain;
       
  1750 		}
       
  1751 	}
       
  1752 	// only 1 helicoptergroup, check all helipads
       
  1753 	// The blocks for helipads start after the last terminal (MAX_TERMINALS)
       
  1754 	else {return FreeTerminal(v, MAX_TERMINALS, Airport->nofhelipads + MAX_TERMINALS);}
       
  1755 	return false;	// it shouldn't get here anytime, but just to be sure
       
  1756 }
       
  1757 
       
  1758 static void AircraftEventHandler(Vehicle *v, int loop)
       
  1759 {
       
  1760 	v->tick_counter++;
       
  1761 
       
  1762 	if (v->vehstatus & VS_CRASHED) {
       
  1763 		HandleCrashedAircraft(v);
       
  1764 		return;
       
  1765 	}
       
  1766 
       
  1767 	/* exit if aircraft is stopped */
       
  1768 	if (v->vehstatus & VS_STOPPED)
       
  1769 		return;
       
  1770 
       
  1771 	/* aircraft is broken down? */
       
  1772 	if (v->breakdown_ctr != 0) {
       
  1773 		if (v->breakdown_ctr <= 2) {
       
  1774 			HandleBrokenAircraft(v);
       
  1775 		} else {
       
  1776 			v->breakdown_ctr--;
       
  1777 		}
       
  1778 	}
       
  1779 
       
  1780 	HandleAircraftSmoke(v);
       
  1781 	ProcessAircraftOrder(v);
       
  1782 	HandleAircraftLoading(v, loop);
       
  1783 
       
  1784 	if ((v->next_order&OT_MASK) >= OT_LOADING)
       
  1785 		return;
       
  1786 
       
  1787 	// pass the right airport structure to the functions
       
  1788 	// DEREF_STATION gets target airport (Station *st), its type is passed to GetAirport
       
  1789 	// that returns the correct layout depending on type
       
  1790 	AirportGoToNextPosition(v, GetAirport(DEREF_STATION(v->u.air.targetairport)->airport_type));
       
  1791 }
       
  1792 
       
  1793 void Aircraft_Tick(Vehicle *v)
       
  1794 {
       
  1795 	int i;
       
  1796 
       
  1797 	if (v->subtype > 2)
       
  1798 		return;
       
  1799 
       
  1800 	if (v->subtype == 0)
       
  1801 		HelicopterTickHandler(v);
       
  1802 
       
  1803 	AgeAircraftCargo(v);
       
  1804 
       
  1805 	for(i=0; i!=6; i++) {
       
  1806 		AircraftEventHandler(v, i);
       
  1807 		if (v->type != VEH_Aircraft) // In case it was deleted
       
  1808 			break;
       
  1809 	}
       
  1810 }
       
  1811 
       
  1812 // need to be called to load aircraft from old version
       
  1813 void UpdateOldAircraft()
       
  1814 {
       
  1815 	Station *st;
       
  1816 	Vehicle *v_oldstyle;
       
  1817 	GetNewVehiclePosResult gp;
       
  1818 
       
  1819 	// set airport_flags to 0 for all airports just to be sure
       
  1820 	FOR_ALL_STATIONS(st) {
       
  1821 		st->airport_flags = 0; // reset airport
       
  1822 		// type of oilrig has been moved, update it (3-5)
       
  1823 		if (st->airport_type == 3) {st->airport_type = AT_OILRIG;}
       
  1824 	}
       
  1825 
       
  1826 	FOR_ALL_VEHICLES(v_oldstyle) {
       
  1827 	// airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
       
  1828 	// skip those
       
  1829 		if (v_oldstyle->type == VEH_Aircraft && v_oldstyle->subtype <= 2) {
       
  1830 			// airplane in terminal stopped doesn't hurt anyone, so goto next
       
  1831 			if ((v_oldstyle->vehstatus & VS_STOPPED) && (v_oldstyle->u.air.state == 0)) {
       
  1832 				v_oldstyle->u.air.state = HANGAR;
       
  1833 				continue;
       
  1834 			}
       
  1835 
       
  1836 			AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example
       
  1837 			v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving
       
  1838 			v_oldstyle->u.air.state = FLYING;
       
  1839 			AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport
       
  1840 			GetNewVehiclePos(v_oldstyle, &gp); // get the position of the plane (to be used for setting)
       
  1841 			v_oldstyle->tile = 0; // aircraft in air is tile=0
       
  1842 			
       
  1843 			// correct speed of helicopter-rotors
       
  1844 			if (v_oldstyle->subtype == 0) {v_oldstyle->next->next->cur_speed = 32;}
       
  1845 
       
  1846 			// set new position x,y,z
       
  1847 			SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle));
       
  1848 		}
       
  1849 	}
       
  1850 }
       
  1851 
       
  1852 void UpdateAirplanesOnNewStation(Station *st) 
       
  1853 {
       
  1854 	GetNewVehiclePosResult gp;
       
  1855 	Vehicle *v;
       
  1856 	byte takeofftype;
       
  1857 	uint16 cnt;
       
  1858 	// only 1 station is updated per function call, so it is enough to get entry_point once
       
  1859 	const AirportFTAClass *ap = GetAirport(st->airport_type);
       
  1860 	FOR_ALL_VEHICLES(v) {
       
  1861 		if (v->type == VEH_Aircraft && v->subtype <= 2) {
       
  1862 			if (v->u.air.targetairport == st->index) {	// if heading to this airport
       
  1863 				/*	update position of airplane. If plane is not flying, landing, or taking off
       
  1864 						you cannot delete airport, so it doesn't matter
       
  1865 				*/
       
  1866 				if (v->u.air.state >= FLYING) {	// circle around
       
  1867 					v->u.air.pos = v->u.air.previous_pos = ap->entry_point;
       
  1868 					v->u.air.state = FLYING;
       
  1869 					// landing plane needs to be reset to flying height (only if in pause mode upgrade,
       
  1870 					// in normal mode, plane is reset in Aircraft_5. It doesn't hurt for FLYING
       
  1871 					GetNewVehiclePos(v, &gp);
       
  1872 					// set new position x,y,z
       
  1873 					SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
       
  1874 				}
       
  1875 				else {
       
  1876 					assert(v->u.air.state == ENDTAKEOFF || v->u.air.state == HELITAKEOFF);
       
  1877 					takeofftype = (v->subtype == 0) ? HELITAKEOFF : ENDTAKEOFF;
       
  1878 					// search in airportdata for that heading
       
  1879 					// easiest to do, since this doesn't happen a lot
       
  1880 					for (cnt = 0; cnt < ap->nofelements; cnt++) {
       
  1881 						if (ap->layout[cnt].heading == takeofftype) {
       
  1882 							v->u.air.pos = ap->layout[cnt].position;
       
  1883 							break;
       
  1884 						}
       
  1885 					}
       
  1886 				}
       
  1887 			}
       
  1888 		}
       
  1889 	}
       
  1890 }