Index: code/menuui/mainhallmenu.cpp
===================================================================
--- code/menuui/mainhallmenu.cpp	(revision 10960)
+++ code/menuui/mainhallmenu.cpp	(working copy)
@@ -45,6 +45,8 @@
 #endif
 
 
+// A reference to io/keycontrol.cpp
+extern void game_process_cheats(int k);
 
 // ----------------------------------------------------------------------------
 // MAIN HALL DATA DEFINES
@@ -53,6 +55,7 @@
 #define MISC_ANIM_MODE_HOLD			1		// play to the end and hold the animation
 #define MISC_ANIM_MODE_TIMED		2		// uses timestamps to determine when a finished anim should be checked again
 #define NUM_REGIONS					7		// (6 + 1 for multiplayer equivalent of campaign room)
+#define MAIN_HALL_MAX_CHEAT_LEN		40		// cheat buffer length (also maximum cheat length)
 
 SCP_vector< SCP_vector<main_hall_defines> > Main_hall_defines;
 
@@ -61,7 +64,7 @@
 int Vasudan_funny = 0;
 int Vasudan_funny_plate = -1;
 
-char Main_hall_campaign_cheat[512] = "";
+SCP_string Main_hall_cheat = "";
 
 // ----------------------------------------------------------------------------
 // MISC interface data
@@ -133,7 +136,7 @@
 SCP_vector<generic_anim> Main_hall_misc_anim;
 
 // render all playing misc animations
-void main_hall_render_misc_anims(float frametime);
+void main_hall_render_misc_anims(float frametime, bool over_doors);
 
 
 // ----------------------------------------------------------------------------
@@ -595,8 +598,6 @@
 
 	Main_hall_region_linger_stamp = -1;
 
-	strcpy_s(Main_hall_campaign_cheat, "");
-
 	// initialize door sound handles
 	Main_hall_door_sound_handles.clear();
 	for (idx = 0; idx < Main_hall->num_door_animations; idx++) {
@@ -685,8 +686,91 @@
 	code = snazzy_menu_do(Main_hall_mask_data, Main_hall_mask_w, Main_hall_mask_h, (int)Main_hall->regions.size(), Main_hall_region, &snazzy_action, 1, &key);
 
 	if (key) {
-		extern void game_process_cheats(int k);
 		game_process_cheats(key);
+		
+		Main_hall_cheat += (char) key_to_ascii(key);
+		if(Main_hall_cheat.size() > MAIN_HALL_MAX_CHEAT_LEN) {
+			Main_hall_cheat = Main_hall_cheat.substr(Main_hall_cheat.size() - MAIN_HALL_MAX_CHEAT_LEN);
+		}
+		
+		int cur_frame;
+		float anim_time;
+		bool cheat_anim_found, cheat_found = false;
+		
+		for (int c_idx = 0; c_idx < (int) Main_hall->cheat.size(); c_idx++) {
+			cheat_anim_found = false;
+			
+			if(Main_hall_cheat.find(Main_hall->cheat.at(c_idx)) != SCP_string::npos) {
+				cheat_found = true;
+				// switch animations
+				
+				for (int idx = 0; idx < Main_hall->num_misc_animations; idx++) {
+					if (Main_hall->misc_anim_name.at(idx) == Main_hall->cheat_anim_from.at(c_idx)) {
+						Main_hall->misc_anim_name.at(idx) = Main_hall->cheat_anim_to.at(c_idx);
+						
+						cur_frame = Main_hall_misc_anim.at(idx).current_frame;
+						anim_time = Main_hall_misc_anim.at(idx).anim_time;
+						
+						generic_anim_unload(&Main_hall_misc_anim.at(idx));
+						generic_anim_init(&Main_hall_misc_anim.at(idx), Main_hall->misc_anim_name.at(idx));
+						
+						if (generic_anim_stream(&Main_hall_misc_anim.at(idx)) == -1) {
+							nprintf(("General","WARNING! Could not load misc %s anim in main hall\n", Main_hall->misc_anim_name.at(idx).c_str()));
+						} else {
+							// start paused
+							if (Main_hall->misc_anim_modes.at(idx) == MISC_ANIM_MODE_HOLD)
+								Main_hall_misc_anim.at(idx).direction |= GENERIC_ANIM_DIRECTION_NOLOOP;
+						}
+						
+						Main_hall_misc_anim.at(idx).current_frame = cur_frame;
+						Main_hall_misc_anim.at(idx).anim_time = anim_time;
+
+						// null out the delay timestamps
+						Main_hall->misc_anim_delay.at(idx).at(0) = -1;
+
+						cheat_anim_found = true;
+						break;
+					}
+				}
+				
+				if (!cheat_anim_found) {
+					for (int idx = 0; idx < Main_hall->num_door_animations; idx++) {
+						if (Main_hall->door_anim_name.at(idx) == Main_hall->cheat_anim_from.at(c_idx)) {
+							Main_hall->door_anim_name.at(idx) = Main_hall->cheat_anim_to.at(c_idx);
+							
+							cur_frame = Main_hall_door_anim.at(idx).current_frame;
+							anim_time = Main_hall_door_anim.at(idx).anim_time;
+							
+							generic_anim_unload(&Main_hall_door_anim.at(idx));
+							generic_anim_init(&Main_hall_door_anim.at(idx), Main_hall->door_anim_name.at(idx));
+							
+							if (generic_anim_stream(&Main_hall_door_anim.at(idx)) == -1) {
+								nprintf(("General","WARNING! Could not load door anim %s in main hall\n", Main_hall->door_anim_name.at(idx).c_str()));
+							} else {
+								Main_hall_door_anim.at(idx).direction = GENERIC_ANIM_DIRECTION_BACKWARDS | GENERIC_ANIM_DIRECTION_NOLOOP;
+							}
+							
+							Main_hall_door_anim.at(idx).current_frame = cur_frame;
+							Main_hall_door_anim.at(idx).anim_time = anim_time;
+							
+							cheat_anim_found = true;
+							break;
+						}
+					}
+				}
+				
+				if (!cheat_anim_found) {
+					// Note: This can also happen if the cheat triggers a second time since the animations are already switched at that point.
+					nprintf(("General", "Could not find animation '%s' for cheat '%s'!", Main_hall->cheat_anim_from.at(c_idx).c_str(), Main_hall->cheat.at(c_idx).c_str()));
+				}
+			}
+		}
+		
+		if(cheat_found) {
+			// Found a cheat, clear the buffer.
+			
+			Main_hall_cheat = "";
+		}
 	}
 
 	switch(key) {
@@ -759,11 +843,7 @@
 					Player->flags &= ~PLAYER_FLAGS_IS_MULTI;
 					Game_mode = GM_NORMAL;
 					
-					if (strlen(Main_hall_campaign_cheat)) {
-						gameseq_post_event(GS_EVENT_CAMPAIGN_CHEAT);
-					} else {
-						gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
-					}
+					gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
 					gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
 					break;
 
@@ -873,10 +953,13 @@
 	}
 
 	// render misc animations
-	main_hall_render_misc_anims(frametime);
+	main_hall_render_misc_anims(frametime, false);
 
 	// render door animtions
 	main_hall_render_door_anims(frametime);
+	
+	// render misc animations (over doors)
+	main_hall_render_misc_anims(frametime, true);
 
 	// blit any appropriate tooltips
 	main_hall_maybe_blit_tooltips();
@@ -1098,7 +1181,7 @@
  * 
  * @param frametime Animation frame time
  */
-void main_hall_render_misc_anims(float frametime)
+void main_hall_render_misc_anims(float frametime, bool over_doors)
 {
 	std::deque<bool> group_anims_weve_checked;
 	int idx, s_idx, jdx;
@@ -1109,7 +1192,7 @@
 		group_anims_weve_checked.push_back(false);
 
 		// render it
-		if (Main_hall_misc_anim.at(idx).num_frames > 0) {
+		if (Main_hall_misc_anim.at(idx).num_frames > 0 && Main_hall->misc_anim_over_doors.at(idx) == over_doors) {
 			// animation is paused
 			if (Main_hall->misc_anim_paused.at(idx)) {
 				// if the timestamp is -1, then regenerate it
@@ -2051,7 +2134,27 @@
 
 				m->name = Main_hall_defines.at(count).at(0).name;
 			}
+			
+			// add cheats
+			while (optional_string("+Cheat String:")) {
+				stuff_string(temp_scp_string, F_RAW);
+				m->cheat.push_back(temp_scp_string);
 
+				if(temp_scp_string.size() > MAIN_HALL_MAX_CHEAT_LEN) {
+					// Since the value is longer than the cheat buffer it will never match.
+
+					Warning(LOCATION, "The value '%s' for '+Cheat String:' is too long! It can be at most %d characters long.", temp_scp_string.size(), MAIN_HALL_MAX_CHEAT_LEN);
+				}
+				
+				required_string("+Anim To Change:");
+				stuff_string(temp_scp_string, F_NAME);
+				m->cheat_anim_from.push_back(temp_scp_string);
+				
+				required_string("+Anim To Change To:");
+				stuff_string(temp_scp_string, F_NAME);
+				m->cheat_anim_to.push_back(temp_scp_string);
+			}
+
 			// minimum resolution
 			if (optional_string("+Min Resolution:")) {
 				stuff_int(&m->min_width);
@@ -2221,6 +2324,17 @@
 				}
 			}
 			
+			for (idx = 0; idx < m->num_misc_animations; idx++) {
+				// render over doors - default to false
+				
+				if (optional_string("+Misc anim over doors:")) {
+					stuff_boolean(&rval);
+					m->misc_anim_over_doors.push_back(rval);
+				} else {
+					m->misc_anim_over_doors.push_back(0);
+				}
+			}
+
 			region_info_init(*m);
 			
 			int mask;
Index: code/menuui/mainhallmenu.h
===================================================================
--- code/menuui/mainhallmenu.h	(revision 10960)
+++ code/menuui/mainhallmenu.h	(working copy)
@@ -26,6 +26,10 @@
 typedef struct main_hall_defines {
 	// mainhall name identifier
 	SCP_string name;
+	
+	SCP_vector<SCP_string> cheat;
+	SCP_vector<SCP_string> cheat_anim_from;
+	SCP_vector<SCP_string> cheat_anim_to;
 
 	// minimum resolution and aspect ratio needed to display this main hall
 	int min_width;
@@ -97,6 +101,9 @@
 
 	//flags for each of the misc anim sounds
 	SCP_vector<SCP_vector<int> > misc_anim_sound_flag;
+	
+	// controls the render order
+	SCP_vector<bool> misc_anim_over_doors;
 
 
 	// door animations --------------------
