diff --git a/LEGO1/lego/legoomni/include/act1state.h b/LEGO1/lego/legoomni/include/act1state.h
index 324d7195..988eb8c7 100644
--- a/LEGO1/lego/legoomni/include/act1state.h
+++ b/LEGO1/lego/legoomni/include/act1state.h
@@ -27,9 +27,12 @@ public:
 
 	inline void SetUnknown18(MxU32 p_unk0x18) { m_unk0x18 = p_unk0x18; }
 	inline MxU32 GetUnknown18() { return m_unk0x18; }
-	inline void SetUnknown21(MxS16 p_unk0x21) { m_unk0x21 = p_unk0x21; }
+	inline MxU32 GetUnknown1c() { return m_unk0x1c; }
 	inline MxS16 GetUnknown21() { return m_unk0x21; }
 
+	inline void SetUnknown1c(MxU32 p_unk0x1c) { m_unk0x1c = p_unk0x1c; }
+	inline void SetUnknown21(MxS16 p_unk0x21) { m_unk0x21 = p_unk0x21; }
+
 	void FUN_10034d00();
 
 	// SYNTHETIC: LEGO1 0x10033960
diff --git a/LEGO1/lego/legoomni/include/elevatorbottom.h b/LEGO1/lego/legoomni/include/elevatorbottom.h
index e52f5556..2c8711a3 100644
--- a/LEGO1/lego/legoomni/include/elevatorbottom.h
+++ b/LEGO1/lego/legoomni/include/elevatorbottom.h
@@ -4,6 +4,8 @@
 #include "decomp.h"
 #include "legoworld.h"
 
+class LegoControlManagerEvent;
+
 // VTABLE: LEGO1 0x100d5f20
 // SIZE: 0xfc (from inlined ctor at 0x1000a8aa)
 class ElevatorBottom : public LegoWorld {
@@ -41,7 +43,7 @@ public:
 private:
 	undefined4 m_unk0xf8; // 0xf8
 
-	MxLong HandleNotification17(MxParam& p_param);
+	MxLong HandleClick(LegoControlManagerEvent& p_param);
 };
 
 #endif // ELEVATORBOTTOM_H
diff --git a/LEGO1/lego/legoomni/include/infocenter.h b/LEGO1/lego/legoomni/include/infocenter.h
index b46099cd..56f01e09 100644
--- a/LEGO1/lego/legoomni/include/infocenter.h
+++ b/LEGO1/lego/legoomni/include/infocenter.h
@@ -2,10 +2,12 @@
 #define INFOCENTER_H
 
 #include "legoworld.h"
+#include "mxrect32.h"
 #include "radio.h"
 
 class InfocenterState;
 class MxStillPresenter;
+class LegoControlManagerEvent;
 
 // SIZE 0x18
 struct InfocenterMapEntry {
@@ -14,10 +16,7 @@ struct InfocenterMapEntry {
 
 	MxStillPresenter* m_presenter; // 0x00
 	undefined4 m_unk0x04;          // 0x04
-	undefined4 m_unk0x08;          // 0x08
-	undefined4 m_unk0x0c;          // 0x0c
-	undefined4 m_unk0x10;          // 0x10
-	undefined4 m_unk0x14;          // 0x14
+	MxRect32 m_area;               // 0x08
 };
 
 // VTABLE: LEGO1 0x100d9338
@@ -40,12 +39,15 @@ public:
 		c_leftArrowCtl = 1,
 		c_rightArrowCtl = 2,
 		c_infoCtl = 3,
+		c_doorCtl = 4,
 		c_boatCtl = 10,
 		c_raceCtl = 11,
 		c_pizzaCtl = 12,
 		c_gasCtl = 13,
 		c_medCtl = 14,
 		c_copCtl = 15,
+		c_bigInfoCtl = 16,
+		c_bookCtl = 17,
 		c_radioCtl = 18,
 		c_mamaCtl = 21,
 		c_papaCtl = 22,
@@ -53,6 +55,15 @@ public:
 		c_nickCtl = 24,
 		c_lauraCtl = 25,
 
+		c_mamaSelected = 30,
+		c_papaSelected = 31,
+		c_pepperSelected = 32,
+		c_nickSelected = 33,
+		c_lauraSelected = 34,
+
+		c_goToRegBook = 70,
+		c_goToRegBookRed = 71,
+
 		c_welcomeDialogue = 500,
 		c_goodJobDialogue = 501,
 
@@ -114,6 +125,13 @@ public:
 		c_noCDDialogueUnused1 = 552,
 		c_noCDDialogueUnused2 = 553,
 
+		c_gasCtlDescription = 555,
+		c_medCtlDescription = 556,
+		c_boatCtlDescription = 558,
+		c_copCtlDescription = 559,
+		c_pizzaCtlDescription = 560,
+		c_raceCtlDescription = 561,
+
 		c_leaveInfoCenterDialogue1 = 562,
 		c_leaveInfoCenterDialogue2 = 563,
 		c_leaveInfoCenterDialogue3 = 564,
@@ -163,16 +181,18 @@ private:
 	MxLong HandleKeyPress(MxS8 p_key);
 	MxU8 HandleMouseMove(MxS32 p_x, MxS32 p_y);
 	MxU8 HandleButtonUp(MxS32 p_x, MxS32 p_y);
-	MxU8 HandleNotification17(MxParam&);
+	MxU8 HandleClick(LegoControlManagerEvent& p_param);
 	MxLong HandleEndAction(MxParam& p_param);
 	MxLong HandleNotification0(MxParam&);
 
-	void FUN_10070dc0(MxBool);
+	void UpdateFrameHot(MxBool p_display);
 	void FUN_10070e90();
 
 	void PlayCutscene(Cutscene p_entityId, MxBool p_scale);
 	void StopCutscene();
 
+	void FUN_10070d10(MxS32 p_x, MxS32 p_y);
+
 	void StartCredits();
 	void StopCredits();
 
@@ -185,10 +205,10 @@ private:
 	InfomainScript m_currentInfomainScript; // 0xf8
 	MxS16 m_unk0xfc;                        // 0xfc
 	InfocenterState* m_infocenterState;     // 0x100
-	undefined4 m_unk0x104;                  // 0x104
+	undefined4 m_transitionDestination;     // 0x104
 	Cutscene m_currentCutscene;             // 0x108
 	Radio m_radio;                          // 0x10c
-	undefined4 m_unk0x11c;                  // 0x11c
+	MxStillPresenter* m_unk0x11c;           // 0x11c
 	InfocenterMapEntry m_mapAreas[7];       // 0x120
 	MxS16 m_unk0x1c8;                       // 0x1c8
 	MxStillPresenter* m_frameHotBitmap;     // 0x1cc
diff --git a/LEGO1/lego/legoomni/include/infocenterdoor.h b/LEGO1/lego/legoomni/include/infocenterdoor.h
index 1d7b361d..0869d4e4 100644
--- a/LEGO1/lego/legoomni/include/infocenterdoor.h
+++ b/LEGO1/lego/legoomni/include/infocenterdoor.h
@@ -3,6 +3,8 @@
 
 #include "legoworld.h"
 
+class LegoControlManagerEvent;
+
 // VTABLE: LEGO1 0x100d72d8
 // SIZE 0xfc
 class InfocenterDoor : public LegoWorld {
@@ -39,6 +41,8 @@ public:
 
 private:
 	MxS32 m_unk0xf8; // 0xf8
+
+	MxLong HandleClick(LegoControlManagerEvent& p_param);
 };
 
 #endif // INFOCENTERDOOR_H
diff --git a/LEGO1/lego/legoomni/include/infocenterstate.h b/LEGO1/lego/legoomni/include/infocenterstate.h
index 9399f8f4..ed23acef 100644
--- a/LEGO1/lego/legoomni/include/infocenterstate.h
+++ b/LEGO1/lego/legoomni/include/infocenterstate.h
@@ -30,6 +30,7 @@ public:
 
 	inline MxS16 GetInfocenterBufferSize() { return sizeof(m_buffer) / sizeof(m_buffer[0]); }
 	inline MxStillPresenter* GetInfocenterBufferElement(MxS32 p_index) { return m_buffer[p_index]; }
+	inline StateStruct& GetUnknown0x68() { return m_unk0x68; }
 	inline MxU32 GetUnknown0x74() { return m_unk0x74; }
 
 	inline void SetUnknown0x74(MxU32 p_unk0x74) { m_unk0x74 = p_unk0x74; }
@@ -38,35 +39,10 @@ public:
 	// InfocenterState::`scalar deleting destructor'
 
 private:
-	// Members should be renamed with their offsets before use
-	/*
-	  struct UnkStruct
-	  {
-		undefined4 unk1;
-		undefined2 unk2;
-		undefined2 unk3;
-		undefined2 unk4;
-	  };
-
-	  undefined2 unk1;
-	  undefined2 unk2;
-	  undefined4 unk3;
-	  undefined4 padding1;
-	  void *unk4;
-	  undefined2 unk5;
-	  undefined2 unk6;
-	  undefined2 unk7;
-	  undefined2 padding2;
-	  void *unk8;
-	  undefined2 unk9;
-	  undefined2 unk10;
-	  undefined2 unk11;
-	  undefined2 padding3;
-	  UnkStruct unk12[6];
-	  undefined4 unk13;
-	*/
-
-	undefined m_pad[0x6c];
+	undefined m_unk0x08[0x18];     // 0x08
+	StateStruct m_unk0x20[3];      // 0x20
+	StateStruct m_unk0x44[3];      // 0x44
+	StateStruct m_unk0x68;         // 0x68
 	MxU32 m_unk0x74;               // 0x74
 	MxStillPresenter* m_buffer[7]; // 0x78
 };
diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h
index 5c631c6f..1af22e55 100644
--- a/LEGO1/lego/legoomni/include/legogamestate.h
+++ b/LEGO1/lego/legoomni/include/legogamestate.h
@@ -39,6 +39,7 @@ public:
 	inline MxU32 GetUnknown10() { return m_unk0x10; }
 	inline MxS32 GetCurrentAct() { return m_currentAct; }
 	inline MxU32 GetCurrentArea() { return m_currentArea; }
+	inline MxU32 GetPreviousArea() { return m_previousArea; }
 
 	inline void SetDirty(MxBool p_dirty) { m_isDirty = p_dirty; }
 	inline void SetCurrentArea(MxU32 p_currentArea) { m_currentArea = p_currentArea; }
diff --git a/LEGO1/lego/legoomni/include/legostate.h b/LEGO1/lego/legoomni/include/legostate.h
index de66cdc6..fe10bbf7 100644
--- a/LEGO1/lego/legoomni/include/legostate.h
+++ b/LEGO1/lego/legoomni/include/legostate.h
@@ -51,7 +51,14 @@ public:
 		undefined2 m_unk0x06; // 0x06
 		MxU16 m_unk0x08;      // 0x08
 
-		StateStruct();
+		// FUNCTION: LEGO1 0x10017c00
+		StateStruct()
+		{
+			m_unk0x04 = 0;
+			m_unk0x00 = NULL;
+			m_unk0x06 = 0;
+			m_unk0x08 = 0;
+		}
 
 		MxU32 FUN_10014d00();
 		MxBool FUN_10014de0(MxU32 p_objectId);
diff --git a/LEGO1/lego/legoomni/include/radio.h b/LEGO1/lego/legoomni/include/radio.h
index 347a22d1..dd37ba44 100644
--- a/LEGO1/lego/legoomni/include/radio.h
+++ b/LEGO1/lego/legoomni/include/radio.h
@@ -29,20 +29,21 @@ public:
 	}
 
 	void Initialize(MxBool p_und);
+	void Play();
+	void Stop();
 
 	// SYNTHETIC: LEGO1 0x1002c970
 	// Radio::`scalar deleting destructor'
 
 private:
+	void CreateRadioState();
+
 	RadioState* m_state;               // 0x08
 	MxBool m_unk0x0c;                  // 0x0c
 	MxBool m_bgAudioPreviouslyEnabled; // 0x0d
 
-	void CreateRadioState();
-	void Play();
-	void Stop();
 	MxLong HandleEndAction(MxEndActionNotificationParam& p_param);
-	MxLong HandleNotification17(LegoControlManagerEvent& p_param);
+	MxLong HandleClick(LegoControlManagerEvent& p_param);
 };
 
 #endif // RADIO_H
diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp
index 789cf7c8..0a884a53 100644
--- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp
+++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp
@@ -428,20 +428,32 @@ void LegoGameState::SwitchArea(MxU32 p_area)
 
 	BackgroundAudioManager()->Stop();
 	AnimationManager()->FUN_1005ef10();
-	VideoManager()->SetUnk0x554(0);
+	VideoManager()->SetUnk0x554(FALSE);
 
 	MxAtomId* script = g_isleScript;
 	switch (p_area) {
 	case 1:
 		break;
 	case 2:
-		VideoManager()->SetUnk0x554(1);
+		VideoManager()->SetUnk0x554(TRUE);
 		script = g_infomainScript;
 		break;
 	case 3:
-		VideoManager()->SetUnk0x554(1);
+		VideoManager()->SetUnk0x554(TRUE);
 		script = g_infodoorScript;
 		break;
+		// TODO
+	case 5:
+		script = g_elevbottScript;
+		break;
+	case 12:
+		VideoManager()->SetUnk0x554(TRUE);
+		script = g_regbookScript;
+		break;
+	case 13:
+		VideoManager()->SetUnk0x554(TRUE);
+		script = g_infoscorScript;
+		break;
 
 		// TODO: implement other cases
 	}
diff --git a/LEGO1/lego/legoomni/src/common/legostate.cpp b/LEGO1/lego/legoomni/src/common/legostate.cpp
index 5d3bcf4e..96a08dbe 100644
--- a/LEGO1/lego/legoomni/src/common/legostate.cpp
+++ b/LEGO1/lego/legoomni/src/common/legostate.cpp
@@ -16,12 +16,3 @@ MxBool LegoState::StateStruct::FUN_10014de0(MxU32 p_objectId)
 	// TODO
 	return FALSE;
 }
-
-// FUNCTION: LEGO1 0x10017c00
-LegoState::StateStruct::StateStruct()
-{
-	m_unk0x04 = 0;
-	m_unk0x00 = 0;
-	m_unk0x06 = 0;
-	m_unk0x08 = 0;
-}
diff --git a/LEGO1/lego/legoomni/src/control/mxcontrolpresenter.cpp b/LEGO1/lego/legoomni/src/control/mxcontrolpresenter.cpp
index ae0288f7..39fb5eee 100644
--- a/LEGO1/lego/legoomni/src/control/mxcontrolpresenter.cpp
+++ b/LEGO1/lego/legoomni/src/control/mxcontrolpresenter.cpp
@@ -108,13 +108,13 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxVideoPresenter*
 	if (m_unk0x4c == 3) {
 		MxVideoPresenter* frontPresenter = (MxVideoPresenter*) m_list.front();
 
-		if (p_presenter == frontPresenter || frontPresenter->GetDisplayZ() < frontPresenter->GetDisplayZ()) {
+		if (p_presenter == frontPresenter || frontPresenter->GetDisplayZ() < p_presenter->GetDisplayZ()) {
 			if (p_presenter->VTable0x7c()) {
 				MxS32 height = frontPresenter->GetHeight();
 				MxS32 width = frontPresenter->GetWidth();
 
 				if (frontPresenter->GetLocation().GetX() <= p_x &&
-					p_x < width - 1 + frontPresenter->GetLocation().GetY() &&
+					p_x < width - 1 + frontPresenter->GetLocation().GetX() &&
 					frontPresenter->GetLocation().GetY() <= p_y &&
 					p_y < height - 1 + frontPresenter->GetLocation().GetY()) {
 					MxU8* start;
@@ -198,7 +198,7 @@ MxBool MxControlPresenter::FUN_10044480(LegoControlManagerEvent* p_event, MxPres
 				p_event->SetClickedObjectId(m_action->GetObjectId());
 				p_event->SetClickedAtom(m_action->GetAtomId().GetInternal());
 				VTable0x6c(0);
-				p_event->SetType(c_notificationType17);
+				p_event->SetType(c_notificationClick);
 				p_event->SetUnknown0x28(m_unk0x4e);
 				return TRUE;
 			}
@@ -208,7 +208,7 @@ MxBool MxControlPresenter::FUN_10044480(LegoControlManagerEvent* p_event, MxPres
 				p_event->SetClickedObjectId(m_action->GetObjectId());
 				p_event->SetClickedAtom(m_action->GetAtomId().GetInternal());
 				VTable0x6c(m_unk0x56);
-				p_event->SetType(c_notificationType17);
+				p_event->SetType(c_notificationClick);
 				p_event->SetUnknown0x28(m_unk0x4e);
 				return TRUE;
 			}
diff --git a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp
index 84bbb4c6..08f2cf50 100644
--- a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp
+++ b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp
@@ -1,5 +1,6 @@
 #include "elevatorbottom.h"
 
+#include "act1state.h"
 #include "jukebox.h"
 #include "legocontrolmanager.h"
 #include "legogamestate.h"
@@ -7,9 +8,14 @@
 #include "legoomni.h"
 #include "mxnotificationmanager.h"
 #include "mxomni.h"
+#include "mxtransitionmanager.h"
 
 DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc)
 
+// STRING: LEGO1 0x100f0d34
+// GLOBAL: LEGO1 0x100f3a44
+char* g_cameraLoc = "CAMERA_LOCATION";
+
 // FUNCTION: LEGO1 0x10017e90
 ElevatorBottom::ElevatorBottom()
 {
@@ -52,8 +58,8 @@ MxLong ElevatorBottom::Notify(MxParam& p_param)
 
 	if (m_worldStarted) {
 		switch (((MxNotificationParam&) p_param).GetType()) {
-		case c_notificationType17:
-			ret = HandleNotification17(p_param);
+		case c_notificationClick:
+			ret = HandleClick((LegoControlManagerEvent&) p_param);
 			break;
 		case c_notificationTransitioned:
 			GameState()->SwitchArea(m_unk0xf8);
@@ -72,10 +78,41 @@ void ElevatorBottom::ReadyWorld()
 	FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
 }
 
-// STUB: LEGO1 0x100181d0
-MxLong ElevatorBottom::HandleNotification17(MxParam& p_param)
+// FUNCTION: LEGO1 0x100181d0
+MxLong ElevatorBottom::HandleClick(LegoControlManagerEvent& p_param)
 {
-	return 0;
+	MxLong result = 0;
+
+	if (p_param.GetUnknown0x28() == 1) {
+		switch (p_param.GetClickedObjectId()) {
+		case 1:
+			m_unk0xf8 = 3;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		case 2:
+			m_unk0xf8 = 2;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		case 3:
+			LegoGameState* gs = GameState();
+			Act1State* state = (Act1State*) gs->GetState("Act1State");
+
+			if (state == NULL) {
+				state = (Act1State*) gs->CreateState("Act1State");
+			}
+
+			state->SetUnknown1c(1);
+			m_unk0xf8 = 6;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			VariableTable()->SetVariable(g_cameraLoc, "LCAMZI1,90");
+			result = 1;
+			break;
+		}
+	}
+
+	return result;
 }
 
 // FUNCTION: LEGO1 0x100182c0
diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp
index 3dca5c64..2a98f5af 100644
--- a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp
+++ b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp
@@ -32,7 +32,7 @@ Infocenter::Infocenter()
 	m_infocenterState = NULL;
 	m_frameHotBitmap = 0;
 	m_unk0x11c = 0;
-	m_unk0x104 = 0;
+	m_transitionDestination = 0;
 	m_currentInfomainScript = c_noInfomain;
 	m_currentCutscene = e_noIntro;
 
@@ -126,8 +126,8 @@ MxLong Infocenter::Notify(MxParam& p_param)
 				((LegoEventNotificationParam&) p_param).GetY()
 			);
 			break;
-		case c_notificationType17:
-			result = HandleNotification17(p_param);
+		case c_notificationClick:
+			result = HandleClick((LegoControlManagerEvent&) p_param);
 			break;
 		case c_notificationTransitioned:
 			StopBookAnimation();
@@ -137,10 +137,10 @@ MxLong Infocenter::Notify(MxParam& p_param)
 				StartCredits();
 				m_infocenterState->SetUnknown0x74(0xd);
 			}
-			else if (m_unk0x104 != 0) {
+			else if (m_transitionDestination != 0) {
 				BackgroundAudioManager()->RaiseVolume();
-				GameState()->SwitchArea(m_unk0x104);
-				m_unk0x104 = 0;
+				GameState()->SwitchArea(m_transitionDestination);
+				m_transitionDestination = 0;
 			}
 			break;
 		}
@@ -189,7 +189,7 @@ MxLong Infocenter::HandleEndAction(MxParam& p_param)
 				break;
 			}
 
-			FUN_10070dc0(TRUE);
+			UpdateFrameHot(TRUE);
 		}
 	}
 
@@ -383,63 +383,82 @@ void Infocenter::InitializeBitmaps()
 	((MxPresenter*) Find(m_atom, c_radioCtl))->Enable(TRUE);
 
 	m_mapAreas[0].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Info_A_Bitmap");
-	m_mapAreas[0].m_unk0x08 = 391;
-	m_mapAreas[0].m_unk0x0c = 182;
-	m_mapAreas[0].m_unk0x10 = 427;
-	m_mapAreas[0].m_unk0x14 = 230;
+	m_mapAreas[0].m_area.SetLeft(391);
+	m_mapAreas[0].m_area.SetTop(182);
+	m_mapAreas[0].m_area.SetRight(427);
+	m_mapAreas[0].m_area.SetBottom(230);
 	m_mapAreas[0].m_unk0x04 = 3;
 
 	m_mapAreas[1].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Boat_A_Bitmap");
-	m_mapAreas[1].m_unk0x08 = 304;
-	m_mapAreas[1].m_unk0x0c = 225;
-	m_mapAreas[1].m_unk0x10 = 350;
-	m_mapAreas[1].m_unk0x14 = 268;
+	m_mapAreas[1].m_area.SetLeft(304);
+	m_mapAreas[1].m_area.SetTop(225);
+	m_mapAreas[1].m_area.SetRight(350);
+	m_mapAreas[1].m_area.SetBottom(268);
 	m_mapAreas[1].m_unk0x04 = 10;
 
 	m_mapAreas[2].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Race_A_Bitmap");
-	m_mapAreas[2].m_unk0x08 = 301;
-	m_mapAreas[2].m_unk0x0c = 133;
-	m_mapAreas[2].m_unk0x10 = 347;
-	m_mapAreas[2].m_unk0x14 = 181;
+	m_mapAreas[2].m_area.SetLeft(301);
+	m_mapAreas[2].m_area.SetTop(133);
+	m_mapAreas[2].m_area.SetRight(347);
+	m_mapAreas[2].m_area.SetBottom(181);
 	m_mapAreas[2].m_unk0x04 = 11;
 
 	m_mapAreas[3].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Pizza_A_Bitmap");
-	m_mapAreas[3].m_unk0x08 = 289;
-	m_mapAreas[3].m_unk0x0c = 182;
-	m_mapAreas[3].m_unk0x10 = 335;
-	m_mapAreas[3].m_unk0x14 = 225;
+	m_mapAreas[3].m_area.SetLeft(289);
+	m_mapAreas[3].m_area.SetTop(182);
+	m_mapAreas[3].m_area.SetRight(335);
+	m_mapAreas[3].m_area.SetBottom(225);
 	m_mapAreas[3].m_unk0x04 = 12;
 
 	m_mapAreas[4].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Gas_A_Bitmap");
-	m_mapAreas[4].m_unk0x10 = 391;
-	m_mapAreas[4].m_unk0x08 = 350;
-	m_mapAreas[4].m_unk0x0c = 161;
-	m_mapAreas[4].m_unk0x14 = 209;
+	m_mapAreas[4].m_area.SetLeft(350);
+	m_mapAreas[4].m_area.SetTop(161);
+	m_mapAreas[4].m_area.SetRight(391);
+	m_mapAreas[4].m_area.SetBottom(209);
 	m_mapAreas[4].m_unk0x04 = 13;
 
 	m_mapAreas[5].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Med_A_Bitmap");
-	m_mapAreas[5].m_unk0x08 = 392;
-	m_mapAreas[5].m_unk0x0c = 130;
-	m_mapAreas[5].m_unk0x10 = 438;
-	m_mapAreas[5].m_unk0x14 = 176;
+	m_mapAreas[5].m_area.SetLeft(392);
+	m_mapAreas[5].m_area.SetTop(130);
+	m_mapAreas[5].m_area.SetRight(438);
+	m_mapAreas[5].m_area.SetBottom(176);
 	m_mapAreas[5].m_unk0x04 = 14;
 
 	m_mapAreas[6].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Cop_A_Bitmap");
-	m_mapAreas[6].m_unk0x08 = 396;
-	m_mapAreas[6].m_unk0x0c = 229;
-	m_mapAreas[6].m_unk0x10 = 442;
-	m_mapAreas[6].m_unk0x14 = 272;
+	m_mapAreas[6].m_area.SetLeft(396);
+	m_mapAreas[6].m_area.SetTop(229);
+	m_mapAreas[6].m_area.SetRight(442);
+	m_mapAreas[6].m_area.SetBottom(272);
 	m_mapAreas[6].m_unk0x04 = 15;
 
 	m_frameHotBitmap = (MxStillPresenter*) Find("MxStillPresenter", "FrameHot_Bitmap");
 
-	FUN_10070dc0(TRUE);
+	UpdateFrameHot(TRUE);
 }
 
-// STUB: LEGO1 0x1006fd00
+// FUNCTION: LEGO1 0x1006fd00
 MxU8 Infocenter::HandleMouseMove(MxS32 p_x, MxS32 p_y)
 {
-	return 1;
+	if (m_unk0x11c) {
+		if (!m_unk0x11c->IsEnabled()) {
+			MxS32 oldDisplayZ = m_unk0x11c->GetDisplayZ();
+
+			m_unk0x11c->SetDisplayZ(1000);
+			VideoManager()->SortPresenterList();
+			m_unk0x11c->Enable(TRUE);
+			m_unk0x11c->VTable0x88(p_x, p_y);
+
+			m_unk0x11c->SetDisplayZ(oldDisplayZ);
+		}
+		else {
+			m_unk0x11c->VTable0x88(p_x, p_y);
+		}
+
+		FUN_10070d10(p_x, p_y);
+		return 1;
+	}
+
+	return 0;
 }
 
 // FUNCTION: LEGO1 0x1006fda0
@@ -492,12 +511,129 @@ MxLong Infocenter::HandleKeyPress(MxS8 p_key)
 // STUB: LEGO1 0x1006feb0
 MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y)
 {
-	return 1;
+	return FALSE;
 }
 
-// STUB: LEGO1 0x10070370
-MxU8 Infocenter::HandleNotification17(MxParam&)
+// FUNCTION: LEGO1 0x10070370
+MxU8 Infocenter::HandleClick(LegoControlManagerEvent& p_param)
 {
+	if (p_param.GetUnknown0x28() == 1) {
+		m_infoManDialogueTimer = 0;
+
+		InfomainScript actionToPlay = c_noInfomain;
+		StopCurrentAction();
+		InfomainScript characterBitmap = c_noInfomain;
+
+		GameState();
+
+		switch (p_param.GetClickedObjectId()) {
+		case c_leftArrowCtl:
+			m_infocenterState->SetUnknown0x74(14);
+			StopCurrentAction();
+
+			if (GameState()->GetUnknown10() == 0) {
+				m_radio.Stop();
+				TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+				m_transitionDestination = 5;
+			}
+			else {
+				MxU32 objectId = m_infocenterState->GetUnknown0x68().FUN_10014d00();
+				PlayAction((InfomainScript) objectId);
+			}
+
+			break;
+		case c_rightArrowCtl:
+			m_infocenterState->SetUnknown0x74(14);
+			StopCurrentAction();
+
+			if (GameState()->GetUnknown10() == 0) {
+				m_radio.Stop();
+				TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+				m_transitionDestination = 13;
+			}
+			else {
+				MxU32 objectId = m_infocenterState->GetUnknown0x68().FUN_10014d00();
+				PlayAction((InfomainScript) objectId);
+			}
+
+			break;
+		case c_infoCtl:
+			m_radio.Stop();
+			break;
+		case c_doorCtl:
+			if (m_infocenterState->GetUnknown0x74() != 8) {
+				actionToPlay = c_exitConfirmationDialogue;
+				m_radio.Stop();
+				m_infocenterState->SetUnknown0x74(8);
+			}
+
+			break;
+		case c_boatCtl:
+			actionToPlay = c_boatCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_raceCtl:
+			actionToPlay = c_raceCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_pizzaCtl:
+			actionToPlay = c_pizzaCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_gasCtl:
+			actionToPlay = c_gasCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_medCtl:
+			actionToPlay = c_medCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_copCtlDescription:
+			actionToPlay = c_copCtlDescription;
+			m_radio.Stop();
+			break;
+		case c_bigInfoCtl:
+			// TODO
+			break;
+		case c_bookCtl:
+			m_transitionDestination = 12;
+			m_infocenterState->SetUnknown0x74(4);
+			actionToPlay = GameState()->GetUnknown10() ? c_goToRegBookRed : c_goToRegBook;
+			m_radio.Stop();
+			GameState()->SetCurrentArea(GameState()->GetPreviousArea());
+			InputManager()->DisableInputProcessing();
+			break;
+		case c_mamaCtl:
+			characterBitmap = c_mamaSelected;
+			UpdateFrameHot(FALSE);
+			break;
+		case c_papaCtl:
+			characterBitmap = c_papaSelected;
+			UpdateFrameHot(FALSE);
+			break;
+		case c_pepperCtl:
+			characterBitmap = c_pepperSelected;
+			UpdateFrameHot(FALSE);
+			break;
+		case c_nickCtl:
+			characterBitmap = c_nickSelected;
+			UpdateFrameHot(FALSE);
+			break;
+		case c_lauraCtl:
+			characterBitmap = c_lauraCtl;
+			UpdateFrameHot(FALSE);
+			break;
+		}
+
+		if (actionToPlay != c_noInfomain) {
+			PlayAction(actionToPlay);
+		}
+
+		if (characterBitmap != c_noInfomain) {
+			m_unk0x11c = (MxStillPresenter*) Find(m_atom, characterBitmap);
+		}
+	}
+
 	return 1;
 }
 
@@ -601,9 +737,81 @@ MxBool Infocenter::VTable0x5c()
 	return TRUE;
 }
 
-// STUB: LEGO1 0x10070dc0
-void Infocenter::FUN_10070dc0(MxBool)
+// FUNCTION: LEGO1 0x10070d10
+void Infocenter::FUN_10070d10(MxS32 p_x, MxS32 p_y)
 {
+	MxS16 i;
+	for (i = 0; i < (MxS32) (sizeof(m_mapAreas) / sizeof(m_mapAreas[0])); i++) {
+		MxS32 right = m_mapAreas[i].m_area.GetRight();
+		MxS32 bottom = m_mapAreas[i].m_area.GetBottom();
+		MxS32 left = m_mapAreas[i].m_area.GetLeft();
+		MxS32 top = m_mapAreas[i].m_area.GetTop();
+
+		if (left <= p_x && p_x <= right && top <= p_y && p_y <= bottom)
+			break;
+	}
+
+	if (i == 7) {
+		i = -1;
+	}
+
+	if (i != m_unk0x1c8) {
+		if (m_unk0x1c8 != -1) {
+			m_mapAreas[i].m_presenter->Enable(FALSE);
+		}
+
+		m_unk0x1c8 = i;
+		if (i != -1) {
+			m_mapAreas[i].m_presenter->Enable(TRUE);
+		}
+	}
+}
+
+// FUNCTION: LEGO1 0x10070dc0
+void Infocenter::UpdateFrameHot(MxBool p_display)
+{
+	if (p_display) {
+		MxS32 x, y;
+
+		switch (GameState()->GetUnknownC()) {
+		case 1:
+			x = 302;
+			y = 81;
+			break;
+		case 2:
+			x = 204;
+			y = 81;
+			break;
+		case 3:
+			x = 253;
+			y = 81;
+			break;
+		case 4:
+			x = 353;
+			y = 81;
+			break;
+		case 5:
+			x = 399;
+			y = 81;
+			break;
+		default:
+			return;
+		}
+
+		MxS32 originalDisplayZ = m_frameHotBitmap->GetDisplayZ();
+
+		m_frameHotBitmap->SetDisplayZ(1000);
+		VideoManager()->SortPresenterList();
+
+		m_frameHotBitmap->Enable(TRUE);
+		m_frameHotBitmap->VTable0x88(x, y);
+		m_frameHotBitmap->SetDisplayZ(originalDisplayZ);
+	}
+	else {
+		if (m_frameHotBitmap) {
+			m_frameHotBitmap->Enable(FALSE);
+		}
+	}
 }
 
 // STUB: LEGO1 0x10070e90
@@ -611,9 +819,33 @@ void Infocenter::FUN_10070e90()
 {
 }
 
-// STUB: LEGO1 0x10070f60
+// FUNCTION: LEGO1 0x10070f60
 MxBool Infocenter::VTable0x64()
 {
+	if (m_infocenterState != NULL) {
+		MxU32 val = m_infocenterState->GetUnknown0x74();
+
+		if (val == 0) {
+			StopCutscene();
+			m_infocenterState->SetUnknown0x74(1);
+		}
+		else if (val == 13) {
+			StopCredits();
+		}
+		else if (val != 8) {
+			m_infocenterState->SetUnknown0x74(8);
+
+#ifdef COMPAT_MODE
+			{
+				MxNotificationParam param(c_notificationType0, NULL);
+				Notify(param);
+			}
+#else
+			Notify(MxNotificationParam(c_notificationType0, NULL));
+#endif
+		}
+	}
+
 	return FALSE;
 }
 
diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp
index 4ed626ff..47ab29ac 100644
--- a/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp
+++ b/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp
@@ -1,11 +1,15 @@
 #include "infocenterdoor.h"
 
+#include "infocenterstate.h"
 #include "jukebox.h"
 #include "legocontrolmanager.h"
 #include "legogamestate.h"
 #include "legoinputmanager.h"
 #include "legoomni.h"
+#include "mxactionnotificationparam.h"
+#include "mxbackgroundaudiomanager.h"
 #include "mxnotificationmanager.h"
+#include "mxtransitionmanager.h"
 
 DECOMP_SIZE_ASSERT(InfocenterDoor, 0xfc)
 
@@ -45,11 +49,31 @@ MxResult InfocenterDoor::Create(MxDSAction& p_dsAction)
 	return result;
 }
 
-// STUB: LEGO1 0x100379e0
+// FUNCTION: LEGO1 0x100379e0
 MxLong InfocenterDoor::Notify(MxParam& p_param)
 {
-	// TODO
-	return LegoWorld::Notify(p_param);
+	MxLong result = 0;
+	LegoWorld::Notify(p_param);
+
+	if (m_worldStarted) {
+		switch (((MxNotificationParam&) p_param).GetType()) {
+		case c_notificationEndAction:
+			if (((MxEndActionNotificationParam&) p_param).GetAction()->GetAtomId() == m_atom) {
+				BackgroundAudioManager()->RaiseVolume();
+				result = 1;
+			}
+			break;
+		case c_notificationClick:
+			result = HandleClick((LegoControlManagerEvent&) p_param);
+			break;
+		case c_notificationTransitioned:
+			GameState()->SwitchArea(m_unk0xf8);
+			result = 1;
+			break;
+		}
+	}
+
+	return result;
 }
 
 // FUNCTION: LEGO1 0x10037a70
@@ -60,6 +84,61 @@ void InfocenterDoor::ReadyWorld()
 	FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
 }
 
+// FUNCTION: LEGO1 0x10037a90
+MxLong InfocenterDoor::HandleClick(LegoControlManagerEvent& p_param)
+{
+	MxLong result = 0;
+
+	if (p_param.GetUnknown0x28() == 1) {
+		DeleteObjects(&m_atom, 500, 510);
+
+		switch (p_param.GetClickedObjectId()) {
+		case 1:
+			m_unk0xf8 = 13;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		case 2:
+			m_unk0xf8 = 5;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		case 3:
+			m_unk0xf8 = 2;
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		case 4:
+			if (GameState()->GetUnknownC()) {
+				InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState");
+				if (state->GetInfocenterBufferElement(0) != NULL) {
+					m_unk0xf8 = 4;
+				}
+				else {
+					MxDSAction action;
+					action.SetObjectId(503);
+					action.SetAtomId(*g_infodoorScript);
+					BackgroundAudioManager()->LowerVolume();
+					Start(&action);
+				}
+			}
+			else {
+				MxDSAction action;
+				action.SetObjectId(500);
+				action.SetAtomId(*g_infodoorScript);
+				BackgroundAudioManager()->LowerVolume();
+				Start(&action);
+			}
+
+			TransitionManager()->StartTransition(MxTransitionManager::e_pixelation, 50, FALSE, FALSE);
+			result = 1;
+			break;
+		}
+	}
+
+	return result;
+}
+
 // FUNCTION: LEGO1 0x10037c80
 void InfocenterDoor::VTable0x68(MxBool p_add)
 {
diff --git a/LEGO1/lego/legoomni/src/infocenter/score.cpp b/LEGO1/lego/legoomni/src/infocenter/score.cpp
index f75e0418..ce378399 100644
--- a/LEGO1/lego/legoomni/src/infocenter/score.cpp
+++ b/LEGO1/lego/legoomni/src/infocenter/score.cpp
@@ -91,7 +91,7 @@ MxLong Score::Notify(MxParam& p_param)
 				DeleteScript(); // Shutting down
 			ret = 1;
 			break;
-		case c_notificationType17:
+		case c_notificationClick:
 			ret = FUN_100016d0((LegoControlManagerEvent&) p_param);
 			break;
 		case c_notificationTransitioned:
diff --git a/LEGO1/lego/legoomni/src/isle/isle.cpp b/LEGO1/lego/legoomni/src/isle/isle.cpp
index bb6d4fd8..c8c67570 100644
--- a/LEGO1/lego/legoomni/src/isle/isle.cpp
+++ b/LEGO1/lego/legoomni/src/isle/isle.cpp
@@ -115,7 +115,7 @@ MxLong Isle::Notify(MxParam& p_param)
 				break;
 			}
 			break;
-		case c_notificationType17:
+		case c_notificationClick:
 			result = HandleType17Notification(p_param);
 			break;
 		case c_notificationType18:
diff --git a/LEGO1/lego/legoomni/src/isle/radio.cpp b/LEGO1/lego/legoomni/src/isle/radio.cpp
index ad5d96b7..2f18ae59 100644
--- a/LEGO1/lego/legoomni/src/isle/radio.cpp
+++ b/LEGO1/lego/legoomni/src/isle/radio.cpp
@@ -41,8 +41,8 @@ MxLong Radio::Notify(MxParam& p_param)
 		case c_notificationEndAction:
 			result = HandleEndAction((MxEndActionNotificationParam&) p_param);
 			break;
-		case c_notificationType17:
-			result = HandleNotification17((LegoControlManagerEvent&) p_param);
+		case c_notificationClick:
+			result = HandleClick((LegoControlManagerEvent&) p_param);
 			break;
 		}
 	}
@@ -89,7 +89,7 @@ void Radio::Stop()
 }
 
 // FUNCTION: LEGO1 0x1002cbc0
-MxLong Radio::HandleNotification17(LegoControlManagerEvent& p_param)
+MxLong Radio::HandleClick(LegoControlManagerEvent& p_param)
 {
 	MxDSAction action; // Unused
 	MxS32 objectId = p_param.GetClickedObjectId();
diff --git a/LEGO1/omni/include/mxnotificationparam.h b/LEGO1/omni/include/mxnotificationparam.h
index 9fe01c18..d0ad675f 100644
--- a/LEGO1/omni/include/mxnotificationparam.h
+++ b/LEGO1/omni/include/mxnotificationparam.h
@@ -23,7 +23,7 @@ enum NotificationId {
 	c_notificationDragStart = 13,
 	c_notificationDrag = 14,
 	c_notificationTimer = 15, // 100d6aa0
-	c_notificationType17 = 17,
+	c_notificationClick = 17,
 	c_notificationType18 = 18, // 100d7e80
 	c_notificationType19 = 19, // 100d6230
 	c_notificationType20 = 20,
diff --git a/LEGO1/omni/include/mxpresenter.h b/LEGO1/omni/include/mxpresenter.h
index 3d9dd355..6198cd09 100644
--- a/LEGO1/omni/include/mxpresenter.h
+++ b/LEGO1/omni/include/mxpresenter.h
@@ -121,6 +121,8 @@ public:
 		m_compositePresenter = p_compositePresenter;
 	}
 
+	inline void SetDisplayZ(MxS32 p_displayZ) { m_displayZ = p_displayZ; }
+
 	// SYNTHETIC: LEGO1 0x1000c070
 	// MxPresenter::`scalar deleting destructor'
 
diff --git a/LEGO1/omni/include/mxrect32.h b/LEGO1/omni/include/mxrect32.h
index 20e1706e..207d93fa 100644
--- a/LEGO1/omni/include/mxrect32.h
+++ b/LEGO1/omni/include/mxrect32.h
@@ -65,6 +65,7 @@ public:
 	}
 
 	inline MxBool IsValid() const { return m_left < m_right && m_top < m_bottom; }
+
 	inline MxBool IntersectsWith(const MxRect32& p_rect) const
 	{
 		return m_left < p_rect.m_right && p_rect.m_left < m_right && m_top < p_rect.m_bottom && p_rect.m_top < m_bottom;