changeset 15881:75df4bf4f199 draft

(svn r20563) -Change: [NoAI] rename AIAbstractList to AIList
author yexo <yexo@openttd.org>
date Thu, 19 Aug 2010 15:37:28 +0000
parents 383c02988b9d
children a7597c21c962
files bin/ai/compat_0.7.nut bin/ai/compat_1.0.nut bin/ai/regression/regression.nut projects/openttd_vs100.vcxproj projects/openttd_vs100.vcxproj.filters projects/openttd_vs80.vcproj projects/openttd_vs90.vcproj source.list src/ai/ai_instance.cpp src/ai/api/ai_abstractlist.cpp src/ai/api/ai_abstractlist.hpp src/ai/api/ai_abstractlist.hpp.sq src/ai/api/ai_bridgelist.hpp src/ai/api/ai_bridgelist.hpp.sq src/ai/api/ai_cargolist.hpp src/ai/api/ai_cargolist.hpp.sq src/ai/api/ai_changelog.hpp src/ai/api/ai_depotlist.hpp src/ai/api/ai_depotlist.hpp.sq src/ai/api/ai_enginelist.hpp src/ai/api/ai_enginelist.hpp.sq src/ai/api/ai_grouplist.hpp src/ai/api/ai_grouplist.hpp.sq src/ai/api/ai_industrylist.hpp src/ai/api/ai_industrylist.hpp.sq src/ai/api/ai_industrytype.cpp src/ai/api/ai_industrytype.hpp src/ai/api/ai_industrytypelist.hpp src/ai/api/ai_industrytypelist.hpp.sq src/ai/api/ai_list.cpp src/ai/api/ai_list.hpp src/ai/api/ai_list.hpp.sq src/ai/api/ai_railtypelist.hpp src/ai/api/ai_railtypelist.hpp.sq src/ai/api/ai_signlist.hpp src/ai/api/ai_signlist.hpp.sq src/ai/api/ai_stationlist.hpp src/ai/api/ai_stationlist.hpp.sq src/ai/api/ai_subsidylist.hpp src/ai/api/ai_subsidylist.hpp.sq src/ai/api/ai_tile.hpp src/ai/api/ai_tilelist.hpp src/ai/api/ai_tilelist.hpp.sq src/ai/api/ai_townlist.hpp src/ai/api/ai_townlist.hpp.sq src/ai/api/ai_vehiclelist.hpp src/ai/api/ai_vehiclelist.hpp.sq src/ai/api/ai_waypointlist.hpp src/ai/api/ai_waypointlist.hpp.sq src/ai/api/squirrel_export.sh
diffstat 50 files changed, 1361 insertions(+), 1355 deletions(-) [+]
line wrap: on
line diff
--- a/bin/ai/compat_0.7.nut
+++ b/bin/ai/compat_0.7.nut
@@ -275,7 +275,6 @@
 	return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id);
 }
 
-AIAbstractList.HasNext <-
 AIBridgeList.HasNext <-
 AIBridgeList_Length.HasNext <-
 AICargoList.HasNext <-
@@ -316,3 +315,5 @@
 {
 	return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED;
 }
+
+AIAbstractList <- AIList;
--- a/bin/ai/compat_1.0.nut
+++ b/bin/ai/compat_1.0.nut
@@ -25,7 +25,6 @@
 	return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id);
 }
 
-AIAbstractList.HasNext <-
 AIBridgeList.HasNext <-
 AIBridgeList_Length.HasNext <-
 AICargoList.HasNext <-
@@ -67,3 +66,5 @@
 {
 	return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED;
 }
+
+AIAbstractList <- AIList;
--- a/bin/ai/regression/regression.nut
+++ b/bin/ai/regression/regression.nut
@@ -58,7 +58,7 @@
 	}
 
 	list = AIList();
-	list.Sort(AIAbstractList.SORT_BY_VALUE, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_ASCENDING);
 	print("");
 	print(" Value Ascending");
 	list.AddItem( 5, 10);
@@ -93,7 +93,7 @@
 	}
 
 	list = AIList();
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_DESCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_DESCENDING);
 	print("");
 	print(" Item Descending");
 	list.AddItem( 5, 10);
@@ -128,7 +128,7 @@
 	}
 
 	list = AIList();
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING);
 	print("");
 	print(" Item Ascending");
 	list.AddItem( 5, 10);
@@ -585,7 +585,7 @@
 	print("--Industry--");
 	print("  GetIndustryCount():  " + AIIndustry.GetIndustryCount());
 	local list = AIIndustryList();
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING);
 	for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
 		if (AIIndustry.IsValidIndustry(i)) j++;
 		print("  Industry " + i);
@@ -704,12 +704,12 @@
 	}
 	list.RemoveItem(1050);
 	list.RemoveItem(1150);
-	list.ChangeItem(1051, 12);
+	list.SetValue(1051, 12);
 	print("  Count():       " + list.Count());
 	print("  HasItem(1050): " + list.HasItem(1050));
 	print("  HasItem(1051): " + list.HasItem(1051));
 	print("  IsEmpty():     " + list.IsEmpty());
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING);
 	print("  List Dump:");
 	for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
 		print("    " + i + " => " + list.GetValue(i));
@@ -1198,7 +1198,7 @@
 	print("  RemoveSign(" + sign_id + "):                       " + AISign.RemoveSign(sign_id));
 	print("");
 	local list = AISignList();
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING);
 	for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
 		j++;
 		print("  Sign " + i);
@@ -1467,7 +1467,7 @@
 	print("--Town--");
 	print("  GetTownCount():    " + AITown.GetTownCount());
 	local list = AITownList();
-	list.Sort(AIAbstractList.SORT_BY_ITEM, AIAbstractList.SORT_ASCENDING);
+	list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING);
 	for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
 		if (AITown.IsValidTown(i)) j++;
 		print("  Town " + i);
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -845,7 +845,6 @@
     <ClCompile Include="..\src\ai\ai_scanner.cpp" />
     <ClInclude Include="..\src\ai\ai_scanner.hpp" />
     <ClInclude Include="..\src\ai\ai_storage.hpp" />
-    <ClInclude Include="..\src\ai\api\ai_abstractlist.hpp" />
     <ClInclude Include="..\src\ai\api\ai_accounting.hpp" />
     <ClInclude Include="..\src\ai\api\ai_airport.hpp" />
     <ClInclude Include="..\src\ai\api\ai_base.hpp" />
@@ -873,6 +872,7 @@
     <ClInclude Include="..\src\ai\api\ai_industrytype.hpp" />
     <ClInclude Include="..\src\ai\api\ai_industrytypelist.hpp" />
     <ClInclude Include="..\src\ai\api\ai_info_docs.hpp" />
+    <ClInclude Include="..\src\ai\api\ai_list.hpp" />
     <ClInclude Include="..\src\ai\api\ai_log.hpp" />
     <ClInclude Include="..\src\ai\api\ai_map.hpp" />
     <ClInclude Include="..\src\ai\api\ai_marine.hpp" />
@@ -898,7 +898,6 @@
     <ClInclude Include="..\src\ai\api\ai_vehiclelist.hpp" />
     <ClInclude Include="..\src\ai\api\ai_waypoint.hpp" />
     <ClInclude Include="..\src\ai\api\ai_waypointlist.hpp" />
-    <ClCompile Include="..\src\ai\api\ai_abstractlist.cpp" />
     <ClCompile Include="..\src\ai\api\ai_accounting.cpp" />
     <ClCompile Include="..\src\ai\api\ai_airport.cpp" />
     <ClCompile Include="..\src\ai\api\ai_base.cpp" />
@@ -924,6 +923,7 @@
     <ClCompile Include="..\src\ai\api\ai_industrylist.cpp" />
     <ClCompile Include="..\src\ai\api\ai_industrytype.cpp" />
     <ClCompile Include="..\src\ai\api\ai_industrytypelist.cpp" />
+    <ClCompile Include="..\src\ai\api\ai_list.cpp" />
     <ClCompile Include="..\src\ai\api\ai_log.cpp" />
     <ClCompile Include="..\src\ai\api\ai_map.cpp" />
     <ClCompile Include="..\src\ai\api\ai_marine.cpp" />
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -1738,9 +1738,6 @@
     <ClInclude Include="..\src\ai\ai_storage.hpp">
       <Filter>AI Core</Filter>
     </ClInclude>
-    <ClInclude Include="..\src\ai\api\ai_abstractlist.hpp">
-      <Filter>AI API</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\ai\api\ai_accounting.hpp">
       <Filter>AI API</Filter>
     </ClInclude>
@@ -1822,6 +1819,9 @@
     <ClInclude Include="..\src\ai\api\ai_info_docs.hpp">
       <Filter>AI API</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\ai\api\ai_list.hpp">
+      <Filter>AI API</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\ai\api\ai_log.hpp">
       <Filter>AI API</Filter>
     </ClInclude>
@@ -1897,9 +1897,6 @@
     <ClInclude Include="..\src\ai\api\ai_waypointlist.hpp">
       <Filter>AI API</Filter>
     </ClInclude>
-    <ClCompile Include="..\src\ai\api\ai_abstractlist.cpp">
-      <Filter>AI API Implementation</Filter>
-    </ClCompile>
     <ClCompile Include="..\src\ai\api\ai_accounting.cpp">
       <Filter>AI API Implementation</Filter>
     </ClCompile>
@@ -1975,6 +1972,9 @@
     <ClCompile Include="..\src\ai\api\ai_industrytypelist.cpp">
       <Filter>AI API Implementation</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\ai\api\ai_list.cpp">
+      <Filter>AI API Implementation</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\ai\api\ai_log.cpp">
       <Filter>AI API Implementation</Filter>
     </ClCompile>
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -2696,10 +2696,6 @@
 			Name="AI API"
 			>
 			<File
-				RelativePath=".\..\src\ai\api\ai_abstractlist.hpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\api\ai_accounting.hpp"
 				>
 			</File>
@@ -2808,6 +2804,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\api\ai_list.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\api\ai_log.hpp"
 				>
 			</File>
@@ -2912,10 +2912,6 @@
 			Name="AI API Implementation"
 			>
 			<File
-				RelativePath=".\..\src\ai\api\ai_abstractlist.cpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\api\ai_accounting.cpp"
 				>
 			</File>
@@ -3016,6 +3012,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\api\ai_list.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\api\ai_log.cpp"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -2693,10 +2693,6 @@
 			Name="AI API"
 			>
 			<File
-				RelativePath=".\..\src\ai\api\ai_abstractlist.hpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\api\ai_accounting.hpp"
 				>
 			</File>
@@ -2805,6 +2801,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\api\ai_list.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\api\ai_log.hpp"
 				>
 			</File>
@@ -2909,10 +2909,6 @@
 			Name="AI API Implementation"
 			>
 			<File
-				RelativePath=".\..\src\ai\api\ai_abstractlist.cpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\api\ai_accounting.cpp"
 				>
 			</File>
@@ -3013,6 +3009,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\api\ai_list.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\api\ai_log.cpp"
 				>
 			</File>
--- a/source.list
+++ b/source.list
@@ -611,7 +611,6 @@
 ai/ai_storage.hpp
 
 # AI API
-ai/api/ai_abstractlist.hpp
 ai/api/ai_accounting.hpp
 ai/api/ai_airport.hpp
 ai/api/ai_base.hpp
@@ -639,6 +638,7 @@
 ai/api/ai_industrytype.hpp
 ai/api/ai_industrytypelist.hpp
 ai/api/ai_info_docs.hpp
+ai/api/ai_list.hpp
 ai/api/ai_log.hpp
 ai/api/ai_map.hpp
 ai/api/ai_marine.hpp
@@ -666,7 +666,6 @@
 ai/api/ai_waypointlist.hpp
 
 # AI API Implementation
-ai/api/ai_abstractlist.cpp
 ai/api/ai_accounting.cpp
 ai/api/ai_airport.cpp
 ai/api/ai_base.cpp
@@ -692,6 +691,7 @@
 ai/api/ai_industrylist.cpp
 ai/api/ai_industrytype.cpp
 ai/api/ai_industrytypelist.cpp
+ai/api/ai_list.cpp
 ai/api/ai_log.cpp
 ai/api/ai_map.cpp
 ai/api/ai_marine.cpp
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -26,7 +26,6 @@
 
 /* Convert all AI related classes to Squirrel data.
  * Note: this line a marker in squirrel_export.sh. Do not change! */
-#include "api/ai_abstractlist.hpp.sq"
 #include "api/ai_accounting.hpp.sq"
 #include "api/ai_airport.hpp.sq"
 #include "api/ai_base.hpp.sq"
@@ -52,6 +51,7 @@
 #include "api/ai_industrylist.hpp.sq"
 #include "api/ai_industrytype.hpp.sq"
 #include "api/ai_industrytypelist.hpp.sq"
+#include "api/ai_list.hpp.sq"
 #include "api/ai_log.hpp.sq"
 #include "api/ai_map.hpp.sq"
 #include "api/ai_marine.hpp.sq"
@@ -171,7 +171,7 @@
 {
 /* Register all classes */
 	squirrel_register_std(this->engine);
-	SQAIAbstractList_Register(this->engine);
+	SQAIList_Register(this->engine);
 	SQAIAccounting_Register(this->engine);
 	SQAIAirport_Register(this->engine);
 	SQAIBase_Register(this->engine);
deleted file mode 100644
--- a/src/ai/api/ai_abstractlist.cpp
+++ /dev/null
@@ -1,881 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** @file ai_abstractlist.cpp Implementation of AIAbstractList. */
-
-#include "ai_abstractlist.hpp"
-#include "../../debug.h"
-#include "../../script/squirrel.hpp"
-
-/**
- * Base class for any AIAbstractList sorter.
- */
-class AIAbstractListSorter {
-protected:
-	AIAbstractList *list;
-
-public:
-	/**
-	 * Virtual dtor, needed to mute warnings.
-	 */
-	virtual ~AIAbstractListSorter() { }
-
-	/**
-	 * Get the first item of the sorter.
-	 */
-	virtual int32 Begin() = 0;
-
-	/**
-	 * Stop iterating a sorter.
-	 */
-	virtual void End() = 0;
-
-	/**
-	 * Get the next item of the sorter.
-	 */
-	virtual int32 Next() = 0;
-
-	/**
-	 * See if the sorter has reached the end.
-	 */
-	virtual bool IsEnd() = 0;
-
-	/**
-	 * Callback from the list if an item gets removed.
-	 */
-	virtual void Remove(int item) = 0;
-};
-
-/**
- * Sort by value, ascending.
- */
-class AIAbstractListSorterValueAscending : public AIAbstractListSorter {
-private:
-	AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
-	AIAbstractList::AIItemList *bucket_list;
-	AIAbstractList::AIItemList::iterator bucket_list_iter;
-	bool has_no_more_items;
-	int32 item_next;
-
-public:
-	AIAbstractListSorterValueAscending(AIAbstractList *list)
-	{
-		this->list = list;
-		this->End();
-	}
-
-	int32 Begin()
-	{
-		if (this->list->buckets.empty()) return 0;
-		this->has_no_more_items = false;
-
-		this->bucket_iter = this->list->buckets.begin();
-		this->bucket_list = &(*this->bucket_iter).second;
-		this->bucket_list_iter = this->bucket_list->begin();
-		this->item_next = *this->bucket_list_iter;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void End()
-	{
-		this->bucket_list = NULL;
-		this->has_no_more_items = true;
-		this->item_next = 0;
-	}
-
-	void FindNext()
-	{
-		if (this->bucket_list == NULL) {
-			this->has_no_more_items = true;
-			return;
-		}
-
-		this->bucket_list_iter++;
-		if (this->bucket_list_iter == this->bucket_list->end()) {
-			this->bucket_iter++;
-			if (this->bucket_iter == this->list->buckets.end()) {
-				this->bucket_list = NULL;
-				return;
-			}
-			this->bucket_list = &(*this->bucket_iter).second;
-			this->bucket_list_iter = this->bucket_list->begin();
-		}
-		this->item_next = *this->bucket_list_iter;
-	}
-
-	int32 Next()
-	{
-		if (this->IsEnd()) return 0;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void Remove(int item)
-	{
-		if (this->IsEnd()) return;
-
-		/* If we remove the 'next' item, skip to the next */
-		if (item == this->item_next) {
-			FindNext();
-			return;
-		}
-	}
-
-	bool IsEnd()
-	{
-		return this->list->buckets.empty() || this->has_no_more_items;
-	}
-};
-
-/**
- * Sort by value, descending.
- */
-class AIAbstractListSorterValueDescending : public AIAbstractListSorter {
-private:
-	AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
-	AIAbstractList::AIItemList *bucket_list;
-	AIAbstractList::AIItemList::iterator bucket_list_iter;
-	bool has_no_more_items;
-	int32 item_next;
-
-public:
-	AIAbstractListSorterValueDescending(AIAbstractList *list)
-	{
-		this->list = list;
-		this->End();
-	}
-
-	int32 Begin()
-	{
-		if (this->list->buckets.empty()) return 0;
-		this->has_no_more_items = false;
-
-		/* Go to the end of the bucket-list */
-		this->bucket_iter = this->list->buckets.begin();
-		for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
-		this->bucket_list = &(*this->bucket_iter).second;
-
-		/* Go to the end of the items in the bucket */
-		this->bucket_list_iter = this->bucket_list->begin();
-		for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
-		this->item_next = *this->bucket_list_iter;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void End()
-	{
-		this->bucket_list = NULL;
-		this->has_no_more_items = true;
-		this->item_next = 0;
-	}
-
-	void FindNext()
-	{
-		if (this->bucket_list == NULL) {
-			this->has_no_more_items = true;
-			return;
-		}
-
-		if (this->bucket_list_iter == this->bucket_list->begin()) {
-			if (this->bucket_iter == this->list->buckets.begin()) {
-				this->bucket_list = NULL;
-				return;
-			}
-			this->bucket_iter--;
-			this->bucket_list = &(*this->bucket_iter).second;
-			/* Go to the end of the items in the bucket */
-			this->bucket_list_iter = this->bucket_list->begin();
-			for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
-		} else {
-			this->bucket_list_iter--;
-		}
-		this->item_next = *this->bucket_list_iter;
-	}
-
-	int32 Next()
-	{
-		if (this->IsEnd()) return 0;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void Remove(int item)
-	{
-		if (this->IsEnd()) return;
-
-		/* If we remove the 'next' item, skip to the next */
-		if (item == this->item_next) {
-			FindNext();
-			return;
-		}
-	}
-
-	bool IsEnd()
-	{
-		return this->list->buckets.empty() || this->has_no_more_items;
-	}
-};
-
-/**
- * Sort by item, ascending.
- */
-class AIAbstractListSorterItemAscending : public AIAbstractListSorter {
-private:
-	AIAbstractList::AIAbstractListMap::iterator item_iter;
-	bool has_no_more_items;
-	int32 item_next;
-
-public:
-	AIAbstractListSorterItemAscending(AIAbstractList *list)
-	{
-		this->list = list;
-		this->End();
-	}
-
-	int32 Begin()
-	{
-		if (this->list->items.empty()) return 0;
-		this->has_no_more_items = false;
-
-		this->item_iter = this->list->items.begin();
-		this->item_next = (*this->item_iter).first;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void End()
-	{
-		this->has_no_more_items = true;
-	}
-
-	void FindNext()
-	{
-		if (this->item_iter == this->list->items.end()) {
-			this->has_no_more_items = true;
-			return;
-		}
-		this->item_iter++;
-		if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
-	}
-
-	int32 Next()
-	{
-		if (this->IsEnd()) return 0;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void Remove(int item)
-	{
-		if (this->IsEnd()) return;
-
-		/* If we remove the 'next' item, skip to the next */
-		if (item == this->item_next) {
-			FindNext();
-			return;
-		}
-	}
-
-	bool IsEnd()
-	{
-		return this->list->items.empty() || this->has_no_more_items;
-	}
-};
-
-/**
- * Sort by item, descending.
- */
-class AIAbstractListSorterItemDescending : public AIAbstractListSorter {
-private:
-	AIAbstractList::AIAbstractListMap::iterator item_iter;
-	bool has_no_more_items;
-	int32 item_next;
-
-public:
-	AIAbstractListSorterItemDescending(AIAbstractList *list)
-	{
-		this->list = list;
-		this->End();
-	}
-
-	int32 Begin()
-	{
-		if (this->list->items.empty()) return 0;
-		this->has_no_more_items = false;
-
-		this->item_iter = this->list->items.begin();
-		for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
-		this->item_next = (*this->item_iter).first;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void End()
-	{
-		this->has_no_more_items = true;
-	}
-
-	void FindNext()
-	{
-		if (this->item_iter == this->list->items.end()) {
-			this->has_no_more_items = true;
-			return;
-		}
-		this->item_iter--;
-		if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
-	}
-
-	int32 Next()
-	{
-		if (this->IsEnd()) return 0;
-
-		int32 item_current = this->item_next;
-		FindNext();
-		return item_current;
-	}
-
-	void Remove(int item)
-	{
-		if (this->IsEnd()) return;
-
-		/* If we remove the 'next' item, skip to the next */
-		if (item == this->item_next) {
-			FindNext();
-			return;
-		}
-	}
-
-	bool IsEnd()
-	{
-		return this->list->items.empty() || this->has_no_more_items;
-	}
-};
-
-
-
-AIAbstractList::AIAbstractList()
-{
-	/* Default sorter */
-	this->sorter         = new AIAbstractListSorterValueDescending(this);
-	this->sorter_type    = SORT_BY_VALUE;
-	this->sort_ascending = false;
-	this->initialized    = false;
-	this->modifications  = 0;
-}
-
-AIAbstractList::~AIAbstractList()
-{
-	delete this->sorter;
-}
-
-bool AIAbstractList::HasItem(int32 item)
-{
-	return this->items.count(item) == 1;
-}
-
-void AIAbstractList::Clear()
-{
-	this->modifications++;
-
-	this->items.clear();
-	this->buckets.clear();
-	this->sorter->End();
-}
-
-void AIAbstractList::AddItem(int32 item, int32 value)
-{
-	this->modifications++;
-
-	if (this->HasItem(item)) return;
-
-	this->items[item] = 0;
-	this->buckets[0].insert(item);
-
-	this->SetValue(item, value);
-}
-
-void AIAbstractList::RemoveItem(int32 item)
-{
-	this->modifications++;
-
-	if (!this->HasItem(item)) return;
-
-	int32 value = this->GetValue(item);
-
-	this->sorter->Remove(item);
-	this->buckets[value].erase(item);
-	if (this->buckets[value].empty()) this->buckets.erase(value);
-	this->items.erase(item);
-}
-
-int32 AIAbstractList::Begin()
-{
-	this->initialized = true;
-	return this->sorter->Begin();
-}
-
-int32 AIAbstractList::Next()
-{
-	if (this->initialized == false) {
-		DEBUG(ai, 0, "Next() is invalid as Begin() is never called");
-		return 0;
-	}
-	return this->sorter->Next();
-}
-
-bool AIAbstractList::IsEmpty()
-{
-	return this->items.empty();
-}
-
-bool AIAbstractList::IsEnd()
-{
-	if (this->initialized == false) {
-		DEBUG(ai, 0, "IsEnd() is invalid as Begin() is never called");
-		return true;
-	}
-	return this->sorter->IsEnd();
-}
-
-int32 AIAbstractList::Count()
-{
-	return (int32)this->items.size();
-}
-
-int32 AIAbstractList::GetValue(int32 item)
-{
-	if (!this->HasItem(item)) return 0;
-
-	return this->items[item];
-}
-
-bool AIAbstractList::SetValue(int32 item, int32 value)
-{
-	this->modifications++;
-
-	if (!this->HasItem(item)) return false;
-
-	int32 value_old = this->GetValue(item);
-	if (value_old == value) return true;
-
-	this->sorter->Remove(item);
-	this->buckets[value_old].erase(item);
-	if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
-	this->items[item] = value;
-	this->buckets[value].insert(item);
-
-	return true;
-}
-
-void AIAbstractList::Sort(SorterType sorter, bool ascending)
-{
-	this->modifications++;
-
-	if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
-	if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
-
-	delete this->sorter;
-	switch (sorter) {
-		case SORT_BY_ITEM:
-			if (ascending) {
-				this->sorter = new AIAbstractListSorterItemAscending(this);
-			} else {
-				this->sorter = new AIAbstractListSorterItemDescending(this);
-			}
-			break;
-
-		case SORT_BY_VALUE:
-			if (ascending) {
-				this->sorter = new AIAbstractListSorterValueAscending(this);
-			} else {
-				this->sorter = new AIAbstractListSorterValueDescending(this);
-			}
-			break;
-
-		default:
-			this->Sort(SORT_BY_ITEM, false);
-			return;
-	}
-	this->sorter_type    = sorter;
-	this->sort_ascending = ascending;
-	this->initialized    = false;
-}
-
-void AIAbstractList::AddList(AIAbstractList *list)
-{
-	AIAbstractListMap *list_items = &list->items;
-	for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
-		this->AddItem((*iter).first);
-		this->SetValue((*iter).first, (*iter).second);
-	}
-}
-
-void AIAbstractList::RemoveAboveValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::RemoveBelowValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::RemoveBetweenValue(int32 start, int32 end)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::RemoveValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::RemoveTop(int32 count)
-{
-	this->modifications++;
-
-	if (!this->sort_ascending) {
-		this->Sort(this->sorter_type, !this->sort_ascending);
-		this->RemoveBottom(count);
-		this->Sort(this->sorter_type, !this->sort_ascending);
-		return;
-	}
-
-	switch (this->sorter_type) {
-		default: NOT_REACHED();
-		case SORT_BY_VALUE:
-			for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
-				AIItemList *items = &(*iter).second;
-				size_t size = items->size();
-				for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
-					if (--count < 0) return;
-					this->RemoveItem(*iter);
-					/* When the last item is removed from the bucket, the bucket itself is removed.
-					 * This means that the iterators can be invalid after a call to RemoveItem.
-					 */
-					if (--size == 0) break;
-				}
-			}
-			break;
-
-		case SORT_BY_ITEM:
-			for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
-				if (--count < 0) return;
-				this->RemoveItem((*iter).first);
-			}
-			break;
-	}
-}
-
-void AIAbstractList::RemoveBottom(int32 count)
-{
-	this->modifications++;
-
-	if (!this->sort_ascending) {
-		this->Sort(this->sorter_type, !this->sort_ascending);
-		this->RemoveTop(count);
-		this->Sort(this->sorter_type, !this->sort_ascending);
-		return;
-	}
-
-	switch (this->sorter_type) {
-		default: NOT_REACHED();
-		case SORT_BY_VALUE:
-			for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
-				AIItemList *items = &(*iter).second;
-				size_t size = items->size();
-				for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
-					if (--count < 0) return;
-					this->RemoveItem(*iter);
-					/* When the last item is removed from the bucket, the bucket itself is removed.
-					 * This means that the iterators can be invalid after a call to RemoveItem.
-					 */
-					if (--size == 0) break;
-				}
-			}
-
-		case SORT_BY_ITEM:
-			for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
-				if (--count < 0) return;
-				this->RemoveItem((*iter).first);
-			}
-			break;
-	}
-}
-
-void AIAbstractList::RemoveList(AIAbstractList *list)
-{
-	this->modifications++;
-
-	AIAbstractListMap *list_items = &list->items;
-	for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
-		this->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::KeepAboveValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::KeepBelowValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::KeepBetweenValue(int32 start, int32 end)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::KeepValue(int32 value)
-{
-	this->modifications++;
-
-	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->RemoveItem((*iter).first);
-	}
-}
-
-void AIAbstractList::KeepTop(int32 count)
-{
-	this->modifications++;
-
-	this->RemoveBottom(this->Count() - count);
-}
-
-void AIAbstractList::KeepBottom(int32 count)
-{
-	this->modifications++;
-
-	this->RemoveTop(this->Count() - count);
-}
-
-void AIAbstractList::KeepList(AIAbstractList *list)
-{
-	this->modifications++;
-
-	AIAbstractList tmp;
-	for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
-		tmp.AddItem((*iter).first);
-		tmp.SetValue((*iter).first, (*iter).second);
-	}
-
-	tmp.RemoveList(list);
-	this->RemoveList(&tmp);
-}
-
-SQInteger AIAbstractList::_get(HSQUIRRELVM vm)
-{
-	if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
-
-	SQInteger idx;
-	sq_getinteger(vm, 2, &idx);
-
-	if (!this->HasItem(idx)) return SQ_ERROR;
-
-	sq_pushinteger(vm, this->GetValue(idx));
-	return 1;
-}
-
-SQInteger AIAbstractList::_set(HSQUIRRELVM vm)
-{
-	if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
-	if (sq_gettype(vm, 3) != OT_INTEGER || sq_gettype(vm, 3) == OT_NULL) {
-		return sq_throwerror(vm, _SC("you can only assign integers to this list"));
-	}
-
-	SQInteger idx, val;
-	sq_getinteger(vm, 2, &idx);
-	if (sq_gettype(vm, 3) == OT_NULL) {
-		this->RemoveItem(idx);
-		return 0;
-	}
-
-	sq_getinteger(vm, 3, &val);
-	if (!this->HasItem(idx)) {
-		this->AddItem(idx, val);
-		return 0;
-	}
-
-	this->SetValue(idx, val);
-	return 0;
-}
-
-SQInteger AIAbstractList::_nexti(HSQUIRRELVM vm)
-{
-	if (sq_gettype(vm, 2) == OT_NULL) {
-		if (this->IsEmpty()) {
-			sq_pushnull(vm);
-			return 1;
-		}
-		sq_pushinteger(vm, this->Begin());
-		return 1;
-	}
-
-	SQInteger idx;
-	sq_getinteger(vm, 2, &idx);
-
-	int val = this->Next();
-	if (this->IsEnd()) {
-		sq_pushnull(vm);
-		return 1;
-	}
-
-	sq_pushinteger(vm, val);
-	return 1;
-}
-
-SQInteger AIAbstractList::Valuate(HSQUIRRELVM vm)
-{
-	this->modifications++;
-
-	/* The first parameter is the instance of AIAbstractList. */
-	int nparam = sq_gettop(vm) - 1;
-
-	if (nparam < 1) {
-		return sq_throwerror(vm, _SC("You need to give a least a Valuator as parameter to AIAbstractList::Valuate"));
-	}
-
-	/* Make sure the valuator function is really a function, and not any
-	 * other type. It's parameter 2 for us, but for the user it's the
-	 * first parameter they give. */
-	SQObjectType valuator_type = sq_gettype(vm, 2);
-	if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
-		return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected function)"));
-	}
-
-	/* Don't allow docommand from a Valuator, as we can't resume in
-	 * mid C++-code. */
-	bool backup_allow = AIObject::GetAllowDoCommand();
-	AIObject::SetAllowDoCommand(false);
-
-	/* Push the function to call */
-	sq_push(vm, 2);
-
-	for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
-		/* Check for changing of items. */
-		int previous_modification_count = this->modifications;
-
-		/* Push the root table as instance object, this is what squirrel does for meta-functions. */
-		sq_pushroottable(vm);
-		/* Push all arguments for the valuator function. */
-		sq_pushinteger(vm, (*iter).first);
-		for (int i = 0; i < nparam - 1; i++) {
-			sq_push(vm, i + 3);
-		}
-
-		/* Call the function. Squirrel pops all parameters and pushes the return value. */
-		if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
-			AIObject::SetAllowDoCommand(backup_allow);
-			return SQ_ERROR;
-		}
-
-		/* Retreive the return value */
-		SQInteger value;
-		switch (sq_gettype(vm, -1)) {
-			case OT_INTEGER: {
-				sq_getinteger(vm, -1, &value);
-				break;
-			}
-
-			case OT_BOOL: {
-				SQBool v;
-				sq_getbool(vm, -1, &v);
-				value = v ? 1 : 0;
-				break;
-			}
-
-			default: {
-				/* See below for explanation. The extra pop is the return value. */
-				sq_pop(vm, nparam + 4);
-
-				AIObject::SetAllowDoCommand(backup_allow);
-				return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
-			}
-		}
-
-		/* Was something changed? */
-		if (previous_modification_count != this->modifications) {
-			/* See below for explanation. The extra pop is the return value. */
-			sq_pop(vm, nparam + 4);
-
-			AIObject::SetAllowDoCommand(backup_allow);
-			return sq_throwerror(vm, _SC("modifying valuated list outside of valuator function"));
-		}
-
-		this->SetValue((*iter).first, value);
-
-		/* Pop the return value. */
-		sq_poptop(vm);
-
-		Squirrel::DecreaseOps(vm, 5);
-	}
-	/* Pop from the squirrel stack:
-	 * 1. The root stable (as instance object).
-	 * 2. The valuator function.
-	 * 3. The parameters given to this function.
-	 * 4. The AIAbstractList instance object. */
-	sq_pop(vm, nparam + 3);
-
-	AIObject::SetAllowDoCommand(backup_allow);
-	return 0;
-}
deleted file mode 100644
--- a/src/ai/api/ai_abstractlist.hpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** @file ai_abstractlist.hpp A list which can keep item/value pairs, which you can walk. */
-/** @defgroup AIList Classes that create a list of items. */
-
-#ifndef AI_ABSTRACTLIST_HPP
-#define AI_ABSTRACTLIST_HPP
-
-#include "ai_object.hpp"
-#include <map>
-#include <set>
-
-class AIAbstractListSorter;
-
-/**
- * Class that creates a list which can keep item/value pairs, which you can walk.
- */
-class AIAbstractList : public AIObject {
-public:
-	/** Get the name of this class to identify it towards squirrel. */
-	static const char *GetClassName() { return "AIAbstractList"; }
-
-	/** Type of sorter */
-	enum SorterType {
-		SORT_BY_VALUE, ///< Sort the list based on the value of the item.
-		SORT_BY_ITEM,  ///< Sort the list based on the item itself.
-	};
-
-	/** Sort ascending */
-	static const bool SORT_ASCENDING = true;
-	/** Sort descnding */
-	static const bool SORT_DESCENDING = false;
-
-private:
-	AIAbstractListSorter *sorter; ///< Sorting algorithm
-	SorterType sorter_type;       ///< Sorting type
-	bool sort_ascending;          ///< Whether to sort ascending or descending
-	bool initialized;             ///< Whether an iteration has been started
-	int modifications;            ///< Number of modification that has been done. To prevent changing data while valuating.
-
-public:
-	typedef std::set<int32> AIItemList;                       ///< The list of items inside the bucket
-	typedef std::map<int32, AIItemList> AIAbstractListBucket; ///< The bucket list per value
-	typedef std::map<int32, int32> AIAbstractListMap;         ///< List per item
-
-	AIAbstractListMap items;           ///< The items in the list
-	AIAbstractListBucket buckets;      ///< The items in the list, sorted by value
-
-	AIAbstractList();
-	~AIAbstractList();
-
-	/**
-	 * Add a single item to the list.
-	 * @param item the item to add. Should be unique, otherwise it is ignored.
-	 * @param value the value to assign.
-	 * @note the value is set to 0 by default.
-	 */
-	void AddItem(int32 item, int32 value = 0);
-
-	/**
-	 * Remove a single item from the list.
-	 * @param item the item to remove. If not existing, it is ignored.
-	 */
-	void RemoveItem(int32 item);
-
-	/**
-	 * Clear the list, making Count() returning 0 and IsEmpty() returning true.
-	 */
-	void Clear();
-
-	/**
-	 * Check if an item is in the list.
-	 * @param item the item to check for.
-	 * @return true if the item is in the list.
-	 */
-	bool HasItem(int32 item);
-
-	/**
-	 * Go to the beginning of the list.
-	 * @return the item value of the first item.
-	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
-	 */
-	int32 Begin();
-
-	/**
-	 * Go to the next item in the list.
-	 * @return the item value of the next item.
-	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
-	 */
-	int32 Next();
-
-	/**
-	 * Check if a list is empty.
-	 * @return true if the list is empty.
-	 */
-	bool IsEmpty();
-
-	/**
-	 * Check if there is a element left. In other words, if this is false,
-	 * the last call to Begin() or Next() returned a valid item.
-	 * @return true if the current item is beyond end-of-list.
-	 */
-	bool IsEnd();
-
-	/**
-	 * Returns the amount of items in the list.
-	 * @return amount of items in the list.
-	 */
-	int32 Count();
-
-	/**
-	 * Get the value that belongs to this item.
-	 * @param item the item to get the value from
-	 * @return the value that belongs to this item.
-	 */
-	int32 GetValue(int32 item);
-
-	/**
-	 * Set a value of an item directly.
-	 * @param item the item to set the value for.
-	 * @param value the value to give to the item
-	 * @return true if we could set the item to value, false otherwise.
-	 * @note Changing values of items while looping through a list might cause
-	 *  entries to be skipped. Be very careful with such operations.
-	 */
-	bool SetValue(int32 item, int32 value);
-
-	/**
-	 * Sort this list by the given sorter and direction.
-	 * @param sorter    the type of sorter to use
-	 * @param ascending if true, lowest value is on top, else at bottom.
-	 * @note the current item stays at the same place.
-	 * @see SORT_ASCENDING SORT_DESCENDING
-	 */
-	void Sort(SorterType sorter, bool ascending);
-
-	/**
-	 * Add one list to another one.
-	 * @param list The list that will be added to the caller.
-	 * @post The list to be added ('list') stays unmodified.
-	 * @note All added items keep their value as it was in 'list'.
-	 * @note If the item already exists inside the caller, the value of the
-	 *  list that is added is set on the item.
-	 */
-	void AddList(AIAbstractList *list);
-
-	/**
-	 * Removes all items with a higher value than 'value'.
-	 * @param value the value above which all items are removed.
-	 */
-	void RemoveAboveValue(int32 value);
-
-	/**
-	 * Removes all items with a lower value than 'value'.
-	 * @param value the value below which all items are removed.
-	 */
-	void RemoveBelowValue(int32 value);
-
-	/**
-	 * Removes all items with a value above start and below end.
-	 * @param start the lower bound of the to be removed values (exclusive).
-	 * @param end   the upper bound of the to be removed valuens (exclusive).
-	 */
-	void RemoveBetweenValue(int32 start, int32 end);
-
-	/**
-	 * Remove all items with this value.
-	 * @param value the value to remove.
-	 */
-	void RemoveValue(int32 value);
-
-	/**
-	 * Remove the first count items.
-	 * @param count the amount of items to remove.
-	 */
-	void RemoveTop(int32 count);
-
-	/**
-	 * Remove the last count items.
-	 * @param count the amount of items to remove.
-	 */
-	void RemoveBottom(int32 count);
-
-	/**
-	 * Remove everything that is in the given list from this list (same item index that is).
-	 * @param list the list of items to remove.
-	 * @pre list != NULL
-	 */
-	void RemoveList(AIAbstractList *list);
-
-	/**
-	 * Keep all items with a higher value than 'value'.
-	 * @param value the value above which all items are kept.
-	 */
-	void KeepAboveValue(int32 value);
-
-	/**
-	 * Keep all items with a lower value than 'value'.
-	 * @param value the value below which all items are kept.
-	 */
-	void KeepBelowValue(int32 value);
-
-	/**
-	 * Keep all items with a value above start and below end.
-	 * @param start the lower bound of the to be kept values (exclusive).
-	 * @param end   the upper bound of the to be kept values (exclusive).
-	 */
-	void KeepBetweenValue(int32 start, int32 end);
-
-	/**
-	 * Keep all items with this value.
-	 * @param value the value to keep.
-	 */
-	void KeepValue(int32 value);
-
-	/**
-	 * Keep the first count items, i.e. remove everything except the first count items.
-	 * @param count the amount of items to keep.
-	 */
-	void KeepTop(int32 count);
-
-	/**
-	 * Keep the last count items, i.e. remove everything except the last count items.
-	 * @param count the amount of items to keep.
-	 */
-	void KeepBottom(int32 count);
-
-	/**
-	 * Keeps everything that is in the given list from this list (same item index that is).
-	 * @param list the list of items to keep.
-	 * @pre list != NULL
-	 */
-	void KeepList(AIAbstractList *list);
-
-#ifndef DOXYGEN_SKIP
-	/**
-	 * Used for 'foreach()' and [] get from Squirrel.
-	 */
-	SQInteger _get(HSQUIRRELVM vm);
-
-	/**
-	 * Used for [] set from Squirrel.
-	 */
-	SQInteger _set(HSQUIRRELVM vm);
-
-	/**
-	 * Used for 'foreach()' from Squirrel.
-	 */
-	SQInteger _nexti(HSQUIRRELVM vm);
-
-	/**
-	 * The Valuate() wrapper from Squirrel.
-	 */
-	SQInteger Valuate(HSQUIRRELVM vm);
-#else
-	/**
-	 * Give all items a value defined by the valuator you give.
-	 * @param valuator_function The function which will be doing the valuation.
-	 * @param params The params to give to the valuators (minus the first param,
-	 *  which is always the index-value we are valuating).
-	 * @note You may not add, remove or change (setting the value of) items while
-	 *  valuating. You may also not (re)sort while valuating.
-	 * @note You can write your own valuators and use them. Just remember that
-	 *  the first parameter should be the index-value, and it should return
-	 *  an integer.
-	 * @note Example:
-	 *  list.Valuate(AIBridge.GetPrice, 5);
-	 *  list.Valuate(AIBridge.GetMaxLength);
-	 *  function MyVal(bridge_id, myparam)
-	 *  {
-	 *    return myparam * bridge_id; // This is silly
-	 *  }
-	 *  list.Valuate(MyVal, 12);
-	 */
-	void Valuate(void *valuator_function, int params, ...);
-#endif /* DOXYGEN_SKIP */
-};
-
-#endif /* AI_LIST_HPP */
deleted file mode 100644
--- a/src/ai/api/ai_abstractlist.hpp.sq
+++ /dev/null
@@ -1,72 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
-
-#include "ai_abstractlist.hpp"
-
-namespace SQConvert {
-	/* Allow enums to be used as Squirrel parameters */
-	template <> AIAbstractList::SorterType GetParam(ForceType<AIAbstractList::SorterType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIAbstractList::SorterType)tmp; }
-	template <> int Return<AIAbstractList::SorterType>(HSQUIRRELVM vm, AIAbstractList::SorterType res) { sq_pushinteger(vm, (int32)res); return 1; }
-
-	/* Allow AIAbstractList to be used as Squirrel parameter */
-	template <> AIAbstractList *GetParam(ForceType<AIAbstractList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return  (AIAbstractList *)instance; }
-	template <> AIAbstractList &GetParam(ForceType<AIAbstractList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAbstractList *)instance; }
-	template <> const AIAbstractList *GetParam(ForceType<const AIAbstractList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return  (AIAbstractList *)instance; }
-	template <> const AIAbstractList &GetParam(ForceType<const AIAbstractList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAbstractList *)instance; }
-	template <> int Return<AIAbstractList *>(HSQUIRRELVM vm, AIAbstractList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIAbstractList", res, NULL, DefSQDestructorCallback<AIAbstractList>); return 1; }
-} // namespace SQConvert
-
-void SQAIAbstractList_Register(Squirrel *engine)
-{
-	DefSQClass <AIAbstractList> SQAIAbstractList("AIAbstractList");
-	SQAIAbstractList.PreRegister(engine);
-	SQAIAbstractList.AddConstructor<void (AIAbstractList::*)(), 1>(engine, "x");
-
-	SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_BY_VALUE, "SORT_BY_VALUE");
-	SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_BY_ITEM,  "SORT_BY_ITEM");
-
-	SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_ASCENDING,  "SORT_ASCENDING");
-	SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_DESCENDING, "SORT_DESCENDING");
-
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::AddItem,            "AddItem",            3, "xii");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveItem,         "RemoveItem",         2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Clear,              "Clear",              1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::HasItem,            "HasItem",            2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Begin,              "Begin",              1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Next,               "Next",               1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::IsEmpty,            "IsEmpty",            1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::IsEnd,              "IsEnd",              1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Count,              "Count",              1, "x");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::GetValue,           "GetValue",           2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::SetValue,           "SetValue",           3, "xii");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Sort,               "Sort",               3, "xib");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::AddList,            "AddList",            2, "xx");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveAboveValue,   "RemoveAboveValue",   2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBelowValue,   "RemoveBelowValue",   2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBetweenValue, "RemoveBetweenValue", 3, "xii");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveValue,        "RemoveValue",        2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveTop,          "RemoveTop",          2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBottom,       "RemoveBottom",       2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveList,         "RemoveList",         2, "xx");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepAboveValue,     "KeepAboveValue",     2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBelowValue,     "KeepBelowValue",     2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBetweenValue,   "KeepBetweenValue",   3, "xii");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepValue,          "KeepValue",          2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepTop,            "KeepTop",            2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBottom,         "KeepBottom",         2, "xi");
-	SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepList,           "KeepList",           2, "xx");
-	SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::_get,       "_get");
-	SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::_set,       "_set");
-	SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::_nexti,     "_nexti");
-	SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::Valuate,    "Valuate");
-
-	SQAIAbstractList.PostRegister(engine);
-}
--- a/src/ai/api/ai_bridgelist.hpp
+++ b/src/ai/api/ai_bridgelist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_BRIDGELIST_HPP
 #define AI_BRIDGELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Create a list of bridges.
  * @ingroup AIList
  */
-class AIBridgeList : public AIAbstractList {
+class AIBridgeList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIBridgeList"; }
@@ -29,7 +29,7 @@
  * Create a list of bridges that can be built on a specific length.
  * @ingroup AIList
  */
-class AIBridgeList_Length : public AIAbstractList {
+class AIBridgeList_Length : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIBridgeList_Length"; }
--- a/src/ai/api/ai_bridgelist.hpp.sq
+++ b/src/ai/api/ai_bridgelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIBridgeList_Register(Squirrel *engine)
 {
 	DefSQClass <AIBridgeList> SQAIBridgeList("AIBridgeList");
-	SQAIBridgeList.PreRegister(engine, "AIAbstractList");
+	SQAIBridgeList.PreRegister(engine, "AIList");
 	SQAIBridgeList.AddConstructor<void (AIBridgeList::*)(), 1>(engine, "x");
 
 	SQAIBridgeList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAIBridgeList_Length_Register(Squirrel *engine)
 {
 	DefSQClass <AIBridgeList_Length> SQAIBridgeList_Length("AIBridgeList_Length");
-	SQAIBridgeList_Length.PreRegister(engine, "AIAbstractList");
+	SQAIBridgeList_Length.PreRegister(engine, "AIList");
 	SQAIBridgeList_Length.AddConstructor<void (AIBridgeList_Length::*)(uint length), 2>(engine, "xi");
 
 	SQAIBridgeList_Length.PostRegister(engine);
--- a/src/ai/api/ai_cargolist.hpp
+++ b/src/ai/api/ai_cargolist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_CARGOLIST_HPP
 #define AI_CARGOLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of cargos that can be produced in the current game.
  * @ingroup AIList
  */
-class AICargoList : public AIAbstractList {
+class AICargoList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AICargoList"; }
@@ -31,7 +31,7 @@
  *   by this industry, @see AIIndustry::IsCargoAccepted.
  * @ingroup AIList
  */
-class AICargoList_IndustryAccepting : public AIAbstractList {
+class AICargoList_IndustryAccepting : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AICargoList_IndustryAccepting"; }
@@ -46,7 +46,7 @@
  * Creates a list of cargos that the given industry can produce.
  * @ingroup AIList
  */
-class AICargoList_IndustryProducing : public AIAbstractList {
+class AICargoList_IndustryProducing : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AICargoList_IndustryProducing"; }
--- a/src/ai/api/ai_cargolist.hpp.sq
+++ b/src/ai/api/ai_cargolist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAICargoList_Register(Squirrel *engine)
 {
 	DefSQClass <AICargoList> SQAICargoList("AICargoList");
-	SQAICargoList.PreRegister(engine, "AIAbstractList");
+	SQAICargoList.PreRegister(engine, "AIList");
 	SQAICargoList.AddConstructor<void (AICargoList::*)(), 1>(engine, "x");
 
 	SQAICargoList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAICargoList_IndustryAccepting_Register(Squirrel *engine)
 {
 	DefSQClass <AICargoList_IndustryAccepting> SQAICargoList_IndustryAccepting("AICargoList_IndustryAccepting");
-	SQAICargoList_IndustryAccepting.PreRegister(engine, "AIAbstractList");
+	SQAICargoList_IndustryAccepting.PreRegister(engine, "AIList");
 	SQAICargoList_IndustryAccepting.AddConstructor<void (AICargoList_IndustryAccepting::*)(IndustryID industry_id), 2>(engine, "xi");
 
 	SQAICargoList_IndustryAccepting.PostRegister(engine);
@@ -59,7 +59,7 @@
 void SQAICargoList_IndustryProducing_Register(Squirrel *engine)
 {
 	DefSQClass <AICargoList_IndustryProducing> SQAICargoList_IndustryProducing("AICargoList_IndustryProducing");
-	SQAICargoList_IndustryProducing.PreRegister(engine, "AIAbstractList");
+	SQAICargoList_IndustryProducing.PreRegister(engine, "AIList");
 	SQAICargoList_IndustryProducing.AddConstructor<void (AICargoList_IndustryProducing::*)(IndustryID industry_id), 2>(engine, "xi");
 
 	SQAICargoList_IndustryProducing.PostRegister(engine);
--- a/src/ai/api/ai_changelog.hpp
+++ b/src/ai/api/ai_changelog.hpp
@@ -28,6 +28,8 @@
  *
  * API removals:
  * \li HasNext for all lists.
+ * \li AIAbstractList, use AIList instead.
+ * \li AIList::ChangeItem, use AIList::SetValue instead.
  *
  * Other changes:
  * \li AIEngine::GetMaxTractiveEffort can be used for road vehicles.
--- a/src/ai/api/ai_depotlist.hpp
+++ b/src/ai/api/ai_depotlist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_DEPOTLIST_HPP
 #define AI_DEPOTLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_tile.hpp"
 
 /**
  * Creates a list of the locations of the depots (and hangars) of which you are the owner.
  * @ingroup AIList
  */
-class AIDepotList : public AIAbstractList {
+class AIDepotList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIDepotList"; }
--- a/src/ai/api/ai_depotlist.hpp.sq
+++ b/src/ai/api/ai_depotlist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIDepotList_Register(Squirrel *engine)
 {
 	DefSQClass <AIDepotList> SQAIDepotList("AIDepotList");
-	SQAIDepotList.PreRegister(engine, "AIAbstractList");
+	SQAIDepotList.PreRegister(engine, "AIList");
 	SQAIDepotList.AddConstructor<void (AIDepotList::*)(AITile::TransportType transport_type), 2>(engine, "xi");
 
 	SQAIDepotList.PostRegister(engine);
--- a/src/ai/api/ai_enginelist.hpp
+++ b/src/ai/api/ai_enginelist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_ENGINELIST_HPP
 #define AI_ENGINELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_vehicle.hpp"
 
 /**
  * Create a list of engines based on a vehicle type.
  * @ingroup AIList
  */
-class AIEngineList : public AIAbstractList {
+class AIEngineList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIEngineList"; }
--- a/src/ai/api/ai_enginelist.hpp.sq
+++ b/src/ai/api/ai_enginelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIEngineList_Register(Squirrel *engine)
 {
 	DefSQClass <AIEngineList> SQAIEngineList("AIEngineList");
-	SQAIEngineList.PreRegister(engine, "AIAbstractList");
+	SQAIEngineList.PreRegister(engine, "AIList");
 	SQAIEngineList.AddConstructor<void (AIEngineList::*)(AIVehicle::VehicleType vehicle_type), 2>(engine, "xi");
 
 	SQAIEngineList.PostRegister(engine);
--- a/src/ai/api/ai_grouplist.hpp
+++ b/src/ai/api/ai_grouplist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_GROUPLIST_HPP
 #define AI_GROUPLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of groups of which you are the owner.
  * @note Neither AIGroup::GROUP_ALL nor AIGroup::GROUP_DEFAULT is in this list.
  * @ingroup AIList
  */
-class AIGroupList : public AIAbstractList {
+class AIGroupList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIGroupList"; }
--- a/src/ai/api/ai_grouplist.hpp.sq
+++ b/src/ai/api/ai_grouplist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIGroupList_Register(Squirrel *engine)
 {
 	DefSQClass <AIGroupList> SQAIGroupList("AIGroupList");
-	SQAIGroupList.PreRegister(engine, "AIAbstractList");
+	SQAIGroupList.PreRegister(engine, "AIList");
 	SQAIGroupList.AddConstructor<void (AIGroupList::*)(), 1>(engine, "x");
 
 	SQAIGroupList.PostRegister(engine);
--- a/src/ai/api/ai_industrylist.hpp
+++ b/src/ai/api/ai_industrylist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_INDUSTRYLIST_HPP
 #define AI_INDUSTRYLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of industries that are currently on the map.
  * @ingroup AIList
  */
-class AIIndustryList : public AIAbstractList {
+class AIIndustryList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIIndustryList"; }
@@ -29,7 +29,7 @@
  * Creates a list of industries that accepts a given cargo.
  * @ingroup AIList
  */
-class AIIndustryList_CargoAccepting : public AIAbstractList {
+class AIIndustryList_CargoAccepting : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIIndustryList_CargoAccepting"; }
@@ -45,7 +45,7 @@
  * @note It also contains industries that currently produces 0 units of the cargo.
  * @ingroup AIList
  */
-class AIIndustryList_CargoProducing : public AIAbstractList {
+class AIIndustryList_CargoProducing : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIIndustryList_CargoProducing"; }
--- a/src/ai/api/ai_industrylist.hpp.sq
+++ b/src/ai/api/ai_industrylist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIIndustryList_Register(Squirrel *engine)
 {
 	DefSQClass <AIIndustryList> SQAIIndustryList("AIIndustryList");
-	SQAIIndustryList.PreRegister(engine, "AIAbstractList");
+	SQAIIndustryList.PreRegister(engine, "AIList");
 	SQAIIndustryList.AddConstructor<void (AIIndustryList::*)(), 1>(engine, "x");
 
 	SQAIIndustryList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAIIndustryList_CargoAccepting_Register(Squirrel *engine)
 {
 	DefSQClass <AIIndustryList_CargoAccepting> SQAIIndustryList_CargoAccepting("AIIndustryList_CargoAccepting");
-	SQAIIndustryList_CargoAccepting.PreRegister(engine, "AIAbstractList");
+	SQAIIndustryList_CargoAccepting.PreRegister(engine, "AIList");
 	SQAIIndustryList_CargoAccepting.AddConstructor<void (AIIndustryList_CargoAccepting::*)(CargoID cargo_id), 2>(engine, "xi");
 
 	SQAIIndustryList_CargoAccepting.PostRegister(engine);
@@ -59,7 +59,7 @@
 void SQAIIndustryList_CargoProducing_Register(Squirrel *engine)
 {
 	DefSQClass <AIIndustryList_CargoProducing> SQAIIndustryList_CargoProducing("AIIndustryList_CargoProducing");
-	SQAIIndustryList_CargoProducing.PreRegister(engine, "AIAbstractList");
+	SQAIIndustryList_CargoProducing.PreRegister(engine, "AIList");
 	SQAIIndustryList_CargoProducing.AddConstructor<void (AIIndustryList_CargoProducing::*)(CargoID cargo_id), 2>(engine, "xi");
 
 	SQAIIndustryList_CargoProducing.PostRegister(engine);
--- a/src/ai/api/ai_industrytype.cpp
+++ b/src/ai/api/ai_industrytype.cpp
@@ -58,13 +58,13 @@
 	return industrytype_name;
 }
 
-/* static */ AIAbstractList *AIIndustryType::GetProducedCargo(IndustryType industry_type)
+/* static */ AIList *AIIndustryType::GetProducedCargo(IndustryType industry_type)
 {
 	if (!IsValidIndustryType(industry_type)) return NULL;
 
 	const IndustrySpec *ins = ::GetIndustrySpec(industry_type);
 
-	AIAbstractList *list = new AIAbstractList();
+	AIList *list = new AIList();
 	for (size_t i = 0; i < lengthof(ins->produced_cargo); i++) {
 		if (ins->produced_cargo[i] != CT_INVALID) list->AddItem(ins->produced_cargo[i]);
 	}
@@ -72,13 +72,13 @@
 	return list;
 }
 
-/* static */ AIAbstractList *AIIndustryType::GetAcceptedCargo(IndustryType industry_type)
+/* static */ AIList *AIIndustryType::GetAcceptedCargo(IndustryType industry_type)
 {
 	if (!IsValidIndustryType(industry_type)) return NULL;
 
 	const IndustrySpec *ins = ::GetIndustrySpec(industry_type);
 
-	AIAbstractList *list = new AIAbstractList();
+	AIList *list = new AIList();
 	for (size_t i = 0; i < lengthof(ins->accepts_cargo); i++) {
 		if (ins->accepts_cargo[i] != CT_INVALID) list->AddItem(ins->accepts_cargo[i]);
 	}
--- a/src/ai/api/ai_industrytype.hpp
+++ b/src/ai/api/ai_industrytype.hpp
@@ -14,7 +14,7 @@
 
 #include "ai_object.hpp"
 #include "ai_error.hpp"
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Class that handles all industry-type related functions.
@@ -55,7 +55,7 @@
 	 * @pre IsValidIndustryType(industry_type).
 	 * @return The CargoIDs of all cargotypes this industry could produce.
 	 */
-	static AIAbstractList *GetProducedCargo(IndustryType industry_type);
+	static AIList *GetProducedCargo(IndustryType industry_type);
 
 	/**
 	 * Get a list of CargoID accepted by this industry-type.
@@ -65,7 +65,7 @@
 	 * @pre IsValidIndustryType(industry_type).
 	 * @return The CargoIDs of all cargotypes this industry accepts.
 	 */
-	static AIAbstractList *GetAcceptedCargo(IndustryType industry_type);
+	static AIList *GetAcceptedCargo(IndustryType industry_type);
 
 	/**
 	 * Is this industry type a raw industry?
--- a/src/ai/api/ai_industrytypelist.hpp
+++ b/src/ai/api/ai_industrytypelist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_INDUSTRYTYPELIST_HPP
 #define AI_INDUSTRYTYPELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_industrytype.hpp"
 
 /**
  * Creates a list of valid industry types.
  * @ingroup AIList
  */
-class AIIndustryTypeList : public AIAbstractList {
+class AIIndustryTypeList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIIndustryTypeList"; }
--- a/src/ai/api/ai_industrytypelist.hpp.sq
+++ b/src/ai/api/ai_industrytypelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIIndustryTypeList_Register(Squirrel *engine)
 {
 	DefSQClass <AIIndustryTypeList> SQAIIndustryTypeList("AIIndustryTypeList");
-	SQAIIndustryTypeList.PreRegister(engine, "AIAbstractList");
+	SQAIIndustryTypeList.PreRegister(engine, "AIList");
 	SQAIIndustryTypeList.AddConstructor<void (AIIndustryTypeList::*)(), 1>(engine, "x");
 
 	SQAIIndustryTypeList.PostRegister(engine);
new file mode 100644
--- /dev/null
+++ b/src/ai/api/ai_list.cpp
@@ -0,0 +1,881 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file ai_list.cpp Implementation of AIList. */
+
+#include "ai_list.hpp"
+#include "../../debug.h"
+#include "../../script/squirrel.hpp"
+
+/**
+ * Base class for any AIList sorter.
+ */
+class AIListSorter {
+protected:
+	AIList *list;
+
+public:
+	/**
+	 * Virtual dtor, needed to mute warnings.
+	 */
+	virtual ~AIListSorter() { }
+
+	/**
+	 * Get the first item of the sorter.
+	 */
+	virtual int32 Begin() = 0;
+
+	/**
+	 * Stop iterating a sorter.
+	 */
+	virtual void End() = 0;
+
+	/**
+	 * Get the next item of the sorter.
+	 */
+	virtual int32 Next() = 0;
+
+	/**
+	 * See if the sorter has reached the end.
+	 */
+	virtual bool IsEnd() = 0;
+
+	/**
+	 * Callback from the list if an item gets removed.
+	 */
+	virtual void Remove(int item) = 0;
+};
+
+/**
+ * Sort by value, ascending.
+ */
+class AIListSorterValueAscending : public AIListSorter {
+private:
+	AIList::AIListBucket::iterator bucket_iter;
+	AIList::AIItemList *bucket_list;
+	AIList::AIItemList::iterator bucket_list_iter;
+	bool has_no_more_items;
+	int32 item_next;
+
+public:
+	AIListSorterValueAscending(AIList *list)
+	{
+		this->list = list;
+		this->End();
+	}
+
+	int32 Begin()
+	{
+		if (this->list->buckets.empty()) return 0;
+		this->has_no_more_items = false;
+
+		this->bucket_iter = this->list->buckets.begin();
+		this->bucket_list = &(*this->bucket_iter).second;
+		this->bucket_list_iter = this->bucket_list->begin();
+		this->item_next = *this->bucket_list_iter;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void End()
+	{
+		this->bucket_list = NULL;
+		this->has_no_more_items = true;
+		this->item_next = 0;
+	}
+
+	void FindNext()
+	{
+		if (this->bucket_list == NULL) {
+			this->has_no_more_items = true;
+			return;
+		}
+
+		this->bucket_list_iter++;
+		if (this->bucket_list_iter == this->bucket_list->end()) {
+			this->bucket_iter++;
+			if (this->bucket_iter == this->list->buckets.end()) {
+				this->bucket_list = NULL;
+				return;
+			}
+			this->bucket_list = &(*this->bucket_iter).second;
+			this->bucket_list_iter = this->bucket_list->begin();
+		}
+		this->item_next = *this->bucket_list_iter;
+	}
+
+	int32 Next()
+	{
+		if (this->IsEnd()) return 0;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void Remove(int item)
+	{
+		if (this->IsEnd()) return;
+
+		/* If we remove the 'next' item, skip to the next */
+		if (item == this->item_next) {
+			FindNext();
+			return;
+		}
+	}
+
+	bool IsEnd()
+	{
+		return this->list->buckets.empty() || this->has_no_more_items;
+	}
+};
+
+/**
+ * Sort by value, descending.
+ */
+class AIListSorterValueDescending : public AIListSorter {
+private:
+	AIList::AIListBucket::iterator bucket_iter;
+	AIList::AIItemList *bucket_list;
+	AIList::AIItemList::iterator bucket_list_iter;
+	bool has_no_more_items;
+	int32 item_next;
+
+public:
+	AIListSorterValueDescending(AIList *list)
+	{
+		this->list = list;
+		this->End();
+	}
+
+	int32 Begin()
+	{
+		if (this->list->buckets.empty()) return 0;
+		this->has_no_more_items = false;
+
+		/* Go to the end of the bucket-list */
+		this->bucket_iter = this->list->buckets.begin();
+		for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
+		this->bucket_list = &(*this->bucket_iter).second;
+
+		/* Go to the end of the items in the bucket */
+		this->bucket_list_iter = this->bucket_list->begin();
+		for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
+		this->item_next = *this->bucket_list_iter;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void End()
+	{
+		this->bucket_list = NULL;
+		this->has_no_more_items = true;
+		this->item_next = 0;
+	}
+
+	void FindNext()
+	{
+		if (this->bucket_list == NULL) {
+			this->has_no_more_items = true;
+			return;
+		}
+
+		if (this->bucket_list_iter == this->bucket_list->begin()) {
+			if (this->bucket_iter == this->list->buckets.begin()) {
+				this->bucket_list = NULL;
+				return;
+			}
+			this->bucket_iter--;
+			this->bucket_list = &(*this->bucket_iter).second;
+			/* Go to the end of the items in the bucket */
+			this->bucket_list_iter = this->bucket_list->begin();
+			for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
+		} else {
+			this->bucket_list_iter--;
+		}
+		this->item_next = *this->bucket_list_iter;
+	}
+
+	int32 Next()
+	{
+		if (this->IsEnd()) return 0;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void Remove(int item)
+	{
+		if (this->IsEnd()) return;
+
+		/* If we remove the 'next' item, skip to the next */
+		if (item == this->item_next) {
+			FindNext();
+			return;
+		}
+	}
+
+	bool IsEnd()
+	{
+		return this->list->buckets.empty() || this->has_no_more_items;
+	}
+};
+
+/**
+ * Sort by item, ascending.
+ */
+class AIListSorterItemAscending : public AIListSorter {
+private:
+	AIList::AIListMap::iterator item_iter;
+	bool has_no_more_items;
+	int32 item_next;
+
+public:
+	AIListSorterItemAscending(AIList *list)
+	{
+		this->list = list;
+		this->End();
+	}
+
+	int32 Begin()
+	{
+		if (this->list->items.empty()) return 0;
+		this->has_no_more_items = false;
+
+		this->item_iter = this->list->items.begin();
+		this->item_next = (*this->item_iter).first;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void End()
+	{
+		this->has_no_more_items = true;
+	}
+
+	void FindNext()
+	{
+		if (this->item_iter == this->list->items.end()) {
+			this->has_no_more_items = true;
+			return;
+		}
+		this->item_iter++;
+		if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
+	}
+
+	int32 Next()
+	{
+		if (this->IsEnd()) return 0;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void Remove(int item)
+	{
+		if (this->IsEnd()) return;
+
+		/* If we remove the 'next' item, skip to the next */
+		if (item == this->item_next) {
+			FindNext();
+			return;
+		}
+	}
+
+	bool IsEnd()
+	{
+		return this->list->items.empty() || this->has_no_more_items;
+	}
+};
+
+/**
+ * Sort by item, descending.
+ */
+class AIListSorterItemDescending : public AIListSorter {
+private:
+	AIList::AIListMap::iterator item_iter;
+	bool has_no_more_items;
+	int32 item_next;
+
+public:
+	AIListSorterItemDescending(AIList *list)
+	{
+		this->list = list;
+		this->End();
+	}
+
+	int32 Begin()
+	{
+		if (this->list->items.empty()) return 0;
+		this->has_no_more_items = false;
+
+		this->item_iter = this->list->items.begin();
+		for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
+		this->item_next = (*this->item_iter).first;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void End()
+	{
+		this->has_no_more_items = true;
+	}
+
+	void FindNext()
+	{
+		if (this->item_iter == this->list->items.end()) {
+			this->has_no_more_items = true;
+			return;
+		}
+		this->item_iter--;
+		if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
+	}
+
+	int32 Next()
+	{
+		if (this->IsEnd()) return 0;
+
+		int32 item_current = this->item_next;
+		FindNext();
+		return item_current;
+	}
+
+	void Remove(int item)
+	{
+		if (this->IsEnd()) return;
+
+		/* If we remove the 'next' item, skip to the next */
+		if (item == this->item_next) {
+			FindNext();
+			return;
+		}
+	}
+
+	bool IsEnd()
+	{
+		return this->list->items.empty() || this->has_no_more_items;
+	}
+};
+
+
+
+AIList::AIList()
+{
+	/* Default sorter */
+	this->sorter         = new AIListSorterValueDescending(this);
+	this->sorter_type    = SORT_BY_VALUE;
+	this->sort_ascending = false;
+	this->initialized    = false;
+	this->modifications  = 0;
+}
+
+AIList::~AIList()
+{
+	delete this->sorter;
+}
+
+bool AIList::HasItem(int32 item)
+{
+	return this->items.count(item) == 1;
+}
+
+void AIList::Clear()
+{
+	this->modifications++;
+
+	this->items.clear();
+	this->buckets.clear();
+	this->sorter->End();
+}
+
+void AIList::AddItem(int32 item, int32 value)
+{
+	this->modifications++;
+
+	if (this->HasItem(item)) return;
+
+	this->items[item] = 0;
+	this->buckets[0].insert(item);
+
+	this->SetValue(item, value);
+}
+
+void AIList::RemoveItem(int32 item)
+{
+	this->modifications++;
+
+	if (!this->HasItem(item)) return;
+
+	int32 value = this->GetValue(item);
+
+	this->sorter->Remove(item);
+	this->buckets[value].erase(item);
+	if (this->buckets[value].empty()) this->buckets.erase(value);
+	this->items.erase(item);
+}
+
+int32 AIList::Begin()
+{
+	this->initialized = true;
+	return this->sorter->Begin();
+}
+
+int32 AIList::Next()
+{
+	if (this->initialized == false) {
+		DEBUG(ai, 0, "Next() is invalid as Begin() is never called");
+		return 0;
+	}
+	return this->sorter->Next();
+}
+
+bool AIList::IsEmpty()
+{
+	return this->items.empty();
+}
+
+bool AIList::IsEnd()
+{
+	if (this->initialized == false) {
+		DEBUG(ai, 0, "IsEnd() is invalid as Begin() is never called");
+		return true;
+	}
+	return this->sorter->IsEnd();
+}
+
+int32 AIList::Count()
+{
+	return (int32)this->items.size();
+}
+
+int32 AIList::GetValue(int32 item)
+{
+	if (!this->HasItem(item)) return 0;
+
+	return this->items[item];
+}
+
+bool AIList::SetValue(int32 item, int32 value)
+{
+	this->modifications++;
+
+	if (!this->HasItem(item)) return false;
+
+	int32 value_old = this->GetValue(item);
+	if (value_old == value) return true;
+
+	this->sorter->Remove(item);
+	this->buckets[value_old].erase(item);
+	if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
+	this->items[item] = value;
+	this->buckets[value].insert(item);
+
+	return true;
+}
+
+void AIList::Sort(SorterType sorter, bool ascending)
+{
+	this->modifications++;
+
+	if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
+	if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
+
+	delete this->sorter;
+	switch (sorter) {
+		case SORT_BY_ITEM:
+			if (ascending) {
+				this->sorter = new AIListSorterItemAscending(this);
+			} else {
+				this->sorter = new AIListSorterItemDescending(this);
+			}
+			break;
+
+		case SORT_BY_VALUE:
+			if (ascending) {
+				this->sorter = new AIListSorterValueAscending(this);
+			} else {
+				this->sorter = new AIListSorterValueDescending(this);
+			}
+			break;
+
+		default:
+			this->Sort(SORT_BY_ITEM, false);
+			return;
+	}
+	this->sorter_type    = sorter;
+	this->sort_ascending = ascending;
+	this->initialized    = false;
+}
+
+void AIList::AddList(AIList *list)
+{
+	AIListMap *list_items = &list->items;
+	for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
+		this->AddItem((*iter).first);
+		this->SetValue((*iter).first, (*iter).second);
+	}
+}
+
+void AIList::RemoveAboveValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second > value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::RemoveBelowValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second < value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::RemoveBetweenValue(int32 start, int32 end)
+{
+	this->modifications++;
+
+	for (AIListMap::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->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::RemoveValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second == value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::RemoveTop(int32 count)
+{
+	this->modifications++;
+
+	if (!this->sort_ascending) {
+		this->Sort(this->sorter_type, !this->sort_ascending);
+		this->RemoveBottom(count);
+		this->Sort(this->sorter_type, !this->sort_ascending);
+		return;
+	}
+
+	switch (this->sorter_type) {
+		default: NOT_REACHED();
+		case SORT_BY_VALUE:
+			for (AIListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
+				AIItemList *items = &(*iter).second;
+				size_t size = items->size();
+				for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
+					if (--count < 0) return;
+					this->RemoveItem(*iter);
+					/* When the last item is removed from the bucket, the bucket itself is removed.
+					 * This means that the iterators can be invalid after a call to RemoveItem.
+					 */
+					if (--size == 0) break;
+				}
+			}
+			break;
+
+		case SORT_BY_ITEM:
+			for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
+				if (--count < 0) return;
+				this->RemoveItem((*iter).first);
+			}
+			break;
+	}
+}
+
+void AIList::RemoveBottom(int32 count)
+{
+	this->modifications++;
+
+	if (!this->sort_ascending) {
+		this->Sort(this->sorter_type, !this->sort_ascending);
+		this->RemoveTop(count);
+		this->Sort(this->sorter_type, !this->sort_ascending);
+		return;
+	}
+
+	switch (this->sorter_type) {
+		default: NOT_REACHED();
+		case SORT_BY_VALUE:
+			for (AIListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
+				AIItemList *items = &(*iter).second;
+				size_t size = items->size();
+				for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
+					if (--count < 0) return;
+					this->RemoveItem(*iter);
+					/* When the last item is removed from the bucket, the bucket itself is removed.
+					 * This means that the iterators can be invalid after a call to RemoveItem.
+					 */
+					if (--size == 0) break;
+				}
+			}
+
+		case SORT_BY_ITEM:
+			for (AIListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
+				if (--count < 0) return;
+				this->RemoveItem((*iter).first);
+			}
+			break;
+	}
+}
+
+void AIList::RemoveList(AIList *list)
+{
+	this->modifications++;
+
+	AIListMap *list_items = &list->items;
+	for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
+		this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::KeepAboveValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second <= value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::KeepBelowValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second >= value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::KeepBetweenValue(int32 start, int32 end)
+{
+	this->modifications++;
+
+	for (AIListMap::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->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::KeepValue(int32 value)
+{
+	this->modifications++;
+
+	for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
+		next_iter = iter; next_iter++;
+		if ((*iter).second != value) this->RemoveItem((*iter).first);
+	}
+}
+
+void AIList::KeepTop(int32 count)
+{
+	this->modifications++;
+
+	this->RemoveBottom(this->Count() - count);
+}
+
+void AIList::KeepBottom(int32 count)
+{
+	this->modifications++;
+
+	this->RemoveTop(this->Count() - count);
+}
+
+void AIList::KeepList(AIList *list)
+{
+	this->modifications++;
+
+	AIList tmp;
+	for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
+		tmp.AddItem((*iter).first);
+		tmp.SetValue((*iter).first, (*iter).second);
+	}
+
+	tmp.RemoveList(list);
+	this->RemoveList(&tmp);
+}
+
+SQInteger AIList::_get(HSQUIRRELVM vm)
+{
+	if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
+
+	SQInteger idx;
+	sq_getinteger(vm, 2, &idx);
+
+	if (!this->HasItem(idx)) return SQ_ERROR;
+
+	sq_pushinteger(vm, this->GetValue(idx));
+	return 1;
+}
+
+SQInteger AIList::_set(HSQUIRRELVM vm)
+{
+	if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
+	if (sq_gettype(vm, 3) != OT_INTEGER || sq_gettype(vm, 3) == OT_NULL) {
+		return sq_throwerror(vm, _SC("you can only assign integers to this list"));
+	}
+
+	SQInteger idx, val;
+	sq_getinteger(vm, 2, &idx);
+	if (sq_gettype(vm, 3) == OT_NULL) {
+		this->RemoveItem(idx);
+		return 0;
+	}
+
+	sq_getinteger(vm, 3, &val);
+	if (!this->HasItem(idx)) {
+		this->AddItem(idx, val);
+		return 0;
+	}
+
+	this->SetValue(idx, val);
+	return 0;
+}
+
+SQInteger AIList::_nexti(HSQUIRRELVM vm)
+{
+	if (sq_gettype(vm, 2) == OT_NULL) {
+		if (this->IsEmpty()) {
+			sq_pushnull(vm);
+			return 1;
+		}
+		sq_pushinteger(vm, this->Begin());
+		return 1;
+	}
+
+	SQInteger idx;
+	sq_getinteger(vm, 2, &idx);
+
+	int val = this->Next();
+	if (this->IsEnd()) {
+		sq_pushnull(vm);
+		return 1;
+	}
+
+	sq_pushinteger(vm, val);
+	return 1;
+}
+
+SQInteger AIList::Valuate(HSQUIRRELVM vm)
+{
+	this->modifications++;
+
+	/* The first parameter is the instance of AIList. */
+	int nparam = sq_gettop(vm) - 1;
+
+	if (nparam < 1) {
+		return sq_throwerror(vm, _SC("You need to give a least a Valuator as parameter to AIList::Valuate"));
+	}
+
+	/* Make sure the valuator function is really a function, and not any
+	 * other type. It's parameter 2 for us, but for the user it's the
+	 * first parameter they give. */
+	SQObjectType valuator_type = sq_gettype(vm, 2);
+	if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
+		return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected function)"));
+	}
+
+	/* Don't allow docommand from a Valuator, as we can't resume in
+	 * mid C++-code. */
+	bool backup_allow = AIObject::GetAllowDoCommand();
+	AIObject::SetAllowDoCommand(false);
+
+	/* Push the function to call */
+	sq_push(vm, 2);
+
+	for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
+		/* Check for changing of items. */
+		int previous_modification_count = this->modifications;
+
+		/* Push the root table as instance object, this is what squirrel does for meta-functions. */
+		sq_pushroottable(vm);
+		/* Push all arguments for the valuator function. */
+		sq_pushinteger(vm, (*iter).first);
+		for (int i = 0; i < nparam - 1; i++) {
+			sq_push(vm, i + 3);
+		}
+
+		/* Call the function. Squirrel pops all parameters and pushes the return value. */
+		if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
+			AIObject::SetAllowDoCommand(backup_allow);
+			return SQ_ERROR;
+		}
+
+		/* Retreive the return value */
+		SQInteger value;
+		switch (sq_gettype(vm, -1)) {
+			case OT_INTEGER: {
+				sq_getinteger(vm, -1, &value);
+				break;
+			}
+
+			case OT_BOOL: {
+				SQBool v;
+				sq_getbool(vm, -1, &v);
+				value = v ? 1 : 0;
+				break;
+			}
+
+			default: {
+				/* See below for explanation. The extra pop is the return value. */
+				sq_pop(vm, nparam + 4);
+
+				AIObject::SetAllowDoCommand(backup_allow);
+				return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
+			}
+		}
+
+		/* Was something changed? */
+		if (previous_modification_count != this->modifications) {
+			/* See below for explanation. The extra pop is the return value. */
+			sq_pop(vm, nparam + 4);
+
+			AIObject::SetAllowDoCommand(backup_allow);
+			return sq_throwerror(vm, _SC("modifying valuated list outside of valuator function"));
+		}
+
+		this->SetValue((*iter).first, value);
+
+		/* Pop the return value. */
+		sq_poptop(vm);
+
+		Squirrel::DecreaseOps(vm, 5);
+	}
+	/* Pop from the squirrel stack:
+	 * 1. The root stable (as instance object).
+	 * 2. The valuator function.
+	 * 3. The parameters given to this function.
+	 * 4. The AIList instance object. */
+	sq_pop(vm, nparam + 3);
+
+	AIObject::SetAllowDoCommand(backup_allow);
+	return 0;
+}
new file mode 100644
--- /dev/null
+++ b/src/ai/api/ai_list.hpp
@@ -0,0 +1,286 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file ai_list.hpp A list which can keep item/value pairs, which you can walk. */
+/** @defgroup AIList Classes that create a list of items. */
+
+#ifndef AI_LIST_HPP
+#define AI_LIST_HPP
+
+#include "ai_object.hpp"
+#include <map>
+#include <set>
+
+class AIListSorter;
+
+/**
+ * Class that creates a list which can keep item/value pairs, which you can walk.
+ */
+class AIList : public AIObject {
+public:
+	/** Get the name of this class to identify it towards squirrel. */
+	static const char *GetClassName() { return "AIList"; }
+
+	/** Type of sorter */
+	enum SorterType {
+		SORT_BY_VALUE, ///< Sort the list based on the value of the item.
+		SORT_BY_ITEM,  ///< Sort the list based on the item itself.
+	};
+
+	/** Sort ascending */
+	static const bool SORT_ASCENDING = true;
+	/** Sort descnding */
+	static const bool SORT_DESCENDING = false;
+
+private:
+	AIListSorter *sorter;         ///< Sorting algorithm
+	SorterType sorter_type;       ///< Sorting type
+	bool sort_ascending;          ///< Whether to sort ascending or descending
+	bool initialized;             ///< Whether an iteration has been started
+	int modifications;            ///< Number of modification that has been done. To prevent changing data while valuating.
+
+public:
+	typedef std::set<int32> AIItemList;               ///< The list of items inside the bucket
+	typedef std::map<int32, AIItemList> AIListBucket; ///< The bucket list per value
+	typedef std::map<int32, int32> AIListMap;         ///< List per item
+
+	AIListMap items;           ///< The items in the list
+	AIListBucket buckets;      ///< The items in the list, sorted by value
+
+	AIList();
+	~AIList();
+
+	/**
+	 * Add a single item to the list.
+	 * @param item the item to add. Should be unique, otherwise it is ignored.
+	 * @param value the value to assign.
+	 * @note the value is set to 0 by default.
+	 */
+	void AddItem(int32 item, int32 value = 0);
+
+	/**
+	 * Remove a single item from the list.
+	 * @param item the item to remove. If not existing, it is ignored.
+	 */
+	void RemoveItem(int32 item);
+
+	/**
+	 * Clear the list, making Count() returning 0 and IsEmpty() returning true.
+	 */
+	void Clear();
+
+	/**
+	 * Check if an item is in the list.
+	 * @param item the item to check for.
+	 * @return true if the item is in the list.
+	 */
+	bool HasItem(int32 item);
+
+	/**
+	 * Go to the beginning of the list.
+	 * @return the item value of the first item.
+	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
+	 */
+	int32 Begin();
+
+	/**
+	 * Go to the next item in the list.
+	 * @return the item value of the next item.
+	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
+	 */
+	int32 Next();
+
+	/**
+	 * Check if a list is empty.
+	 * @return true if the list is empty.
+	 */
+	bool IsEmpty();
+
+	/**
+	 * Check if there is a element left. In other words, if this is false,
+	 * the last call to Begin() or Next() returned a valid item.
+	 * @return true if the current item is beyond end-of-list.
+	 */
+	bool IsEnd();
+
+	/**
+	 * Returns the amount of items in the list.
+	 * @return amount of items in the list.
+	 */
+	int32 Count();
+
+	/**
+	 * Get the value that belongs to this item.
+	 * @param item the item to get the value from
+	 * @return the value that belongs to this item.
+	 */
+	int32 GetValue(int32 item);
+
+	/**
+	 * Set a value of an item directly.
+	 * @param item the item to set the value for.
+	 * @param value the value to give to the item
+	 * @return true if we could set the item to value, false otherwise.
+	 * @note Changing values of items while looping through a list might cause
+	 *  entries to be skipped. Be very careful with such operations.
+	 */
+	bool SetValue(int32 item, int32 value);
+
+	/**
+	 * Sort this list by the given sorter and direction.
+	 * @param sorter    the type of sorter to use
+	 * @param ascending if true, lowest value is on top, else at bottom.
+	 * @note the current item stays at the same place.
+	 * @see SORT_ASCENDING SORT_DESCENDING
+	 */
+	void Sort(SorterType sorter, bool ascending);
+
+	/**
+	 * Add one list to another one.
+	 * @param list The list that will be added to the caller.
+	 * @post The list to be added ('list') stays unmodified.
+	 * @note All added items keep their value as it was in 'list'.
+	 * @note If the item already exists inside the caller, the value of the
+	 *  list that is added is set on the item.
+	 */
+	void AddList(AIList *list);
+
+	/**
+	 * Removes all items with a higher value than 'value'.
+	 * @param value the value above which all items are removed.
+	 */
+	void RemoveAboveValue(int32 value);
+
+	/**
+	 * Removes all items with a lower value than 'value'.
+	 * @param value the value below which all items are removed.
+	 */
+	void RemoveBelowValue(int32 value);
+
+	/**
+	 * Removes all items with a value above start and below end.
+	 * @param start the lower bound of the to be removed values (exclusive).
+	 * @param end   the upper bound of the to be removed valuens (exclusive).
+	 */
+	void RemoveBetweenValue(int32 start, int32 end);
+
+	/**
+	 * Remove all items with this value.
+	 * @param value the value to remove.
+	 */
+	void RemoveValue(int32 value);
+
+	/**
+	 * Remove the first count items.
+	 * @param count the amount of items to remove.
+	 */
+	void RemoveTop(int32 count);
+
+	/**
+	 * Remove the last count items.
+	 * @param count the amount of items to remove.
+	 */
+	void RemoveBottom(int32 count);
+
+	/**
+	 * Remove everything that is in the given list from this list (same item index that is).
+	 * @param list the list of items to remove.
+	 * @pre list != NULL
+	 */
+	void RemoveList(AIList *list);
+
+	/**
+	 * Keep all items with a higher value than 'value'.
+	 * @param value the value above which all items are kept.
+	 */
+	void KeepAboveValue(int32 value);
+
+	/**
+	 * Keep all items with a lower value than 'value'.
+	 * @param value the value below which all items are kept.
+	 */
+	void KeepBelowValue(int32 value);
+
+	/**
+	 * Keep all items with a value above start and below end.
+	 * @param start the lower bound of the to be kept values (exclusive).
+	 * @param end   the upper bound of the to be kept values (exclusive).
+	 */
+	void KeepBetweenValue(int32 start, int32 end);
+
+	/**
+	 * Keep all items with this value.
+	 * @param value the value to keep.
+	 */
+	void KeepValue(int32 value);
+
+	/**
+	 * Keep the first count items, i.e. remove everything except the first count items.
+	 * @param count the amount of items to keep.
+	 */
+	void KeepTop(int32 count);
+
+	/**
+	 * Keep the last count items, i.e. remove everything except the last count items.
+	 * @param count the amount of items to keep.
+	 */
+	void KeepBottom(int32 count);
+
+	/**
+	 * Keeps everything that is in the given list from this list (same item index that is).
+	 * @param list the list of items to keep.
+	 * @pre list != NULL
+	 */
+	void KeepList(AIList *list);
+
+#ifndef DOXYGEN_SKIP
+	/**
+	 * Used for 'foreach()' and [] get from Squirrel.
+	 */
+	SQInteger _get(HSQUIRRELVM vm);
+
+	/**
+	 * Used for [] set from Squirrel.
+	 */
+	SQInteger _set(HSQUIRRELVM vm);
+
+	/**
+	 * Used for 'foreach()' from Squirrel.
+	 */
+	SQInteger _nexti(HSQUIRRELVM vm);
+
+	/**
+	 * The Valuate() wrapper from Squirrel.
+	 */
+	SQInteger Valuate(HSQUIRRELVM vm);
+#else
+	/**
+	 * Give all items a value defined by the valuator you give.
+	 * @param valuator_function The function which will be doing the valuation.
+	 * @param params The params to give to the valuators (minus the first param,
+	 *  which is always the index-value we are valuating).
+	 * @note You may not add, remove or change (setting the value of) items while
+	 *  valuating. You may also not (re)sort while valuating.
+	 * @note You can write your own valuators and use them. Just remember that
+	 *  the first parameter should be the index-value, and it should return
+	 *  an integer.
+	 * @note Example:
+	 *  list.Valuate(AIBridge.GetPrice, 5);
+	 *  list.Valuate(AIBridge.GetMaxLength);
+	 *  function MyVal(bridge_id, myparam)
+	 *  {
+	 *    return myparam * bridge_id; // This is silly
+	 *  }
+	 *  list.Valuate(MyVal, 12);
+	 */
+	void Valuate(void *valuator_function, int params, ...);
+#endif /* DOXYGEN_SKIP */
+};
+
+#endif /* AI_LIST_HPP */
new file mode 100644
--- /dev/null
+++ b/src/ai/api/ai_list.hpp.sq
@@ -0,0 +1,72 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
+
+#include "ai_list.hpp"
+
+namespace SQConvert {
+	/* Allow enums to be used as Squirrel parameters */
+	template <> AIList::SorterType GetParam(ForceType<AIList::SorterType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIList::SorterType)tmp; }
+	template <> int Return<AIList::SorterType>(HSQUIRRELVM vm, AIList::SorterType res) { sq_pushinteger(vm, (int32)res); return 1; }
+
+	/* Allow AIList to be used as Squirrel parameter */
+	template <> AIList *GetParam(ForceType<AIList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return  (AIList *)instance; }
+	template <> AIList &GetParam(ForceType<AIList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIList *)instance; }
+	template <> const AIList *GetParam(ForceType<const AIList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return  (AIList *)instance; }
+	template <> const AIList &GetParam(ForceType<const AIList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIList *)instance; }
+	template <> int Return<AIList *>(HSQUIRRELVM vm, AIList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIList", res, NULL, DefSQDestructorCallback<AIList>); return 1; }
+} // namespace SQConvert
+
+void SQAIList_Register(Squirrel *engine)
+{
+	DefSQClass <AIList> SQAIList("AIList");
+	SQAIList.PreRegister(engine);
+	SQAIList.AddConstructor<void (AIList::*)(), 1>(engine, "x");
+
+	SQAIList.DefSQConst(engine, AIList::SORT_BY_VALUE, "SORT_BY_VALUE");
+	SQAIList.DefSQConst(engine, AIList::SORT_BY_ITEM,  "SORT_BY_ITEM");
+
+	SQAIList.DefSQConst(engine, AIList::SORT_ASCENDING,  "SORT_ASCENDING");
+	SQAIList.DefSQConst(engine, AIList::SORT_DESCENDING, "SORT_DESCENDING");
+
+	SQAIList.DefSQMethod(engine, &AIList::AddItem,            "AddItem",            3, "xii");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveItem,         "RemoveItem",         2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::Clear,              "Clear",              1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::HasItem,            "HasItem",            2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::Begin,              "Begin",              1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::Next,               "Next",               1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::IsEmpty,            "IsEmpty",            1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::IsEnd,              "IsEnd",              1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::Count,              "Count",              1, "x");
+	SQAIList.DefSQMethod(engine, &AIList::GetValue,           "GetValue",           2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::SetValue,           "SetValue",           3, "xii");
+	SQAIList.DefSQMethod(engine, &AIList::Sort,               "Sort",               3, "xib");
+	SQAIList.DefSQMethod(engine, &AIList::AddList,            "AddList",            2, "xx");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveAboveValue,   "RemoveAboveValue",   2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveBelowValue,   "RemoveBelowValue",   2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveBetweenValue, "RemoveBetweenValue", 3, "xii");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveValue,        "RemoveValue",        2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveTop,          "RemoveTop",          2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveBottom,       "RemoveBottom",       2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::RemoveList,         "RemoveList",         2, "xx");
+	SQAIList.DefSQMethod(engine, &AIList::KeepAboveValue,     "KeepAboveValue",     2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::KeepBelowValue,     "KeepBelowValue",     2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::KeepBetweenValue,   "KeepBetweenValue",   3, "xii");
+	SQAIList.DefSQMethod(engine, &AIList::KeepValue,          "KeepValue",          2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::KeepTop,            "KeepTop",            2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::KeepBottom,         "KeepBottom",         2, "xi");
+	SQAIList.DefSQMethod(engine, &AIList::KeepList,           "KeepList",           2, "xx");
+	SQAIList.DefSQAdvancedMethod(engine, &AIList::_get,       "_get");
+	SQAIList.DefSQAdvancedMethod(engine, &AIList::_set,       "_set");
+	SQAIList.DefSQAdvancedMethod(engine, &AIList::_nexti,     "_nexti");
+	SQAIList.DefSQAdvancedMethod(engine, &AIList::Valuate,    "Valuate");
+
+	SQAIList.PostRegister(engine);
+}
--- a/src/ai/api/ai_railtypelist.hpp
+++ b/src/ai/api/ai_railtypelist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_RAILTYPELIST_HPP
 #define AI_RAILTYPELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of all available railtypes.
  * @ingroup AIList
  */
-class AIRailTypeList : public AIAbstractList {
+class AIRailTypeList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIRailTypeList"; }
--- a/src/ai/api/ai_railtypelist.hpp.sq
+++ b/src/ai/api/ai_railtypelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIRailTypeList_Register(Squirrel *engine)
 {
 	DefSQClass <AIRailTypeList> SQAIRailTypeList("AIRailTypeList");
-	SQAIRailTypeList.PreRegister(engine, "AIAbstractList");
+	SQAIRailTypeList.PreRegister(engine, "AIList");
 	SQAIRailTypeList.AddConstructor<void (AIRailTypeList::*)(), 1>(engine, "x");
 
 	SQAIRailTypeList.PostRegister(engine);
--- a/src/ai/api/ai_signlist.hpp
+++ b/src/ai/api/ai_signlist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_SIGNLIST_HPP
 #define AI_SIGNLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Create a list of signs your company has created.
  * @ingroup AIList
  */
-class AISignList : public AIAbstractList {
+class AISignList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AISignList"; }
--- a/src/ai/api/ai_signlist.hpp.sq
+++ b/src/ai/api/ai_signlist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAISignList_Register(Squirrel *engine)
 {
 	DefSQClass <AISignList> SQAISignList("AISignList");
-	SQAISignList.PreRegister(engine, "AIAbstractList");
+	SQAISignList.PreRegister(engine, "AIList");
 	SQAISignList.AddConstructor<void (AISignList::*)(), 1>(engine, "x");
 
 	SQAISignList.PostRegister(engine);
--- a/src/ai/api/ai_stationlist.hpp
+++ b/src/ai/api/ai_stationlist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_STATIONLIST_HPP
 #define AI_STATIONLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_station.hpp"
 
 /**
  * Creates a list of stations of which you are the owner.
  * @ingroup AIList
  */
-class AIStationList : public AIAbstractList {
+class AIStationList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIStationList"; }
@@ -34,7 +34,7 @@
  * Creates a list of stations which the vehicle has in its orders.
  * @ingroup AIList
  */
-class AIStationList_Vehicle : public AIAbstractList {
+class AIStationList_Vehicle : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIStationList_Vehicle"; }
--- a/src/ai/api/ai_stationlist.hpp.sq
+++ b/src/ai/api/ai_stationlist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIStationList_Register(Squirrel *engine)
 {
 	DefSQClass <AIStationList> SQAIStationList("AIStationList");
-	SQAIStationList.PreRegister(engine, "AIAbstractList");
+	SQAIStationList.PreRegister(engine, "AIList");
 	SQAIStationList.AddConstructor<void (AIStationList::*)(AIStation::StationType station_type), 2>(engine, "xi");
 
 	SQAIStationList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAIStationList_Vehicle_Register(Squirrel *engine)
 {
 	DefSQClass <AIStationList_Vehicle> SQAIStationList_Vehicle("AIStationList_Vehicle");
-	SQAIStationList_Vehicle.PreRegister(engine, "AIAbstractList");
+	SQAIStationList_Vehicle.PreRegister(engine, "AIList");
 	SQAIStationList_Vehicle.AddConstructor<void (AIStationList_Vehicle::*)(VehicleID vehicle_id), 2>(engine, "xi");
 
 	SQAIStationList_Vehicle.PostRegister(engine);
--- a/src/ai/api/ai_subsidylist.hpp
+++ b/src/ai/api/ai_subsidylist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_SUBSIDYLIST_HPP
 #define AI_SUBSIDYLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of all current subsidies.
  * @ingroup AIList
  */
-class AISubsidyList : public AIAbstractList {
+class AISubsidyList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AISubsidyList"; }
--- a/src/ai/api/ai_subsidylist.hpp.sq
+++ b/src/ai/api/ai_subsidylist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAISubsidyList_Register(Squirrel *engine)
 {
 	DefSQClass <AISubsidyList> SQAISubsidyList("AISubsidyList");
-	SQAISubsidyList.PreRegister(engine, "AIAbstractList");
+	SQAISubsidyList.PreRegister(engine, "AIList");
 	SQAISubsidyList.AddConstructor<void (AISubsidyList::*)(), 1>(engine, "x");
 
 	SQAISubsidyList.PostRegister(engine);
--- a/src/ai/api/ai_tile.hpp
+++ b/src/ai/api/ai_tile.hpp
@@ -12,7 +12,7 @@
 #ifndef AI_TILE_HPP
 #define AI_TILE_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_error.hpp"
 #include "ai_company.hpp"
 
--- a/src/ai/api/ai_tilelist.hpp
+++ b/src/ai/api/ai_tilelist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_TILELIST_HPP
 #define AI_TILELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_station.hpp"
 
 /**
  * Creates an empty list, in which you can add tiles.
  * @ingroup AIList
  */
-class AITileList : public AIAbstractList {
+class AITileList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AITileList"; }
--- a/src/ai/api/ai_tilelist.hpp.sq
+++ b/src/ai/api/ai_tilelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAITileList_Register(Squirrel *engine)
 {
 	DefSQClass <AITileList> SQAITileList("AITileList");
-	SQAITileList.PreRegister(engine, "AIAbstractList");
+	SQAITileList.PreRegister(engine, "AIList");
 	SQAITileList.AddConstructor<void (AITileList::*)(), 1>(engine, "x");
 
 	SQAITileList.DefSQMethod(engine, &AITileList::AddRectangle,    "AddRectangle",    3, "xii");
--- a/src/ai/api/ai_townlist.hpp
+++ b/src/ai/api/ai_townlist.hpp
@@ -12,13 +12,13 @@
 #ifndef AI_TOWNLIST_HPP
 #define AI_TOWNLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 
 /**
  * Creates a list of towns that are currently on the map.
  * @ingroup AIList
  */
-class AITownList : public AIAbstractList {
+class AITownList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AITownList"; }
--- a/src/ai/api/ai_townlist.hpp.sq
+++ b/src/ai/api/ai_townlist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAITownList_Register(Squirrel *engine)
 {
 	DefSQClass <AITownList> SQAITownList("AITownList");
-	SQAITownList.PreRegister(engine, "AIAbstractList");
+	SQAITownList.PreRegister(engine, "AIList");
 	SQAITownList.AddConstructor<void (AITownList::*)(), 1>(engine, "x");
 
 	SQAITownList.PostRegister(engine);
--- a/src/ai/api/ai_vehiclelist.hpp
+++ b/src/ai/api/ai_vehiclelist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_VEHICLELIST_HPP
 #define AI_VEHICLELIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_vehicle.hpp"
 
 /**
  * Creates a list of vehicles of which you are the owner.
  * @ingroup AIList
  */
-class AIVehicleList : public AIAbstractList {
+class AIVehicleList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList"; }
@@ -30,7 +30,7 @@
  * Creates a list of vehicles that have orders to a given station.
  * @ingroup AIList
  */
-class AIVehicleList_Station : public AIAbstractList {
+class AIVehicleList_Station : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList_Station"; }
@@ -50,7 +50,7 @@
  * an empty list will be returned.
  * @ingroup AIList
  */
-class AIVehicleList_Depot : public AIAbstractList {
+class AIVehicleList_Depot : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList_Depot"; }
@@ -65,7 +65,7 @@
  * Creates a list of vehicles that share orders.
  * @ingroup AIList
  */
-class AIVehicleList_SharedOrders : public AIAbstractList {
+class AIVehicleList_SharedOrders : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList_SharedOrders"; }
@@ -80,7 +80,7 @@
  * Creates a list of vehicles that are in a group.
  * @ingroup AIList
  */
-class AIVehicleList_Group : public AIAbstractList {
+class AIVehicleList_Group : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList_Group"; }
@@ -95,7 +95,7 @@
  * Creates a list of vehicles that are in the default group.
  * @ingroup AIList
  */
-class AIVehicleList_DefaultGroup : public AIAbstractList {
+class AIVehicleList_DefaultGroup : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIVehicleList_DefaultGroup"; }
--- a/src/ai/api/ai_vehiclelist.hpp.sq
+++ b/src/ai/api/ai_vehiclelist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIVehicleList_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList> SQAIVehicleList("AIVehicleList");
-	SQAIVehicleList.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList.PreRegister(engine, "AIList");
 	SQAIVehicleList.AddConstructor<void (AIVehicleList::*)(), 1>(engine, "x");
 
 	SQAIVehicleList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAIVehicleList_Station_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList_Station> SQAIVehicleList_Station("AIVehicleList_Station");
-	SQAIVehicleList_Station.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList_Station.PreRegister(engine, "AIList");
 	SQAIVehicleList_Station.AddConstructor<void (AIVehicleList_Station::*)(StationID station_id), 2>(engine, "xi");
 
 	SQAIVehicleList_Station.PostRegister(engine);
@@ -59,7 +59,7 @@
 void SQAIVehicleList_Depot_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList_Depot> SQAIVehicleList_Depot("AIVehicleList_Depot");
-	SQAIVehicleList_Depot.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList_Depot.PreRegister(engine, "AIList");
 	SQAIVehicleList_Depot.AddConstructor<void (AIVehicleList_Depot::*)(TileIndex tile), 2>(engine, "xi");
 
 	SQAIVehicleList_Depot.PostRegister(engine);
@@ -77,7 +77,7 @@
 void SQAIVehicleList_SharedOrders_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList_SharedOrders> SQAIVehicleList_SharedOrders("AIVehicleList_SharedOrders");
-	SQAIVehicleList_SharedOrders.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList_SharedOrders.PreRegister(engine, "AIList");
 	SQAIVehicleList_SharedOrders.AddConstructor<void (AIVehicleList_SharedOrders::*)(VehicleID vehicle_id), 2>(engine, "xi");
 
 	SQAIVehicleList_SharedOrders.PostRegister(engine);
@@ -95,7 +95,7 @@
 void SQAIVehicleList_Group_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList_Group> SQAIVehicleList_Group("AIVehicleList_Group");
-	SQAIVehicleList_Group.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList_Group.PreRegister(engine, "AIList");
 	SQAIVehicleList_Group.AddConstructor<void (AIVehicleList_Group::*)(GroupID group_id), 2>(engine, "xi");
 
 	SQAIVehicleList_Group.PostRegister(engine);
@@ -113,7 +113,7 @@
 void SQAIVehicleList_DefaultGroup_Register(Squirrel *engine)
 {
 	DefSQClass <AIVehicleList_DefaultGroup> SQAIVehicleList_DefaultGroup("AIVehicleList_DefaultGroup");
-	SQAIVehicleList_DefaultGroup.PreRegister(engine, "AIAbstractList");
+	SQAIVehicleList_DefaultGroup.PreRegister(engine, "AIList");
 	SQAIVehicleList_DefaultGroup.AddConstructor<void (AIVehicleList_DefaultGroup::*)(AIVehicle::VehicleType vehicle_type), 2>(engine, "xi");
 
 	SQAIVehicleList_DefaultGroup.PostRegister(engine);
--- a/src/ai/api/ai_waypointlist.hpp
+++ b/src/ai/api/ai_waypointlist.hpp
@@ -12,14 +12,14 @@
 #ifndef AI_WAYPOINTLIST_HPP
 #define AI_WAYPOINTLIST_HPP
 
-#include "ai_abstractlist.hpp"
+#include "ai_list.hpp"
 #include "ai_waypoint.hpp"
 
 /**
  * Creates a list of waypoints of which you are the owner.
  * @ingroup AIList
  */
-class AIWaypointList : public AIAbstractList {
+class AIWaypointList : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIWaypointList"; }
@@ -34,7 +34,7 @@
  * Creates a list of waypoints which the vehicle has in its orders.
  * @ingroup AIList
  */
-class AIWaypointList_Vehicle : public AIAbstractList {
+class AIWaypointList_Vehicle : public AIList {
 public:
 	/** Get the name of this class to identify it towards squirrel. */
 	static const char *GetClassName() { return "AIWaypointList_Vehicle"; }
--- a/src/ai/api/ai_waypointlist.hpp.sq
+++ b/src/ai/api/ai_waypointlist.hpp.sq
@@ -23,7 +23,7 @@
 void SQAIWaypointList_Register(Squirrel *engine)
 {
 	DefSQClass <AIWaypointList> SQAIWaypointList("AIWaypointList");
-	SQAIWaypointList.PreRegister(engine, "AIAbstractList");
+	SQAIWaypointList.PreRegister(engine, "AIList");
 	SQAIWaypointList.AddConstructor<void (AIWaypointList::*)(AIWaypoint::WaypointType waypoint_type), 2>(engine, "xi");
 
 	SQAIWaypointList.PostRegister(engine);
@@ -41,7 +41,7 @@
 void SQAIWaypointList_Vehicle_Register(Squirrel *engine)
 {
 	DefSQClass <AIWaypointList_Vehicle> SQAIWaypointList_Vehicle("AIWaypointList_Vehicle");
-	SQAIWaypointList_Vehicle.PreRegister(engine, "AIAbstractList");
+	SQAIWaypointList_Vehicle.PreRegister(engine, "AIList");
 	SQAIWaypointList_Vehicle.AddConstructor<void (AIWaypointList_Vehicle::*)(VehicleID vehicle_id), 2>(engine, "xi");
 
 	SQAIWaypointList_Vehicle.PostRegister(engine);
--- a/src/ai/api/squirrel_export.sh
+++ b/src/ai/api/squirrel_export.sh
@@ -89,7 +89,9 @@
 	print \$0
 	gsub(\"^.*/\", \"\")
 	print \"	squirrel_register_std(this->engine);\" \$0
-	split(\"`grep '^void SQAI.*_Register(Squirrel \*engine)$' *.hpp.sq | sed 's/^.*void //;s/Squirrel \*/this->/;s/$/;/;s/_Register/0000Register/g;' | sort | sed 's/0000Register/_Register/g' | tr -d '\r' | tr '\n' ' '`\", regs, \" \")
+	# AIList needs to be registered with squirrel before all AIList subclasses.
+	print \"	SQAIList_Register(this->engine);\" \$0
+	split(\"`grep '^void SQAI.*_Register(Squirrel \*engine)$' *.hpp.sq | grep -v 'SQAIList_Register' | sed 's/^.*void //;s/Squirrel \*/this->/;s/$/;/;s/_Register/0000Register/g;' | sort | sed 's/0000Register/_Register/g' | tr -d '\r' | tr '\n' ' '`\", regs, \" \")
 
 	for (i = 1; regs[i] != \"\"; i++) {
 		if (regs[i] == \"SQAIController_Register(this->engine);\") continue