diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 6e0ce75ec6..80e2497104 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -483,36 +483,8 @@ static uint32 PositionHelper(const Vehicle *v, bool consecutive) return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16; } -static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) +static uint32 VehicleGetVariable(Vehicle *v, const ResolverObject *object, byte variable, byte parameter, bool *available) { - Vehicle *v = const_cast(GRV(object)); - - if (v == NULL) { - /* Vehicle does not exist, so we're in a purchase list */ - switch (variable) { - case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(object->u.vehicle.self_type, NULL)); // Owner information - case 0x46: return 0; // Motion counter - case 0x47: { // Vehicle cargo info - const Engine *e = Engine::Get(object->u.vehicle.self_type); - CargoID cargo_type = e->GetDefaultCargoType(); - if (cargo_type != CT_INVALID) { - const CargoSpec *cs = CargoSpec::Get(cargo_type); - return (cs->classes << 16) | (cs->weight << 8) | GetEngineGRF(e->index)->cargo_map[cargo_type]; - } else { - return 0x000000FF; - } - } - case 0x48: return Engine::Get(object->u.vehicle.self_type)->flags; // Vehicle Type Info - case 0x49: return _cur_year; // 'Long' format build year - case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year - case 0xDA: return INVALID_VEHICLE; // Next vehicle - case 0xF2: return 0; // Cargo subtype - } - - *available = false; - return UINT_MAX; - } - /* Calculated vehicle parameters */ switch (variable) { case 0x25: // Get engine GRF ID @@ -668,6 +640,18 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by return count; } + case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle] + if (!v->IsGroundVehicle() || parameter == 0x61) return 0; + + /* Only allow callbacks that don't change properties to avoid circular dependencies. */ + if (object->callback == CBID_NO_CALLBACK || object->callback == CBID_TRAIN_ALLOW_WAGON_ATTACH || object->callback == CBID_VEHICLE_START_STOP_CHECK || object->callback == CBID_VEHICLE_32DAY_CALLBACK) { + Vehicle *u = v->Move((int32)GetRegister(0x10F)); + if (u == NULL) return 0; + + return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available); + } + return 0; + case 0xFE: case 0xFF: { uint16 modflags = 0; @@ -846,6 +830,39 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by return UINT_MAX; } +static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) +{ + Vehicle *v = const_cast(GRV(object)); + + if (v == NULL) { + /* Vehicle does not exist, so we're in a purchase list */ + switch (variable) { + case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(object->u.vehicle.self_type, NULL)); // Owner information + case 0x46: return 0; // Motion counter + case 0x47: { // Vehicle cargo info + const Engine *e = Engine::Get(object->u.vehicle.self_type); + CargoID cargo_type = e->GetDefaultCargoType(); + if (cargo_type != CT_INVALID) { + const CargoSpec *cs = CargoSpec::Get(cargo_type); + return (cs->classes << 16) | (cs->weight << 8) | GetEngineGRF(e->index)->cargo_map[cargo_type]; + } else { + return 0x000000FF; + } + } + case 0x48: return Engine::Get(object->u.vehicle.self_type)->flags; // Vehicle Type Info + case 0x49: return _cur_year; // 'Long' format build year + case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year + case 0xDA: return INVALID_VEHICLE; // Next vehicle + case 0xF2: return 0; // Cargo subtype + } + + *available = false; + return UINT_MAX; + } + + return VehicleGetVariable(v, object, variable, parameter, available); +} + static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const RealSpriteGroup *group) { diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 958144115a..5fc2500ebc 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -498,6 +498,22 @@ public: return v; } + /** + * Get the vehicle at offset #n of this vehicle chain. + * @param n Offset from the current vehicle. + * @return The new vehicle or NULL if the offset is out-of-bounds. + */ + inline Vehicle *Move(int n) + { + Vehicle *v = this; + if (n < 0) { + for (int i = 0; i != n && v != NULL; i--) v = v->Previous(); + } else { + for (int i = 0; i != n && v != NULL; i++) v = v->Next(); + } + return v; + } + /** * Get the first order of the vehicles order list. * @return first order of order list.