diff options
author | peter1138 <peter1138@openttd.org> | 2008-04-19 23:19:12 +0000 |
---|---|---|
committer | peter1138 <peter1138@openttd.org> | 2008-04-19 23:19:12 +0000 |
commit | 3b7558b89c2c491b61b9fe41e93bb80f400aecb5 (patch) | |
tree | b590f481987fb948fc51c4d6da6e843f20b8c979 /src/newgrf_station.cpp | |
parent | fa4967d8459b1626348ff62342e77c8bd14720c0 (diff) | |
download | openttd-3b7558b89c2c491b61b9fe41e93bb80f400aecb5.tar.xz |
(svn r12798) -Feature: Add some support for NewGRF station animation. (Thanks to mart3p for samples and fixes)
Diffstat (limited to 'src/newgrf_station.cpp')
-rw-r--r-- | src/newgrf_station.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 98c93c62c..019bfce2e 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -740,8 +740,12 @@ void DeallocateSpecFromStation(Station* st, byte specindex) free(st->speclist); st->num_specs = 0; st->speclist = NULL; + st->cached_anim_triggers = 0; + return; } } + + StationUpdateAnimTriggers(st); } /** Draw representation of a station tile for GUI purposes. @@ -853,3 +857,178 @@ bool IsStationTileElectrifiable(TileIndex tile) HasBit(statspec->pylons, GetStationGfx(tile)) || !HasBit(statspec->wires, GetStationGfx(tile)); } + +void AnimateStationTile(TileIndex tile) +{ + const StationSpec *ss = GetStationSpec(tile); + if (ss == NULL) return; + + const Station *st = GetStationByTile(tile); + + uint8 animation_speed = ss->anim_speed; + + if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_SPEED)) { + uint16 callback = GetStationCallback(CBID_STATION_ANIMATION_SPEED, 0, 0, ss, st, tile); + if (callback != CALLBACK_FAILED) animation_speed = Clamp(callback & 0xFF, 0, 16); + } + + if (_tick_counter % (1 << animation_speed) != 0) return; + + uint8 frame = GetStationAnimationFrame(tile); + uint8 num_frames = ss->anim_frames; + + bool frame_set_by_callback = false; + + if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_NEXT_FRAME)) { + uint32 param = HasBit(ss->flags, 2) ? Random() : 0; + uint16 callback = GetStationCallback(CBID_STATION_ANIM_NEXT_FRAME, param, 0, ss, st, tile); + + if (callback != CALLBACK_FAILED) { + frame_set_by_callback = true; + + switch (callback & 0xFF) { + case 0xFF: + DeleteAnimatedTile(tile); + break; + + case 0xFE: + frame_set_by_callback = false; + break; + + default: + frame = callback & 0xFF; + break; + } + } + } + + if (!frame_set_by_callback) { + if (frame < num_frames) { + frame++; + } else if (frame == num_frames && HasBit(ss->anim_status, 0)) { + /* This animation loops, so start again from the beginning */ + frame = 0; + } else { + /* This animation doesn't loop, so stay here */ + DeleteAnimatedTile(tile); + } + } + + SetStationAnimationFrame(tile, frame); + MarkTileDirtyByTile(tile); +} + + +static void ChangeStationAnimationFrame(const StationSpec *ss, const Station *st, TileIndex tile, uint16 random_bits, StatAnimTrigger trigger, CargoID cargo_type) +{ + uint16 callback = GetStationCallback(CBID_STATION_ANIM_START_STOP, (random_bits << 16) | Random(), (uint8)trigger | (cargo_type << 8), ss, st, tile); + if (callback == CALLBACK_FAILED) return; + + switch (callback & 0xFF) { + case 0xFD: /* Do nothing. */ break; + case 0xFE: AddAnimatedTile(tile); break; + case 0xFF: DeleteAnimatedTile(tile); break; + default: + SetStationAnimationFrame(tile, callback); + AddAnimatedTile(tile); + break; + } +} + +enum TriggerArea { + TA_TILE, + TA_PLATFORM, + TA_WHOLE, +}; + +struct TileArea { + TileIndex tile; + uint8 w; + uint8 h; + + TileArea(const Station *st, TileIndex tile, TriggerArea ta) + { + switch (ta) { + default: NOT_REACHED(); + + case TA_TILE: + this->tile = tile; + this->w = 1; + this->h = 1; + break; + + case TA_PLATFORM: { + TileIndex start, end; + Axis axis = GetRailStationAxis(tile); + TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis)); + + for (end = tile; IsRailwayStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta); + for (start = tile; IsRailwayStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta); + + this->tile = start; + this->w = TileX(end) - TileX(start) + 1; + this->h = TileY(end) - TileY(start) + 1; + break; + } + + case TA_WHOLE: + this->tile = st->train_tile; + this->w = st->trainst_w + 1; + this->h = st->trainst_h + 1; + break; + } + } +}; + +void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type) +{ + /* List of coverage areas for each animation trigger */ + static const TriggerArea tas[] = { + TA_TILE, TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_WHOLE + }; + + /* Get Station if it wasn't supplied */ + if (st == NULL) st = GetStationByTile(tile); + + /* Check the cached animation trigger bitmask to see if we need + * to bother with any further processing. */ + if (!HasBit(st->cached_anim_triggers, trigger)) return; + + uint16 random_bits = Random(); + TileArea area = TileArea(st, tile, tas[trigger]); + + for (uint y = 0; y < area.h; y++) { + for (uint x = 0; x < area.w; x++) { + if (st->TileBelongsToRailStation(area.tile)) { + const StationSpec *ss = GetStationSpec(area.tile); + if (ss != NULL && HasBit(ss->anim_triggers, trigger)) { + CargoID cargo; + if (cargo_type == CT_INVALID) { + cargo = CT_INVALID; + } else { + cargo = GetReverseCargoTranslation(cargo_type, ss->grffile); + } + ChangeStationAnimationFrame(ss, st, area.tile, random_bits, trigger, cargo); + } + } + area.tile += TileDiffXY(1, 0); + } + area.tile += TileDiffXY(-area.w, 1); + } +} + +/** + * Update the cached animation trigger bitmask for a station. + * @param st Station to update. + */ +void StationUpdateAnimTriggers(Station *st) +{ + st->cached_anim_triggers = 0; + + /* Combine animation trigger bitmask for all station specs + * of this station. */ + for (uint i = 0; i < st->num_specs; i++) { + const StationSpec *ss = st->speclist[i].spec; + if (ss != NULL) st->cached_anim_triggers |= ss->anim_triggers; + } +} |