diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp
index 130dd0bd5..f4a33522b 100644
--- a/src/menu/loadsavemenu.cpp
+++ b/src/menu/loadsavemenu.cpp
@@ -56,46 +56,66 @@ class DLoadSaveMenu : public DListMenu
 	DECLARE_CLASS(DLoadSaveMenu, DListMenu)
 
 protected:
-	static List SaveGames;
-	static FSaveGameNode *TopSaveGame;
-	static FSaveGameNode *lastSaveSlot;
-	static FSaveGameNode *SelSaveGame;
+	static TDeletingArray<FSaveGameNode*> SaveGames;
+	static int LastSaved;
+
+	int Selected;
+	int TopItem;
 
 
-	friend void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
+	int savepicLeft;
+	int savepicTop;
+	int savepicWidth;
+	int savepicHeight;
 
-	static FSaveGameNode *RemoveSaveSlot (FSaveGameNode *file);
-	static void UnloadSaveStrings();
-	static void InsertSaveNode (FSaveGameNode *node);
+	int rowHeight;
+	int listboxLeft;
+	int listboxTop;
+	int listboxWidth;
+	
+	int listboxRows;
+	int listboxHeight;
+	int listboxRight;
+	int listboxBottom;
+
+	int commentLeft;
+	int commentTop;
+	int commentWidth;
+	int commentHeight;
+	int commentRight;
+	int commentBottom;
+
+
+	static int InsertSaveNode (FSaveGameNode *node);
 	static void ReadSaveStrings ();
-	static void NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
 
 
 	FTexture *SavePic;
 	FBrokenLines *SaveComment;
 	bool mEntering;
 	char savegamestring[SAVESTRINGSIZE];
-	bool mWheelScrolled;
 
 	DLoadSaveMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL);
 	void Destroy();
 
+	int RemoveSaveSlot (int index);
 	void UnloadSaveData ();
 	void ClearSaveStuff ();
-	void ExtractSaveData (const FSaveGameNode *node);
+	void ExtractSaveData (int index);
 	void Drawer ();
 	bool MenuEvent (int mkey, bool fromcontroller);
 	bool MouseEvent(int type, int x, int y);
 	bool Responder(event_t *ev);
 
+public:
+	static void NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
+
 };
 
 IMPLEMENT_CLASS(DLoadSaveMenu)
 
-List DLoadSaveMenu::SaveGames;
-FSaveGameNode *DLoadSaveMenu::TopSaveGame;
-FSaveGameNode *DLoadSaveMenu::lastSaveSlot;
-FSaveGameNode *DLoadSaveMenu::SelSaveGame;
+TDeletingArray<FSaveGameNode*> DLoadSaveMenu::SaveGames;
+int DLoadSaveMenu::LastSaved = -1;
 
 FSaveGameNode *quickSaveSlot;
 
@@ -105,78 +125,54 @@ FSaveGameNode *quickSaveSlot;
 //
 //=============================================================================
 
-FSaveGameNode *DLoadSaveMenu::RemoveSaveSlot (FSaveGameNode *file)
+int DLoadSaveMenu::RemoveSaveSlot (int index)
 {
-	FSaveGameNode *next = static_cast<FSaveGameNode *>(file->Succ);
+	FSaveGameNode *file = SaveGames[index];
 
-	if (file == TopSaveGame)
-	{
-		TopSaveGame = next;
-	}
-	if (quickSaveSlot == file)
+	if (quickSaveSlot == SaveGames[index])
 	{
 		quickSaveSlot = NULL;
 	}
-	if (lastSaveSlot == file)
+	if (Selected == index)
 	{
-		lastSaveSlot = NULL;
+		Selected = -1;
 	}
-	file->Remove ();
 	if (!file->bNoDelete) delete file;
-	return next;
+	SaveGames.Delete(index);
+	if ((unsigned)index >= SaveGames.Size()) index--;
+	return index;
 }
 
-
 //=============================================================================
 //
 //
 //
 //=============================================================================
 
-void DLoadSaveMenu::UnloadSaveStrings()
+int DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node)
 {
-	while (!SaveGames.IsEmpty())
+	if (SaveGames.Size() == 0)
 	{
-		RemoveSaveSlot (static_cast<FSaveGameNode *>(SaveGames.Head));
-	}
-}
-
-
-//=============================================================================
-//
-//
-//
-//=============================================================================
-
-void DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node)
-{
-	FSaveGameNode *probe;
-
-	if (SaveGames.IsEmpty ())
-	{
-		SaveGames.AddHead (node);
-		return;
+		return SaveGames.Push(node);
 	}
 
 	if (node->bOldVersion)
 	{ // Add node at bottom of list
-		probe = static_cast<FSaveGameNode *>(SaveGames.TailPred);
-		while (probe->Pred != NULL && probe->bOldVersion &&
-			stricmp (node->Title, probe->Title) < 0)
-		{
-			probe = static_cast<FSaveGameNode *>(probe->Pred);
-		}
-		node->Insert (probe);
+		return SaveGames.Push(node);
 	}
 	else
-	{ // Add node at top of list
-		probe = static_cast<FSaveGameNode *>(SaveGames.Head);
-		while (probe->Succ != NULL && !probe->bOldVersion &&
-			stricmp (node->Title, probe->Title) > 0)
+	{	// Add node at top of list
+		unsigned int i;
+		for(i = 0; i < SaveGames.Size(); i++)
 		{
-			probe = static_cast<FSaveGameNode *>(probe->Succ);
+			if (SaveGames[i]->bOldVersion ||
+				stricmp (node->Title, SaveGames[i]->Title) <= 0)
+			{
+				break;
+			}
 		}
-		node->InsertBefore (probe);
+		SaveGames.Insert(i, node);
+		return i;
 	}
 }
 
@@ -191,14 +187,12 @@ void DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node)
 
 void DLoadSaveMenu::ReadSaveStrings ()
 {
-	if (SaveGames.IsEmpty ())
+	if (SaveGames.Size() == 0)
 	{
 		void *filefirst;
 		findstate_t c_file;
 		FString filter;
 
-		atterm (UnloadSaveStrings);
-
 		filter = G_BuildSaveName ("*.zds", -1);
 		filefirst = I_FindFirst (filter.GetChars(), &c_file);
 		if (filefirst != ((void *)(-1)))
@@ -309,10 +303,6 @@ void DLoadSaveMenu::ReadSaveStrings ()
 			I_FindClose (filefirst);
 		}
 	}
-	if (SelSaveGame == NULL || SelSaveGame->Succ == NULL)
-	{
-		SelSaveGame = static_cast<FSaveGameNode *>(SaveGames.Head);
-	}
 }
 
 
@@ -332,10 +322,9 @@ void DLoadSaveMenu::NotifyNewSave (const char *file, const char *title, bool okF
 	ReadSaveStrings ();
 
 	// See if the file is already in our list
-	for (node = static_cast<FSaveGameNode *>(SaveGames.Head);
-		 node->Succ != NULL;
-		 node = static_cast<FSaveGameNode *>(node->Succ))
+	for (unsigned i=0; i<SaveGames.Size(); i++)
 	{
+		FSaveGameNode *node = SaveGames[i];
 #ifdef unix
 		if (node->Filename.Compare (file) == 0)
 #else
@@ -345,25 +334,26 @@ void DLoadSaveMenu::NotifyNewSave (const char *file, const char *title, bool okF
 			strcpy (node->Title, title);
 			node->bOldVersion = false;
 			node->bMissingWads = false;
-			break;
+			if (okForQuicksave)
+			{
+				if (quickSaveSlot == NULL) quickSaveSlot = node;
+				LastSaved = i;
+			}
+			return;
 		}
 	}
 
-	if (node->Succ == NULL)
-	{
-		node = new FSaveGameNode;
-		strcpy (node->Title, title);
-		node->Filename = file;
-		node->bOldVersion = false;
-		node->bMissingWads = false;
-		InsertSaveNode (node);
-		SelSaveGame = node;
-	}
+	node = new FSaveGameNode;
+	strcpy (node->Title, title);
+	node->Filename = file;
+	node->bOldVersion = false;
+	node->bMissingWads = false;
+	int index = InsertSaveNode (node);
 
 	if (okForQuicksave)
 	{
 		if (quickSaveSlot == NULL) quickSaveSlot = node;
-		lastSaveSlot = node;
+		LastSaved = index;
 	}
 }
 
@@ -382,7 +372,28 @@ DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, FListMenuDescriptor *desc)
 : DListMenu(parent, desc)
 {
 	ReadSaveStrings();
-	mWheelScrolled = false;
+
+	savepicLeft = 10;
+	savepicTop = 54*CleanYfac;
+	savepicWidth = 216*screen->GetWidth()/640;
+	savepicHeight = 135*screen->GetHeight()/400;
+
+	rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac;
+	listboxLeft = savepicLeft + savepicWidth + 14;
+	listboxTop = savepicTop;
+	listboxWidth = screen->GetWidth() - listboxLeft - 10;
+	int listboxHeight1 = screen->GetHeight() - listboxTop - 10;
+	listboxRows = (listboxHeight1 - 1) / rowHeight;
+	listboxHeight = listboxRows * rowHeight + 1;
+	listboxRight = listboxLeft + listboxWidth;
+	listboxBottom = listboxTop + listboxHeight;
+
+	commentLeft = savepicLeft;
+	commentTop = savepicTop + savepicHeight + 16;
+	commentWidth = savepicWidth;
+	commentHeight = (51+(screen->GetHeight()>200?10:0))*CleanYfac;
+	commentRight = commentLeft + commentWidth;
+	commentBottom = commentTop + commentHeight;
 }
 
 void DLoadSaveMenu::Destroy()
@@ -420,7 +431,7 @@ void DLoadSaveMenu::UnloadSaveData ()
 void DLoadSaveMenu::ClearSaveStuff ()
 {
 	UnloadSaveData();
-	if (quickSaveSlot == (FSaveGameNode *)1)
+	if (quickSaveSlot == (FSaveGameNode*)1)
 	{
 		quickSaveSlot = NULL;
 	}
@@ -432,15 +443,16 @@ void DLoadSaveMenu::ClearSaveStuff ()
 //
 //=============================================================================
 
-void DLoadSaveMenu::ExtractSaveData (const FSaveGameNode *node)
+void DLoadSaveMenu::ExtractSaveData (int index)
 {
 	FILE *file;
 	PNGHandle *png;
+	FSaveGameNode *node;
 
 	UnloadSaveData ();
 
-	if (node != NULL &&
-		node->Succ != NULL &&
+	if ((unsigned)index < SaveGames.Size() &&
+		(node = SaveGames[index]) &&
 		!node->Filename.IsEmpty() &&
 		!node->bOldVersion &&
 		(file = fopen (node->Filename.GetChars(), "rb")) != NULL)
@@ -512,30 +524,9 @@ void DLoadSaveMenu::Drawer ()
 {
 	Super::Drawer();
 
-	const int savepicLeft = 10;
-	const int savepicTop = 54*CleanYfac;
-	const int savepicWidth = 216*screen->GetWidth()/640;
-	const int savepicHeight = 135*screen->GetHeight()/400;
-
-	const int rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac;
-	const int listboxLeft = savepicLeft + savepicWidth + 14;
-	const int listboxTop = savepicTop;
-	const int listboxWidth = screen->GetWidth() - listboxLeft - 10;
-	const int listboxHeight1 = screen->GetHeight() - listboxTop - 10;
-	const int listboxRows = (listboxHeight1 - 1) / rowHeight;
-	const int listboxHeight = listboxRows * rowHeight + 1;
-	const int listboxRight = listboxLeft + listboxWidth;
-	const int listboxBottom = listboxTop + listboxHeight;
-
-	const int commentLeft = savepicLeft;
-	const int commentTop = savepicTop + savepicHeight + 16;
-	const int commentWidth = savepicWidth;
-	const int commentHeight = (51+(screen->GetHeight()>200?10:0))*CleanYfac;
-	const int commentRight = commentLeft + commentWidth;
-	const int commentBottom = commentTop + commentHeight;
-
 	FSaveGameNode *node;
 	int i;
+	unsigned j;
 	bool didSeeSelected = false;
 
 	// Draw picture area
@@ -558,10 +549,10 @@ void DLoadSaveMenu::Drawer ()
 		screen->Clear (savepicLeft, savepicTop,
 			savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0);
 
-		if (!SaveGames.IsEmpty ())
+		if (SaveGames.Size() > 0)
 		{
 			const char *text =
-				(SelSaveGame == NULL || !SelSaveGame->bOldVersion)
+				(Selected == -1 || SaveGames[Selected]->bOldVersion)
 				? GStrings("MNU_NOPICTURE") : GStrings("MNU_DIFFVERSION");
 			const int textlen = SmallFont->StringWidth (text)*CleanXfac;
 
@@ -588,110 +579,73 @@ void DLoadSaveMenu::Drawer ()
 	}
 
 	// Draw file area
-	do
+	V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight);
+	screen->Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0);
+
+	if (SaveGames.Size() == 0)
 	{
-		V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight);
-		screen->Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0);
+		const char * text = GStrings("MNU_NOFILES");
+		const int textlen = SmallFont->StringWidth (text)*CleanXfac;
 
-		if (SaveGames.IsEmpty ())
+		screen->DrawText (SmallFont, CR_GOLD, listboxLeft+(listboxWidth-textlen)/2,
+			listboxTop+(listboxHeight-rowHeight)/2, text,
+			DTA_CleanNoMove, true, TAG_DONE);
+		return;
+	}
+
+	for (i = 0, j = TopItem; i < listboxRows && j < SaveGames.Size(); i++,j++)
+	{
+		int color;
+		node = SaveGames[j];
+		if (node->bOldVersion)
 		{
-			const char * text = GStrings("MNU_NOFILES");
-			const int textlen = SmallFont->StringWidth (text)*CleanXfac;
-
-			screen->DrawText (SmallFont, CR_GOLD, listboxLeft+(listboxWidth-textlen)/2,
-				listboxTop+(listboxHeight-rowHeight)/2, text,
-				DTA_CleanNoMove, true, TAG_DONE);
-			return;
+			color = CR_BLUE;
 		}
-
-		for (i = 0, node = TopSaveGame;
-			 i < listboxRows && node->Succ != NULL;
-			 ++i, node = static_cast<FSaveGameNode *>(node->Succ))
+		else if (node->bMissingWads)
 		{
-			int color;
-			if (node->bOldVersion)
-			{
-				color = CR_BLUE;
-			}
-			else if (node->bMissingWads)
-			{
-				color = CR_ORANGE;
-			}
-			else if (node == SelSaveGame)
-			{
-				color = CR_WHITE;
-			}
-			else
-			{
-				color = CR_TAN;
-			}
-			if (node == SelSaveGame)
-			{
-				screen->Clear (listboxLeft, listboxTop+rowHeight*i,
-					listboxRight, listboxTop+rowHeight*(i+1), -1,
-					mEntering ? MAKEARGB(255,255,0,0) : MAKEARGB(255,0,0,255));
-				didSeeSelected = true;
-				if (!mEntering)
-				{
-					screen->DrawText (SmallFont, color,
-						listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->Title,
-						DTA_CleanNoMove, true, TAG_DONE);
-				}
-				else
-				{
-					screen->DrawText (SmallFont, CR_WHITE,
-						listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, savegamestring,
-						DTA_CleanNoMove, true, TAG_DONE);
-
-					screen->DrawText (SmallFont, CR_WHITE,
-						listboxLeft+1+SmallFont->StringWidth (savegamestring)*CleanXfac,
-						listboxTop+rowHeight*i+CleanYfac, 
-						(gameinfo.gametype & (GAME_DoomStrifeChex)) ? "_" : "[",
-						DTA_CleanNoMove, true, TAG_DONE);
-				}
-			}
-			else
+			color = CR_ORANGE;
+		}
+		else if (j == Selected)
+		{
+			color = CR_WHITE;
+		}
+		else
+		{
+			color = CR_TAN;
+		}
+		if (j == Selected)
+		{
+			screen->Clear (listboxLeft, listboxTop+rowHeight*i,
+				listboxRight, listboxTop+rowHeight*(i+1), -1,
+				mEntering ? MAKEARGB(255,255,0,0) : MAKEARGB(255,0,0,255));
+			didSeeSelected = true;
+			if (!mEntering)
 			{
 				screen->DrawText (SmallFont, color,
 					listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->Title,
 					DTA_CleanNoMove, true, TAG_DONE);
 			}
-		}
-
-		// This is dumb: If the selected node was not visible,
-		// scroll down and redraw. M_SaveLoadResponder()
-		// guarantees that if the node is not visible, it will
-		// always be below the visible list instead of above it.
-		// This should not really be done here, but I don't care.
-
-		if (!didSeeSelected)
-		{
-			// no, this shouldn't be here - and that's why there's now another hack in here
-			// so that the mouse scrolling does not get screwed by this code...
-			if (mWheelScrolled)
-			{
-				didSeeSelected = true;
-				SelSaveGame = NULL;
-				mWheelScrolled = false;
-			}
-			for (i = 1; node->Succ != NULL && node != SelSaveGame; ++i)
-			{
-				node = static_cast<FSaveGameNode *>(node->Succ);
-			}
-			if (node->Succ == NULL)
-			{ // SelSaveGame is invalid
-				didSeeSelected = true;
-			}
 			else
 			{
-				do
-				{
-					TopSaveGame = static_cast<FSaveGameNode *>(TopSaveGame->Succ);
-				} while (--i);
+				screen->DrawText (SmallFont, CR_WHITE,
+					listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, savegamestring,
+					DTA_CleanNoMove, true, TAG_DONE);
+
+				screen->DrawText (SmallFont, CR_WHITE,
+					listboxLeft+1+SmallFont->StringWidth (savegamestring)*CleanXfac,
+					listboxTop+rowHeight*i+CleanYfac, 
+					(gameinfo.gametype & (GAME_DoomStrifeChex)) ? "_" : "[",
+					DTA_CleanNoMove, true, TAG_DONE);
 			}
 		}
-	} while (!didSeeSelected);
-}
+		else
+		{
+			screen->DrawText (SmallFont, color,
+				listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->Title,
+				DTA_CleanNoMove, true, TAG_DONE);
+		}
+	}
+} 
 
 //=============================================================================
 //
@@ -704,47 +658,68 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller)
 	switch (mkey)
 	{
 	case MKEY_Up:
-		if (SelSaveGame == NULL) 
+		if (SaveGames.Size() > 1)
 		{
-			SelSaveGame = TopSaveGame;
-		}
-		else if (SelSaveGame->Succ != NULL)
-		{
-			if (SelSaveGame != SaveGames.Head)
-			{
-				if (SelSaveGame == TopSaveGame)
-				{
-					TopSaveGame = static_cast<FSaveGameNode *>(TopSaveGame->Pred);
-				}
-				SelSaveGame = static_cast<FSaveGameNode *>(SelSaveGame->Pred);
-			}
+			if (Selected == -1) Selected = TopItem;
 			else
 			{
-				SelSaveGame = static_cast<FSaveGameNode *>(SaveGames.TailPred);
+				if (--Selected < 0) Selected = SaveGames.Size()-1;
+				if (Selected < TopItem) TopItem = Selected;
+				else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
 			}
 			UnloadSaveData ();
-			ExtractSaveData (SelSaveGame);
+			ExtractSaveData (Selected);
 		}
 		return true;
 
 	case MKEY_Down:
-		if (SelSaveGame == NULL) 
+		if (SaveGames.Size() > 1)
 		{
-			SelSaveGame = TopSaveGame;
-		}
-		else if (SelSaveGame->Succ != NULL)
-		{
-			if (SelSaveGame != SaveGames.TailPred)
+			if (Selected == -1) Selected = TopItem;
+			else
 			{
-				SelSaveGame = static_cast<FSaveGameNode *>(SelSaveGame->Succ);
+				if (unsigned(++Selected) >= SaveGames.Size()) Selected = 0;
+				if (Selected < TopItem) TopItem = Selected;
+				else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
+			}
+			UnloadSaveData ();
+			ExtractSaveData (Selected);
+		}
+		return true;
+
+	case MKEY_PageDown:
+		if (SaveGames.Size() > 1)
+		{
+			if (TopItem >= (int)SaveGames.Size() - listboxRows)
+			{
+				TopItem = 0;
+				if (Selected != -1) Selected = 0;
 			}
 			else
 			{
-				SelSaveGame = TopSaveGame =
-					static_cast<FSaveGameNode *>(SaveGames.Head);
+				TopItem = MIN<int>(TopItem + listboxRows, SaveGames.Size() - listboxRows);
+				if (TopItem > Selected && Selected != -1) Selected = TopItem;
 			}
 			UnloadSaveData ();
-			ExtractSaveData (SelSaveGame);
+			ExtractSaveData (Selected);
+		}
+		return true;
+
+	case MKEY_PageUp:
+		if (SaveGames.Size() > 1)
+		{
+			if (TopItem == 0)
+			{
+				TopItem = SaveGames.Size() - listboxRows;
+				if (Selected != -1) Selected = TopItem;
+			}
+			else
+			{
+				TopItem = MAX(TopItem - listboxRows, 0);
+				if (Selected >= TopItem + listboxRows) Selected = TopItem;
+			}
+			UnloadSaveData ();
+			ExtractSaveData (Selected);
 		}
 		return true;
 
@@ -753,22 +728,12 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller)
 
 	case MKEY_MBYes:
 	{
-		if (SelSaveGame != NULL && SelSaveGame->Succ != NULL)
+		if (Selected != -1)
 		{
-			FSaveGameNode *next = static_cast<FSaveGameNode *>(SelSaveGame->Succ);
-			if (next->Succ == NULL)
-			{
-				next = static_cast<FSaveGameNode *>(SelSaveGame->Pred);
-				if (next->Pred == NULL)
-				{
-					next = NULL;
-				}
-			}
-
-			remove (SelSaveGame->Filename.GetChars());
+			remove (SaveGames[Selected]->Filename.GetChars());
 			UnloadSaveData ();
-			SelSaveGame = RemoveSaveSlot (SelSaveGame);
-			ExtractSaveData (SelSaveGame);
+			Selected = RemoveSaveSlot (Selected);
+			ExtractSaveData (Selected);
 		}
 		return true;
 	}
@@ -786,39 +751,16 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller)
 
 bool DLoadSaveMenu::MouseEvent(int type, int x, int y)
 {
-	const int savepicLeft = 10;
-	const int savepicTop = 54*CleanYfac;
-	const int savepicWidth = 216*screen->GetWidth()/640;
-
-	const int rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac;
-	const int listboxLeft = savepicLeft + savepicWidth + 14;
-	const int listboxTop = savepicTop;
-	const int listboxWidth = screen->GetWidth() - listboxLeft - 10;
-	const int listboxHeight1 = screen->GetHeight() - listboxTop - 10;
-	const int listboxRows = (listboxHeight1 - 1) / rowHeight;
-	const int listboxHeight = listboxRows * rowHeight + 1;
-	const int listboxRight = listboxLeft + listboxWidth;
-	const int listboxBottom = listboxTop + listboxHeight;
-
 	if (x >= listboxLeft && x < listboxLeft + listboxWidth && 
 		y >= listboxTop && y < listboxTop + listboxHeight)
 	{
 		int lineno = (y - listboxTop) / rowHeight;
-		FSaveGameNode *top = TopSaveGame;
-		while (lineno > 0 && top->Succ != NULL)
+
+		if (TopItem + lineno < (int)SaveGames.Size())
 		{
-			lineno--;
-			top = (FSaveGameNode *)top->Succ;
-		}
-		if (lineno == 0)
-		{
-			if (SelSaveGame != top)
-			{
-				SelSaveGame = top;
-				UnloadSaveData ();
-				ExtractSaveData (SelSaveGame);
-				// Sound?
-			}
+			Selected = TopItem + lineno;
+			UnloadSaveData ();
+			ExtractSaveData (Selected);
 			if (type == MOUSE_Release)
 			{
 				if (MenuEvent(MKEY_Enter, true))
@@ -827,12 +769,10 @@ bool DLoadSaveMenu::MouseEvent(int type, int x, int y)
 				}
 			}
 		}
-		else SelSaveGame = NULL;
-	}
-	else
-	{
-		SelSaveGame = NULL;
+		else Selected = -1;
 	}
+	else Selected = -1;
+
 	return Super::MouseEvent(type, x, y);
 }
 
@@ -848,16 +788,16 @@ bool DLoadSaveMenu::Responder (event_t *ev)
 	{
 		if (ev->subtype == EV_GUI_KeyDown)
 		{
-			if (SelSaveGame != NULL && SelSaveGame->Succ != NULL)
+			if (Selected != -1)
 			{
 				switch (ev->data1)
 				{
 				case GK_F1:
-					if (!SelSaveGame->Filename.IsEmpty())
+					if (!SaveGames[Selected]->Filename.IsEmpty())
 					{
 						char workbuf[512];
 
-						mysnprintf (workbuf, countof(workbuf), "File on disk:\n%s", SelSaveGame->Filename.GetChars());
+						mysnprintf (workbuf, countof(workbuf), "File on disk:\n%s", SaveGames[Selected]->Filename.GetChars());
 						if (SaveComment != NULL)
 						{
 							V_FreeBrokenLines (SaveComment);
@@ -871,7 +811,7 @@ bool DLoadSaveMenu::Responder (event_t *ev)
 					{
 						FString EndString;
 						EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s",
-							GStrings("MNU_DELETESG"), SelSaveGame->Title, GStrings("PRESSYN"));
+							GStrings("MNU_DELETESG"), SaveGames[Selected]->Title, GStrings("PRESSYN"));
 						M_StartMessage (EndString, 0);
 					}
 					return true;
@@ -880,36 +820,13 @@ bool DLoadSaveMenu::Responder (event_t *ev)
 		}
 		else if (ev->subtype == EV_GUI_WheelUp)
 		{
-			if (TopSaveGame != SaveGames.Head && TopSaveGame != NULL)
-			{
-				TopSaveGame = static_cast<FSaveGameNode *>(TopSaveGame->Pred);
-				mWheelScrolled = true;
-			}
+			if (TopItem > 0) TopItem--;
 			return true;
 		}
 		else if (ev->subtype == EV_GUI_WheelDown)
 		{
-			const int savepicTop = 54*CleanYfac;
-			const int listboxTop = savepicTop;
-			const int rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac;
-			const int listboxHeight1 = screen->GetHeight() - listboxTop - 10;
-			const int listboxRows = (listboxHeight1 - 1) / rowHeight;
-
-			FSaveGameNode *node = TopSaveGame;
-			if (node != NULL)
-			{
-				int count = 1;
-				while (node != NULL && node != SaveGames.TailPred)
-				{
-					node = (FSaveGameNode*)node->Succ;
-					count++;
-				}
-				if (count > listboxRows)
-				{
-					TopSaveGame = (FSaveGameNode*)TopSaveGame->Succ;
-					mWheelScrolled = true;
-				}
-			}
+			if (TopItem < (int)SaveGames.Size() - listboxRows) TopItem++;
+			return true;
 		}
 	}
 	return Super::Responder(ev);
@@ -952,17 +869,17 @@ DSaveMenu::DSaveMenu(DMenu *parent, FListMenuDescriptor *desc)
 {
 	strcpy (NewSaveNode.Title, "<New Save Game>");
 	NewSaveNode.bNoDelete = true;
-	SaveGames.AddHead (&NewSaveNode);
-	TopSaveGame = static_cast<FSaveGameNode *>(SaveGames.Head);
-	if (lastSaveSlot == NULL)
+	SaveGames.Insert(0, &NewSaveNode);
+	TopItem = 0;
+	if (LastSaved == -1)
 	{
-		SelSaveGame = &NewSaveNode;
+		Selected = 0;
 	}
 	else
 	{
-		SelSaveGame = lastSaveSlot;
+		Selected = LastSaved + 1;
 	}
-	ExtractSaveData (SelSaveGame);
+	ExtractSaveData (Selected);
 }
 
 //=============================================================================
@@ -973,17 +890,11 @@ DSaveMenu::DSaveMenu(DMenu *parent, FListMenuDescriptor *desc)
 
 void DSaveMenu::Destroy()
 {
-	if (SaveGames.Head == &NewSaveNode)
+	if (SaveGames[0] == &NewSaveNode)
 	{
-		SaveGames.RemHead ();
-		if (SelSaveGame == &NewSaveNode)
-		{
-			SelSaveGame = static_cast<FSaveGameNode *>(SaveGames.Head);
-		}
-		if (TopSaveGame == &NewSaveNode)
-		{
-			TopSaveGame = static_cast<FSaveGameNode *>(SaveGames.Head);
-		}
+		SaveGames.Delete(0);
+		if (Selected == 0) Selected = -1;
+		else Selected--;
 	}
 }
 
@@ -1034,16 +945,16 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller)
 	{
 		return true;
 	}
-	if (SelSaveGame == NULL || SelSaveGame->Succ == NULL)
+	if (Selected == -1)
 	{
 		return false;
 	}
 
 	if (mkey == MKEY_Enter)
 	{
-		if (SelSaveGame != &NewSaveNode)
+		if (Selected != 0)
 		{
-			strcpy (savegamestring, SelSaveGame->Title);
+			strcpy (savegamestring, SaveGames[Selected]->Title);
 		}
 		else
 		{
@@ -1056,7 +967,7 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller)
 	else if (mkey == MKEY_Input)
 	{
 		mEntering = false;
-		DoSave(SelSaveGame);
+		DoSave(SaveGames[Selected]);
 	}
 	else if (mkey == MKEY_Abort)
 	{
@@ -1075,18 +986,18 @@ bool DSaveMenu::Responder (event_t *ev)
 {
 	if (ev->subtype == EV_GUI_KeyDown)
 	{
-		if (SelSaveGame != NULL && SelSaveGame->Succ != NULL)
+		if (Selected != -1)
 		{
 			switch (ev->data1)
 			{
 			case GK_DEL:
 			case '\b':
 				// cannot delete 'new save game' item
-				if (SelSaveGame == &NewSaveNode) return true;
+				if (Selected == 0) return true;
 				break;
 
 			case 'N':
-				SelSaveGame = TopSaveGame = &NewSaveNode;
+				Selected = TopItem = 0;
 				UnloadSaveData ();
 				return true;
 			}
@@ -1124,8 +1035,9 @@ IMPLEMENT_CLASS(DLoadMenu)
 DLoadMenu::DLoadMenu(DMenu *parent, FListMenuDescriptor *desc)
 : DLoadSaveMenu(parent, desc)
 {
-	TopSaveGame = static_cast<FSaveGameNode *>(SaveGames.Head);
-	ExtractSaveData (SelSaveGame);
+	TopItem = 0;
+	ExtractSaveData (Selected);
+
 }
 
 //=============================================================================
@@ -1140,21 +1052,21 @@ bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller)
 	{
 		return true;
 	}
-	if (SelSaveGame == NULL || SelSaveGame->Succ == NULL)
+	if (Selected == -1)
 	{
 		return false;
 	}
 
 	if (mkey == MKEY_Enter)
 	{
-		G_LoadGame (SelSaveGame->Filename.GetChars());
+		G_LoadGame (SaveGames[Selected]->Filename.GetChars());
 		if (gamestate == GS_FULLCONSOLE)
 		{
 			gamestate = GS_HIDECONSOLE;
 		}
-		if (quickSaveSlot == (FSaveGameNode *)1)
+		if (quickSaveSlot == (FSaveGameNode*)1)
 		{
-			quickSaveSlot = SelSaveGame;
+			quickSaveSlot = SaveGames[Selected];
 		}
 		M_ClearMenus();
 		BorderNeedRefresh = screen->GetPageCount ();
diff --git a/src/menu/menu.h b/src/menu/menu.h
index b1073a041..c4dc8b9e5 100644
--- a/src/menu/menu.h
+++ b/src/menu/menu.h
@@ -56,7 +56,7 @@ struct FGameStartup
 
 extern FGameStartup GameStartupInfo;
 
-struct FSaveGameNode : public Node
+struct FSaveGameNode
 {
 	char Title[SAVESTRINGSIZE];
 	FString Filename;