diff --git a/bin/ai/regression/regression.nut b/bin/ai/regression/regression.nut index 69019f04fb..c27929d6b9 100644 --- a/bin/ai/regression/regression.nut +++ b/bin/ai/regression/regression.nut @@ -785,6 +785,36 @@ function Regression::List() list.Clear(); print(" IsEmpty(): " + list.IsEmpty()); + + for (local i = 0; i < 10; i++) { + list.AddItem(i, 5 + i / 2); + } + + local it = list.Begin(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + list.Sort(list.SORT_BY_VALUE, list.SORT_ASCENDING); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + + it = list.Begin(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + + list.SetValue(it + 1, -5); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + + list.RemoveValue(list.GetValue(it) + 1); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + + list.RemoveAboveValue(list.GetValue(it)); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + list.HasNext() + ")"); + + while (list.HasNext()) { + it = list.Next(); + print(" " + it + " => " + list.GetValue(it)); + } } function Regression::Map() diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt index be69ce3889..5a50a0b5cb 100644 --- a/bin/ai/regression/regression.txt +++ b/bin/ai/regression/regression.txt @@ -569,6 +569,14 @@ []: 4000 => 50 IsEmpty(): true + 0 => 5 (true) +ERROR: Next() is invalid as Begin() is never called +ERROR: HasNext() is invalid as Begin() is never called + 0 => 5 (false) + 0 => 5 (true) + 2 => 6 (true) + 3 => 6 (true) + 9 => 0 (false) --Company-- SetName(): true diff --git a/bin/data/opntitle.dat b/bin/data/opntitle.dat index 264aaff60b..9375089323 100644 Binary files a/bin/data/opntitle.dat and b/bin/data/opntitle.dat differ diff --git a/src/ai/api/ai_abstractlist.cpp b/src/ai/api/ai_abstractlist.cpp index 4d5cea3cba..9aeff4fc4c 100644 --- a/src/ai/api/ai_abstractlist.cpp +++ b/src/ai/api/ai_abstractlist.cpp @@ -437,8 +437,8 @@ int32 AIAbstractList::Begin() int32 AIAbstractList::Next() { if (this->initialized == false) { - DEBUG(ai, 0, "ERROR: Next() is invalid as Begin() is never called"); - return false; + DEBUG(ai, 0, "Next() is invalid as Begin() is never called"); + return 0; } return this->sorter->Next(); } @@ -451,7 +451,7 @@ bool AIAbstractList::IsEmpty() bool AIAbstractList::HasNext() { if (this->initialized == false) { - DEBUG(ai, 0, "ERROR: HasNext() is invalid as Begin() is never called"); + DEBUG(ai, 0, "HasNext() is invalid as Begin() is never called"); return false; } return this->sorter->HasNext(); @@ -517,6 +517,7 @@ void AIAbstractList::Sort(SorterType sorter, bool ascending) } this->sorter_type = sorter; this->sort_ascending = ascending; + this->initialized = false; } void AIAbstractList::AddList(AIAbstractList *list) @@ -534,12 +535,7 @@ void AIAbstractList::RemoveAboveValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second > value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first > value) this->buckets.erase(iter); + if ((*iter).second > value) this->RemoveItem((*iter).first); } } @@ -549,12 +545,7 @@ void AIAbstractList::RemoveBelowValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second < value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first < value) this->buckets.erase(iter); + if ((*iter).second < value) this->RemoveItem((*iter).first); } } @@ -564,12 +555,7 @@ void AIAbstractList::RemoveBetweenValue(int32 start, int32 end) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second > start && (*iter).second < end) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter); + if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first); } } @@ -579,12 +565,7 @@ void AIAbstractList::RemoveValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second == value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first == value) this->buckets.erase(iter); + if ((*iter).second == value) this->RemoveItem((*iter).first); } } @@ -677,12 +658,7 @@ void AIAbstractList::KeepAboveValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second <= value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first <= value) this->buckets.erase(iter); + if ((*iter).second <= value) this->RemoveItem((*iter).first); } } @@ -692,12 +668,7 @@ void AIAbstractList::KeepBelowValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second >= value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first >= value) this->buckets.erase(iter); + if ((*iter).second >= value) this->RemoveItem((*iter).first); } } @@ -707,12 +678,7 @@ void AIAbstractList::KeepBetweenValue(int32 start, int32 end) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter); + if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first); } } @@ -722,12 +688,7 @@ void AIAbstractList::KeepValue(int32 value) for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; - if ((*iter).second != value) this->items.erase(iter); - } - - for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { - next_iter = iter; next_iter++; - if ((*iter).first != value) this->buckets.erase(iter); + if ((*iter).second != value) this->RemoveItem((*iter).first); } } diff --git a/src/ai/api/ai_abstractlist.hpp b/src/ai/api/ai_abstractlist.hpp index 1fa99c0fa5..bf4c9897d4 100644 --- a/src/ai/api/ai_abstractlist.hpp +++ b/src/ai/api/ai_abstractlist.hpp @@ -63,6 +63,7 @@ protected: /** * Remove a single item from the list. * @param item the item to remove. If not existing, it is ignored. + * @note Always use this function for removing items. It keeps the iterator valid! */ void RemoveItem(int32 item); diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 982fcf833f..2dbec89cef 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -486,6 +486,25 @@ static uint32 PositionHelper(const Vehicle *v, bool consecutive) return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16; } +byte MapAirportTypeToTTDType(byte ottd_type) +{ + switch (ottd_type) { + /* Note, Helidepot and Helistation are treated as small airports + * as they are at ground level. */ + case AT_HELIDEPOT: + case AT_HELISTATION: + case AT_COMMUTER: + case AT_SMALL: return ATP_TTDP_SMALL; + case AT_METROPOLITAN: + case AT_INTERNATIONAL: + case AT_INTERCON: + case AT_LARGE: return ATP_TTDP_LARGE; + case AT_HELIPORT: return ATP_TTDP_HELIPORT; + case AT_OILRIG: return ATP_TTDP_OILRIG; + default: return ATP_TTDP_LARGE; + } +} + static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) { Vehicle *v = const_cast(GRV(object)); @@ -609,21 +628,7 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by const Station *st = GetTargetAirportIfValid(Aircraft::From(v)); if (st != NULL) { - switch (st->airport_type) { - /* Note, Helidepot and Helistation are treated as small airports - * as they are at ground level. */ - case AT_HELIDEPOT: - case AT_HELISTATION: - case AT_COMMUTER: - case AT_SMALL: airporttype = ATP_TTDP_SMALL; break; - case AT_METROPOLITAN: - case AT_INTERNATIONAL: - case AT_INTERCON: - case AT_LARGE: airporttype = ATP_TTDP_LARGE; break; - case AT_HELIPORT: airporttype = ATP_TTDP_HELIPORT; break; - case AT_OILRIG: airporttype = ATP_TTDP_OILRIG; break; - default: airporttype = ATP_TTDP_LARGE; break; - } + airporttype = MapAirportTypeToTTDType(st->airport_type); } return (altitude << 8) | airporttype; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 52c7c1edb2..4ca4f1339b 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -510,6 +510,8 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by return st->GetNewGRFVariable(object, variable, parameter, available); } +byte MapAirportTypeToTTDType(byte ottd_type); + uint32 Station::GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const { switch (variable) { @@ -524,9 +526,9 @@ uint32 Station::GetNewGRFVariable(const ResolverObject *object, byte variable, b } case 0x8A: return this->had_vehicle_of_type; - case 0xF1: return this->airport_type; - case 0xF2: return this->truck_stops->status; - case 0xF3: return this->bus_stops->status; + case 0xF1: return MapAirportTypeToTTDType(this->airport_type); + case 0xF2: return (this->truck_stops != NULL) ? this->truck_stops->status : 0; + case 0xF3: return (this->bus_stops != NULL) ? this->bus_stops->status : 0; case 0xF6: return this->airport_flags; case 0xF7: return GB(this->airport_flags, 8, 8); } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2b8861ca48..2b2f7c458f 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -3367,8 +3367,11 @@ static void TrainController(Train *v, Vehicle *nomove) } /* If we would reverse but are currently in a PBS block and - * reversing of stuck trains is disabled, don't reverse. */ - if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) { + * reversing of stuck trains is disabled, don't reverse. + * This does not apply if the reason for reversing is a one-way + * signal blocking us, because a train would then be stuck forever. */ + if (_settings_game.pf.wait_for_pbs_path == 255 && !HasOnewaySignalBlockingTrackdir(gp.new_tile, i) && + UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) { v->wait_counter = 0; return; }