articulated_vehicles.cpp

Go to the documentation of this file.
00001 /* $Id: articulated_vehicles.cpp 15655 2009-03-09 19:14:36Z michi_cc $ */
00002 
00005 #include "stdafx.h"
00006 #include "train.h"
00007 #include "roadveh.h"
00008 #include "aircraft.h"
00009 #include "newgrf_engine.h"
00010 #include "vehicle_func.h"
00011 
00012 static const uint MAX_ARTICULATED_PARTS = 100; 
00013 
00014 uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
00015 {
00016   if (!HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return 0;
00017 
00018   /* If we can't allocate a vehicle now, we can't allocate it in the command
00019    * either, so it doesn't matter how many articulated parts there are. */
00020   if (!Vehicle::CanAllocateItem()) return 0;
00021 
00022   Vehicle *v = NULL;;
00023   if (!purchase_window) {
00024     v = new InvalidVehicle();
00025     v->engine_type = engine_type;
00026   }
00027 
00028   uint i;
00029   for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00030     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v);
00031     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
00032   }
00033 
00034   delete v;
00035 
00036   return i - 1;
00037 }
00038 
00039 
00047 static inline uint16 GetVehicleDefaultCapacity(EngineID engine, VehicleType type, CargoID *cargo_type)
00048 {
00049   const Engine *e = GetEngine(engine);
00050   CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
00051   if (cargo_type != NULL) *cargo_type = cargo;
00052   if (cargo == CT_INVALID) return 0;
00053   switch (type) {
00054     case VEH_TRAIN:
00055       return GetEngineProperty(engine, 0x14, e->u.rail.capacity) + (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? e->u.rail.capacity : 0);
00056 
00057     case VEH_ROAD:
00058       return GetEngineProperty(engine, 0x0F, e->u.road.capacity);
00059 
00060     case VEH_SHIP:
00061       return GetEngineProperty(engine, 0x0D, e->u.ship.capacity);
00062 
00063     case VEH_AIRCRAFT:
00064       return AircraftDefaultCargoCapacity(cargo, &e->u.air);
00065 
00066     default: NOT_REACHED();
00067   }
00068 
00069 }
00070 
00078 static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, VehicleType type, bool include_initial_cargo_type)
00079 {
00080   uint32 cargos = 0;
00081   CargoID initial_cargo_type;
00082 
00083   if (GetVehicleDefaultCapacity(engine, type, &initial_cargo_type) > 0) {
00084     if (type != VEH_SHIP || ShipVehInfo(engine)->refittable) {
00085       const EngineInfo *ei = EngInfo(engine);
00086       cargos = ei->refit_mask;
00087     }
00088     if (include_initial_cargo_type && initial_cargo_type < NUM_CARGO) SetBit(cargos, initial_cargo_type);
00089   }
00090 
00091   return cargos;
00092 }
00093 
00094 uint16 *GetCapacityOfArticulatedParts(EngineID engine, VehicleType type)
00095 {
00096   static uint16 capacity[NUM_CARGO];
00097   memset(capacity, 0, sizeof(capacity));
00098 
00099   CargoID cargo_type;
00100   uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, type, &cargo_type);
00101   if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
00102 
00103   if (type != VEH_TRAIN && type != VEH_ROAD) return capacity;
00104 
00105   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
00106 
00107   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00108     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
00109     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
00110 
00111     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
00112 
00113     cargo_capacity = GetVehicleDefaultCapacity(artic_engine, type, &cargo_type);
00114     if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
00115   }
00116 
00117   return capacity;
00118 }
00119 
00125 bool IsArticulatedVehicleRefittable(EngineID engine)
00126 {
00127   if (IsEngineRefittable(engine)) return true;
00128 
00129   const Engine *e = GetEngine(engine);
00130   if (e->type != VEH_TRAIN && e->type != VEH_ROAD) return false;
00131 
00132   if (!HasBit(e->info.callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return false;
00133 
00134   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00135     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
00136     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
00137 
00138     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), e->type, GB(callback, 0, 7));
00139     if (IsEngineRefittable(artic_engine)) return true;
00140   }
00141 
00142   return false;
00143 }
00144 
00152 uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
00153 {
00154   uint32 cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
00155 
00156   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
00157 
00158   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
00159 
00160   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00161     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
00162     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
00163 
00164     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
00165     cargos |= GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
00166   }
00167 
00168   return cargos;
00169 }
00170 
00178 uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type)
00179 {
00180   uint32 cargos = UINT32_MAX;
00181 
00182   uint32 veh_cargos = GetAvailableVehicleCargoTypes(engine, type, include_initial_cargo_type);
00183   if (veh_cargos != 0) cargos &= veh_cargos;
00184 
00185   if (type != VEH_TRAIN && type != VEH_ROAD) return cargos;
00186 
00187   if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return cargos;
00188 
00189   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00190     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
00191     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
00192 
00193     EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
00194     veh_cargos = GetAvailableVehicleCargoTypes(artic_engine, type, include_initial_cargo_type);
00195     if (veh_cargos != 0) cargos &= veh_cargos;
00196   }
00197 
00198   return cargos;
00199 }
00200 
00201 
00209 bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *cargo_type)
00210 {
00211   CargoID first_cargo = CT_INVALID;
00212 
00213   do {
00214     if (v->cargo_cap > 0 && v->cargo_type != CT_INVALID) {
00215       if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
00216       if (first_cargo != v->cargo_type) {
00217         if (cargo_type != NULL) *cargo_type = CT_INVALID;
00218         return true;
00219       }
00220     }
00221 
00222     switch (v->type) {
00223       case VEH_TRAIN:
00224         v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
00225         break;
00226 
00227       case VEH_ROAD:
00228         v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
00229         break;
00230 
00231       default:
00232         v = NULL;
00233         break;
00234     }
00235   } while (v != NULL);
00236 
00237   if (cargo_type != NULL) *cargo_type = first_cargo;
00238   return false;
00239 }
00240 
00241 
00242 void AddArticulatedParts(Vehicle **vl, VehicleType type)
00243 {
00244   const Vehicle *v = vl[0];
00245   Vehicle *u = vl[0];
00246 
00247   if (!HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return;
00248 
00249   for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
00250     uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, v->engine_type, v);
00251     if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return;
00252 
00253     /* Attempt to use pre-allocated vehicles until they run out. This can happen
00254      * if the callback returns different values depending on the cargo type. */
00255     u->SetNext(vl[i]);
00256     if (u->Next() == NULL) return;
00257 
00258     Vehicle *previous = u;
00259     u = u->Next();
00260 
00261     EngineID engine_type = GetNewEngineID(GetEngineGRF(v->engine_type), type, GB(callback, 0, 7));
00262     bool flip_image = HasBit(callback, 7);
00263 
00264     const Engine *e_artic = GetEngine(engine_type);
00265     switch (type) {
00266       default: NOT_REACHED();
00267 
00268       case VEH_TRAIN:
00269         u = new (u) Train();
00270         u->subtype = 0;
00271         previous->SetNext(u);
00272         u->u.rail.track = v->u.rail.track;
00273         u->u.rail.railtype = v->u.rail.railtype;
00274         u->u.rail.first_engine = v->engine_type;
00275 
00276         u->spritenum = e_artic->u.rail.image_index;
00277         if (e_artic->CanCarryCargo()) {
00278           u->cargo_type = e_artic->GetDefaultCargoType();
00279           u->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
00280         } else {
00281           u->cargo_type = v->cargo_type; // Needed for livery selection
00282           u->cargo_cap = 0;
00283         }
00284 
00285         SetArticulatedPart(u);
00286         break;
00287 
00288       case VEH_ROAD:
00289         u = new (u) RoadVehicle();
00290         u->subtype = 0;
00291         previous->SetNext(u);
00292         u->u.road.first_engine = v->engine_type;
00293         u->u.road.cached_veh_length = 8; // Callback is called when the consist is finished
00294         u->u.road.state = RVSB_IN_DEPOT;
00295 
00296         u->u.road.roadtype = v->u.road.roadtype;
00297         u->u.road.compatible_roadtypes = v->u.road.compatible_roadtypes;
00298 
00299         u->spritenum = e_artic->u.road.image_index;
00300         if (e_artic->CanCarryCargo()) {
00301           u->cargo_type = e_artic->GetDefaultCargoType();
00302           u->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
00303         } else {
00304           u->cargo_type = v->cargo_type; // Needed for livery selection
00305           u->cargo_cap = 0;
00306         }
00307 
00308         SetRoadVehArticPart(u);
00309         break;
00310     }
00311 
00312     /* get common values from first engine */
00313     u->direction = v->direction;
00314     u->owner = v->owner;
00315     u->tile = v->tile;
00316     u->x_pos = v->x_pos;
00317     u->y_pos = v->y_pos;
00318     u->z_pos = v->z_pos;
00319     u->build_year = v->build_year;
00320     u->vehstatus = v->vehstatus & ~VS_STOPPED;
00321 
00322     u->cargo_subtype = 0;
00323     u->max_speed = 0;
00324     u->max_age = 0;
00325     u->engine_type = engine_type;
00326     u->value = 0;
00327     u->cur_image = 0xAC2;
00328     u->random_bits = VehicleRandomBits();
00329 
00330     if (flip_image) u->spritenum++;
00331 
00332     VehiclePositionChanged(u);
00333   }
00334 }

Generated on Mon Mar 9 23:33:46 2009 for openttd by  doxygen 1.5.6