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 }

Generated on Wed Oct 1 17:03:22 2008 for openttd by  doxygen 1.5.6