00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "variables.h"
00008 #include "tile_cmd.h"
00009 #include "landscape.h"
00010 #include "debug.h"
00011 #include "sprite.h"
00012 #include "station.h"
00013 #include "station_map.h"
00014 #include "newgrf.h"
00015 #include "newgrf_callbacks.h"
00016 #include "newgrf_commons.h"
00017 #include "newgrf_station.h"
00018 #include "newgrf_spritegroup.h"
00019 #include "cargotype.h"
00020 #include "town.h"
00021 #include "newgrf_town.h"
00022 #include "gfx_func.h"
00023 #include "date_func.h"
00024 #include "player_func.h"
00025 #include "tunnelbridge_map.h"
00026
00027 #include "table/sprites.h"
00028 #include "table/strings.h"
00029
00030 static StationClass _station_classes[STAT_CLASS_MAX];
00031
00032 enum {
00033 MAX_SPECLIST = 255,
00034 };
00035
00041 void ResetStationClasses()
00042 {
00043 for (StationClassID i = STAT_CLASS_BEGIN; i < STAT_CLASS_MAX; i++) {
00044 _station_classes[i].id = 0;
00045 _station_classes[i].name = STR_EMPTY;
00046 _station_classes[i].stations = 0;
00047
00048 free(_station_classes[i].spec);
00049 _station_classes[i].spec = NULL;
00050 }
00051
00052
00053 _station_classes[0].id = 'DFLT';
00054 _station_classes[0].name = STR_STAT_CLASS_DFLT;
00055 _station_classes[0].stations = 1;
00056 _station_classes[0].spec = MallocT<StationSpec*>(1);
00057 _station_classes[0].spec[0] = NULL;
00058
00059 _station_classes[1].id = 'WAYP';
00060 _station_classes[1].name = STR_STAT_CLASS_WAYP;
00061 _station_classes[1].stations = 1;
00062 _station_classes[1].spec = MallocT<StationSpec*>(1);
00063 _station_classes[1].spec[0] = NULL;
00064 }
00065
00071 StationClassID AllocateStationClass(uint32 cls)
00072 {
00073 for (StationClassID i = STAT_CLASS_BEGIN; i < STAT_CLASS_MAX; i++) {
00074 if (_station_classes[i].id == cls) {
00075
00076 return i;
00077 } else if (_station_classes[i].id == 0) {
00078
00079 _station_classes[i].id = cls;
00080 return i;
00081 }
00082 }
00083
00084 grfmsg(2, "StationClassAllocate: already allocated %d classes, using default", STAT_CLASS_MAX);
00085 return STAT_CLASS_DFLT;
00086 }
00087
00089 void SetStationClassName(StationClassID sclass, StringID name)
00090 {
00091 assert(sclass < STAT_CLASS_MAX);
00092 _station_classes[sclass].name = name;
00093 }
00094
00096 StringID GetStationClassName(StationClassID sclass)
00097 {
00098 assert(sclass < STAT_CLASS_MAX);
00099 return _station_classes[sclass].name;
00100 }
00101
00106 uint GetNumStationClasses()
00107 {
00108 uint i;
00109 for (i = 0; i < STAT_CLASS_MAX && _station_classes[i].id != 0; i++) {}
00110 return i;
00111 }
00112
00118 uint GetNumCustomStations(StationClassID sclass)
00119 {
00120 assert(sclass < STAT_CLASS_MAX);
00121 return _station_classes[sclass].stations;
00122 }
00123
00128 void SetCustomStationSpec(StationSpec *statspec)
00129 {
00130 StationClass *station_class;
00131 int i;
00132
00133
00134 if (statspec->allocated) return;
00135
00136 assert(statspec->sclass < STAT_CLASS_MAX);
00137 station_class = &_station_classes[statspec->sclass];
00138
00139 i = station_class->stations++;
00140 station_class->spec = ReallocT(station_class->spec, station_class->stations);
00141
00142 station_class->spec[i] = statspec;
00143 statspec->allocated = true;
00144 }
00145
00152 const StationSpec *GetCustomStationSpec(StationClassID sclass, uint station)
00153 {
00154 assert(sclass < STAT_CLASS_MAX);
00155 if (station < _station_classes[sclass].stations)
00156 return _station_classes[sclass].spec[station];
00157
00158
00159
00160 return NULL;
00161 }
00162
00163
00164 const StationSpec *GetCustomStationSpecByGrf(uint32 grfid, byte localidx)
00165 {
00166 uint j;
00167
00168 for (StationClassID i = STAT_CLASS_BEGIN; i < STAT_CLASS_MAX; i++) {
00169 for (j = 0; j < _station_classes[i].stations; j++) {
00170 const StationSpec *statspec = _station_classes[i].spec[j];
00171 if (statspec == NULL) continue;
00172 if (statspec->grffile->grfid == grfid && statspec->localidx == localidx) return statspec;
00173 }
00174 }
00175
00176 return NULL;
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred)
00188 {
00189 uint32 retval = 0;
00190
00191 if (axis == AXIS_X) {
00192 Swap(platforms, length);
00193 Swap(x, y);
00194 }
00195
00196
00197 platforms = min(15, platforms);
00198 length = min(15, length);
00199 x = min(15, x);
00200 y = min(15, y);
00201 if (centred) {
00202 x -= platforms / 2;
00203 y -= length / 2;
00204 SB(retval, 0, 4, y & 0xF);
00205 SB(retval, 4, 4, x & 0xF);
00206 } else {
00207 SB(retval, 0, 4, y);
00208 SB(retval, 4, 4, length - y - 1);
00209 SB(retval, 8, 4, x);
00210 SB(retval, 12, 4, platforms - x - 1);
00211 }
00212 SB(retval, 16, 4, length);
00213 SB(retval, 20, 4, platforms);
00214 SB(retval, 24, 4, tile);
00215
00216 return retval;
00217 }
00218
00219
00220
00221
00222
00223
00224 static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
00225 {
00226 bool waypoint;
00227 byte orig_type = 0;
00228 Axis orig_axis = AXIS_X;
00229
00230 waypoint = IsTileType(tile, MP_RAILWAY);
00231
00232 if (waypoint) {
00233 if (check_axis) orig_axis = GetWaypointAxis(tile);
00234 } else {
00235 if (check_type) orig_type = GetCustomStationSpecIndex(tile);
00236 if (check_axis) orig_axis = GetRailStationAxis(tile);
00237 }
00238
00239 while (true) {
00240 TileIndex new_tile = TILE_ADD(tile, delta);
00241
00242 if (waypoint) {
00243 if (!IsTileType(new_tile, MP_RAILWAY)) break;
00244 if (!IsRailWaypoint(new_tile)) break;
00245 if (check_axis && GetWaypointAxis(new_tile) != orig_axis) break;
00246 } else {
00247 if (!IsRailwayStationTile(new_tile)) break;
00248 if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
00249 if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
00250 }
00251
00252 tile = new_tile;
00253 }
00254 return tile;
00255 }
00256
00257
00258 static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred)
00259 {
00260 int tx = TileX(tile);
00261 int ty = TileY(tile);
00262 int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1, 0), check_type, check_axis));
00263 int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis));
00264 int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1;
00265 int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1;
00266 Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
00267
00268 tx -= sx; ex -= sx;
00269 ty -= sy; ey -= sy;
00270
00271 return GetPlatformInfo(axis, IsTileType(tile, MP_RAILWAY) ? 2 : GetStationGfx(tile), ex, ey, tx, ty, centred);
00272 }
00273
00274
00275 static uint32 GetRailContinuationInfo(TileIndex tile)
00276 {
00277
00278 static const Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N };
00279 static const DiagDirection x_exits[8] = { DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SW, DIAGDIR_NE };
00280
00281
00282 static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N };
00283 static const DiagDirection y_exits[8] = { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NW };
00284
00285 Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
00286
00287
00288 const Direction *dir = axis == AXIS_X ? x_dir : y_dir;
00289 const DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits;
00290
00291 uint32 res = 0;
00292 uint i;
00293
00294 for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) {
00295 TileIndex neighbour_tile = tile + TileOffsByDir(*dir);
00296 TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(neighbour_tile, TRANSPORT_RAIL, 0));
00297 if (trackbits != TRACK_BIT_NONE) {
00298
00299 SetBit(res, i + 8);
00300
00301
00302
00303 if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) {
00304 continue;
00305 }
00306
00307
00308 if (trackbits & DiagdirReachesTracks(*diagdir)) SetBit(res, i);
00309 }
00310 }
00311
00312 return res;
00313 }
00314
00315
00316
00317 static uint32 StationGetRandomBits(const ResolverObject *object)
00318 {
00319 const Station *st = object->u.station.st;
00320 const TileIndex tile = object->u.station.tile;
00321 return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16);
00322 }
00323
00324
00325 static uint32 StationGetTriggers(const ResolverObject *object)
00326 {
00327 const Station *st = object->u.station.st;
00328 return st == NULL ? 0 : st->waiting_triggers;
00329 }
00330
00331
00332 static void StationSetTriggers(const ResolverObject *object, int triggers)
00333 {
00334 Station *st = (Station*)object->u.station.st;
00335 assert(st != NULL);
00336 st->waiting_triggers = triggers;
00337 }
00338
00344 static struct {
00345 uint32 v40;
00346 uint32 v41;
00347 uint32 v45;
00348 uint32 v46;
00349 uint32 v47;
00350 uint32 v49;
00351 uint8 valid;
00352 } _svc;
00353
00354 static uint32 StationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
00355 {
00356 const Station *st = object->u.station.st;
00357 TileIndex tile = object->u.station.tile;
00358
00359 if (object->scope == VSG_SCOPE_PARENT) {
00360
00361 const Town *t;
00362
00363 if (st != NULL) {
00364 t = st->town;
00365 } else if (tile != INVALID_TILE) {
00366 t = ClosestTownFromTile(tile, UINT_MAX);
00367 } else {
00368 *available = false;
00369 return UINT_MAX;
00370 }
00371
00372 return TownGetVariable(variable, parameter, available, t);
00373 }
00374
00375 if (st == NULL) {
00376
00377 switch (variable) {
00378 case 0x40:
00379 case 0x41:
00380 case 0x46:
00381 case 0x47:
00382 case 0x49: return 0x2110000;
00383 case 0x42: return 0;
00384 case 0x43: return _current_player;
00385 case 0x44: return 2;
00386 case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
00387 }
00388
00389 *available = false;
00390 return UINT_MAX;
00391 }
00392
00393 switch (variable) {
00394
00395 case 0x40:
00396 if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(tile, false, false, false); SetBit(_svc.valid, 0); }
00397 return _svc.v40;
00398
00399 case 0x41:
00400 if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(tile, true, false, false); SetBit(_svc.valid, 1); }
00401 return _svc.v41;
00402
00403 case 0x42: return GetTerrainType(tile) | (GetRailType(tile) << 8);
00404 case 0x43: return st->owner;
00405 case 0x44: return 2;
00406 case 0x45:
00407 if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); }
00408 return _svc.v45;
00409
00410 case 0x46:
00411 if (!HasBit(_svc.valid, 3)) { _svc.v46 = GetPlatformInfoHelper(tile, false, false, true); SetBit(_svc.valid, 3); }
00412 return _svc.v46;
00413
00414 case 0x47:
00415 if (!HasBit(_svc.valid, 4)) { _svc.v47 = GetPlatformInfoHelper(tile, true, false, true); SetBit(_svc.valid, 4); }
00416 return _svc.v47;
00417
00418 case 0x48: {
00419 CargoID cargo_type;
00420 uint32 value = 0;
00421
00422 for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
00423 if (HasBit(st->goods[cargo_type].acceptance_pickup, GoodsEntry::PICKUP)) SetBit(value, cargo_type);
00424 }
00425 return value;
00426 }
00427 case 0x49:
00428 if (!HasBit(_svc.valid, 5)) { _svc.v49 = GetPlatformInfoHelper(tile, false, true, false); SetBit(_svc.valid, 5); }
00429 return _svc.v49;
00430
00431
00432
00433 case 0x67: {
00434 Axis axis = GetRailStationAxis(tile);
00435
00436 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
00437
00438 Slope tileh = GetTileSlope(tile, NULL);
00439 bool swap = (axis == AXIS_Y && HasBit(tileh, SLOPE_W) != HasBit(tileh, SLOPE_E));
00440
00441 return GetNearbyTileInformation(tile) ^ (swap ? SLOPE_EW : 0);
00442 }
00443
00444 case 0x68: {
00445 TileIndex nearby_tile = GetNearbyTile(parameter, tile);
00446
00447 if (!IsRailwayStationTile(nearby_tile)) return 0xFFFFFFFF;
00448
00449 uint32 grfid = st->speclist[GetCustomStationSpecIndex(tile)].grfid;
00450 bool perpendicular = GetRailStationAxis(tile) != GetRailStationAxis(nearby_tile);
00451 bool same_station = st->TileBelongsToRailStation(nearby_tile);
00452 uint32 res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
00453
00454 if (IsCustomStationSpecIndex(nearby_tile)) {
00455 const StationSpecList ssl = GetStationByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
00456 res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ssl.localidx;
00457 }
00458 return res;
00459 }
00460
00461
00462 case 0x82: return 50;
00463 case 0x84: return st->string_id;
00464 case 0x86: return 0;
00465 case 0x8A: return st->had_vehicle_of_type;
00466 case 0xF0: return st->facilities;
00467 case 0xF1: return st->airport_type;
00468 case 0xF2: return st->truck_stops->status;
00469 case 0xF3: return st->bus_stops->status;
00470 case 0xF6: return st->airport_flags;
00471 case 0xF7: return GB(st->airport_flags, 8, 8);
00472 case 0xFA: return Clamp(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
00473 }
00474
00475
00476 if (variable >= 0x60 && variable <= 0x65) {
00477 CargoID c = GetCargoTranslation(parameter, object->u.station.statspec->grffile);
00478
00479 if (c == CT_INVALID) return 0;
00480 const GoodsEntry *ge = &st->goods[c];
00481
00482 switch (variable) {
00483 case 0x60: return min(ge->cargo.Count(), 4095);
00484 case 0x61: return ge->days_since_pickup;
00485 case 0x62: return ge->rating;
00486 case 0x63: return ge->cargo.DaysInTransit();
00487 case 0x64: return ge->last_speed | (ge->last_age << 8);
00488 case 0x65: return GB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1) << 3;
00489 }
00490 }
00491
00492
00493 if (variable >= 0x8C && variable <= 0xEC) {
00494 const GoodsEntry *g = &st->goods[GB(variable - 0x8C, 3, 4)];
00495 switch (GB(variable - 0x8C, 0, 3)) {
00496 case 0: return g->cargo.Count();
00497 case 1: return GB(min(g->cargo.Count(), 4095), 0, 4) | (GB(g->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1) << 7);
00498 case 2: return g->days_since_pickup;
00499 case 3: return g->rating;
00500 case 4: return g->cargo.Source();
00501 case 5: return g->cargo.DaysInTransit();
00502 case 6: return g->last_speed;
00503 case 7: return g->last_age;
00504 }
00505 }
00506
00507 DEBUG(grf, 1, "Unhandled station property 0x%X", variable);
00508
00509 *available = false;
00510 return UINT_MAX;
00511 }
00512
00513
00514 static const SpriteGroup *StationResolveReal(const ResolverObject *object, const SpriteGroup *group)
00515 {
00516 const Station *st = object->u.station.st;
00517 const StationSpec *statspec = object->u.station.statspec;
00518 uint set;
00519
00520 uint cargo = 0;
00521 CargoID cargo_type = object->u.station.cargo_type;
00522
00523 if (st == NULL || statspec->sclass == STAT_CLASS_WAYP) {
00524 return group->g.real.loading[0];
00525 }
00526
00527 switch (cargo_type) {
00528 case CT_INVALID:
00529 case CT_DEFAULT_NA:
00530 case CT_PURCHASE:
00531 cargo = 0;
00532 break;
00533
00534 case CT_DEFAULT:
00535 for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
00536 cargo += st->goods[cargo_type].cargo.Count();
00537 }
00538 break;
00539
00540 default:
00541 cargo = st->goods[cargo_type].cargo.Count();
00542 break;
00543 }
00544
00545 if (HasBit(statspec->flags, 1)) cargo /= (st->trainst_w + st->trainst_h);
00546 cargo = min(0xfff, cargo);
00547
00548 if (cargo > statspec->cargo_threshold) {
00549 if (group->g.real.num_loading > 0) {
00550 set = ((cargo - statspec->cargo_threshold) * group->g.real.num_loading) / (4096 - statspec->cargo_threshold);
00551 return group->g.real.loading[set];
00552 }
00553 } else {
00554 if (group->g.real.num_loaded > 0) {
00555 set = (cargo * group->g.real.num_loaded) / (statspec->cargo_threshold + 1);
00556 return group->g.real.loaded[set];
00557 }
00558 }
00559
00560 return group->g.real.loading[0];
00561 }
00562
00563
00564 static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, const Station *st, TileIndex tile)
00565 {
00566 res->GetRandomBits = StationGetRandomBits;
00567 res->GetTriggers = StationGetTriggers;
00568 res->SetTriggers = StationSetTriggers;
00569 res->GetVariable = StationGetVariable;
00570 res->ResolveReal = StationResolveReal;
00571
00572 res->u.station.st = st;
00573 res->u.station.statspec = statspec;
00574 res->u.station.tile = tile;
00575
00576 res->callback = CBID_NO_CALLBACK;
00577 res->callback_param1 = 0;
00578 res->callback_param2 = 0;
00579 res->last_value = 0;
00580 res->trigger = 0;
00581 res->reseed = 0;
00582 }
00583
00584 static const SpriteGroup *ResolveStation(ResolverObject *object)
00585 {
00586 const SpriteGroup *group;
00587 CargoID ctype = CT_DEFAULT_NA;
00588
00589 if (object->u.station.st == NULL) {
00590
00591 ctype = CT_PURCHASE;
00592 } else {
00593
00594 for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
00595 const CargoSpec *cs = GetCargo(cargo);
00596 if (cs->IsValid() && object->u.station.statspec->spritegroup[cargo] != NULL &&
00597 !object->u.station.st->goods[cargo].cargo.Empty()) {
00598 ctype = cargo;
00599 break;
00600 }
00601 }
00602 }
00603
00604 group = object->u.station.statspec->spritegroup[ctype];
00605 if (group == NULL) {
00606 ctype = CT_DEFAULT;
00607 group = object->u.station.statspec->spritegroup[ctype];
00608 }
00609
00610 if (group == NULL) return NULL;
00611
00612
00613 object->u.station.cargo_type = ctype;
00614
00615
00616 _svc.valid = 0;
00617
00618 return Resolve(group, object);
00619 }
00620
00621 SpriteID GetCustomStationRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
00622 {
00623 const SpriteGroup *group;
00624 ResolverObject object;
00625
00626 NewStationResolver(&object, statspec, st, tile);
00627
00628 group = ResolveStation(&object);
00629 if (group == NULL || group->type != SGT_RESULT) return 0;
00630 return group->g.result.sprite - 0x42D;
00631 }
00632
00633
00634 SpriteID GetCustomStationGroundRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
00635 {
00636 const SpriteGroup *group;
00637 ResolverObject object;
00638
00639 NewStationResolver(&object, statspec, st, tile);
00640 object.callback_param1 = 1;
00641
00642 group = ResolveStation(&object);
00643 if (group == NULL || group->type != SGT_RESULT) return 0;
00644 return group->g.result.sprite - 0x42D;
00645 }
00646
00647
00648 uint16 GetStationCallback(CallbackID callback, uint32 param1, uint32 param2, const StationSpec *statspec, const Station *st, TileIndex tile)
00649 {
00650 const SpriteGroup *group;
00651 ResolverObject object;
00652
00653 NewStationResolver(&object, statspec, st, tile);
00654
00655 object.callback = callback;
00656 object.callback_param1 = param1;
00657 object.callback_param2 = param2;
00658
00659 group = ResolveStation(&object);
00660 if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
00661 return group->g.callback.result;
00662 }
00663
00664
00672 int AllocateSpecToStation(const StationSpec *statspec, Station *st, bool exec)
00673 {
00674 uint i;
00675
00676 if (statspec == NULL || st == NULL) return 0;
00677
00678
00679 for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
00680 if (st->speclist[i].spec == statspec) return i;
00681 }
00682
00683 for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
00684 if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break;
00685 }
00686
00687 if (i == MAX_SPECLIST) return -1;
00688
00689 if (exec) {
00690 if (i >= st->num_specs) {
00691 st->num_specs = i + 1;
00692 st->speclist = ReallocT(st->speclist, st->num_specs);
00693
00694 if (st->num_specs == 2) {
00695
00696 st->speclist[0].spec = NULL;
00697 st->speclist[0].grfid = 0;
00698 st->speclist[0].localidx = 0;
00699 }
00700 }
00701
00702 st->speclist[i].spec = statspec;
00703 st->speclist[i].grfid = statspec->grffile->grfid;
00704 st->speclist[i].localidx = statspec->localidx;
00705 }
00706
00707 return i;
00708 }
00709
00710
00716 void DeallocateSpecFromStation(Station* st, byte specindex)
00717 {
00718
00719 if (specindex == 0) return;
00720
00721
00722 BEGIN_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile) {
00723 if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile) && GetCustomStationSpecIndex(tile) == specindex) {
00724 return;
00725 }
00726 } END_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile)
00727
00728
00729 st->speclist[specindex].spec = NULL;
00730 st->speclist[specindex].grfid = 0;
00731 st->speclist[specindex].localidx = 0;
00732
00733
00734 if (specindex == st->num_specs - 1) {
00735 for (; st->speclist[st->num_specs - 1].grfid == 0 && st->num_specs > 1; st->num_specs--) {}
00736
00737 if (st->num_specs > 1) {
00738 st->speclist = ReallocT(st->speclist, st->num_specs);
00739 } else {
00740 free(st->speclist);
00741 st->num_specs = 0;
00742 st->speclist = NULL;
00743 }
00744 }
00745 }
00746
00756 bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
00757 {
00758 const StationSpec *statspec;
00759 const DrawTileSprites *sprites;
00760 const DrawTileSeqStruct *seq;
00761 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
00762 SpriteID relocation;
00763 SpriteID image;
00764 SpriteID palette = PLAYER_SPRITE_COLOR(_local_player);
00765 uint tile = 2;
00766
00767 statspec = GetCustomStationSpec(sclass, station);
00768 if (statspec == NULL) return false;
00769
00770 relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE);
00771
00772 if (HasBit(statspec->callbackmask, CBM_STATION_SPRITE_LAYOUT)) {
00773 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, NULL, INVALID_TILE);
00774 if (callback != CALLBACK_FAILED) tile = callback;
00775 }
00776
00777 if (statspec->renderdata == NULL) {
00778 sprites = GetStationTileLayout(STATION_RAIL, tile + axis);
00779 } else {
00780 sprites = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : (uint)axis];
00781 }
00782
00783 image = sprites->ground.sprite;
00784 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
00785 image += GetCustomStationGroundRelocation(statspec, NULL, INVALID_TILE);
00786 image += rti->custom_ground_offset;
00787 } else {
00788 image += rti->total_offset;
00789 }
00790
00791 DrawSprite(image, PAL_NONE, x, y);
00792
00793 foreach_draw_tile_seq(seq, sprites->seq) {
00794 Point pt;
00795 image = seq->image.sprite;
00796 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
00797 image += rti->total_offset;
00798 } else {
00799 image += relocation;
00800 }
00801
00802 SpriteID pal;
00803 if (HasBit(image, PALETTE_MODIFIER_TRANSPARENT) || HasBit(image, PALETTE_MODIFIER_COLOR)) {
00804 if (seq->image.pal > 0) {
00805 pal = seq->image.pal;
00806 } else {
00807 pal = palette;
00808 }
00809 } else {
00810 pal = PAL_NONE;
00811 }
00812
00813 if ((byte)seq->delta_z != 0x80) {
00814 pt = RemapCoords(seq->delta_x, seq->delta_y, seq->delta_z);
00815 DrawSprite(image, pal, x + pt.x, y + pt.y);
00816 }
00817 }
00818
00819 return true;
00820 }
00821
00822
00823 static const StationSpec* GetStationSpec(TileIndex t)
00824 {
00825 const Station* st;
00826 uint specindex;
00827
00828 if (!IsCustomStationSpecIndex(t)) return NULL;
00829
00830 st = GetStationByTile(t);
00831 specindex = GetCustomStationSpecIndex(t);
00832 return specindex < st->num_specs ? st->speclist[specindex].spec : NULL;
00833 }
00834
00835
00836
00837
00838 bool IsStationTileBlocked(TileIndex tile)
00839 {
00840 const StationSpec* statspec = GetStationSpec(tile);
00841
00842 return statspec != NULL && HasBit(statspec->blocked, GetStationGfx(tile));
00843 }
00844
00845
00846
00847 bool IsStationTileElectrifiable(TileIndex tile)
00848 {
00849 const StationSpec* statspec = GetStationSpec(tile);
00850
00851 return
00852 statspec == NULL ||
00853 HasBit(statspec->pylons, GetStationGfx(tile)) ||
00854 !HasBit(statspec->wires, GetStationGfx(tile));
00855 }