# articulated_vehicles.cpp

Go to the documentation of this file.

    00001 /* $Id: articulated_vehicles.cpp 15299 2009-01-31 20:16:06Z smatz $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "train.h"
    00007 #include "roadveh.h"
    00008 #include "newgrf_engine.h"
    00009 #include "vehicle_func.h"
    00010
    00011 static const uint MAX_ARTICULATED_PARTS = 100;
    00012
    00013 uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
    00014 {
    00015   if (!HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return 0;
    00016
    00017   /* If we can't allocate a vehicle now, we can't allocate it in the command
    00018    * either, so it doesn't matter how many articulated parts there are. */
    00019   if (!Vehicle::CanAllocateItem()) return 0;
    00020
    00021   Vehicle *v = NULL;;
    00022   if (!purchase_window) {
    00023     v = new InvalidVehicle();
    00024     v->engine_type = engine_type;
    00025   }
    00026
    00027   uint i;
    00028   for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00029     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v);
    00030     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00031   }
    00032
    00033   delete v;
    00034
    00035   return i - 1;
    00036 }
    00037
    00038
    00046 static inline uint16 GetVehicleDefaultCapacity(EngineID engine, VehicleType type, CargoID *cargo_type)
    00047 {
    00048   switch (type) {
    00049     case VEH_TRAIN: {
    00050       const RailVehicleInfo *rvi = RailVehInfo(engine);
    00051       if (cargo_type != NULL) *cargo_type = rvi->cargo_type;
    00052       return GetEngineProperty(engine, 0x14, rvi->capacity) + (rvi->railveh_type == RAILVEH_MULTIHEAD ? rvi->capacity : 0);
    00053     }
    00054
    00055     case VEH_ROAD: {
    00056       const RoadVehicleInfo *rvi = RoadVehInfo(engine);
    00057       if (cargo_type != NULL) *cargo_type = rvi->cargo_type;
    00058       return GetEngineProperty(engine, 0x0F, rvi->capacity);
    00059     }
    00060
    00061     case VEH_SHIP: {
    00062       const ShipVehicleInfo *svi = ShipVehInfo(engine);
    00063       if (cargo_type != NULL) *cargo_type = svi->cargo_type;
    00064       return GetEngineProperty(engine, 0x0D, svi->capacity);
    00065     }
    00066
    00067     case VEH_AIRCRAFT: {
    00068       const AircraftVehicleInfo *avi = AircraftVehInfo(engine);
    00069       if (cargo_type != NULL) *cargo_type = CT_PASSENGERS;
    00070       return avi->passenger_capacity;
    00071     }
    00072
    00073     default: NOT_REACHED();
    00074   }
    00075
    00076 }
    00077
    00085 static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00086 {
    00087   uint32 cargos = 0;
    00088   CargoID initial_cargo_type;
    00089
    00090   if (GetVehicleDefaultCapacity(engine, type, &initial_cargo_type) > 0) {
    00091     if (type != VEH_SHIP || ShipVehInfo(engine)->refittable) {
    00092       const EngineInfo *ei = EngInfo(engine);
    00093       cargos = ei->refit_mask;
    00094     }
    00095     if (include_initial_cargo_type && initial_cargo_type < NUM_CARGO) SetBit(cargos, initial_cargo_type);
    00096   }
    00097
    00098   return cargos;
    00099 }
    00100
    00101 uint16 *GetCapacityOfArticulatedParts(EngineID engine, VehicleType type)
    00102 {
    00103   static uint16 capacity[NUM_CARGO];
    00104   memset(capacity, 0, sizeof(capacity));
    00105
    00106   CargoID cargo_type;
    00107   uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, type, &cargo_type);
    00108   if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
    00109
    00110   if (type != VEH_TRAIN && type != VEH_ROAD) return capacity;
    00111
    00112   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
    00113
    00114   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00115     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00116     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00117
    00118     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00119
    00120     cargo_capacity = GetVehicleDefaultCapacity(artic_engine, type, &cargo_type);
    00121     if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
    00122   }
    00123
    00124   return capacity;
    00125 }
    00126
    00135 uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00136 {
    00137   uint32 cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
    00138
    00139   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
    00140
    00141   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
    00142
    00143   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00144     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00145     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00146
    00147     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00148     cargos |= GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
    00149   }
    00150
    00151   return cargos;
    00152 }
    00153
    00162 uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00163 {
    00164   uint32 cargos = UINT32_MAX;
    00165
    00166   uint32 veh_cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
    00167   if (veh_cargos != 0) cargos &= veh_cargos;
    00168
    00169   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
    00170
    00171   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
    00172
    00173   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00174     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00175     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00176
    00177     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00178     veh_cargos = GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
    00179     if (veh_cargos != 0) cargos &= veh_cargos;
    00180   }
    00181
    00182   return cargos;
    00183 }
    00184
    00185
    00193 bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *cargo_type)
    00194 {
    00195   CargoID first_cargo = CT_INVALID;
    00196
    00197   do {
    00198     if (v->cargo_cap > 0 && v->cargo_type != CT_INVALID) {
    00199       if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
    00200       if (first_cargo != v->cargo_type) {
    00201         if (cargo_type != NULL) *cargo_type = CT_INVALID;
    00202         return true;
    00203       }
    00204     }
    00205
    00206     switch (v->type) {
    00207       case VEH_TRAIN:
    00208         v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
    00209         break;
    00210
    00211       case VEH_ROAD:
    00212         v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
    00213         break;
    00214
    00215       default:
    00216         v = NULL;
    00217         break;
    00218     }
    00219   } while (v != NULL);
    00220
    00221   if (cargo_type != NULL) *cargo_type = first_cargo;
    00222   return false;
    00223 }
    00224
    00225
    00226 void AddArticulatedParts(Vehicle **vl, VehicleType type)
    00227 {
    00228   const Vehicle *v = vl[0];
    00229   Vehicle *u = vl[0];
    00230
    00231   if (!HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return;
    00232
    00233   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00234     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, v->engine_type, v);
    00235     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return;
    00236
    00237     /* Attempt to use pre-allocated vehicles until they run out. This can happen
    00238      * if the callback returns different values depending on the cargo type. */
    00239     u->SetNext(vl[i]);
    00240     if (u->Next() == NULL) return;
    00241
    00242     Vehicle *previous = u;
    00243     u = u->Next();
    00244
    00245     EngineID engine_type = GetNewEngineID(GetEngineGRF(v->engine_type), type, GB(callback, 0, 7));
    00246     bool flip_image = HasBit(callback, 7);
    00247
    00248     /* get common values from first engine */
    00249     u->direction = v->direction;
    00250     u->owner = v->owner;
    00251     u->tile = v->tile;
    00252     u->x_pos = v->x_pos;
    00253     u->y_pos = v->y_pos;
    00254     u->z_pos = v->z_pos;
    00255     u->build_year = v->build_year;
    00256     u->vehstatus = v->vehstatus & ~VS_STOPPED;
    00257
    00258     u->cargo_subtype = 0;
    00259     u->max_speed = 0;
    00260     u->max_age = 0;
    00261     u->engine_type = engine_type;
    00262     u->value = 0;
    00263     u->subtype = 0;
    00264     u->cur_image = 0xAC2;
    00265     u->random_bits = VehicleRandomBits();
    00266
    00267     switch (type) {
    00268       default: NOT_REACHED();
    00269
    00270       case VEH_TRAIN: {
    00271         const RailVehicleInfo *rvi_artic = RailVehInfo(engine_type);
    00272
    00273         u = new (u) Train();
    00274         previous->SetNext(u);
    00275         u->u.rail.track = v->u.rail.track;
    00276         u->u.rail.railtype = v->u.rail.railtype;
    00277         u->u.rail.first_engine = v->engine_type;
    00278
    00279         u->spritenum = rvi_artic->image_index;
    00280         u->cargo_type = rvi_artic->cargo_type;
    00281         u->cargo_cap = rvi_artic->capacity;  // Callback 36 is called when the consist is finished
    00282
    00283         SetArticulatedPart(u);
    00284       } break;
    00285
    00286       case VEH_ROAD: {
    00287         const RoadVehicleInfo *rvi_artic = RoadVehInfo(engine_type);
    00288
    00289         u = new (u) RoadVehicle();
    00290         previous->SetNext(u);
    00291         u->u.road.first_engine = v->engine_type;
    00292         u->u.road.cached_veh_length = GetRoadVehLength(u);
    00293         u->u.road.state = RVSB_IN_DEPOT;
    00294
    00295         u->u.road.roadtype = v->u.road.roadtype;
    00296         u->u.road.compatible_roadtypes = v->u.road.compatible_roadtypes;
    00297
    00298         u->spritenum = rvi_artic->image_index;
    00299         u->cargo_type = rvi_artic->cargo_type;
    00300         u->cargo_cap = rvi_artic->capacity;  // Callback 36 is called when the consist is finished
    00301
    00302         SetRoadVehArticPart(u);
    00303       } break;
    00304     }
    00305
    00306     if (flip_image) u->spritenum++;
    00307
    00308     VehiclePositionChanged(u);
    00309   }
    00310 }