# 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 }