00001
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);
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
00062
00063
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
00076
00077
00078
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
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
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
00228
00229
00230
00231
00232
00233 if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
00234
00235
00236
00237 if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
00238
00239
00240
00241 if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR;
00242
00243
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
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:
00268 if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
00269 if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
00270 return AMS_TTDP_TO_JUNCTION;
00271
00272 case TAKEOFF:
00273 return AMS_TTDP_TO_OUTWAY;
00274
00275 case STARTTAKEOFF:
00276 return AMS_TTDP_TAKEOFF;
00277
00278 case ENDTAKEOFF:
00279 return AMS_TTDP_CLIMBING;
00280
00281 case HELITAKEOFF:
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:
00293 return AMS_TTDP_FLIGHT_DESCENT;
00294
00295 case ENDLANDING:
00296 if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING;
00297
00298 return AMS_TTDP_TO_INWAY;
00299
00300 case HELILANDING:
00301 case HELIENDLANDING:
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
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:
00369 case STARTTAKEOFF:
00370 case ENDTAKEOFF:
00371 case HELITAKEOFF:
00372
00373 return AMA_TTDP_PAD1_TO_TAKEOFF;
00374
00375 case FLYING:
00376 return AMA_TTDP_IN_FLIGHT;
00377
00378 case LANDING:
00379 case ENDLANDING:
00380 case HELILANDING:
00381 case HELIENDLANDING:
00382
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
00393 enum {
00394 ATP_TTDP_SMALL,
00395 ATP_TTDP_LARGE,
00396 ATP_TTDP_HELIPORT,
00397 ATP_TTDP_OILRIG,
00398 };
00399
00400
00401
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
00423
00424
00425
00426 Vehicle *v = (Vehicle*)GRV(object);
00427
00428
00429
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
00468 switch (variable) {
00469 case 0x43: return _current_player | (LiveryHelper(object->u.vehicle.self_type, NULL) << 24);
00470 case 0x46: return 0;
00471 case 0x48: return GetEngine(object->u.vehicle.self_type)->flags;
00472 case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
00473 case 0xDA: return INVALID_VEHICLE;
00474 case 0x7F: return GetGRFParameter(object->u.vehicle.self_type, parameter);
00475 }
00476
00477 *available = false;
00478 return UINT_MAX;
00479 }
00480
00481
00482 switch (variable) {
00483 case 0x40:
00484 case 0x41:
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: {
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
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
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
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:
00548 return v->owner | (GetPlayer(v->owner)->is_ai ? 0x10000 : 0) | (LiveryHelper(v->engine_type, v) << 24);
00549
00550 case 0x44:
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;
00556 byte airporttype = ATP_TTDP_LARGE;
00557
00558 const Station *st = GetTargetAirportIfValid(v);
00559
00560 if (st != NULL) {
00561 switch (st->airport_type) {
00562
00563
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: {
00582
00583
00584
00585
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:
00601 return v->motion_counter;
00602
00603 case 0x47: {
00604
00605
00606
00607
00608
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;
00616
00617
00618 case 0x60:
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);
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
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;
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
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;
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);
00764 case 0x63: return v->u.air.targetairport;
00765 case 0x66: return MapAircraftMovementAction(v);
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
00851
00852
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
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
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
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
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
01015
01016
01017
01018
01019
01020
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
01027
01028
01029 if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, 0, true);
01030 break;
01031
01032 case VEHICLE_TRIGGER_EMPTY:
01033
01034
01035
01036
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
01042
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
01049 break;
01050 }
01051 }
01052
01053 void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
01054 {
01055 if (trigger == VEHICLE_TRIGGER_DEPOT) {
01056
01057 VehicleEnteredDepotThisTick(v);
01058 }
01059
01060 DoTriggerVehicle(v, trigger, 0, true);
01061 }
01062
01063
01064
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
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
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
01125 for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
01126 _engine_list_position[_engine_list_order[i]] = i;
01127 }
01128 }