articulated_vehicles.cpp

Go to the documentation of this file.
00001 /* $Id: articulated_vehicles.cpp 21924 2011-01-29 17:30:25Z terkhen $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "train.h"
00014 #include "roadveh.h"
00015 #include "vehicle_func.h"
00016 #include "engine_func.h"
00017 
00018 #include "table/strings.h"
00019 #include "table/sprites.h"
00020 
00021 static const uint MAX_ARTICULATED_PARTS = 100; 
00022 
00031 static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = NULL, bool *mirrored = NULL)
00032 {
00033   assert(front == NULL || front->engine_type == front_type);
00034 
00035   uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front);
00036   if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return INVALID_ENGINE;
00037 
00038   if (mirrored != NULL) *mirrored = HasBit(callback, 7);
00039   return GetNewEngineID(GetEngineGRF(front_type), Engine::Get(front_type)->type, GB(callback, 0, 7));
00040 }
00041 
00042 uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
00043 {
00044   if (!HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return 0;
00045 
00046   /* If we can't allocate a vehicle now, we can't allocate it in the command
00047    * either, so it doesn't matter how many articulated parts there are. */
00048   if (!Vehicle::CanAllocateItem()) return 0;
00049 
00050   Vehicle *v = NULL;
00051   if (!purchase_window) {
00052     v = new Vehicle();
00053     v->engine_type = engine_type;
00054   }
00055 
00056   uint i;
00057   for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00058     if (GetNextArticulatedPart(i, engine_type, v) == INVALID_ENGINE) break;
00059   }
00060 
00061   delete v;
00062 
00063   return i - 1;
00064 }
00065 
00066 
00073 static inline uint16 GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type)
00074 {
00075   const Engine *e = Engine::Get(engine);
00076   CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
00077   if (cargo_type != NULL) *cargo_type = cargo;
00078   if (cargo == CT_INVALID) return 0;
00079   return e->GetDisplayDefaultCapacity();
00080 }
00081 
00088 static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
00089 {
00090   uint32 cargos = 0;
00091   CargoID initial_cargo_type;
00092 
00093   if (GetVehicleDefaultCapacity(engine, &initial_cargo_type) > 0) {
00094     const EngineInfo *ei = EngInfo(engine);
00095     cargos = ei->refit_mask;
00096     if (include_initial_cargo_type && initial_cargo_type < NUM_CARGO) SetBit(cargos, initial_cargo_type);
00097   }
00098 
00099   return cargos;
00100 }
00101 
00102 CargoArray GetCapacityOfArticulatedParts(EngineID engine)
00103 {
00104   CargoArray capacity;
00105   const Engine *e = Engine::Get(engine);
00106 
00107   CargoID cargo_type;
00108   uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
00109   if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
00110 
00111   if (!e->IsGroundVehicle()) return capacity;
00112 
00113   if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
00114 
00115   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00116     EngineID artic_engine = GetNextArticulatedPart(i, engine);
00117     if (artic_engine == INVALID_ENGINE) break;
00118 
00119     cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type);
00120     if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
00121   }
00122 
00123   return capacity;
00124 }
00125 
00131 bool IsArticulatedVehicleRefittable(EngineID engine)
00132 {
00133   if (IsEngineRefittable(engine)) return true;
00134 
00135   const Engine *e = Engine::Get(engine);
00136   if (!e->IsGroundVehicle()) return false;
00137 
00138   if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return false;
00139 
00140   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00141     EngineID artic_engine = GetNextArticulatedPart(i, engine);
00142     if (artic_engine == INVALID_ENGINE) break;
00143 
00144     if (IsEngineRefittable(artic_engine)) return true;
00145   }
00146 
00147   return false;
00148 }
00149 
00157 void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask)
00158 {
00159   const Engine *e = Engine::Get(engine);
00160   uint32 veh_cargos = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type);
00161   *union_mask = veh_cargos;
00162   *intersection_mask = (veh_cargos != 0) ? veh_cargos : UINT32_MAX;
00163 
00164   if (!e->IsGroundVehicle()) return;
00165   if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;
00166 
00167   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00168     EngineID artic_engine = GetNextArticulatedPart(i, engine);
00169     if (artic_engine == INVALID_ENGINE) break;
00170 
00171     veh_cargos = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type);
00172     *union_mask |= veh_cargos;
00173     if (veh_cargos != 0) *intersection_mask &= veh_cargos;
00174   }
00175 }
00176 
00183 uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
00184 {
00185   uint32 union_mask, intersection_mask;
00186   GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask);
00187   return union_mask;
00188 }
00189 
00196 uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
00197 {
00198   uint32 union_mask, intersection_mask;
00199   GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask);
00200   return intersection_mask;
00201 }
00202 
00203 
00211 bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *cargo_type)
00212 {
00213   CargoID first_cargo = CT_INVALID;
00214 
00215   do {
00216     if (v->cargo_cap > 0 && v->cargo_type != CT_INVALID) {
00217       if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
00218       if (first_cargo != v->cargo_type) {
00219         if (cargo_type != NULL) *cargo_type = CT_INVALID;
00220         return true;
00221       }
00222     }
00223 
00224     v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL;
00225   } while (v != NULL);
00226 
00227   if (cargo_type != NULL) *cargo_type = first_cargo;
00228   return false;
00229 }
00230 
00239 void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
00240 {
00241   const Engine *engine = Engine::Get(v->engine_type);
00242 
00243   uint32 purchase_refit_union, purchase_refit_intersection;
00244   GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection);
00245   CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type);
00246 
00247   uint32 real_refit_union = 0;
00248   uint32 real_refit_intersection = UINT_MAX;
00249   CargoArray real_default_capacity;
00250 
00251   do {
00252     uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
00253     real_refit_union |= refit_mask;
00254     if (refit_mask != 0) real_refit_intersection &= refit_mask;
00255 
00256     assert(v->cargo_type < NUM_CARGO);
00257     real_default_capacity[v->cargo_type] += v->cargo_cap;
00258 
00259     v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL;
00260   } while (v != NULL);
00261 
00262   /* Check whether the vehicle carries more cargos than expected */
00263   bool carries_more = false;
00264   for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00265     if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) {
00266       carries_more = true;
00267       break;
00268     }
00269   }
00270 
00271   /* show a warning once for each GRF after each game load */
00272   if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
00273     ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false);
00274   }
00275 }
00276 
00277 void AddArticulatedParts(Vehicle *first)
00278 {
00279   VehicleType type = first->type;
00280   if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;
00281 
00282   Vehicle *v = first;
00283   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00284     bool flip_image;
00285     EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image);
00286     if (engine_type == INVALID_ENGINE) return;
00287 
00288     /* In the (very rare) case the GRF reported wrong number of articulated parts
00289      * and we run out of available vehicles, bail out. */
00290     if (!Vehicle::CanAllocateItem()) return;
00291 
00292     GroundVehicleCache *gcache = v->GetGroundVehicleCache();
00293     gcache->first_engine = v->engine_type; // Needs to be set before first callback
00294 
00295     const Engine *e_artic = Engine::Get(engine_type);
00296     switch (type) {
00297       default: NOT_REACHED();
00298 
00299       case VEH_TRAIN: {
00300         Train *front = Train::From(first);
00301         Train *t = new Train();
00302         v->SetNext(t);
00303         v = t;
00304 
00305         t->subtype = 0;
00306         t->track = front->track;
00307         t->railtype = front->railtype;
00308 
00309         t->spritenum = e_artic->u.rail.image_index;
00310         if (e_artic->CanCarryCargo()) {
00311           t->cargo_type = e_artic->GetDefaultCargoType();
00312           t->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
00313         } else {
00314           t->cargo_type = front->cargo_type; // Needed for livery selection
00315           t->cargo_cap = 0;
00316         }
00317 
00318         t->SetArticulatedPart();
00319         break;
00320       }
00321 
00322       case VEH_ROAD: {
00323         RoadVehicle *front = RoadVehicle::From(first);
00324         RoadVehicle *rv = new RoadVehicle();
00325         v->SetNext(rv);
00326         v = rv;
00327 
00328         rv->subtype = 0;
00329         gcache->cached_veh_length = 8; // Callback is called when the consist is finished
00330         rv->state = RVSB_IN_DEPOT;
00331 
00332         rv->roadtype = front->roadtype;
00333         rv->compatible_roadtypes = front->compatible_roadtypes;
00334 
00335         rv->spritenum = e_artic->u.road.image_index;
00336         if (e_artic->CanCarryCargo()) {
00337           rv->cargo_type = e_artic->GetDefaultCargoType();
00338           rv->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
00339         } else {
00340           rv->cargo_type = front->cargo_type; // Needed for livery selection
00341           rv->cargo_cap = 0;
00342         }
00343 
00344         rv->SetArticulatedPart();
00345         break;
00346       }
00347     }
00348 
00349     /* get common values from first engine */
00350     v->direction = first->direction;
00351     v->owner = first->owner;
00352     v->tile = first->tile;
00353     v->x_pos = first->x_pos;
00354     v->y_pos = first->y_pos;
00355     v->z_pos = first->z_pos;
00356     v->build_year = first->build_year;
00357     v->vehstatus = first->vehstatus & ~VS_STOPPED;
00358 
00359     v->cargo_subtype = 0;
00360     v->max_age = 0;
00361     v->engine_type = engine_type;
00362     v->value = 0;
00363     v->cur_image = SPR_IMG_QUERY;
00364     v->random_bits = VehicleRandomBits();
00365 
00366     if (flip_image) v->spritenum++;
00367 
00368     VehicleMove(v, false);
00369   }
00370 }

Generated on Fri Feb 4 20:53:38 2011 for OpenTTD by  doxygen 1.6.1