diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 6019f477fa..f371d16af4 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -803,9 +803,10 @@ byte GetAircraftFlyingAltitude(const Aircraft *v) * * @param v The vehicle that is approaching the airport * @param apc The Airport Class being approached. + * @param rotation The rotation of the airport. * @returns The index of the entry point */ -static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc) +static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation) { assert(v != NULL); assert(apc != NULL); @@ -832,6 +833,7 @@ static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc) /* We are northwest or southeast of the airport */ dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE; } + dir = ChangeDiagDir(dir, (DiagDirDiff)ReverseDiagDir(DirToDiagDir(rotation))); return apc->entry_points[dir]; } @@ -863,7 +865,7 @@ static bool AircraftController(Aircraft *v) if (st == NULL || st->airport.tile == INVALID_TILE) { /* Jump into our "holding pattern" state machine if possible */ if (v->pos >= afc->nofelements) { - v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc); + v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N); } else if (v->targetairport != v->current_order.GetDestination()) { /* If not possible, just get out of here fast */ v->state = FLYING; @@ -1358,7 +1360,8 @@ void AircraftNextAirportPos_and_Order(Aircraft *v) const Station *st = GetTargetAirportIfValid(v); const AirportFTAClass *apc = st == NULL ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); - v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc); + Direction rotation = st == NULL ? DIR_N : st->airport.rotation; + v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation); } void AircraftLeaveHangar(Aircraft *v) @@ -1997,7 +2000,8 @@ void UpdateAirplanesOnNewStation(const Station *st) /* update position of airplane. If plane is not flying, landing, or taking off * you cannot delete airport, so it doesn't matter */ if (v->state >= FLYING) { // circle around - v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap); + Direction rotation = st->airport.tile == INVALID_TILE ? DIR_N : st->airport.rotation; + v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation); v->state = FLYING; UpdateAircraftCache(v); /* landing plane needs to be reset to flying height (only if in pause mode upgrade, diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index a5fda15674..00297d62aa 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -356,7 +356,11 @@ public: this->DisableWidget(BAIRW_LAYOUT_INCREASE); } else { const AirportSpec *as = GetAirportSpecFromClass(_selected_airport_class, _selected_airport_index); - SetTileSelectSize(as->size_x, as->size_y); + int w = as->size_x; + int h = as->size_y; + Direction rotation = as->rotation[_selected_airport_layout]; + if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); + SetTileSelectSize(w, h); this->SetWidgetDisabledState(BAIRW_LAYOUT_DECREASE, _selected_airport_layout == 0); this->SetWidgetDisabledState(BAIRW_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); diff --git a/src/newgrf_airport.h b/src/newgrf_airport.h index bcaa7e274c..5895a00cb9 100644 --- a/src/newgrf_airport.h +++ b/src/newgrf_airport.h @@ -59,6 +59,7 @@ struct HangarTileTable { struct AirportSpec { const struct AirportFTAClass *fsm; ///< the finite statemachine for the default airports const AirportTileTable * const *table; ///< list of the tiles composing the airport + Direction *rotation; ///< the rotation of each tiletable byte num_table; ///< number of elements in the table const HangarTileTable *depot_table; ///< gives the position of the depots on the airports byte nof_depots; ///< the number of hangar tiles in this airport diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index a57c71c55c..31f024cd0d 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -337,6 +337,7 @@ static const SaveLoad _station_desc[] = { SLE_VAR(Station, airport.type, SLE_UINT8), SLE_CONDVAR(Station, airport.layout, SLE_UINT8, 145, SL_MAX_VERSION), SLE_VAR(Station, airport.flags, SLE_UINT64), + SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, 145, SL_MAX_VERSION), SLE_VAR(Station, indtype, SLE_UINT8), diff --git a/src/station_base.h b/src/station_base.h index 5329a26428..997539943d 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -49,9 +49,10 @@ struct GoodsEntry { struct Airport : public TileArea { Airport() : TileArea(INVALID_TILE, 0, 0) {} - uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 - byte type; ///< Type of this airport, @see AirportTypes. - byte layout; ///< Airport layout number. + uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 + byte type; ///< Type of this airport, @see AirportTypes. + byte layout; ///< Airport layout number. + Direction rotation; ///< How this airport is rotated. /** * Get the AirportSpec that from the airport type of this airport. If there @@ -81,6 +82,30 @@ struct Airport : public TileArea { return this->GetSpec()->nof_depots > 0; } + /** + * Add the tileoffset to the base tile of this airport but rotate it first. + * The base tile is the northernmost tile of this airport. This function + * helps to make sure that getting the tile of a hangar works even for + * rotated airport layouts without requiring a rotated array of hangar tiles. + * @param tidc The tilediff to add to the airport tile. + * @return The tile of this airport plus the rotated offset. + */ + FORCEINLINE TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const + { + const AirportSpec *as = this->GetSpec(); + switch (this->rotation) { + case DIR_N: return this->tile + ToTileIndexDiff(tidc); + + case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x); + + case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y); + + case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x); + + default: NOT_REACHED(); + } + } + /** * Get the first tile of the given hangar. * @param hangar_num The hangar to get the location of. @@ -92,7 +117,7 @@ struct Airport : public TileArea { const AirportSpec *as = this->GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { if (as->depot_table[i].hangar_num == hangar_num) { - return this->tile + ToTileIndexDiff(as->depot_table[i].ti); + return this->GetRotatedTileFromOffset(as->depot_table[i].ti); } } NOT_REACHED(); @@ -108,7 +133,7 @@ struct Airport : public TileArea { { const AirportSpec *as = this->GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { - if (this->tile + ToTileIndexDiff(as->depot_table[i].ti) == tile) { + if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) { return as->depot_table[i].hangar_num; } } diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 67000272b9..3265679094 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2125,9 +2125,11 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint const AirportSpec *as = AirportSpec::Get(airport_type); if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR; + Direction rotation = as->rotation[layout]; Town *t = ClosestTownFromTile(tile, UINT_MAX); int w = as->size_x; int h = as->size_y; + if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); if (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread) { return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); @@ -2216,6 +2218,7 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint st->airport.type = airport_type; st->airport.layout = layout; st->airport.flags = 0; + st->airport.rotation = rotation; st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY); diff --git a/src/table/airport_defaults.h b/src/table/airport_defaults.h index dfebdc1d50..5e2d82b727 100644 --- a/src/table/airport_defaults.h +++ b/src/table/airport_defaults.h @@ -373,21 +373,25 @@ static AirportTileTable *_tile_table_helistation[] = { _tile_table_helistation_0, }; +static Direction _default_airports_rotation[] = { + DIR_N, +}; + #undef MK #undef MKEND /** General AirportSpec definition. */ -#define AS_GENERIC(fsm, att, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, enabled) \ - {fsm, att, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, enabled, {AT_INVALID, 0, NULL, NULL, AT_INVALID}} +#define AS_GENERIC(fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, enabled) \ + {fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, enabled, {AT_INVALID, 0, NULL, NULL, AT_INVALID}} /** AirportSpec definition for airports without any depot. */ #define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, ttdpatch_type, class_id, name) \ - AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, lengthof(_tile_table_##ap_name), NULL, 0, \ + AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), NULL, 0, \ size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, true) /** AirportSpec definition for airports with at least one depot. */ #define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, ttdpatch_type, class_id, name) \ - AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, lengthof(_tile_table_##ap_name), _airport_depots_##ap_name, lengthof(_airport_depots_##ap_name), \ + AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), _airport_depots_##ap_name, lengthof(_airport_depots_##ap_name), \ size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, true) /* The helidepot and helistation have ATP_TTDP_SMALL because they are at ground level */ @@ -401,12 +405,12 @@ extern const AirportSpec _origin_airport_specs[] = { AS(helidepot, 2, 2, 1976, MAX_YEAR, 4, 2, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELIDEPOT), AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERCONTINENTAL), AS(helistation, 4, 2, 1980, MAX_YEAR, 4, 3, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELISTATION), - AS_GENERIC(&_airportfta_oilrig, NULL, 0, NULL, 0, 1, 1, 0, 4, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, false), + AS_GENERIC(&_airportfta_oilrig, NULL, _default_airports_rotation, 0, NULL, 0, 1, 1, 0, 4, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, false), }; assert_compile(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); -AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, false); +AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, _default_airports_rotation, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, false); #undef AS #undef AS_ND