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 }

Generated on Wed Jul 15 20:35:57 2009 for OpenTTD by  doxygen 1.5.6