articulated_vehicles.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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 "newgrf_engine.h"
00016 #include "vehicle_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 GetNextArticPart(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 (GetNextArticPart(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->type != VEH_TRAIN && e->type != VEH_ROAD) 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 = GetNextArticPart(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->type != VEH_TRAIN && e->type != VEH_ROAD) 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 = GetNextArticPart(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->type != VEH_TRAIN && e->type != VEH_ROAD) 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 = GetNextArticPart(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     switch (v->type) {
00225       case VEH_TRAIN:
00226         v = Train::From(v)->HasArticulatedPart() ? Train::From(v)->GetNextArticPart() : NULL;
00227         break;
00228 
00229       case VEH_ROAD:
00230         v = RoadVehicle::From(v)->HasArticulatedPart() ? v->Next() : NULL;
00231         break;
00232 
00233       default:
00234         v = NULL;
00235         break;
00236     }
00237   } while (v != NULL);
00238 
00239   if (cargo_type != NULL) *cargo_type = first_cargo;
00240   return false;
00241 }
00242 
00251 void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
00252 {
00253   const Engine *engine = Engine::Get(v->engine_type);
00254 
00255   uint32 purchase_refit_union, purchase_refit_intersection;
00256   GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection);
00257   CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type);
00258 
00259   uint32 real_refit_union = 0;
00260   uint32 real_refit_intersection = UINT_MAX;
00261   CargoArray real_default_capacity;
00262 
00263   do {
00264     uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
00265     real_refit_union |= refit_mask;
00266     if (refit_mask != 0) real_refit_intersection &= refit_mask;
00267 
00268     assert(v->cargo_type < NUM_CARGO);
00269     real_default_capacity[v->cargo_type] += v->cargo_cap;
00270 
00271     switch (v->type) {
00272       case VEH_TRAIN:
00273         v = Train::From(v)->HasArticulatedPart() ? Train::From(v)->GetNextArticPart() : NULL;
00274         break;
00275 
00276       case VEH_ROAD:
00277         v = RoadVehicle::From(v)->HasArticulatedPart() ? v->Next() : NULL;
00278         break;
00279 
00280       default:
00281         v = NULL;
00282         break;
00283     }
00284   } while (v != NULL);
00285 
00286   /* Check whether the vehicle carries more cargos than expected */
00287   bool carries_more = false;
00288   for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00289     if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) {
00290       carries_more = true;
00291       break;
00292     }
00293   }
00294 
00295   /* show a warning once for each GRF after each game load */
00296   if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
00297     ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false);
00298   }
00299 }
00300 
00301 void AddArticulatedParts(Vehicle *first)
00302 {
00303   VehicleType type = first->type;
00304   if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;
00305 
00306   Vehicle *v = first;
00307   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00308     bool flip_image;
00309     EngineID engine_type = GetNextArticPart(i, first->engine_type, first, &flip_image);
00310     if (engine_type == INVALID_ENGINE) return;
00311 
00312     /* In the (very rare) case the GRF reported wrong number of articulated parts
00313      * and we run out of available vehicles, bail out. */
00314     if (!Vehicle::CanAllocateItem()) return;
00315 
00316     const Engine *e_artic = Engine::Get(engine_type);
00317     switch (type) {
00318       default: NOT_REACHED();
00319 
00320       case VEH_TRAIN: {
00321         Train *front = Train::From(first);
00322         Train *t = new Train();
00323         v->SetNext(t);
00324         v = t;
00325 
00326         t->subtype = 0;
00327         t->track = front->track;
00328         t->railtype = front->railtype;
00329         t->tcache.first_engine = front->engine_type; // needs to be set before first callback
00330 
00331         t->spritenum = e_artic->u.rail.image_index;
00332         if (e_artic->CanCarryCargo()) {
00333           t->cargo_type = e_artic->GetDefaultCargoType();
00334           t->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
00335         } else {
00336           t->cargo_type = front->cargo_type; // Needed for livery selection
00337           t->cargo_cap = 0;
00338         }
00339 
00340         t->SetArticulatedPart();
00341       } break;
00342 
00343       case VEH_ROAD: {
00344         RoadVehicle *front = RoadVehicle::From(first);
00345         RoadVehicle *rv = new RoadVehicle();
00346         v->SetNext(rv);
00347         v = rv;
00348 
00349         rv->subtype = 0;
00350         rv->rcache.first_engine = front->engine_type; // needs to be set before first callback
00351         rv->rcache.cached_veh_length = 8; // Callback is called when the consist is finished
00352         rv->state = RVSB_IN_DEPOT;
00353 
00354         rv->roadtype = front->roadtype;
00355         rv->compatible_roadtypes = front->compatible_roadtypes;
00356 
00357         rv->spritenum = e_artic->u.road.image_index;
00358         if (e_artic->CanCarryCargo()) {
00359           rv->cargo_type = e_artic->GetDefaultCargoType();
00360           rv->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
00361         } else {
00362           rv->cargo_type = front->cargo_type; // Needed for livery selection
00363           rv->cargo_cap = 0;
00364         }
00365 
00366         rv->SetArticulatedPart();
00367       } break;
00368     }
00369 
00370     /* get common values from first engine */
00371     v->direction = first->direction;
00372     v->owner = first->owner;
00373     v->tile = first->tile;
00374     v->x_pos = first->x_pos;
00375     v->y_pos = first->y_pos;
00376     v->z_pos = first->z_pos;
00377     v->build_year = first->build_year;
00378     v->vehstatus = first->vehstatus & ~VS_STOPPED;
00379 
00380     v->cargo_subtype = 0;
00381     v->max_speed = 0;
00382     v->max_age = 0;
00383     v->engine_type = engine_type;
00384     v->value = 0;
00385     v->cur_image = SPR_IMG_QUERY;
00386     v->random_bits = VehicleRandomBits();
00387 
00388     if (flip_image) v->spritenum++;
00389 
00390     VehicleMove(v, false);
00391   }
00392 }

Generated on Wed Dec 30 20:40:00 2009 for OpenTTD by  doxygen 1.5.6