From c00a400cc7e7626a430ed65d29a47c02a7a14eaa Mon Sep 17 00:00:00 2001 From: peter1138 Date: Fri, 11 Jan 2013 07:39:25 +0000 Subject: [PATCH] (svn r24905) -Feature(ish): Implement station randomisation triggers. --- src/base_station_base.h | 1 + src/economy.cpp | 6 +- src/newgrf.cpp | 3 + src/newgrf_station.cpp | 94 +++++++++++++++++++++++++++++-- src/newgrf_station.h | 13 ++++- src/pathfinder/yapf/yapf_rail.cpp | 3 + src/pbs.cpp | 5 +- src/pbs.h | 2 +- src/saveload/station_sl.cpp | 2 +- src/station_cmd.cpp | 1 + src/train_cmd.cpp | 3 +- src/vehicle.cpp | 5 +- 12 files changed, 127 insertions(+), 11 deletions(-) diff --git a/src/base_station_base.h b/src/base_station_base.h index 7cfd8c2e99..812692bb17 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -71,6 +71,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { uint16 random_bits; ///< Random bits assigned to this station byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen. + uint32 cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask TileArea train_station; ///< Tile area the train 'station' part covers StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions diff --git a/src/economy.cpp b/src/economy.cpp index 3cdb793212..d9229351dc 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1535,6 +1535,7 @@ static void LoadUnloadVehicle(Vehicle *front, int *cargo_left) st->last_vehicle_type = v->type; if (ge->cargo.Empty()) { + TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type); TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type); AirportAnimationTrigger(st, AAT_STATION_CARGO_TAKEN, v->cargo_type); } @@ -1552,7 +1553,10 @@ static void LoadUnloadVehicle(Vehicle *front, int *cargo_left) } if (anything_loaded || anything_unloaded) { - if (front->type == VEH_TRAIN) TriggerStationAnimation(st, front->tile, SAT_TRAIN_LOADS); + if (front->type == VEH_TRAIN) { + TriggerStationRandomisation(st, front->tile, SRT_TRAIN_LOADS); + TriggerStationAnimation(st, front->tile, SAT_TRAIN_LOADS); + } } /* Only set completely_emptied, if we just unloaded all remaining cargo */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 5a91551032..cce8215730 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1908,6 +1908,9 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte case 0x12: // Cargo types for random triggers statspec->cargo_triggers = buf->ReadDWord(); + if (_cur.grffile->grf_version >= 7) { + statspec->cargo_triggers = TranslateRefitMask(statspec->cargo_triggers); + } break; case 0x13: // General flags diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index c7ec8a2412..717c866f5d 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -731,7 +731,7 @@ int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exe st->speclist[i].grfid = statspec->grf_prop.grffile->grfid; st->speclist[i].localidx = statspec->grf_prop.local_id; - StationUpdateAnimTriggers(st); + StationUpdateCachedTriggers(st); } return i; @@ -773,11 +773,12 @@ void DeallocateSpecFromStation(BaseStation *st, byte specindex) st->num_specs = 0; st->speclist = NULL; st->cached_anim_triggers = 0; + st->cached_cargo_triggers = 0; return; } } - StationUpdateAnimTriggers(st); + StationUpdateCachedTriggers(st); } /** @@ -968,19 +969,104 @@ void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTr } } +/** + * Trigger station randomisation + * @param st station being triggered + * @param tile specific tile of platform to trigger + * @param trigger trigger type + * @param cargo_type cargo type causing trigger + */ +void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type) +{ + /* List of coverage areas for each animation trigger */ + static const TriggerArea tas[] = { + TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM + }; + + /* Get Station if it wasn't supplied */ + if (st == NULL) st = Station::GetByTile(tile); + + /* Check the cached cargo trigger bitmask to see if we need + * to bother with any further processing. */ + if (st->cached_cargo_triggers == 0) return; + if (cargo_type != CT_INVALID && !HasBit(st->cached_cargo_triggers, cargo_type)) return; + + uint32 whole_reseed = 0; + ETileArea area = ETileArea(st, tile, tas[trigger]); + + uint32 empty_mask = 0; + if (trigger == SRT_CARGO_TAKEN) { + /* Create a bitmask of completely empty cargo types to be matched */ + for (CargoID i = 0; i < NUM_CARGO; i++) { + if (st->goods[i].cargo.Empty()) { + SetBit(empty_mask, i); + } + } + } + + /* Convert trigger to bit */ + uint8 trigger_bit = 1 << trigger; + + /* Check all tiles over the station to check if the specindex is still in use */ + TILE_AREA_LOOP(tile, area) { + if (st->TileBelongsToRailStation(tile)) { + const StationSpec *ss = GetStationSpec(tile); + if (ss == NULL) continue; + + /* Cargo taken "will only be triggered if all of those + * cargo types have no more cargo waiting." */ + if (trigger == SRT_CARGO_TAKEN) { + if ((ss->cargo_triggers & ~empty_mask) != 0) continue; + } + + if (cargo_type == CT_INVALID || HasBit(ss->cargo_triggers, cargo_type)) { + StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0); + object.trigger = trigger_bit; + + const SpriteGroup *group = ResolveStation(&object); + if (group == NULL) continue; + + uint32 reseed = object.GetReseedSum(); + if (reseed != 0) { + whole_reseed |= reseed; + reseed >>= 16; + + /* Set individual tile random bits */ + uint8 random_bits = GetStationTileRandomBits(tile); + random_bits &= ~reseed; + random_bits |= Random() & reseed; + SetStationTileRandomBits(tile, random_bits); + + MarkTileDirtyByTile(tile); + } + } + } + } + + /* Update whole station random bits */ + if ((whole_reseed & 0xFFFF) != 0) { + st->random_bits &= ~whole_reseed; + st->random_bits |= Random() & whole_reseed; + } +} + /** * Update the cached animation trigger bitmask for a station. * @param st Station to update. */ -void StationUpdateAnimTriggers(BaseStation *st) +void StationUpdateCachedTriggers(BaseStation *st) { st->cached_anim_triggers = 0; + st->cached_cargo_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->animation.triggers; + if (ss != NULL) { + st->cached_anim_triggers |= ss->animation.triggers; + st->cached_cargo_triggers |= ss->cargo_triggers; + } } } diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 111a4dd002..62bb940a4e 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -90,6 +90,16 @@ enum StationSpecFlags { SSF_EXTENDED_FOUNDATIONS, ///< Extended foundation block instead of simple. }; +/** Randomisation triggers for stations */ +enum StationRandomTrigger { + SRT_NEW_CARGO, ///< Trigger station on new cargo arrival. + SRT_CARGO_TAKEN, ///< Trigger station when cargo is completely taken. + SRT_TRAIN_ARRIVES, ///< Trigger platform when train arrives. + SRT_TRAIN_DEPARTS, ///< Trigger platform when train leaves. + SRT_TRAIN_LOADS, ///< Trigger platform when train loads/unloads. + SRT_PATH_RESERVATION, ///< Trigger platform when train reserves path. +}; + /* Station layout for given dimensions - it is a two-dimensional array * where index is computed as (x * platforms) + platform. */ typedef byte *StationLayout; @@ -176,6 +186,7 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID void AnimateStationTile(TileIndex tile); void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTrigger trigger, CargoID cargo_type = CT_INVALID); -void StationUpdateAnimTriggers(BaseStation *st); +void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type = CT_INVALID); +void StationUpdateCachedTriggers(BaseStation *st); #endif /* NEWGRF_STATION_H */ diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index 48417b2b3d..f66140046a 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -17,6 +17,7 @@ #include "yapf_costrail.hpp" #include "yapf_destrail.hpp" #include "../../viewport_func.h" +#include "../../newgrf_station.h" #define DEBUG_YAPF_CACHE 0 @@ -83,6 +84,8 @@ private: tile = TILE_ADD(tile, diff); } while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile); + TriggerStationRandomisation(NULL, start, SRT_PATH_RESERVATION); + return true; } diff --git a/src/pbs.cpp b/src/pbs.cpp index 2e0919b0f2..68069c0f9d 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -12,6 +12,7 @@ #include "stdafx.h" #include "viewport_func.h" #include "vehicle_func.h" +#include "newgrf_station.h" #include "pathfinder/follow_track.hpp" /** @@ -72,10 +73,11 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool * Try to reserve a specific track on a tile * @param tile the tile * @param t the track + * @param trigger_stations whether to call station randomisation trigger * @return \c true if reservation was successful, i.e. the track was * free and didn't cross any other reserved tracks. */ -bool TryReserveRailTrack(TileIndex tile, Track t) +bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) { assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0); @@ -108,6 +110,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t) case MP_STATION: if (HasStationRail(tile) && !HasStationReservation(tile)) { SetRailStationReservation(tile, true); + if (trigger_stations) TriggerStationRandomisation(NULL, tile, SRT_PATH_RESERVATION); MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track return true; } diff --git a/src/pbs.h b/src/pbs.h index 2e1fb89680..a02d4d06e1 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -21,7 +21,7 @@ TrackBits GetReservedTrackbits(TileIndex t); void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b); -bool TryReserveRailTrack(TileIndex tile, Track t); +bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true); void UnreserveRailTrack(TileIndex tile, Track t); /** This struct contains information about the end of a reserved path. */ diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 579e9458a2..9feb1f2742 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -123,7 +123,7 @@ void AfterLoadStations() for (const RoadStop *rs = sta->truck_stops; rs != NULL; rs = rs->next) sta->truck_station.Add(rs->xy); } - StationUpdateAnimTriggers(st); + StationUpdateCachedTriggers(st); } } diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 398ac0c8f5..180a25d767 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3380,6 +3380,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT SetBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP); } + TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, type); TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type); AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e34dbb665a..c28bc13ace 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2810,6 +2810,7 @@ static void TrainEnterStation(Train *v, StationID station) v->BeginLoading(); + TriggerStationRandomisation(st, v->tile, SRT_TRAIN_ARRIVES); TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES); } @@ -3184,7 +3185,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } goto reverse_train_direction; } else { - TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track)); + TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false); } } else { /* The wagon is active, simply follow the prev vehicle. */ diff --git a/src/vehicle.cpp b/src/vehicle.cpp index d78942d32a..5620547537 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2001,7 +2001,10 @@ void Vehicle::LeaveStation() if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) { /* Trigger station animation (trains only) */ - if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS); + if (IsTileType(this->tile, MP_STATION)) { + TriggerStationRandomisation(st, this->tile, SRT_TRAIN_DEPARTS); + TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS); + } SetBit(Train::From(this)->flags, VRF_LEAVING_STATION); }