00001
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
00019
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
00254
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;
00280 } else {
00281 u->cargo_type = v->cargo_type;
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;
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;
00303 } else {
00304 u->cargo_type = v->cargo_type;
00305 u->cargo_cap = 0;
00306 }
00307
00308 SetRoadVehArticPart(u);
00309 break;
00310 }
00311
00312
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 }