# articulated_vehicles.cpp

Go to the documentation of this file.

    00001 /* $Id: articulated_vehicles.cpp 15765 2009-03-18 19:50:34Z rubidium $ */
    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 #include "table/strings.h"
    00012
    00013 static const uint MAX_ARTICULATED_PARTS = 100;
    00014
    00015 uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
    00016 {
    00017   if (!HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return 0;
    00018
    00019   /* If we can't allocate a vehicle now, we can't allocate it in the command
    00020    * either, so it doesn't matter how many articulated parts there are. */
    00021   if (!Vehicle::CanAllocateItem()) return 0;
    00022
    00023   Vehicle *v = NULL;;
    00024   if (!purchase_window) {
    00025     v = new InvalidVehicle();
    00026     v->engine_type = engine_type;
    00027   }
    00028
    00029   uint i;
    00030   for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00031     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v);
    00032     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00033   }
    00034
    00035   delete v;
    00036
    00037   return i - 1;
    00038 }
    00039
    00040
    00048 static inline uint16 GetVehicleDefaultCapacity(EngineID engine, VehicleType type, CargoID *cargo_type)
    00049 {
    00050   const Engine *e = GetEngine(engine);
    00051   CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
    00052   if (cargo_type != NULL) *cargo_type = cargo;
    00053   if (cargo == CT_INVALID) return 0;
    00054   return e->GetDisplayDefaultCapacity();
    00055 }
    00056
    00064 static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00065 {
    00066   uint32 cargos = 0;
    00067   CargoID initial_cargo_type;
    00068
    00069   if (GetVehicleDefaultCapacity(engine, type, &initial_cargo_type) > 0) {
    00070     if (type != VEH_SHIP || ShipVehInfo(engine)->refittable) {
    00071       const EngineInfo *ei = EngInfo(engine);
    00072       cargos = ei->refit_mask;
    00073     }
    00074     if (include_initial_cargo_type && initial_cargo_type < NUM_CARGO) SetBit(cargos, initial_cargo_type);
    00075   }
    00076
    00077   return cargos;
    00078 }
    00079
    00080 uint16 *GetCapacityOfArticulatedParts(EngineID engine, VehicleType type)
    00081 {
    00082   static uint16 capacity[NUM_CARGO];
    00083   memset(capacity, 0, sizeof(capacity));
    00084
    00085   CargoID cargo_type;
    00086   uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, type, &cargo_type);
    00087   if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
    00088
    00089   if (type != VEH_TRAIN && type != VEH_ROAD) return capacity;
    00090
    00091   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
    00092
    00093   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00094     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00095     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00096
    00097     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00098
    00099     cargo_capacity = GetVehicleDefaultCapacity(artic_engine, type, &cargo_type);
    00100     if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
    00101   }
    00102
    00103   return capacity;
    00104 }
    00105
    00111 bool IsArticulatedVehicleRefittable(EngineID engine)
    00112 {
    00113   if (IsEngineRefittable(engine)) return true;
    00114
    00115   const Engine *e = GetEngine(engine);
    00116   if (e->type != VEH_TRAIN && e->type != VEH_ROAD) return false;
    00117
    00118   if (!HasBit(e->info.callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return false;
    00119
    00120   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00121     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00122     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00123
    00124     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), e->type, GB(callback, 0, 7));
    00125     if (IsEngineRefittable(artic_engine)) return true;
    00126   }
    00127
    00128   return false;
    00129 }
    00130
    00138 uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00139 {
    00140   uint32 cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
    00141
    00142   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
    00143
    00144   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
    00145
    00146   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00147     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00148     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00149
    00150     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00151     cargos |= GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
    00152   }
    00153
    00154   return cargos;
    00155 }
    00156
    00164 uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
    00165 {
    00166   uint32 cargos = UINT32_MAX;
    00167
    00168   uint32 veh_cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
    00169   if (veh_cargos != 0) cargos &= veh_cargos;
    00170
    00171   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
    00172
    00173   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
    00174
    00175   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00176     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
    00177     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
    00178
    00179     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
    00180     veh_cargos = GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
    00181     if (veh_cargos != 0) cargos &= veh_cargos;
    00182   }
    00183
    00184   return cargos;
    00185 }
    00186
    00187
    00195 bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *cargo_type)
    00196 {
    00197   CargoID first_cargo = CT_INVALID;
    00198
    00199   do {
    00200     if (v->cargo_cap > 0 && v->cargo_type != CT_INVALID) {
    00201       if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
    00202       if (first_cargo != v->cargo_type) {
    00203         if (cargo_type != NULL) *cargo_type = CT_INVALID;
    00204         return true;
    00205       }
    00206     }
    00207
    00208     switch (v->type) {
    00209       case VEH_TRAIN:
    00210         v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
    00211         break;
    00212
    00213       case VEH_ROAD:
    00214         v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
    00215         break;
    00216
    00217       default:
    00218         v = NULL;
    00219         break;
    00220     }
    00221   } while (v != NULL);
    00222
    00223   if (cargo_type != NULL) *cargo_type = first_cargo;
    00224   return false;
    00225 }
    00226
    00235 void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
    00236 {
    00237   const Engine *engine = GetEngine(v->engine_type);
    00238
    00239   uint32 purchase_refit_union = GetUnionOfArticulatedRefitMasks(v->engine_type, v->type, true);
    00240   uint32 purchase_refit_intersection = GetIntersectionOfArticulatedRefitMasks(v->engine_type, v->type, true);
    00241   uint16 *purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type, v->type);
    00242
    00243   uint32 real_refit_union = 0;
    00244   uint32 real_refit_intersection = UINT_MAX;
    00245   uint16 real_default_capacity[NUM_CARGO];
    00246   memset(real_default_capacity, 0, sizeof(real_default_capacity));
    00247
    00248   do {
    00249     uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, v->type, true);
    00250     real_refit_union |= refit_mask;
    00251     if (refit_mask != 0) real_refit_intersection &= refit_mask;
    00252
    00253     assert(v->cargo_type < NUM_CARGO);
    00254     real_default_capacity[v->cargo_type] += v->cargo_cap;
    00255
    00256     switch (v->type) {
    00257       case VEH_TRAIN:
    00258         v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
    00259         break;
    00260
    00261       case VEH_ROAD:
    00262         v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
    00263         break;
    00264
    00265       default:
    00266         v = NULL;
    00267         break;
    00268     }
    00269   } while (v != NULL);
    00270
    00271   /* Check whether the vehicle carries more cargos than expected */
    00272   bool carries_more = false;
    00273   for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
    00274     if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) {
    00275       carries_more = true;
    00276       break;
    00277     }
    00278   }
    00279
    00280   /* show a warning once for each GRF after each game load */
    00281   if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
    00282     ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false);
    00283   }
    00284 }
    00285
    00286 void AddArticulatedParts(Vehicle **vl, VehicleType type)
    00287 {
    00288   const Vehicle *v = vl[0];
    00289   Vehicle *u = vl[0];
    00290
    00291   if (!HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return;
    00292
    00293   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
    00294     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, v->engine_type, v);
    00295     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return;
    00296
    00297     /* Attempt to use pre-allocated vehicles until they run out. This can happen
    00298      * if the callback returns different values depending on the cargo type. */
    00299     u->SetNext(vl[i]);
    00300     if (u->Next() == NULL) return;
    00301
    00302     Vehicle *previous = u;
    00303     u = u->Next();
    00304
    00305     EngineID engine_type = GetNewEngineID(GetEngineGRF(v->engine_type), type, GB(callback, 0, 7));
    00306     bool flip_image = HasBit(callback, 7);
    00307
    00308     const Engine *e_artic = GetEngine(engine_type);
    00309     switch (type) {
    00310       default: NOT_REACHED();
    00311
    00312       case VEH_TRAIN:
    00313         u = new (u) Train();
    00314         u->subtype = 0;
    00315         previous->SetNext(u);
    00316         u->u.rail.track = v->u.rail.track;
    00317         u->u.rail.railtype = v->u.rail.railtype;
    00318         u->u.rail.first_engine = v->engine_type;
    00319
    00320         u->spritenum = e_artic->u.rail.image_index;
    00321         if (e_artic->CanCarryCargo()) {
    00322           u->cargo_type = e_artic->GetDefaultCargoType();
    00323           u->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
    00324         } else {
    00325           u->cargo_type = v->cargo_type; // Needed for livery selection
    00326           u->cargo_cap = 0;
    00327         }
    00328
    00329         SetArticulatedPart(u);
    00330         break;
    00331
    00332       case VEH_ROAD:
    00333         u = new (u) RoadVehicle();
    00334         u->subtype = 0;
    00335         previous->SetNext(u);
    00336         u->u.road.first_engine = v->engine_type;
    00337         u->u.road.cached_veh_length = 8; // Callback is called when the consist is finished
    00338         u->u.road.state = RVSB_IN_DEPOT;
    00339
    00340         u->u.road.roadtype = v->u.road.roadtype;
    00341         u->u.road.compatible_roadtypes = v->u.road.compatible_roadtypes;
    00342
    00343         u->spritenum = e_artic->u.road.image_index;
    00344         if (e_artic->CanCarryCargo()) {
    00345           u->cargo_type = e_artic->GetDefaultCargoType();
    00346           u->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
    00347         } else {
    00348           u->cargo_type = v->cargo_type; // Needed for livery selection
    00349           u->cargo_cap = 0;
    00350         }
    00351
    00352         SetRoadVehArticPart(u);
    00353         break;
    00354     }
    00355
    00356     /* get common values from first engine */
    00357     u->direction = v->direction;
    00358     u->owner = v->owner;
    00359     u->tile = v->tile;
    00360     u->x_pos = v->x_pos;
    00361     u->y_pos = v->y_pos;
    00362     u->z_pos = v->z_pos;
    00363     u->build_year = v->build_year;
    00364     u->vehstatus = v->vehstatus & ~VS_STOPPED;
    00365
    00366     u->cargo_subtype = 0;
    00367     u->max_speed = 0;
    00368     u->max_age = 0;
    00369     u->engine_type = engine_type;
    00370     u->value = 0;
    00371     u->cur_image = 0xAC2;
    00372     u->random_bits = VehicleRandomBits();
    00373
    00374     if (flip_image) u->spritenum++;
    00375
    00376     VehicleMove(u, false);
    00377   }
    00378 }