# newgrf_engine.cpp

Go to the documentation of this file.

    00001 /* $Id: newgrf_engine.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "variables.h"
    00008 #include "debug.h"
    00009 #include "engine.h"
    00010 #include "train.h"
    00011 #include "player_func.h"
    00012 #include "player_base.h"
    00013 #include "station.h"
    00014 #include "airport.h"
    00015 #include "newgrf.h"
    00016 #include "newgrf_callbacks.h"
    00017 #include "newgrf_engine.h"
    00018 #include "newgrf_station.h"
    00019 #include "newgrf_spritegroup.h"
    00020 #include "newgrf_cargo.h"
    00021 #include "cargotype.h"
    00022 #include "date_func.h"
    00023 #include "vehicle_func.h"
    00024 #include "core/random_func.hpp"
    00025 #include "direction_func.h"
    00026 #include "rail_map.h"
    00027 #include "rail.h"
    00028 #include "aircraft.h"
    00029
    00030
    00031 int _traininfo_vehicle_pitch = 0;
    00032 int _traininfo_vehicle_width = 29;
    00033
    00034 struct WagonOverride {
    00035   EngineID *train_id;
    00036   uint trains;
    00037   CargoID cargo;
    00038   const SpriteGroup *group;
    00039 };
    00040
    00041 struct WagonOverrides {
    00042   uint overrides_count;
    00043   WagonOverride *overrides;
    00044 };
    00045
    00046 static WagonOverrides _engine_wagon_overrides[TOTAL_NUM_ENGINES];
    00047
    00048 void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, EngineID *train_id, uint trains)
    00049 {
    00050   WagonOverrides *wos;
    00051   WagonOverride *wo;
    00052
    00053   assert(engine < TOTAL_NUM_ENGINES);
    00054   assert(cargo < NUM_CARGO + 2); // Include CT_DEFAULT and CT_PURCHASE pseudo cargos.
    00055
    00056   wos = &_engine_wagon_overrides[engine];
    00057   wos->overrides_count++;
    00058   wos->overrides = ReallocT(wos->overrides, wos->overrides_count);
    00059
    00060   wo = &wos->overrides[wos->overrides_count - 1];
    00061   /* FIXME: If we are replacing an override, release original SpriteGroup
    00062    * to prevent leaks. But first we need to refcount the SpriteGroup.
    00063    * --pasky */
    00064   wo->group = group;
    00065   wo->cargo = cargo;
    00066   wo->trains = trains;
    00067   wo->train_id = MallocT<EngineID>(trains);
    00068   memcpy(wo->train_id, train_id, trains * sizeof *train_id);
    00069 }
    00070
    00071 const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine)
    00072 {
    00073   const WagonOverrides *wos = &_engine_wagon_overrides[engine];
    00074
    00075   /* XXX: This could turn out to be a timesink on profiles. We could
    00076    * always just dedicate 65535 bytes for an [engine][train] trampoline
    00077    * for O(1). Or O(logMlogN) and searching binary tree or smt. like
    00078    * that. --pasky */
    00079
    00080   for (uint i = 0; i < wos->overrides_count; i++) {
    00081     const WagonOverride *wo = &wos->overrides[i];
    00082
    00083     if (wo->cargo != cargo && wo->cargo != CT_DEFAULT) continue;
    00084
    00085     for (uint j = 0; j < wo->trains; j++) {
    00086       if (wo->train_id[j] == overriding_engine) return wo->group;
    00087     }
    00088   }
    00089   return NULL;
    00090 }
    00091
    00095 void UnloadWagonOverrides()
    00096 {
    00097   for (EngineID engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
    00098     WagonOverrides *wos = &_engine_wagon_overrides[engine];
    00099     for (uint i = 0; i < wos->overrides_count; i++) {
    00100       WagonOverride *wo = &wos->overrides[i];
    00101       free(wo->train_id);
    00102     }
    00103     free(wos->overrides);
    00104     wos->overrides_count = 0;
    00105     wos->overrides = NULL;
    00106   }
    00107 }
    00108
    00109 /* Space for NUM_CARGO real cargos and 2 pseudo cargos, CT_DEFAULT and CT_PURCHASE */
    00110 static const SpriteGroup *_engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_CARGO + 2];
    00111 const GRFFile *_engine_grf[TOTAL_NUM_ENGINES];
    00112
    00113 void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group)
    00114 {
    00115   assert(engine < lengthof(_engine_custom_sprites));
    00116   assert(cargo < lengthof(*_engine_custom_sprites));
    00117
    00118   if (_engine_custom_sprites[engine][cargo] != NULL) {
    00119     grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo);
    00120   }
    00121   _engine_custom_sprites[engine][cargo] = group;
    00122 }
    00123
    00127 void UnloadCustomEngineSprites()
    00128 {
    00129   memset(_engine_custom_sprites, 0, sizeof(_engine_custom_sprites));
    00130   memset(_engine_grf, 0, sizeof(_engine_grf));
    00131 }
    00132
    00139 void SetEngineGRF(EngineID engine, const GRFFile *file)
    00140 {
    00141   assert(engine < TOTAL_NUM_ENGINES);
    00142   _engine_grf[engine] = file;
    00143 }
    00144
    00145
    00151 const GRFFile *GetEngineGRF(EngineID engine)
    00152 {
    00153   assert(engine < TOTAL_NUM_ENGINES);
    00154   return _engine_grf[engine];
    00155 }
    00156
    00157
    00163 uint32 GetEngineGRFID(EngineID engine)
    00164 {
    00165   assert(engine < TOTAL_NUM_ENGINES);
    00166   return _engine_grf[engine]->grfid;
    00167 }
    00168
    00169
    00170 static int MapOldSubType(const Vehicle *v)
    00171 {
    00172   if (v->type != VEH_TRAIN) return v->subtype;
    00173   if (IsTrainEngine(v)) return 0;
    00174   if (IsFreeWagon(v)) return 4;
    00175   return 2;
    00176 }
    00177
    00178
    00179 /* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
    00180 enum {
    00181   AMS_TTDP_HANGAR,
    00182   AMS_TTDP_TO_HANGAR,
    00183   AMS_TTDP_TO_PAD1,
    00184   AMS_TTDP_TO_PAD2,
    00185   AMS_TTDP_TO_PAD3,
    00186   AMS_TTDP_TO_ENTRY_2_AND_3,
    00187   AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
    00188   AMS_TTDP_TO_JUNCTION,
    00189   AMS_TTDP_LEAVE_RUNWAY,
    00190   AMS_TTDP_TO_INWAY,
    00191   AMS_TTDP_TO_RUNWAY,
    00192   AMS_TTDP_TO_OUTWAY,
    00193   AMS_TTDP_WAITING,
    00194   AMS_TTDP_TAKEOFF,
    00195   AMS_TTDP_TO_TAKEOFF,
    00196   AMS_TTDP_CLIMBING,
    00197   AMS_TTDP_FLIGHT_APPROACH,
    00198   AMS_TTDP_UNUSED_0x11,
    00199   AMS_TTDP_FLIGHT_TO_TOWER,
    00200   AMS_TTDP_UNUSED_0x13,
    00201   AMS_TTDP_FLIGHT_FINAL,
    00202   AMS_TTDP_FLIGHT_DESCENT,
    00203   AMS_TTDP_BRAKING,
    00204   AMS_TTDP_HELI_TAKEOFF_AIRPORT,
    00205   AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
    00206   AMS_TTDP_HELI_LAND_AIRPORT,
    00207   AMS_TTDP_HELI_TAKEOFF_HELIPORT,
    00208   AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
    00209   AMS_TTDP_HELI_LAND_HELIPORT,
    00210 };
    00211
    00212
    00217 static byte MapAircraftMovementState(const Vehicle *v)
    00218 {
    00219   const Station *st = GetTargetAirportIfValid(v);
    00220   if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER;
    00221
    00222   const AirportFTAClass *afc = st->Airport();
    00223   uint16 amdflag = afc->MovingData(v->u.air.pos)->flag;
    00224
    00225   switch (v->u.air.state) {
    00226     case HANGAR:
    00227       /* The international airport is a special case as helicopters can land in
    00228        * front of the hanger. Helicopters also change their air.state to
    00229        * AMED_HELI_LOWER some time before actually descending. */
    00230
    00231       /* This condition only occurs for helicopters, during descent,
    00232        * to a landing by the hanger of an international airport. */
    00233       if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
    00234
    00235       /* This condition only occurs for helicopters, before starting descent,
    00236        * to a landing by the hanger of an international airport. */
    00237       if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
    00238
    00239       /* The final two conditions apply to helicopters or aircraft.
    00240        * Has reached hanger? */
    00241       if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR;
    00242
    00243       /* Still moving towards hanger. */
    00244       return AMS_TTDP_TO_HANGAR;
    00245
    00246     case TERM1:
    00247       if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD1;
    00248       return AMS_TTDP_TO_JUNCTION;
    00249
    00250     case TERM2:
    00251       if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD2;
    00252       return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
    00253
    00254     case TERM3:
    00255     case TERM4:
    00256     case TERM5:
    00257     case TERM6:
    00258     case TERM7:
    00259     case TERM8:
    00260       /* TTDPatch only has 3 terminals, so treat these states the same */
    00261       if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD3;
    00262       return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
    00263
    00264     case HELIPAD1:
    00265     case HELIPAD2:
    00266     case HELIPAD3:
    00267     case HELIPAD4: // Will only occur for helicopters.
    00268       if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
    00269       if (amdflag & AMED_SLOWTURN)   return AMS_TTDP_FLIGHT_TO_TOWER;   // Still hasn't started descent.
    00270       return AMS_TTDP_TO_JUNCTION; // On the ground.
    00271
    00272     case TAKEOFF: // Moving to takeoff position.
    00273       return AMS_TTDP_TO_OUTWAY;
    00274
    00275     case STARTTAKEOFF: // Accelerating down runway.
    00276       return AMS_TTDP_TAKEOFF;
    00277
    00278     case ENDTAKEOFF: // Ascent
    00279       return AMS_TTDP_CLIMBING;
    00280
    00281     case HELITAKEOFF: // Helicopter is moving to take off position.
    00282       if (afc->delta_z == 0) {
    00283         return amdflag & AMED_HELI_RAISE ?
    00284           AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION;
    00285       } else {
    00286         return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
    00287       }
    00288
    00289     case FLYING:
    00290       return amdflag & AMED_HOLD ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER;
    00291
    00292     case LANDING: // Descent
    00293       return AMS_TTDP_FLIGHT_DESCENT;
    00294
    00295     case ENDLANDING: // On the runway braking
    00296       if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING;
    00297       /* Landed - moving off runway */
    00298       return AMS_TTDP_TO_INWAY;
    00299
    00300     case HELILANDING:
    00301     case HELIENDLANDING: // Helicoptor is decending.
    00302       if (amdflag & AMED_HELI_LOWER) {
    00303         return afc->delta_z == 0 ?
    00304           AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT;
    00305       } else {
    00306         return AMS_TTDP_FLIGHT_TO_TOWER;
    00307       }
    00308
    00309     default:
    00310       return AMS_TTDP_HANGAR;
    00311   }
    00312 }
    00313
    00314
    00315 /* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
    00316 enum {
    00317   AMA_TTDP_IN_HANGAR,
    00318   AMA_TTDP_ON_PAD1,
    00319   AMA_TTDP_ON_PAD2,
    00320   AMA_TTDP_ON_PAD3,
    00321   AMA_TTDP_HANGAR_TO_PAD1,
    00322   AMA_TTDP_HANGAR_TO_PAD2,
    00323   AMA_TTDP_HANGAR_TO_PAD3,
    00324   AMA_TTDP_LANDING_TO_PAD1,
    00325   AMA_TTDP_LANDING_TO_PAD2,
    00326   AMA_TTDP_LANDING_TO_PAD3,
    00327   AMA_TTDP_PAD1_TO_HANGAR,
    00328   AMA_TTDP_PAD2_TO_HANGAR,
    00329   AMA_TTDP_PAD3_TO_HANGAR,
    00330   AMA_TTDP_PAD1_TO_TAKEOFF,
    00331   AMA_TTDP_PAD2_TO_TAKEOFF,
    00332   AMA_TTDP_PAD3_TO_TAKEOFF,
    00333   AMA_TTDP_HANGAR_TO_TAKOFF,
    00334   AMA_TTDP_LANDING_TO_HANGAR,
    00335   AMA_TTDP_IN_FLIGHT,
    00336 };
    00337
    00338
    00344 static byte MapAircraftMovementAction(const Vehicle *v)
    00345 {
    00346   switch (v->u.air.state) {
    00347     case HANGAR:
    00348       return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
    00349
    00350     case TERM1:
    00351     case HELIPAD1:
    00352       return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
    00353
    00354     case TERM2:
    00355     case HELIPAD2:
    00356       return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
    00357
    00358     case TERM3:
    00359     case TERM4:
    00360     case TERM5:
    00361     case TERM6:
    00362     case TERM7:
    00363     case TERM8:
    00364     case HELIPAD3:
    00365     case HELIPAD4:
    00366       return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
    00367
    00368     case TAKEOFF:      // Moving to takeoff position
    00369     case STARTTAKEOFF: // Accelerating down runway
    00370     case ENDTAKEOFF:   // Ascent
    00371     case HELITAKEOFF:
    00372       /* @todo Need to find which terminal (or hanger) we've come from. How? */
    00373       return AMA_TTDP_PAD1_TO_TAKEOFF;
    00374
    00375     case FLYING:
    00376       return AMA_TTDP_IN_FLIGHT;
    00377
    00378     case LANDING:    // Descent
    00379     case ENDLANDING: // On the runway braking
    00380     case HELILANDING:
    00381     case HELIENDLANDING:
    00382       /* @todo Need to check terminal we're landing to. Is it known yet? */
    00383       return (v->current_order.type == OT_GOTO_DEPOT) ?
    00384         AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
    00385
    00386     default:
    00387       return AMA_TTDP_IN_HANGAR;
    00388   }
    00389 }
    00390
    00391
    00392 /* TTDP airport types. Used to map our types to TTDPatch's */
    00393 enum {
    00394   ATP_TTDP_SMALL,
    00395   ATP_TTDP_LARGE,
    00396   ATP_TTDP_HELIPORT,
    00397   ATP_TTDP_OILRIG,
    00398 };
    00399
    00400
    00401 /* Vehicle Resolver Functions */
    00402 static inline const Vehicle *GRV(const ResolverObject *object)
    00403 {
    00404   return object->scope == VSG_SCOPE_SELF ? object->u.vehicle.self : object->u.vehicle.parent;
    00405 }
    00406
    00407
    00408 static uint32 VehicleGetRandomBits(const ResolverObject *object)
    00409 {
    00410   return GRV(object) == NULL ? 0 : GRV(object)->random_bits;
    00411 }
    00412
    00413
    00414 static uint32 VehicleGetTriggers(const ResolverObject *object)
    00415 {
    00416   return GRV(object) == NULL ? 0 : GRV(object)->waiting_triggers;
    00417 }
    00418
    00419
    00420 static void VehicleSetTriggers(const ResolverObject *object, int triggers)
    00421 {
    00422   /* Evil cast to get around const-ness. This used to be achieved by an
    00423    * innocent looking function pointer cast... Currently I cannot see a
    00424    * way of avoiding this without removing consts deep within gui code.
    00425    */
    00426   Vehicle *v = (Vehicle*)GRV(object);
    00427
    00428   /* This function must only be called when processing triggers -- any
    00429    * other time is an error. */
    00430   assert(object->trigger != 0);
    00431
    00432   if (v != NULL) v->waiting_triggers = triggers;
    00433 }
    00434
    00435
    00436 static uint32 GetGRFParameter(EngineID engine_type, byte parameter)
    00437 {
    00438   const GRFFile *file = GetEngineGRF(engine_type);
    00439
    00440   if (parameter >= file->param_end) return 0;
    00441   return file->param[parameter];
    00442 }
    00443
    00444
    00445 static uint8 LiveryHelper(EngineID engine, const Vehicle *v)
    00446 {
    00447   const Livery *l;
    00448
    00449   if (v == NULL) {
    00450     if (!IsValidPlayer(_current_player)) return 0;
    00451     l = GetEngineLivery(engine, _current_player, INVALID_ENGINE, NULL);
    00452   } else if (v->type == VEH_TRAIN) {
    00453     l = GetEngineLivery((v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ? v->u.rail.first_engine : v->engine_type, v->owner, v->u.rail.first_engine, v);
    00454   } else {
    00455     l = GetEngineLivery(v->engine_type, v->owner, INVALID_ENGINE, v);
    00456   }
    00457
    00458   return l->colour1 + l->colour2 * 16;
    00459 }
    00460
    00461
    00462 static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
    00463 {
    00464   const Vehicle *v = GRV(object);
    00465
    00466   if (v == NULL) {
    00467     /* Vehicle does not exist, so we're in a purchase list */
    00468     switch (variable) {
    00469       case 0x43: return _current_player | (LiveryHelper(object->u.vehicle.self_type, NULL) << 24); // Owner information
    00470       case 0x46: return 0;               // Motion counter
    00471       case 0x48: return GetEngine(object->u.vehicle.self_type)->flags; // Vehicle Type Info
    00472       case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year
    00473       case 0xDA: return INVALID_VEHICLE; // Next vehicle
    00474       case 0x7F: return GetGRFParameter(object->u.vehicle.self_type, parameter); // Read GRF parameter
    00475     }
    00476
    00477     *available = false;
    00478     return UINT_MAX;
    00479   }
    00480
    00481   /* Calculated vehicle parameters */
    00482   switch (variable) {
    00483     case 0x40: // Get length of consist
    00484     case 0x41: // Get length of same consecutive wagons
    00485       {
    00486         const Vehicle* u;
    00487         byte chain_before = 0;
    00488         byte chain_after  = 0;
    00489
    00490         for (u = v->First(); u != v; u = u->Next()) {
    00491           chain_before++;
    00492           if (variable == 0x41 && u->engine_type != v->engine_type) chain_before = 0;
    00493         }
    00494
    00495         while (u->Next() != NULL && (variable == 0x40 || u->Next()->engine_type == v->engine_type)) {
    00496           chain_after++;
    00497           u = u->Next();
    00498         }
    00499
    00500         return chain_before | chain_after << 8 | (chain_before + chain_after + (variable == 0x41)) << 16;
    00501       }
    00502
    00503     case 0x42: { // Consist cargo information
    00504       const Vehicle *u;
    00505       byte cargo_classes = 0;
    00506       uint8 common_cargo_best = 0;
    00507       uint8 common_cargos[NUM_CARGO];
    00508       uint8 common_subtype_best = 0;
    00509       uint8 common_subtypes[256];
    00510       byte user_def_data = 0;
    00511       CargoID common_cargo_type = CT_PASSENGERS;
    00512       uint8 common_subtype = 0;
    00513
    00514       /* Reset our arrays */
    00515       memset(common_cargos, 0, sizeof(common_cargos));
    00516       memset(common_subtypes, 0, sizeof(common_subtypes));
    00517
    00518       for (u = v; u != NULL; u = u->Next()) {
    00519         if (v->type == VEH_TRAIN) user_def_data |= u->u.rail.user_def_data;
    00520
    00521         /* Skip empty engines */
    00522         if (u->cargo_cap == 0) continue;
    00523
    00524         cargo_classes |= GetCargo(u->cargo_type)->classes;
    00525         common_cargos[u->cargo_type]++;
    00526         common_subtypes[u->cargo_subtype]++;
    00527       }
    00528
    00529       /* Pick the most common cargo type */
    00530       for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
    00531         if (common_cargos[cargo] > common_cargo_best) {
    00532           common_cargo_best = common_cargos[cargo];
    00533           common_cargo_type = GetCargo(cargo)->bitnum;
    00534         }
    00535       }
    00536
    00537       for (uint i = 0; i < lengthof(common_subtypes); i++) {
    00538         if (common_subtypes[i] > common_subtype_best) {
    00539           common_subtype_best = common_subtypes[i];
    00540           common_subtype = i;
    00541         }
    00542       }
    00543
    00544       return cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24);
    00545     }
    00546
    00547     case 0x43: // Player information
    00548       return v->owner | (GetPlayer(v->owner)->is_ai ? 0x10000 : 0) | (LiveryHelper(v->engine_type, v) << 24);
    00549
    00550     case 0x44: // Aircraft information
    00551       if (v->type != VEH_AIRCRAFT) return UINT_MAX;
    00552
    00553       {
    00554         const Vehicle *w = v->Next();
    00555         uint16 altitude = v->z_pos - w->z_pos; // Aircraft height - shadow height
    00556         byte airporttype = ATP_TTDP_LARGE;
    00557
    00558         const Station *st = GetTargetAirportIfValid(v);
    00559
    00560         if (st != NULL) {
    00561           switch (st->airport_type) {
    00562             /* Note, Helidepot and Helistation are treated as small airports
    00563              * as they are at ground level. */
    00564             case AT_HELIDEPOT:
    00565             case AT_HELISTATION:
    00566             case AT_COMMUTER:
    00567             case AT_SMALL:         airporttype = ATP_TTDP_SMALL; break;
    00568             case AT_METROPOLITAN:
    00569             case AT_INTERNATIONAL:
    00570             case AT_INTERCON:
    00571             case AT_LARGE:         airporttype = ATP_TTDP_LARGE; break;
    00572             case AT_HELIPORT:      airporttype = ATP_TTDP_HELIPORT; break;
    00573             case AT_OILRIG:        airporttype = ATP_TTDP_OILRIG; break;
    00574             default:               airporttype = ATP_TTDP_LARGE; break;
    00575           }
    00576         }
    00577
    00578         return (altitude << 8) | airporttype;
    00579       }
    00580
    00581     case 0x45: { // Curvature info
    00582       /* Format: xxxTxBxF
    00583        * F - previous wagon to current wagon, 0 if vehicle is first
    00584        * B - current wagon to next wagon, 0 if wagon is last
    00585        * T - previous wagon to next wagon, 0 in an S-bend
    00586        */
    00587       if (v->type != VEH_TRAIN) return 0;
    00588
    00589       const Vehicle *u_p = v->Previous();
    00590       const Vehicle *u_n = v->Next();
    00591       DirDiff f = (u_p == NULL) ?  DIRDIFF_SAME : DirDifference(u_p->direction, v->direction);
    00592       DirDiff b = (u_n == NULL) ?  DIRDIFF_SAME : DirDifference(v->direction, u_n->direction);
    00593       DirDiff t = ChangeDirDiff(f, b);
    00594
    00595       return ((t > DIRDIFF_REVERSE ? t | 8 : t) << 16) |
    00596              ((b > DIRDIFF_REVERSE ? b | 8 : b) <<  8) |
    00597              ( f > DIRDIFF_REVERSE ? f | 8 : f);
    00598     }
    00599
    00600     case 0x46: // Motion counter
    00601       return v->motion_counter;
    00602
    00603     case 0x47: { // Vehicle cargo info
    00604       /* Format: ccccwwtt
    00605        * tt - the cargo type transported by the vehicle,
    00606        *     translated if a translation table has been installed.
    00607        * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
    00608        * cccc - the cargo class value of the cargo transported by the vehicle.
    00609        */
    00610       const CargoSpec *cs = GetCargo(v->cargo_type);
    00611
    00612       return (cs->classes << 16) | (cs->weight << 8) | GetEngineGRF(v->engine_type)->cargo_map[v->cargo_type];
    00613     }
    00614
    00615     case 0x48: return GetEngine(v->engine_type)->flags; // Vehicle Type Info
    00616
    00617     /* Variables which use the parameter */
    00618     case 0x60: // Count consist's engine ID occurance
    00619       if (v->type != VEH_TRAIN) return v->engine_type == parameter;
    00620
    00621       {
    00622         uint count = 0;
    00623         for (; v != NULL; v = v->Next()) {
    00624           if (v->engine_type == parameter) count++;
    00625         }
    00626         return count;
    00627       }
    00628
    00629     case 0x7F: return GetGRFParameter(v->engine_type, parameter); // Read GRF parameter
    00630
    00631     case 0xFE:
    00632     case 0xFF: {
    00633       uint16 modflags = 0;
    00634
    00635       if (v->type == VEH_TRAIN) {
    00636         const Vehicle *u = IsTrainWagon(v) && HasBit(v->vehicle_flags, VRF_POWEREDWAGON) ? v->First() : v;
    00637         RailType railtype = GetRailType(v->tile);
    00638         bool powered = IsTrainEngine(v) || (IsTrainWagon(v) && HasBit(v->vehicle_flags, VRF_POWEREDWAGON));
    00639         bool has_power = powered && HasPowerOnRail(u->u.rail.railtype, railtype);
    00640         bool is_electric = powered && u->u.rail.railtype == RAILTYPE_ELECTRIC;
    00641
    00642         if (has_power) SetBit(modflags, 5);
    00643         if (is_electric && !has_power) SetBit(modflags, 6);
    00644         if (HasBit(v->u.rail.flags, VRF_TOGGLE_REVERSE)) SetBit(modflags, 8);
    00645       }
    00646       if (HasBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE)) SetBit(modflags, 10);
    00647
    00648       return variable == 0xFE ? modflags : GB(modflags, 8, 8);
    00649     }
    00650   }
    00651
    00652   /* General vehicle properties */
    00653   switch (variable - 0x80) {
    00654     case 0x00: return v->type;
    00655     case 0x01: return MapOldSubType(v);
    00656     case 0x04: return v->index;
    00657     case 0x05: return GB(v->index, 8, 8);
    00658     case 0x0A: return PackOrder(&v->current_order);
    00659     case 0x0B: return GB(PackOrder(&v->current_order), 8, 8);
    00660     case 0x0C: return v->num_orders;
    00661     case 0x0D: return v->cur_order_index;
    00662     case 0x10: return v->load_unload_time_rem;
    00663     case 0x11: return GB(v->load_unload_time_rem, 8, 8);
    00664     case 0x12: return max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
    00665     case 0x13: return GB(max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0), 8, 8);
    00666     case 0x14: return v->service_interval;
    00667     case 0x15: return GB(v->service_interval, 8, 8);
    00668     case 0x16: return v->last_station_visited;
    00669     case 0x17: return v->tick_counter;
    00670     case 0x18: return v->max_speed;
    00671     case 0x19: return GB(v->max_speed, 8, 8);
    00672     case 0x1A: return v->x_pos;
    00673     case 0x1B: return GB(v->x_pos, 8, 8);
    00674     case 0x1C: return v->y_pos;
    00675     case 0x1D: return GB(v->y_pos, 8, 8);
    00676     case 0x1E: return v->z_pos;
    00677     case 0x1F: return object->info_view ? DIR_W : v->direction;
    00678     case 0x28: return v->cur_image;
    00679     case 0x29: return GB(v->cur_image, 8, 8);
    00680     case 0x32: return v->vehstatus;
    00681     case 0x33: return 0; // non-existent high byte of vehstatus
    00682     case 0x34: return v->cur_speed;
    00683     case 0x35: return GB(v->cur_speed, 8, 8);
    00684     case 0x36: return v->subspeed;
    00685     case 0x37: return v->acceleration;
    00686     case 0x39: return v->cargo_type;
    00687     case 0x3A: return v->cargo_cap;
    00688     case 0x3B: return GB(v->cargo_cap, 8, 8);
    00689     case 0x3C: return v->cargo.Count();
    00690     case 0x3D: return GB(v->cargo.Count(), 8, 8);
    00691     case 0x3E: return v->cargo.Source();
    00692     case 0x3F: return v->cargo.DaysInTransit();
    00693     case 0x40: return v->age;
    00694     case 0x41: return GB(v->age, 8, 8);
    00695     case 0x42: return v->max_age;
    00696     case 0x43: return GB(v->max_age, 8, 8);
    00697     case 0x44: return Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
    00698     case 0x45: return v->unitnumber;
    00699     case 0x46: return v->engine_type;
    00700     case 0x47: return GB(v->engine_type, 8, 8);
    00701     case 0x48:
    00702       if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum;
    00703       return HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD;
    00704
    00705     case 0x49: return v->day_counter;
    00706     case 0x4A: return v->breakdowns_since_last_service;
    00707     case 0x4B: return v->breakdown_ctr;
    00708     case 0x4C: return v->breakdown_delay;
    00709     case 0x4D: return v->breakdown_chance;
    00710     case 0x4E: return v->reliability;
    00711     case 0x4F: return GB(v->reliability, 8, 8);
    00712     case 0x50: return v->reliability_spd_dec;
    00713     case 0x51: return GB(v->reliability_spd_dec, 8, 8);
    00714     case 0x52: return ClampToI32(v->GetDisplayProfitThisYear());
    00715     case 0x53: return GB(ClampToI32(v->GetDisplayProfitThisYear()),  8, 24);
    00716     case 0x54: return GB(ClampToI32(v->GetDisplayProfitThisYear()), 16, 16);
    00717     case 0x55: return GB(ClampToI32(v->GetDisplayProfitThisYear()), 24,  8);
    00718     case 0x56: return ClampToI32(v->GetDisplayProfitLastYear());
    00719     case 0x57: return GB(ClampToI32(v->GetDisplayProfitLastYear()),  8, 24);
    00720     case 0x58: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 16, 16);
    00721     case 0x59: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 24,  8);
    00722     case 0x5A: return v->Next() == NULL ? INVALID_VEHICLE : v->Next()->index;
    00723     case 0x5C: return ClampToI32(v->value);
    00724     case 0x5D: return GB(ClampToI32(v->value),  8, 24);
    00725     case 0x5E: return GB(ClampToI32(v->value), 16, 16);
    00726     case 0x5F: return GB(ClampToI32(v->value), 24,  8);
    00727     case 0x72: return v->cargo_subtype;
    00728     case 0x7A: return v->random_bits;
    00729     case 0x7B: return v->waiting_triggers;
    00730   }
    00731
    00732   /* Vehicle specific properties */
    00733   switch (v->type) {
    00734     case VEH_TRAIN:
    00735       switch (variable - 0x80) {
    00736         case 0x62: return v->u.rail.track;
    00737         case 0x66: return v->u.rail.railtype;
    00738         case 0x73: return v->u.rail.cached_veh_length;
    00739         case 0x74: return v->u.rail.cached_power;
    00740         case 0x75: return GB(v->u.rail.cached_power,  8, 24);
    00741         case 0x76: return GB(v->u.rail.cached_power, 16, 16);
    00742         case 0x77: return GB(v->u.rail.cached_power, 24,  8);
    00743         case 0x7C: return v->First()->index;
    00744         case 0x7D: return GB(v->First()->index, 8, 8);
    00745         case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
    00746       }
    00747       break;
    00748
    00749     case VEH_ROAD:
    00750       switch (variable - 0x80) {
    00751         case 0x62: return v->u.road.state;
    00752         case 0x64: return v->u.road.blocked_ctr;
    00753         case 0x65: return GB(v->u.road.blocked_ctr, 8, 8);
    00754         case 0x66: return v->u.road.overtaking;
    00755         case 0x67: return v->u.road.overtaking_ctr;
    00756         case 0x68: return v->u.road.crashed_ctr;
    00757         case 0x69: return GB(v->u.road.crashed_ctr, 8, 8);
    00758       }
    00759       break;
    00760
    00761     case VEH_AIRCRAFT:
    00762       switch (variable - 0x80) {
    00763         case 0x62: return MapAircraftMovementState(v);  // Current movement state
    00764         case 0x63: return v->u.air.targetairport;       // Airport to which the action refers
    00765         case 0x66: return MapAircraftMovementAction(v); // Current movement action
    00766       }
    00767       break;
    00768
    00769     default: break;
    00770   }
    00771
    00772   DEBUG(grf, 1, "Unhandled vehicle property 0x%X, type 0x%X", variable, v->type);
    00773
    00774   *available = false;
    00775   return UINT_MAX;
    00776 }
    00777
    00778
    00779 static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const SpriteGroup *group)
    00780 {
    00781   const Vehicle *v = object->u.vehicle.self;
    00782   uint totalsets;
    00783   uint set;
    00784
    00785   if (v == NULL) {
    00786     if (group->g.real.num_loading > 0) return group->g.real.loading[0];
    00787     if (group->g.real.num_loaded  > 0) return group->g.real.loaded[0];
    00788     return NULL;
    00789   }
    00790
    00791   bool in_motion = v->First()->current_order.type != OT_LOADING;
    00792
    00793   totalsets = in_motion ? group->g.real.num_loaded : group->g.real.num_loading;
    00794
    00795   if (v->cargo.Count() >= v->cargo_cap || totalsets == 1) {
    00796     set = totalsets - 1;
    00797   } else if (v->cargo.Empty() || totalsets == 2) {
    00798     set = 0;
    00799   } else {
    00800     set = v->cargo.Count() * (totalsets - 2) / max((uint16)1, v->cargo_cap) + 1;
    00801   }
    00802
    00803   return in_motion ? group->g.real.loaded[set] : group->g.real.loading[set];
    00804 }
    00805
    00806
    00807 static inline void NewVehicleResolver(ResolverObject *res, EngineID engine_type, const Vehicle *v)
    00808 {
    00809   res->GetRandomBits = &VehicleGetRandomBits;
    00810   res->GetTriggers   = &VehicleGetTriggers;
    00811   res->SetTriggers   = &VehicleSetTriggers;
    00812   res->GetVariable   = &VehicleGetVariable;
    00813   res->ResolveReal   = &VehicleResolveReal;
    00814
    00815   res->u.vehicle.self   = v;
    00816   res->u.vehicle.parent = (v != NULL) ? v->First() : v;
    00817
    00818   res->u.vehicle.self_type = engine_type;
    00819
    00820   res->info_view = false;
    00821
    00822   res->callback        = CBID_NO_CALLBACK;
    00823   res->callback_param1 = 0;
    00824   res->callback_param2 = 0;
    00825   res->last_value      = 0;
    00826   res->trigger         = 0;
    00827   res->reseed          = 0;
    00828 }
    00829
    00830
    00839 static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *v, bool use_cache = true)
    00840 {
    00841   const SpriteGroup *group;
    00842   CargoID cargo;
    00843
    00844   if (v == NULL) {
    00845     cargo = CT_PURCHASE;
    00846   } else {
    00847     cargo = v->cargo_type;
    00848
    00849     if (v->type == VEH_TRAIN) {
    00850       /* We always use cached value, except for callbacks because the override spriteset
    00851        * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
    00852        * as v->cargo_type is temporary changed to the new type */
    00853       group = use_cache ? v->u.rail.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->u.rail.first_engine);
    00854       if (group != NULL) return group;
    00855     }
    00856   }
    00857
    00858   group = _engine_custom_sprites[engine][cargo];
    00859   if (group != NULL) return group;
    00860
    00861   /* Fall back to the default set if the selected cargo type is not defined */
    00862   return _engine_custom_sprites[engine][CT_DEFAULT];
    00863 }
    00864
    00865
    00866 SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction)
    00867 {
    00868   const SpriteGroup *group;
    00869   ResolverObject object;
    00870
    00871   NewVehicleResolver(&object, engine, v);
    00872
    00873   group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
    00874   if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
    00875
    00876   return group->g.result.sprite + (direction % group->g.result.num_sprites);
    00877 }
    00878
    00879
    00880 SpriteID GetRotorOverrideSprite(EngineID engine, const Vehicle *v, bool info_view)
    00881 {
    00882   const SpriteGroup *group;
    00883   ResolverObject object;
    00884
    00885   assert(engine >= AIRCRAFT_ENGINES_INDEX);
    00886   assert(engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES);
    00887
    00888   /* Only valid for helicopters */
    00889   assert(!(AircraftVehInfo(engine)->subtype & AIR_CTOL));
    00890
    00891   NewVehicleResolver(&object, engine, v);
    00892
    00893   object.info_view = info_view;
    00894
    00895   group = GetWagonOverrideSpriteSet(engine, CT_DEFAULT, engine);
    00896   group = Resolve(group, &object);
    00897
    00898   if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
    00899
    00900   if (v == NULL) return group->g.result.sprite;
    00901
    00902   return group->g.result.sprite + (info_view ? 0 : (v->Next()->Next()->u.air.state % group->g.result.num_sprites));
    00903 }
    00904
    00905
    00911 bool UsesWagonOverride(const Vehicle* v)
    00912 {
    00913   assert(v->type == VEH_TRAIN);
    00914   return v->u.rail.cached_override != NULL;
    00915 }
    00916
    00926 uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
    00927 {
    00928   const SpriteGroup *group;
    00929   ResolverObject object;
    00930
    00931   NewVehicleResolver(&object, engine, v);
    00932
    00933   object.callback        = callback;
    00934   object.callback_param1 = param1;
    00935   object.callback_param2 = param2;
    00936
    00937   group = Resolve(GetVehicleSpriteGroup(engine, v, false), &object);
    00938   if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
    00939
    00940   return group->g.callback.result;
    00941 }
    00942
    00953 uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
    00954 {
    00955   const SpriteGroup *group;
    00956   ResolverObject object;
    00957
    00958   NewVehicleResolver(&object, engine, v);
    00959
    00960   object.callback        = callback;
    00961   object.callback_param1 = param1;
    00962   object.callback_param2 = param2;
    00963
    00964   object.u.vehicle.parent = parent;
    00965
    00966   group = Resolve(GetVehicleSpriteGroup(engine, v, false), &object);
    00967   if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
    00968
    00969   return group->g.callback.result;
    00970 }
    00971
    00972
    00973 /* Callback 36 handlers */
    00974 uint GetVehicleProperty(const Vehicle *v, uint8 property, uint orig_value)
    00975 {
    00976   uint16 callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, v->engine_type, v);
    00977   if (callback != CALLBACK_FAILED) return callback;
    00978
    00979   return orig_value;
    00980 }
    00981
    00982
    00983 uint GetEngineProperty(EngineID engine, uint8 property, uint orig_value)
    00984 {
    00985   uint16 callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, NULL);
    00986   if (callback != CALLBACK_FAILED) return callback;
    00987
    00988   return orig_value;
    00989 }
    00990
    00991
    00992 static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_random_bits, bool first)
    00993 {
    00994   const SpriteGroup *group;
    00995   ResolverObject object;
    00996   byte new_random_bits;
    00997
    00998   /* We can't trigger a non-existent vehicle... */
    00999   assert(v != NULL);
    01000
    01001   NewVehicleResolver(&object, v->engine_type, v);
    01002   object.callback = CBID_RANDOM_TRIGGER;
    01003   object.trigger = trigger;
    01004
    01005   group = Resolve(GetVehicleSpriteGroup(v->engine_type, v), &object);
    01006   if (group == NULL) return;
    01007
    01008   new_random_bits = Random();
    01009   v->random_bits &= ~object.reseed;
    01010   v->random_bits |= (first ? new_random_bits : base_random_bits) & object.reseed;
    01011
    01012   switch (trigger) {
    01013     case VEHICLE_TRIGGER_NEW_CARGO:
    01014       /* All vehicles in chain get ANY_NEW_CARGO trigger now.
    01015        * So we call it for the first one and they will recurse. */
    01016       /* Indexing part of vehicle random bits needs to be
    01017        * same for all triggered vehicles in the chain (to get
    01018        * all the random-cargo wagons carry the same cargo,
    01019        * i.e.), so we give them all the NEW_CARGO triggered
    01020        * vehicle's portion of random bits. */
    01021       assert(first);
    01022       DoTriggerVehicle(v->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false);
    01023       break;
    01024
    01025     case VEHICLE_TRIGGER_DEPOT:
    01026       /* We now trigger the next vehicle in chain recursively.
    01027        * The random bits portions may be different for each
    01028        * vehicle in chain. */
    01029       if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, 0, true);
    01030       break;
    01031
    01032     case VEHICLE_TRIGGER_EMPTY:
    01033       /* We now trigger the next vehicle in chain
    01034        * recursively.  The random bits portions must be same
    01035        * for each vehicle in chain, so we give them all
    01036        * first chained vehicle's portion of random bits. */
    01037       if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, first ? new_random_bits : base_random_bits, false);
    01038       break;
    01039
    01040     case VEHICLE_TRIGGER_ANY_NEW_CARGO:
    01041       /* Now pass the trigger recursively to the next vehicle
    01042        * in chain. */
    01043       assert(!first);
    01044       if (v->Next() != NULL) DoTriggerVehicle(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false);
    01045       break;
    01046
    01047     case VEHICLE_TRIGGER_CALLBACK_32:
    01048       /* Do not do any recursion */
    01049       break;
    01050   }
    01051 }
    01052
    01053 void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
    01054 {
    01055   if (trigger == VEHICLE_TRIGGER_DEPOT) {
    01056     /* store that the vehicle entered a depot this tick */
    01057     VehicleEnteredDepotThisTick(v);
    01058   }
    01059
    01060   DoTriggerVehicle(v, trigger, 0, true);
    01061 }
    01062
    01063 /* Functions for changing the order of vehicle purchase lists
    01064  * This is currently only implemented for rail vehicles. */
    01065 static EngineID _engine_list_order[NUM_TRAIN_ENGINES];
    01066 static byte _engine_list_position[NUM_TRAIN_ENGINES];
    01067
    01068 void ResetEngineListOrder()
    01069 {
    01070   EngineID i;
    01071
    01072   for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
    01073     _engine_list_order[i] = i;
    01074     _engine_list_position[i] = i;
    01075   }
    01076 }
    01077
    01084 EngineID GetRailVehAtPosition(EngineID pos)
    01085 {
    01086   if (pos < NUM_TRAIN_ENGINES) return _engine_list_order[pos];
    01087   return pos;
    01088 }
    01089
    01096 uint16 ListPositionOfEngine(EngineID engine)
    01097 {
    01098   if (engine < NUM_TRAIN_ENGINES) return _engine_list_position[engine];
    01099   return engine;
    01100 }
    01101
    01102 void AlterRailVehListOrder(EngineID engine, EngineID target)
    01103 {
    01104   EngineID i;
    01105   bool moving = false;
    01106
    01107   if (engine == target) return;
    01108
    01109   /* First, remove our ID from the list. */
    01110   for (i = 0; i < NUM_TRAIN_ENGINES - 1; i++) {
    01111     if (_engine_list_order[i] == engine) moving = true;
    01112     if (moving) _engine_list_order[i] = _engine_list_order[i + 1];
    01113   }
    01114
    01115   /* Now, insert it again, before the target engine. */
    01116   for (i = NUM_TRAIN_ENGINES - 1; i > 0; i--) {
    01117     _engine_list_order[i] = _engine_list_order[i - 1];
    01118     if (_engine_list_order[i] == target) {
    01119       _engine_list_order[i - 1] = engine;
    01120       break;
    01121     }
    01122   }
    01123
    01124   /* Update the engine list position (a reverse of engine list order) */
    01125   for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
    01126     _engine_list_position[_engine_list_order[i]] = i;
    01127   }
    01128 }