src/aircraft_cmd.cpp
branchgamebalance
changeset 9911 0b8b245a2391
parent 9910 0b2aebc8283e
child 9913 e79cd19772dd
equal deleted inserted replaced
9910:0b2aebc8283e 9911:0b8b245a2391
    31 #include "newgrf_sound.h"
    31 #include "newgrf_sound.h"
    32 #include "date.h"
    32 #include "date.h"
    33 #include "spritecache.h"
    33 #include "spritecache.h"
    34 #include "cargotype.h"
    34 #include "cargotype.h"
    35 
    35 
       
    36 void Aircraft::UpdateDeltaXY(Direction direction)
       
    37 {
       
    38 	uint32 x;
       
    39 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
       
    40 	switch (this->subtype) {
       
    41 		default: NOT_REACHED();
       
    42 		case AIR_AIRCRAFT:
       
    43 		case AIR_HELICOPTER:
       
    44 			switch (this->u.air.state) {
       
    45 				case ENDTAKEOFF:
       
    46 				case LANDING:
       
    47 				case HELILANDING:
       
    48 				case FLYING:     x = MKIT(24, 24, -1, -1); break;
       
    49 				default:         x = MKIT( 2,  2, -1, -1); break;
       
    50 			}
       
    51 			this->z_height = 5;
       
    52 			break;
       
    53 		case AIR_SHADOW:     this->z_height = 1; x = MKIT(2,  2,  0,  0); break;
       
    54 		case AIR_ROTOR:      this->z_height = 1; x = MKIT(2,  2, -1, -1); break;
       
    55 	}
       
    56 #undef MKIT
       
    57 
       
    58 	this->x_offs        = GB(x,  0, 8);
       
    59 	this->y_offs        = GB(x,  8, 8);
       
    60 	this->sprite_width  = GB(x, 16, 8);
       
    61 	this->sprite_height = GB(x, 24, 8);
       
    62 }
       
    63 
       
    64 
    36 /** this maps the terminal to its corresponding state and block flag
    65 /** this maps the terminal to its corresponding state and block flag
    37  *  currently set for 10 terms, 4 helipads */
    66  *  currently set for 10 terms, 4 helipads */
    38 static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22};
    67 static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22};
    39 static const byte _airport_terminal_flag[] =  {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25};
    68 static const byte _airport_terminal_flag[] =  {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25};
    40 
    69 
   196 
   225 
   197 	width  = spr->width ;
   226 	width  = spr->width ;
   198 	height = spr->height;
   227 	height = spr->height;
   199 }
   228 }
   200 
   229 
   201 static int32 EstimateAircraftCost(const AircraftVehicleInfo *avi)
   230 static int32 EstimateAircraftCost(EngineID engine, const AircraftVehicleInfo *avi)
   202 {
   231 {
   203 	return avi->base_cost * (_eco->GetPrice(CEconomy::AIRCRAFT_BASE) >> 3) >> 5;
   232 	return GetEngineProperty(engine, 0x0B, avi->base_cost) * (_eco->GetPrice(CEconomy::AIRCRAFT_BASE) >> 3) >> 5;
   204 }
   233 }
   205 
   234 
   206 
   235 
   207 /**
   236 /**
   208  * Calculates cargo capacity based on an aircraft's passenger
   237  * Calculates cargo capacity based on an aircraft's passenger
   239 int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   268 int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   240 {
   269 {
   241 	if (!IsEngineBuildable(p1, VEH_AIRCRAFT, _current_player)) return_cmd_error(STR_AIRCRAFT_NOT_AVAILABLE);
   270 	if (!IsEngineBuildable(p1, VEH_AIRCRAFT, _current_player)) return_cmd_error(STR_AIRCRAFT_NOT_AVAILABLE);
   242 
   271 
   243 	const AircraftVehicleInfo *avi = AircraftVehInfo(p1);
   272 	const AircraftVehicleInfo *avi = AircraftVehInfo(p1);
   244 	int32 value = EstimateAircraftCost(avi);
   273 	int32 value = EstimateAircraftCost(p1, avi);
   245 
   274 
   246 	/* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
   275 	/* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
   247 	if (flags & DC_QUERY_COST) return value;
   276 	if (flags & DC_QUERY_COST) return value;
   248 
   277 
   249 	if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
   278 	if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
   267 	if (flags & DC_EXEC) {
   296 	if (flags & DC_EXEC) {
   268 		Vehicle *v = vl[0]; // aircraft
   297 		Vehicle *v = vl[0]; // aircraft
   269 		Vehicle *u = vl[1]; // shadow
   298 		Vehicle *u = vl[1]; // shadow
   270 
   299 
   271 		v->unitnumber = unit_num;
   300 		v->unitnumber = unit_num;
   272 		v->type = u->type = VEH_AIRCRAFT;
   301 		v = new (v) Aircraft();
       
   302 		u = new (u) Aircraft();
   273 		v->direction = DIR_SE;
   303 		v->direction = DIR_SE;
   274 
   304 
   275 		v->owner = u->owner = _current_player;
   305 		v->owner = u->owner = _current_player;
   276 
   306 
   277 		v->tile = tile;
   307 		v->tile = tile;
   284 		v->y_pos = u->y_pos = y;
   314 		v->y_pos = u->y_pos = y;
   285 
   315 
   286 		u->z_pos = GetSlopeZ(x, y);
   316 		u->z_pos = GetSlopeZ(x, y);
   287 		v->z_pos = u->z_pos + 1;
   317 		v->z_pos = u->z_pos + 1;
   288 
   318 
   289 		v->x_offs = v->y_offs = -1;
       
   290 //		u->delta_x = u->delta_y = 0;
   319 //		u->delta_x = u->delta_y = 0;
   291 
       
   292 		v->sprite_width = v->sprite_height = 2;
       
   293 		v->z_height = 5;
       
   294 
       
   295 		u->sprite_width = u->sprite_height = 2;
       
   296 		u->z_height = 1;
       
   297 
   320 
   298 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
   321 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
   299 		u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW;
   322 		u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW;
   300 
   323 
   301 		v->spritenum = avi->image_index;
   324 		v->spritenum = avi->image_index;
   320 		v->max_speed = avi->max_speed;
   343 		v->max_speed = avi->max_speed;
   321 		v->acceleration = avi->acceleration;
   344 		v->acceleration = avi->acceleration;
   322 		v->engine_type = p1;
   345 		v->engine_type = p1;
   323 
   346 
   324 		v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER);
   347 		v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER);
       
   348 		v->UpdateDeltaXY(INVALID_DIR);
   325 		v->value = value;
   349 		v->value = value;
   326 
   350 
   327 		u->subtype = AIR_SHADOW;
   351 		u->subtype = AIR_SHADOW;
       
   352 		u->UpdateDeltaXY(INVALID_DIR);
   328 
   353 
   329 		/* Danger, Will Robinson!
   354 		/* Danger, Will Robinson!
   330 		 * If the aircraft is refittable, but cannot be refitted to
   355 		 * If the aircraft is refittable, but cannot be refitted to
   331 		 * passengers, we select the cargo type from the refit mask.
   356 		 * passengers, we select the cargo type from the refit mask.
   332 		 * This is a fairly nasty hack to get around the fact that TTD
   357 		 * This is a fairly nasty hack to get around the fact that TTD
   402 		if (v->subtype == AIR_HELICOPTER) {
   427 		if (v->subtype == AIR_HELICOPTER) {
   403 			Vehicle *w = vl[2];
   428 			Vehicle *w = vl[2];
   404 
   429 
   405 			u->next = w;
   430 			u->next = w;
   406 
   431 
   407 			w->type = VEH_AIRCRAFT;
   432 			w = new (w) Aircraft();
   408 			w->direction = DIR_N;
   433 			w->direction = DIR_N;
   409 			w->owner = _current_player;
   434 			w->owner = _current_player;
   410 			w->x_pos = v->x_pos;
   435 			w->x_pos = v->x_pos;
   411 			w->y_pos = v->y_pos;
   436 			w->y_pos = v->y_pos;
   412 			w->z_pos = v->z_pos + 5;
   437 			w->z_pos = v->z_pos + 5;
   413 			w->x_offs = w->y_offs = -1;
       
   414 			w->sprite_width = w->sprite_height = 2;
       
   415 			w->z_height = 1;
       
   416 			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
   438 			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
   417 			w->spritenum = 0xFF;
   439 			w->spritenum = 0xFF;
   418 			w->subtype = AIR_ROTOR;
   440 			w->subtype = AIR_ROTOR;
   419 			w->cur_image = SPR_ROTOR_STOPPED;
   441 			w->cur_image = SPR_ROTOR_STOPPED;
   420 			w->random_bits = VehicleRandomBits();
   442 			w->random_bits = VehicleRandomBits();
   421 			/* Use rotor's air.state to store the rotor animation frame */
   443 			/* Use rotor's air.state to store the rotor animation frame */
   422 			w->u.air.state = HRS_ROTOR_STOPPED;
   444 			w->u.air.state = HRS_ROTOR_STOPPED;
       
   445 			w->UpdateDeltaXY(INVALID_DIR);
   423 			VehiclePositionChanged(w);
   446 			VehiclePositionChanged(w);
   424 		}
   447 		}
   425 
   448 
   426 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
   449 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
   427 		RebuildVehicleLists();
   450 		RebuildVehicleLists();
   595  * @param flags for command type
   618  * @param flags for command type
   596  * @param p1 vehicle ID of the aircraft to refit
   619  * @param p1 vehicle ID of the aircraft to refit
   597  * @param p2 various bitstuffed elements
   620  * @param p2 various bitstuffed elements
   598  * - p2 = (bit 0-7) - the new cargo type to refit to
   621  * - p2 = (bit 0-7) - the new cargo type to refit to
   599  * - p2 = (bit 8-15) - the new cargo subtype to refit to
   622  * - p2 = (bit 8-15) - the new cargo subtype to refit to
       
   623  * - p2 = (bit 16) - refit only this vehicle (ignored)
   600  * @return cost of refit or error
   624  * @return cost of refit or error
   601  */
   625  */
   602 int32 CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   626 int32 CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   603 {
   627 {
   604 	byte new_subtype = GB(p2, 8, 8);
   628 	byte new_subtype = GB(p2, 8, 8);
   693 	const Station *st = GetStation(v->current_order.dest);
   717 	const Station *st = GetStation(v->current_order.dest);
   694 	/* only goto depot if the target airport has terminals (eg. it is airport) */
   718 	/* only goto depot if the target airport has terminals (eg. it is airport) */
   695 	if (st->IsValid() && st->airport_tile != 0 && st->Airport()->terminals != NULL) {
   719 	if (st->IsValid() && st->airport_tile != 0 && st->Airport()->terminals != NULL) {
   696 //		printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index);
   720 //		printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index);
   697 //		v->u.air.targetairport = st->index;
   721 //		v->u.air.targetairport = st->index;
       
   722 		if (v->current_order.type == OT_LOADING) v->LeaveStation();
   698 		v->current_order.type = OT_GOTO_DEPOT;
   723 		v->current_order.type = OT_GOTO_DEPOT;
   699 		v->current_order.flags = OF_NON_STOP;
   724 		v->current_order.flags = OF_NON_STOP;
   700 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
   725 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
   701 	} else if (v->current_order.type == OT_GOTO_DEPOT) {
   726 	} else if (v->current_order.type == OT_GOTO_DEPOT) {
   702 		v->current_order.type = OT_DUMMY;
   727 		v->current_order.type = OT_DUMMY;
  1066 			if (st->airport_tile == 0) {
  1091 			if (st->airport_tile == 0) {
  1067 				/* FIXME - AircraftController -> if station no longer exists, do not land
  1092 				/* FIXME - AircraftController -> if station no longer exists, do not land
  1068 				 * helicopter will circle until sign disappears, then go to next order
  1093 				 * helicopter will circle until sign disappears, then go to next order
  1069 				 * what to do when it is the only order left, right now it just stays in 1 place */
  1094 				 * what to do when it is the only order left, right now it just stays in 1 place */
  1070 				v->u.air.state = FLYING;
  1095 				v->u.air.state = FLYING;
       
  1096 				UpdateAircraftCache(v);
  1071 				AircraftNextAirportPos_and_Order(v);
  1097 				AircraftNextAirportPos_and_Order(v);
  1072 				return false;
  1098 				return false;
  1073 			}
  1099 			}
  1074 
  1100 
  1075 			/* Vehicle is now at the airport. */
  1101 			/* Vehicle is now at the airport. */
  1180 
  1206 
  1181 		if (amd->flag & AMED_LAND) {
  1207 		if (amd->flag & AMED_LAND) {
  1182 			if (st->airport_tile == 0) {
  1208 			if (st->airport_tile == 0) {
  1183 				/* Airport has been removed, abort the landing procedure */
  1209 				/* Airport has been removed, abort the landing procedure */
  1184 				v->u.air.state = FLYING;
  1210 				v->u.air.state = FLYING;
       
  1211 				UpdateAircraftCache(v);
  1185 				AircraftNextAirportPos_and_Order(v);
  1212 				AircraftNextAirportPos_and_Order(v);
  1186 				/* get aircraft back on running altitude */
  1213 				/* get aircraft back on running altitude */
  1187 				SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
  1214 				SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
  1188 				continue;
  1215 				continue;
  1189 			}
  1216 			}
  1382 	InvalidateVehicleOrder(v);
  1409 	InvalidateVehicleOrder(v);
  1383 
  1410 
  1384 	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
  1411 	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
  1385 }
  1412 }
  1386 
  1413 
  1387 /** Mark all views dirty for an aircraft.
  1414 void Aircraft::MarkDirty()
  1388  * @param v vehicle to be redrawn.
  1415 {
  1389  */
  1416 		this->cur_image = GetAircraftImage(this, this->direction);
  1390 static void MarkAircraftDirty(Vehicle *v)
  1417 		if (this->subtype == AIR_HELICOPTER) this->next->next->cur_image = GetRotorImage(this);
  1391 {
  1418 		MarkAllViewportsDirty(this->left_coord, this->top_coord, this->right_coord + 1, this->bottom_coord + 1);
  1392 		v->cur_image = GetAircraftImage(v, v->direction);
       
  1393 		if (v->subtype == AIR_HELICOPTER) v->next->next->cur_image = GetRotorImage(v);
       
  1394 		MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
       
  1395 }
       
  1396 
       
  1397 static void HandleAircraftLoading(Vehicle *v, int mode)
       
  1398 {
       
  1399 	switch (v->current_order.type) {
       
  1400 		case OT_LOADING: {
       
  1401 			if (mode != 0) return;
       
  1402 			if (--v->load_unload_time_rem != 0) return;
       
  1403 
       
  1404 			if (CanFillVehicle(v) && (
       
  1405 						v->current_order.flags & OF_FULL_LOAD ||
       
  1406 						(_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED))
       
  1407 					)) {
       
  1408 				SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC);
       
  1409 				if (LoadUnloadVehicle(v, false)) {
       
  1410 					InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
       
  1411 					MarkAircraftDirty(v);
       
  1412 				}
       
  1413 				return;
       
  1414 			}
       
  1415 
       
  1416 			Order b = v->current_order;
       
  1417 			v->LeaveStation();
       
  1418 			v->current_order.Free();
       
  1419 			MarkAircraftDirty(v);
       
  1420 			if (!(b.flags & OF_NON_STOP)) return;
       
  1421 			break;
       
  1422 		}
       
  1423 
       
  1424 		case OT_DUMMY: break;
       
  1425 
       
  1426 		default: return;
       
  1427 	}
       
  1428 
       
  1429 	v->cur_order_index++;
       
  1430 	InvalidateVehicleOrder(v);
       
  1431 }
  1419 }
  1432 
  1420 
  1433 static void CrashAirplane(Vehicle *v)
  1421 static void CrashAirplane(Vehicle *v)
  1434 {
  1422 {
  1435 	v->vehstatus |= VS_CRASHED;
  1423 	v->vehstatus |= VS_CRASHED;
  1507 			flags,
  1495 			flags,
  1508 			v->index,
  1496 			v->index,
  1509 			0);
  1497 			0);
  1510 	}
  1498 	}
  1511 
  1499 
  1512 	Order old_order = v->current_order;
       
  1513 	v->BeginLoading();
  1500 	v->BeginLoading();
  1514 	v->current_order.flags = 0;
       
  1515 
       
  1516 	if (old_order.type == OT_GOTO_STATION &&
       
  1517 			v->current_order.dest == v->last_station_visited) {
       
  1518 		v->current_order.flags =
       
  1519 			(old_order.flags & (OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER)) | OF_NON_STOP;
       
  1520 	}
       
  1521 
       
  1522 	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC);
       
  1523 	LoadUnloadVehicle(v, true);
       
  1524 	MarkAircraftDirty(v);
       
  1525 	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
  1526 	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
       
  1527 }
       
  1528 
       
  1529 static void AircraftLand(Vehicle *v)
       
  1530 {
       
  1531 	v->sprite_width = v->sprite_height = 2;
       
  1532 }
  1501 }
  1533 
  1502 
  1534 static void AircraftLandAirplane(Vehicle *v)
  1503 static void AircraftLandAirplane(Vehicle *v)
  1535 {
  1504 {
  1536 	AircraftLand(v);
  1505 	v->UpdateDeltaXY(INVALID_DIR);
       
  1506 
  1537 	if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
  1507 	if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
  1538 		SndPlayVehicleFx(SND_17_SKID_PLANE, v);
  1508 		SndPlayVehicleFx(SND_17_SKID_PLANE, v);
  1539 	}
  1509 	}
  1540 	MaybeCrashAirplane(v);
  1510 	MaybeCrashAirplane(v);
  1541 }
  1511 }
  1690 	v->u.air.state = STARTTAKEOFF;
  1660 	v->u.air.state = STARTTAKEOFF;
  1691 }
  1661 }
  1692 
  1662 
  1693 static void AircraftEventHandler_StartTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1663 static void AircraftEventHandler_StartTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1694 {
  1664 {
  1695 	v->sprite_width = v->sprite_height = 24; // ??? no idea what this is
       
  1696 	v->u.air.state = ENDTAKEOFF;
  1665 	v->u.air.state = ENDTAKEOFF;
       
  1666 	v->UpdateDeltaXY(INVALID_DIR);
  1697 }
  1667 }
  1698 
  1668 
  1699 static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1669 static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1700 {
  1670 {
  1701 	v->u.air.state = FLYING;
  1671 	v->u.air.state = FLYING;
  1704 }
  1674 }
  1705 
  1675 
  1706 static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1676 static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *apc)
  1707 {
  1677 {
  1708 	const Player* p = GetPlayer(v->owner);
  1678 	const Player* p = GetPlayer(v->owner);
  1709 	v->sprite_width = v->sprite_height = 24; // ??? no idea what this is
       
  1710 	v->u.air.state = FLYING;
  1679 	v->u.air.state = FLYING;
       
  1680 	v->UpdateDeltaXY(INVALID_DIR);
       
  1681 
  1711 	/* get the next position to go to, differs per airport */
  1682 	/* get the next position to go to, differs per airport */
  1712 	AircraftNextAirportPos_and_Order(v);
  1683 	AircraftNextAirportPos_and_Order(v);
  1713 
  1684 
  1714 	/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed
  1685 	/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed
  1715 	 * unless it is due for renewal but the engine is no longer available */
  1686 	 * unless it is due for renewal but the engine is no longer available */
  1716 	if (v->owner == _local_player && (
  1687 	if (v->owner == _local_player && (
  1717 				EngineHasReplacementForPlayer(p, v->engine_type) ||
  1688 				EngineHasReplacementForPlayer(p, v->engine_type, v->group_id) ||
  1718 				((p->engine_renew && v->age - v->max_age > p->engine_renew_months * 30) &&
  1689 				((p->engine_renew && v->age - v->max_age > p->engine_renew_months * 30) &&
  1719 				HASBIT(GetEngine(v->engine_type)->player_avail, _local_player))
  1690 				HASBIT(GetEngine(v->engine_type)->player_avail, _local_player))
  1720 			)) {
  1691 			)) {
  1721 		_current_player = _local_player;
  1692 		_current_player = _local_player;
  1722 		DoCommandP(v->tile, v->index, DEPOT_SERVICE | DEPOT_LOCATE_HANGAR, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
  1693 		DoCommandP(v->tile, v->index, DEPOT_SERVICE | DEPOT_LOCATE_HANGAR, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
  1763 	v->u.air.pos = apc->layout[v->u.air.pos].next_position;
  1734 	v->u.air.pos = apc->layout[v->u.air.pos].next_position;
  1764 }
  1735 }
  1765 
  1736 
  1766 static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *apc)
  1737 static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *apc)
  1767 {
  1738 {
       
  1739 	v->u.air.state = ENDLANDING;
  1768 	AircraftLandAirplane(v);  // maybe crash airplane
  1740 	AircraftLandAirplane(v);  // maybe crash airplane
  1769 	v->u.air.state = ENDLANDING;
  1741 
  1770 	/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
  1742 	/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
  1771 	if (v->current_order.type != OT_GOTO_DEPOT && v->owner == _local_player) {
  1743 	if (v->current_order.type != OT_GOTO_DEPOT && v->owner == _local_player) {
  1772 		/* only the vehicle owner needs to calculate the rest (locally) */
  1744 		/* only the vehicle owner needs to calculate the rest (locally) */
  1773 		const Player* p = GetPlayer(v->owner);
  1745 		const Player* p = GetPlayer(v->owner);
  1774 		if (EngineHasReplacementForPlayer(p, v->engine_type) ||
  1746 		if (EngineHasReplacementForPlayer(p, v->engine_type, v->group_id) ||
  1775 			(p->engine_renew && v->age - v->max_age > (p->engine_renew_months * 30))) {
  1747 			(p->engine_renew && v->age - v->max_age > (p->engine_renew_months * 30))) {
  1776 			/* send the aircraft to the hangar at next airport */
  1748 			/* send the aircraft to the hangar at next airport */
  1777 			_current_player = _local_player;
  1749 			_current_player = _local_player;
  1778 			DoCommandP(v->tile, v->index, DEPOT_SERVICE, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
  1750 			DoCommandP(v->tile, v->index, DEPOT_SERVICE, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
  1779 			_current_player = OWNER_NONE;
  1751 			_current_player = OWNER_NONE;
  1781 	}
  1753 	}
  1782 }
  1754 }
  1783 
  1755 
  1784 static void AircraftEventHandler_HeliLanding(Vehicle *v, const AirportFTAClass *apc)
  1756 static void AircraftEventHandler_HeliLanding(Vehicle *v, const AirportFTAClass *apc)
  1785 {
  1757 {
  1786 	AircraftLand(v); // helicopters don't crash
       
  1787 	v->u.air.state = HELIENDLANDING;
  1758 	v->u.air.state = HELIENDLANDING;
       
  1759 	v->UpdateDeltaXY(INVALID_DIR);
  1788 }
  1760 }
  1789 
  1761 
  1790 static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *apc)
  1762 static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *apc)
  1791 {
  1763 {
  1792 	/* next block busy, don't do a thing, just wait */
  1764 	/* next block busy, don't do a thing, just wait */
  1883 	if (current->heading == v->u.air.state) {
  1855 	if (current->heading == v->u.air.state) {
  1884 		byte prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand
  1856 		byte prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand
  1885 		byte prev_state = v->u.air.state;
  1857 		byte prev_state = v->u.air.state;
  1886 		_aircraft_state_handlers[v->u.air.state](v, apc);
  1858 		_aircraft_state_handlers[v->u.air.state](v, apc);
  1887 		if (v->u.air.state != FLYING) v->u.air.previous_pos = prev_pos;
  1859 		if (v->u.air.state != FLYING) v->u.air.previous_pos = prev_pos;
  1888 		if (v->u.air.state != prev_state) UpdateAircraftCache(v);
  1860 		if (v->u.air.state != prev_state || v->u.air.pos != prev_pos) UpdateAircraftCache(v);
  1889 		return true;
  1861 		return true;
  1890 	}
  1862 	}
  1891 
  1863 
  1892 	v->u.air.previous_pos = v->u.air.pos; // save previous location
  1864 	v->u.air.previous_pos = v->u.air.pos; // save previous location
  1893 
  1865 
  1894 	/* there is only one choice to move to */
  1866 	/* there is only one choice to move to */
  1895 	if (current->next == NULL) {
  1867 	if (current->next == NULL) {
  1896 		if (AirportSetBlocks(v, current, apc)) {
  1868 		if (AirportSetBlocks(v, current, apc)) {
  1897 			v->u.air.pos = current->next_position;
  1869 			v->u.air.pos = current->next_position;
       
  1870 			UpdateAircraftCache(v);
  1898 		} // move to next position
  1871 		} // move to next position
  1899 		return false;
  1872 		return false;
  1900 	}
  1873 	}
  1901 
  1874 
  1902 	/* there are more choices to choose from, choose the one that
  1875 	/* there are more choices to choose from, choose the one that
  1903 	 * matches our heading */
  1876 	 * matches our heading */
  1904 	do {
  1877 	do {
  1905 		if (v->u.air.state == current->heading || current->heading == TO_ALL) {
  1878 		if (v->u.air.state == current->heading || current->heading == TO_ALL) {
  1906 			if (AirportSetBlocks(v, current, apc)) {
  1879 			if (AirportSetBlocks(v, current, apc)) {
  1907 				v->u.air.pos = current->next_position;
  1880 				v->u.air.pos = current->next_position;
       
  1881 				UpdateAircraftCache(v);
  1908 			} // move to next position
  1882 			} // move to next position
  1909 			return false;
  1883 			return false;
  1910 		}
  1884 		}
  1911 		current = current->next;
  1885 		current = current->next;
  1912 	} while (current != NULL);
  1886 	} while (current != NULL);
  2130 		}
  2104 		}
  2131 	}
  2105 	}
  2132 
  2106 
  2133 	HandleAircraftSmoke(v);
  2107 	HandleAircraftSmoke(v);
  2134 	ProcessAircraftOrder(v);
  2108 	ProcessAircraftOrder(v);
  2135 	HandleAircraftLoading(v, loop);
  2109 	v->HandleLoading(loop != 0);
  2136 
  2110 
  2137 	if (v->current_order.type >= OT_LOADING) return;
  2111 	if (v->current_order.type >= OT_LOADING) return;
  2138 
  2112 
  2139 	AirportGoToNextPosition(v);
  2113 	AirportGoToNextPosition(v);
  2140 }
  2114 }
  2207 				/* update position of airplane. If plane is not flying, landing, or taking off
  2181 				/* update position of airplane. If plane is not flying, landing, or taking off
  2208 				 * you cannot delete airport, so it doesn't matter */
  2182 				 * you cannot delete airport, so it doesn't matter */
  2209 				if (v->u.air.state >= FLYING) { // circle around
  2183 				if (v->u.air.state >= FLYING) { // circle around
  2210 					v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, ap);
  2184 					v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, ap);
  2211 					v->u.air.state = FLYING;
  2185 					v->u.air.state = FLYING;
       
  2186 					UpdateAircraftCache(v);
  2212 					/* landing plane needs to be reset to flying height (only if in pause mode upgrade,
  2187 					/* landing plane needs to be reset to flying height (only if in pause mode upgrade,
  2213 					 * in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING */
  2188 					 * in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING */
  2214 					GetNewVehiclePosResult gp = GetNewVehiclePos(v);
  2189 					GetNewVehiclePosResult gp = GetNewVehiclePos(v);
  2215 					/* set new position x,y,z */
  2190 					/* set new position x,y,z */
  2216 					SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
  2191 					SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
  2220 					/* search in airportdata for that heading
  2195 					/* search in airportdata for that heading
  2221 					 * easiest to do, since this doesn't happen a lot */
  2196 					 * easiest to do, since this doesn't happen a lot */
  2222 					for (uint cnt = 0; cnt < ap->nofelements; cnt++) {
  2197 					for (uint cnt = 0; cnt < ap->nofelements; cnt++) {
  2223 						if (ap->layout[cnt].heading == takeofftype) {
  2198 						if (ap->layout[cnt].heading == takeofftype) {
  2224 							v->u.air.pos = ap->layout[cnt].position;
  2199 							v->u.air.pos = ap->layout[cnt].position;
       
  2200 							UpdateAircraftCache(v);
  2225 							break;
  2201 							break;
  2226 						}
  2202 						}
  2227 					}
  2203 					}
  2228 				}
  2204 				}
  2229 			}
  2205 			}