diff --git a/src/engine_type.h b/src/engine_type.h index f0b6ea5450..3eccc663e1 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -155,7 +155,7 @@ enum EngineMiscFlags { EF_ROAD_TRAM = 0, ///< Road vehicle is a tram/light rail vehicle EF_USES_2CC = 1, ///< Vehicle uses two company colours EF_RAIL_IS_MU = 2, ///< Rail vehicle is a multiple-unit (DMU/EMU) - EF_RAIL_FLIPS = 3, ///< Rail vehicle can be flipped in the depot + EF_RAIL_FLIPS = 3, ///< Rail vehicle has old depot-flip handling EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed EF_NO_DEFAULT_CARGO_MULTIPLIER = 5, ///< Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipliers. CB 15 is also called in purchase list. EF_NO_BREAKDOWN_SMOKE = 6, ///< Do not show black smoke during a breakdown. diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 09e8c6fd4e..6045a8438a 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -328,7 +328,6 @@ struct GRFTempEngineData { uint8 roadtramtype; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. - bool prop27_set; ///< Did the NewGRF set property 27 (misc flags)? uint8 rv_max_speed; ///< Temporary storage of RV prop 15, maximum speed in mph/0.8 CargoTypes ctt_include_mask; ///< Cargo types always included in the refit mask. CargoTypes ctt_exclude_mask; ///< Cargo types always excluded from the refit mask. @@ -1295,7 +1294,6 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop case 0x27: // Miscellaneous flags ei->misc_flags = buf->ReadByte(); _loaded_newgrf_features.has_2CC |= HasBit(ei->misc_flags, EF_USES_2CC); - _gted[e->index].prop27_set = true; break; case 0x28: // Cargo classes allowed @@ -8985,13 +8983,6 @@ static void FinaliseEngineArray() if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - /* When the train does not set property 27 (misc flags), but it - * is overridden by a NewGRF graphically we want to disable the - * flipping possibility. */ - if (e->type == VEH_TRAIN && !_gted[e->index].prop27_set && e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { - ClrBit(e->info.misc_flags, EF_RAIL_FLIPS); - } - /* Skip wagons, there livery is defined via the engine */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { LiveryScheme ls = GetEngineLiveryScheme(e->index, INVALID_ENGINE, nullptr); diff --git a/src/table/engines.h b/src/table/engines.h index ab6ba77467..2a207dd760 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -24,7 +24,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_FLIPS, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a multiple-unit train into the EngineInfo struct. @@ -37,7 +37,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_FLIPS | 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a train carriage into the EngineInfo struct. @@ -50,7 +50,7 @@ * @see MT * @note the 5 between b and f is the load amount */ -#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_FLIPS, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a road vehicle into the EngineInfo struct. diff --git a/src/train.h b/src/train.h index 1e5583ea65..4592d32bd8 100644 --- a/src/train.h +++ b/src/train.h @@ -116,6 +116,7 @@ struct Train FINAL : public GroundVehicle { int GetDisplaySpeed() const override { return this->gcache.last_speed; } int GetDisplayMaxSpeed() const override { return this->vcache.cached_max_speed; } Money GetRunningCost() const override; + int GetCursorImageOffset() const; int GetDisplayImageWidth(Point *offset = nullptr) const; bool IsInDepot() const override { return this->track == TRACK_BIT_DEPOT; } bool Tick() override; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index d9f4358691..f30e4d5f6e 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -434,6 +434,21 @@ void Train::UpdateAcceleration() this->acceleration = Clamp(power / weight * 4, 1, 255); } +int Train::GetCursorImageOffset() const +{ + if (this->gcache.cached_veh_length != 8 && HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) { + int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH; + + const Engine *e = this->GetEngine(); + if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { + reference_width = e->GetGRF()->traininfo_vehicle_width; + } + + return ScaleSpriteTrad((this->gcache.cached_veh_length - (int)VEHICLE_LENGTH) * reference_width / (int)VEHICLE_LENGTH); + } + return 0; +} + /** * Get the width of a train vehicle image in the GUI. * @param offset Additional offset for positioning the sprite; set to nullptr if not needed @@ -451,7 +466,11 @@ int Train::GetDisplayImageWidth(Point *offset) const } if (offset != nullptr) { - offset->x = ScaleSpriteTrad(reference_width) / 2; + if (HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) { + offset->x = ScaleSpriteTrad((this->gcache.cached_veh_length - VEHICLE_LENGTH / 2) * reference_width / VEHICLE_LENGTH); + } else { + offset->x = ScaleSpriteTrad(reference_width) / 2; + } offset->y = ScaleSpriteTrad(vehicle_pitch); } return ScaleSpriteTrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH); @@ -1438,7 +1457,15 @@ void Train::UpdateDeltaXY() this->x_bb_offs = 0; this->y_bb_offs = 0; - if (!IsDiagonalDirection(this->direction)) { + /* Set if flipped and engine is NOT flagged with custom flip handling. */ + int flipped = HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS); + /* If flipped and vehicle length is odd, we need to adjust the bounding box offset slightly. */ + int flip_offs = flipped && (this->gcache.cached_veh_length & 1); + + Direction dir = this->direction; + if (flipped) dir = ReverseDir(dir); + + if (!IsDiagonalDirection(dir)) { static const int _sign_table[] = { /* x, y */ @@ -1448,25 +1475,25 @@ void Train::UpdateDeltaXY() 1, -1, // DIR_W }; - int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2; + int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length + flipped) / 2; /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */ - this->x_offs -= half_shorten * _sign_table[this->direction]; - this->y_offs -= half_shorten * _sign_table[this->direction + 1]; - this->x_extent += this->x_bb_offs = half_shorten * _sign_table[direction]; - this->y_extent += this->y_bb_offs = half_shorten * _sign_table[direction + 1]; + this->x_offs -= half_shorten * _sign_table[dir]; + this->y_offs -= half_shorten * _sign_table[dir + 1]; + this->x_extent += this->x_bb_offs = half_shorten * _sign_table[dir]; + this->y_extent += this->y_bb_offs = half_shorten * _sign_table[dir + 1]; } else { - switch (this->direction) { + switch (dir) { /* Shorten southern corner of the bounding box according the vehicle length * and center the bounding box on the vehicle. */ case DIR_NE: - this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2; + this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs; this->x_extent = this->gcache.cached_veh_length - 1; this->x_bb_offs = -1; break; case DIR_NW: - this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2; + this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs; this->y_extent = this->gcache.cached_veh_length - 1; this->y_bb_offs = -1; break; @@ -1474,13 +1501,13 @@ void Train::UpdateDeltaXY() /* Move northern corner of the bounding box down according to vehicle length * and center the bounding box on the vehicle. */ case DIR_SW: - this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH; + this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs; this->x_extent = VEHICLE_LENGTH - 1; this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; break; case DIR_SE: - this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH; + this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs; this->y_extent = VEHICLE_LENGTH - 1; this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; break; @@ -1975,7 +2002,6 @@ CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool if (v->IsMultiheaded() || HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) { return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS); } - if (!HasBit(EngInfo(v->engine_type)->misc_flags, EF_RAIL_FLIPS)) return CMD_ERROR; Train *front = v->First(); /* make sure the vehicle is stopped in the depot */ diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index cb09ea86d8..a0388a6c54 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -3418,11 +3418,14 @@ void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type) if (_cursor.sprite_count + seq.count > lengthof(_cursor.sprite_seq)) break; + int x_offs = 0; + if (v->type == VEH_TRAIN) x_offs = Train::From(v)->GetCursorImageOffset(); + for (uint i = 0; i < seq.count; ++i) { PaletteID pal2 = (v->vehstatus & VS_CRASHED) || !seq.seq[i].pal ? pal : seq.seq[i].pal; _cursor.sprite_seq[_cursor.sprite_count].sprite = seq.seq[i].sprite; _cursor.sprite_seq[_cursor.sprite_count].pal = pal2; - _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width; + _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? (-total_width + x_offs) : (total_width + x_offs); _cursor.sprite_pos[_cursor.sprite_count].y = y_offset; _cursor.sprite_count++; }