Index: java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java	(revision 808)
+++ java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java	(revision 809)
@@ -70,12 +70,4 @@
 
 	/**
-	 * @return list of currently installed mods
-	 */
-	public static Vector<Integer> getInstalledMods() {
-		File installCfg = new File(Paths.getEditionGDF(), "installed_mods.xml");
-		return PackageManager.getInstance().loadModSelection(installCfg);
-	}
-
-	/**
 	 * Install the given set of mods
 	 * 
@@ -115,19 +107,12 @@
 		log.println();
 
-		Paths.getEditionGDF().mkdirs();
-		for (File f : Paths.getEditionGDF().listFiles(new FilenameFilter() {
-			public boolean accept(File arg0, String arg1) {
-				String s = arg1.toLowerCase();
-				return s.endsWith(".dat")
-						|| s.endsWith(".raw")
-						|| s.endsWith(".sep")
-						|| (s.equals("intro.bik") && !SettingsManager
-								.getInstance().get("copyintro", false))
-						|| (s.equals("outro.bik") && !SettingsManager
-								.getInstance().get("copyoutro", false));
-			}
-		})) {
-			f.delete();
-		}
+		HashSet<String> levelsAffectedBefore = null;
+		if (ModInstallationList.getInstance().isLoadedFromFile()) {
+			levelsAffectedBefore = ModInstallationList.getInstance()
+					.getAffectedLevels();
+		}
+		HashSet<String> levelsAffectedNow = new HashSet<String>();
+		// TODO: fill set
+
 		File IGMD = new File(Paths.getEditionGDF(), "IGMD");
 		if (IGMD.exists()) {
@@ -149,7 +134,4 @@
 			}
 		}
-
-		File installCfg = new File(Paths.getEditionGDF(), "installed_mods.xml");
-		PackageManager.getInstance().saveModSelection(installCfg, mods);
 
 		TreeSet<Integer> unlockLevels = new TreeSet<Integer>();
@@ -217,4 +199,5 @@
 				if (levelF.isDirectory()) {
 					levelN = fn;
+					levelsAffectedNow.add(fn.toLowerCase());
 				} else if (fn.endsWith(".dat")) {
 					levelN = fn.substring(0, fn.lastIndexOf('.')).toLowerCase();
@@ -228,7 +211,31 @@
 		}
 
+		Paths.getEditionGDF().mkdirs();
+		for (File f : Paths.getEditionGDF().listFiles(new FilenameFilter() {
+			public boolean accept(File arg0, String arg1) {
+				String s = arg1.toLowerCase();
+				return s.endsWith(".dat")
+						|| s.endsWith(".raw")
+						|| s.endsWith(".sep")
+						|| (s.equals("intro.bik") && !SettingsManager
+								.getInstance().get("copyintro", false))
+						|| (s.equals("outro.bik") && !SettingsManager
+								.getInstance().get("copyoutro", false));
+			}
+		})) {
+			String l = f.getName().toLowerCase();
+			l = l.substring(0, l.length() - 4);
+			if ((levelsAffectedBefore == null)
+					|| levelsAffectedBefore.contains(l)
+					|| levelsAffectedNow.contains(l))
+				f.delete();
+		}
+
 		applyPatches(levels, foldersPatches, listener, log);
 
-		combineBinaryFiles(levels, listener, log);
+		TreeSet<String> levelsAffectedBoth = new TreeSet<String>();
+		levelsAffectedBoth.addAll(levelsAffectedBefore);
+		levelsAffectedBoth.addAll(levelsAffectedNow);
+		combineBinaryFiles(levels, levelsAffectedBoth, listener, log);
 		combineBSLFolders(mods, listener, log);
 
@@ -238,4 +245,13 @@
 			unlockLevels(unlockLevels, log);
 		}
+
+		ModInstallationList mil = ModInstallationList.getInstance();
+		mil.setAffectedLevels(levelsAffectedNow);
+		TreeSet<Integer> modsInstalled = new TreeSet<Integer>();
+		for (Package p : mods) {
+			modsInstalled.add(p.getPackageNumber());
+		}
+		mil.setInstalledMods(modsInstalled);
+		mil.saveList();
 
 		log.println();
@@ -509,5 +525,6 @@
 	private static void combineBinaryFiles(
 			TreeMap<String, Vector<File>> oniLevelFolders,
-			InstallProgressListener listener, Logger log) {
+			TreeSet<String> levelsUpdated, InstallProgressListener listener,
+			Logger log) {
 		long startMS = new Date().getTime();
 
@@ -522,8 +539,13 @@
 					"Installing level " + l);
 
-			ApplicationInvocationResult res = OniSplit.packLevel(
-					oniLevelFolders.get(l), new File(Paths.getEditionGDF(),
-							sanitizeLevelName(l) + ".dat"));
-			log.logAppOutput(res, true);
+			if (levelsUpdated.contains(l.toLowerCase())) {
+				ApplicationInvocationResult res = OniSplit.packLevel(
+						oniLevelFolders.get(l), new File(Paths.getEditionGDF(),
+								sanitizeLevelName(l) + ".dat"));
+				log.logAppOutput(res, true);
+			} else {
+				log.println("\t\tLevel not affected by new mod selection");
+				log.println();
+			}
 
 			stepsDone++;
@@ -539,6 +561,7 @@
 		if (SettingsManager.getInstance().get("copyintro", false)) {
 			File src = new File(Paths.getVanillaGDF(), "intro.bik");
+			File target = new File(Paths.getEditionGDF(), "intro.bik");
 			log.println("Copying intro");
-			if (src.exists()) {
+			if (src.exists() && !target.exists()) {
 				try {
 					FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
@@ -552,6 +575,7 @@
 		if (SettingsManager.getInstance().get("copyoutro", true)) {
 			File src = new File(Paths.getVanillaGDF(), "outro.bik");
+			File target = new File(Paths.getEditionGDF(), "outro.bik");
 			log.println("Copying outro");
-			if (src.exists()) {
+			if (src.exists() && !target.exists()) {
 				try {
 					FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
Index: java/installer2/src/net/oni2/aeinstaller/backend/oni/management/ModInstallationList.java
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/backend/oni/management/ModInstallationList.java	(revision 809)
+++ java/installer2/src/net/oni2/aeinstaller/backend/oni/management/ModInstallationList.java	(revision 809)
@@ -0,0 +1,110 @@
+package net.oni2.aeinstaller.backend.oni.management;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.TreeSet;
+
+import net.oni2.aeinstaller.backend.Paths;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.StaxDriver;
+
+/**
+ * @author Christian Illy
+ */
+public class ModInstallationList {
+	private static ModInstallationList instance = loadList();
+
+	private TreeSet<Integer> mods = new TreeSet<Integer>();
+	private HashSet<String> affectedLevels = new HashSet<String>();
+	private transient boolean isLoaded = false;
+
+	/**
+	 * @return Get singleton instance
+	 */
+	public static ModInstallationList getInstance() {
+		return instance;
+	}
+	
+	public TreeSet<Integer> getInstalledMods() {
+		return mods;
+	}
+	
+	public boolean isInstalled(int packageId) {
+		return mods.contains(packageId);
+	}
+	
+	public void setInstalledMods(TreeSet<Integer> mods) {
+		this.mods = mods;
+	}
+	
+	public HashSet<String> getAffectedLevels() {
+		return affectedLevels;
+	}
+	
+	public boolean isLevelAffected(String level) {
+		return affectedLevels.contains(level.toLowerCase());
+	}
+	
+	public void setAffectedLevels(HashSet<String> levels) {
+		affectedLevels.clear();
+		for (String l : levels) {
+			affectedLevels.add(l.toLowerCase());
+		}
+	}
+	
+	public boolean isLoadedFromFile() {
+		return isLoaded;
+	}
+
+	private static File getFile() {
+		return new File(Paths.getEditionGDF(), "installed_mods.xml");
+	}
+
+	private static XStream getStream() {
+		XStream xs = new XStream(new StaxDriver());
+		xs.alias("MIL", ModInstallationList.class);
+		return xs;
+	}
+
+	private static ModInstallationList loadList() {
+		ModInstallationList mil = new ModInstallationList();
+		try {
+			if (getFile().exists()) {
+				FileInputStream fis = new FileInputStream(getFile());
+				XStream xs = getStream();
+				Object obj = xs.fromXML(fis);
+				if (obj instanceof ModInstallationList) {
+					mil = (ModInstallationList) obj;
+					mil.isLoaded = true;
+				}
+				fis.close();
+			}
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return mil;
+	}
+
+	/**
+	 * Write this mod installation list to the installed_mods.xml file
+	 */
+	public void saveList() {
+		try {
+			FileOutputStream fos = new FileOutputStream(getFile());
+			XStream xs = getStream();
+			xs.toXML(this, fos);
+			fos.close();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+}
Index: java/installer2/src/net/oni2/aeinstaller/backend/packages/PackageManager.java
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/backend/packages/PackageManager.java	(revision 808)
+++ java/installer2/src/net/oni2/aeinstaller/backend/packages/PackageManager.java	(revision 809)
@@ -14,5 +14,5 @@
 
 import net.oni2.aeinstaller.backend.Paths;
-import net.oni2.aeinstaller.backend.oni.management.Installer;
+import net.oni2.aeinstaller.backend.oni.management.ModInstallationList;
 import net.oni2.aeinstaller.backend.oni.management.tools.ToolInstallationList;
 import net.oni2.moddepot.DepotManager;
@@ -32,6 +32,4 @@
 	private HashMap<Integer, Package> mods = new HashMap<Integer, Package>();
 	private HashMap<Integer, Package> tools = new HashMap<Integer, Package>();
-
-	private Vector<Integer> currentlyInstalled = new Vector<Integer>();
 
 	/**
@@ -131,15 +129,4 @@
 				mods.put(m.getPackageNumber(), m);
 		}
-
-		updateInstalledMods();
-	}
-
-	/**
-	 * Update the list of currently installed mods
-	 */
-	public void updateInstalledMods() {
-		currentlyInstalled = Installer.getInstalledMods();
-		if (currentlyInstalled == null)
-			currentlyInstalled = new Vector<Integer>();
 	}
 
@@ -219,5 +206,5 @@
 	public TreeSet<Package> getInstalledMods() {
 		TreeSet<Package> res = new TreeSet<Package>();
-		for (int n : Installer.getInstalledMods()) {
+		for (int n : ModInstallationList.getInstance().getInstalledMods()) {
 			res.add(getPackageByNumber(n));
 		}
@@ -358,5 +345,5 @@
 	 */
 	boolean isModInstalled(Package m) {
-		return currentlyInstalled.contains(m.getPackageNumber());
+		return ModInstallationList.getInstance().isInstalled(m.getPackageNumber());
 	}
 }
Index: java/installer2/src/net/oni2/aeinstaller/gui/MainWin.java
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/gui/MainWin.java	(revision 808)
+++ java/installer2/src/net/oni2/aeinstaller/gui/MainWin.java	(revision 809)
@@ -782,5 +782,4 @@
 	@SuppressWarnings("unused")
 	private void installDone() {
-		PackageManager.getInstance().updateInstalledMods();
 		switch (installState) {
 			case DONE:
