--- a/gemrb/core/Game.cpp
+++ b/gemrb/core/Game.cpp
@@ -782,7 +782,7 @@
 /* Loads an area */
 int Game::LoadMap(const char* ResRef, bool loadscreen)
 {
-	unsigned int i;
+	unsigned int i, last;
 	Map *newMap;
 	PluginHolder<MapMgr> mM(IE_ARE_CLASS_ID);
 	ScriptEngine *sE = core->GetGUIScriptEngine();
@@ -822,9 +822,16 @@
 			newMap->AddActor( PCs[i] );
 		}
 	}
+	// count the number of replaced actors, so we don't need to recheck them
+	// if their max level is still lower than ours, each check would also result in a substitution
+	last = NPCs.size()-1;
 	for (i = 0; i < NPCs.size(); i++) {
 		if (stricmp( NPCs[i]->Area, ResRef ) == 0) {
-			(void)CheckForReplacementActor(i);
+			if (i < last && CheckForReplacementActor(i)) {
+				i--;
+				last--;
+				continue;
+			}
 			newMap->AddActor( NPCs[i] );
 		}
 	}
@@ -841,13 +848,17 @@
 
 // check if the actor is in npclevel.2da and replace accordingly
 bool Game::CheckForReplacementActor(int i) {
+	if (core->InCutSceneMode() || npclevels.empty()) {
+		return false;
+	}
+
 	Actor* act = NPCs[i];
 	ieDword level = GetPartyLevel(false) / GetPartySize(false);
-	if (! npclevels.empty() && !(act->Modified[IE_MC_FLAGS]&MC_BEENINPARTY) && !(act->Modified[IE_STATE_ID]&STATE_DEAD) && act->GetXPLevel(false) < level) {
+	if (!(act->Modified[IE_MC_FLAGS]&MC_BEENINPARTY) && !(act->Modified[IE_STATE_ID]&STATE_DEAD) && act->GetXPLevel(false) < level) {
 		ieResRef newcre = "****"; // default table value
 		std::vector<std::vector<const char *> >::iterator it;
 		for (it = npclevels.begin(); it != npclevels.end(); it++) {
-			if (!stricmp((*it)[0], act->GetScriptName())) {
+			if (!stricmp((*it)[0], act->GetScriptName()) && (level > 2)) {
 				strncpy(newcre, (*it)[level-2], sizeof(ieResRef));
 				break;
 			}
@@ -863,6 +874,7 @@
 					error("Game::CheckForReplacementActor", "GetNPC failed: cannot find act!\n");
 				} else {
 					newact->Pos = act->Pos; // the map is not loaded yet, so no SetPosition
+					strncpy(newact->Area, act->Area, sizeof(ieResRef));
 					DelNPC(InStore(act));
 					return true;
 				}
@@ -1500,8 +1512,8 @@
 	}
 
 	//rest check, if PartyRested should be set, area should return true
-	//area should advance gametime too (so partial rest is possible)
 	int hours = 8;
+	int hoursLeft = 0;
 	if (!(checks&REST_NOAREA) ) {
 		//you cannot rest here
 		if (area->AreaFlags&1) {
@@ -1515,11 +1527,26 @@
 			return;
 		}
 		//area encounters
-		if(area->Rest( leader->Pos, hours, (GameTime/AI_UPDATE_TIME)%7200/3600) ) {
-			return;
-		}
-	}
-	AdvanceTime(2400*AI_UPDATE_TIME);
+		// also advances gametime (so partial rest is possible)
+		hoursLeft = area->Rest( leader->Pos, hours, (GameTime/AI_UPDATE_TIME)%7200/3600);
+		if (hoursLeft) {
+			// partial rest only, so adjust the parameters for the loop below
+			if (hp) {
+				hp = hp * (hours - hoursLeft) / hours;
+				// 0 means full heal, so we need to cancel it if we rounded to 0
+				if (!hp) {
+					hp = 1;
+				}
+			}
+			hours -= hoursLeft;
+			// the interruption occured before any resting could be done, so just bail out
+			if (!hours) {
+				return;
+			}
+		}
+	} else {
+		AdvanceTime(hours*300*AI_UPDATE_TIME);
+	}
 
 	int i = GetPartySize(true); // party size, only alive
 
@@ -1532,7 +1559,14 @@
 		tar->Heal(hp);
 		//removes fatigue, recharges spells
 		tar->Rest(hours);
-		tar->PartyRested();
+		if (hoursLeft) {
+			tar->PartyRested();
+		}
+	}
+
+	// abort the partial rest; we got what we wanted
+	if (hoursLeft) {
+		return;
 	}
 
 	//movie and cutscene dreams