changeset 223:1bd823f52e3a

Merge
author Gloval
date Sun, 17 Feb 2013 11:41:44 +0400
parents 8113753ed2ae (current diff) 335db7429f7c (diff)
children 9917d3b4925e
files Items.cpp Items.h Player.cpp mm7_1.cpp mm7_5.cpp mm7_6.cpp stru157.h
diffstat 24 files changed, 1347 insertions(+), 1493 deletions(-) [+]
line wrap: on
line diff
--- a/Actor.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Actor.h	Sun Feb 17 11:41:44 2013 +0400
@@ -51,7 +51,7 @@
 /*  295 */
 enum ObjectType
 {
-  OBJECT_unk0 = 0x0,
+  OBJECT_Any = 0x0,
   OBJECT_BLVDoor = 0x1,
   OBJECT_Item = 0x2,
   OBJECT_Actor = 0x3,
--- a/GUIFont.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/GUIFont.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -1,4 +1,6 @@
 #include <string>
+#include <assert.h>
+
 #include "LOD.h"
 #include "GUIFont.h"
 #include "GUIWindow.h"
@@ -23,11 +25,11 @@
 
 char temp_string[2048];
 
-char pTmpBuf3[2048];
+char pTmpBuf3[10000];
 
 //----- (0044C448) --------------------------------------------------------
 GUIFont *LoadFont(const char *pFontFile, const char *pFontPalette, ...)
-	{
+{
 	
 	int pallete_index; // eax@3
 	GUIFont *pFont;
@@ -348,6 +350,8 @@
   v8 = strlen(pString);
   v9 = v8;
   v39 = v8;
+
+  assert(strlen(v6) < sizeof(pTmpBuf3));
   strcpy(pTmpBuf3, v6);
   v10 = a5;
   v11 = v35;
--- a/GUIWindow.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/GUIWindow.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -962,66 +962,64 @@
 
 
 //----- (00411621) --------------------------------------------------------
-GUIButton *GUIWindow::OpenSpellBook()
+void GUIWindow::OpenSpellBook()
 {
   Player *pPlayer; // edi@1
-  GUIWindow *pWindow; // esi@1
-  unsigned int v3; // ebp@1
+  //GUIWindow *pWindow; // esi@1
+  //unsigned int v3; // ebp@1
   int v4; // eax@3
-  GUIButton *result; // eax@25
+  ///GUIButton *result; // eax@25
   int a2; // [sp+10h] [bp-8h]@1
-  int v7; // [sp+14h] [bp-4h]@1
-
-  //__debugbreak();
+  //int v7; // [sp+14h] [bp-4h]@1
 
   pPlayer = pPlayers[uActiveCharacter];
-  pWindow = this;
-  LoadSpellbook(pPlayer->pNumSpellBookPage);
-  v3 = 0;
+  //pWindow = this;
+  LoadSpellbook(pPlayer->lastOpenedSpellbookPage);
+  //v3 = 0;
   a2 = 0;
-  v7 = (int)&pPlayer->spellbook.pChapters[pPlayer->pNumSpellBookPage];
-  do
+
+  auto chapter = &pPlayer->spellbook.pChapters[pPlayer->lastOpenedSpellbookPage];
+  for (uint i = 0; i < 11; ++i)
   {
-    if ( *(char *)(v7 + v3) )
-    {
-      v4 = 2 * (12 * pPlayer->pNumSpellBookPage + (unsigned __int8)*(&byte_4E2431[12 * pPlayer->pNumSpellBookPage] + v3));
-      pWindow->CreateButton(pViewport->uViewportX + dword_4E20D0[v4],
-        pViewport->uViewportY + dword_4E20D0[v4 + 1],
-        dword_506408[v3 + 1]->uTextureWidth,
-        dword_506408[v3 + 1]->uTextureHeight,
-        1, 79, 0x56u, v3, 0, "", 0);
+    if (!chapter->bIsSpellAvailable[i])
+      continue;
+
+      v4 = 2 * (12 * pPlayer->lastOpenedSpellbookPage + pSpellbookSpellIndices[pPlayer->lastOpenedSpellbookPage][i + 1]);
+      CreateButton(pViewport->uViewportX + dword_4E20D0[v4],
+                   pViewport->uViewportY + dword_4E20D0[v4 + 1],
+                   dword_506408[i + 1]->uTextureWidth,
+                   dword_506408[i + 1]->uTextureHeight,
+                   1, 79, 0x56u, i, 0, "", 0);
       ++a2;
-    }
-    ++v3;
+    //++v3;
   }
-  while ( (signed int)v3 < 11 );
-  pWindow->CreateButton(0, 0, 0, 0, 1, 0, 0x33u, 0, 9u, "", 0);
+  //while ( (signed int)v3 < 11 );
+
+  CreateButton(0, 0, 0, 0, 1, 0, 0x33u, 0, 9u, "", 0);
   if ( a2 )
-    pWindow->_41D08F(a2, 0, 0, 0);
-  if ( pPlayer->pActiveSkills[12] )
-    pWindow->CreateButton(0x18Fu, 0xAu, 0x32u, 0x24u, 1, 0, 0x57u, 0, 0, aSpellSchoolNames[0], 0);
-  if ( pPlayer->pActiveSkills[13] )
-    pWindow->CreateButton(0x18Fu, 0x2Eu, 0x32u, 0x24u, 1, 0, 0x57u, 1u, 0, aSpellSchoolNames[1], 0);
-  if ( pPlayer->pActiveSkills[14] )
-    pWindow->CreateButton(0x18Fu, 0x53u, 0x32u, 0x24u, 1, 0, 0x57u, 2u, 0, aSpellSchoolNames[2], 0);
-  if ( pPlayer->pActiveSkills[15] )
-    pWindow->CreateButton(0x18Fu, 0x79u, 0x32u, 0x24u, 1, 0, 0x57u, 3u, 0, aSpellSchoolNames[3], 0);
-  if ( pPlayer->pActiveSkills[16] )
-    pWindow->CreateButton(0x18Fu, 0x9Eu, 0x32u, 0x24u, 1, 0, 0x57u, 4u, 0, aSpellSchoolNames[4], 0);
-  if ( pPlayer->pActiveSkills[17] )
-    pWindow->CreateButton(0x190u, 0xC4u, 0x32u, 0x24u, 1, 0, 0x57u, 5u, 0, aSpellSchoolNames[5], 0);
-  if ( pPlayer->pActiveSkills[18] )
-    pWindow->CreateButton(0x190u, 0xEAu, 0x32u, 0x24u, 1, 0, 0x57u, 6u, 0, aSpellSchoolNames[6], 0);
-  if ( pPlayer->pActiveSkills[19] )
-    pWindow->CreateButton(0x190u, 0x10Fu, 0x32u, 0x24u, 1, 0, 0x57u, 7u, 0, aSpellSchoolNames[7], 0);
-  if ( pPlayer->pActiveSkills[20] )
-    pWindow->CreateButton(0x190u, 0x133u, 0x32u, 0x24u, 1, 0, 0x57u, 8u, 0, aSpellSchoolNames[8], 0);
-  pWindow->CreateButton(0x1DCu, 0x1C2u, pTexture_506444->uTextureWidth, pTexture_506444->uTextureHeight, 1, 78, 0x58u, 0, 0, "", 0);
-  pBtn_InstallRemoveSpell = pWindow->CreateButton(0x1DCu, 0x1C2u, 0x30u, 0x20u, 1, 78, 0x58u, 0, 0, "", pTexture_506444, 0);
-  pWindow->CreateButton(0x231u, 0x1C2u, ptr_506440->uTextureWidth, ptr_506440->uTextureHeight, 1, 0, 0x71u, 0, 0, pGlobalTXT_LocalizationStrings[79], 0);
-  pBtn_CloseBook = pWindow->CreateButton(0x231u, 0x1C2u, 0x30u, 0x20u, 1, 0, 0x71u, 0, 0, pGlobalTXT_LocalizationStrings[79], ptr_506440, 0);
-  result = pBtn_CloseBook;
-  return result;
+    _41D08F(a2, 0, 0, 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_FIRE])
+    CreateButton(0x18Fu, 0xAu, 0x32u, 0x24u, 1, 0, 0x57u, 0, 0, aSpellSchoolNames[0], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_AIR])
+    CreateButton(0x18Fu, 0x2Eu, 0x32u, 0x24u, 1, 0, 0x57u, 1u, 0, aSpellSchoolNames[1], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_WATER])
+    CreateButton(0x18Fu, 0x53u, 0x32u, 0x24u, 1, 0, 0x57u, 2u, 0, aSpellSchoolNames[2], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_EARTH])
+    CreateButton(0x18Fu, 0x79u, 0x32u, 0x24u, 1, 0, 0x57u, 3u, 0, aSpellSchoolNames[3], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_SPIRIT])
+    CreateButton(0x18Fu, 0x9Eu, 0x32u, 0x24u, 1, 0, 0x57u, 4u, 0, aSpellSchoolNames[4], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_MIND])
+    CreateButton(0x190u, 0xC4u, 0x32u, 0x24u, 1, 0, 0x57u, 5u, 0, aSpellSchoolNames[5], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_BODY])
+    CreateButton(0x190u, 0xEAu, 0x32u, 0x24u, 1, 0, 0x57u, 6u, 0, aSpellSchoolNames[6], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_LIGHT])
+    CreateButton(0x190u, 0x10Fu, 0x32u, 0x24u, 1, 0, 0x57u, 7u, 0, aSpellSchoolNames[7], 0);
+  if (pPlayer->pActiveSkills[PLAYER_SKILL_DARK])
+    CreateButton(0x190u, 0x133u, 0x32u, 0x24u, 1, 0, 0x57u, 8u, 0, aSpellSchoolNames[8], 0);
+  CreateButton(0x1DCu, 0x1C2u, pTexture_506444->uTextureWidth, pTexture_506444->uTextureHeight, 1, 78, 0x58u, 0, 0, "", 0);
+  pBtn_InstallRemoveSpell = CreateButton(0x1DCu, 0x1C2u, 0x30u, 0x20u, 1, 78, 0x58u, 0, 0, "", pTexture_506444, 0);
+  CreateButton(0x231u, 0x1C2u, ptr_506440->uTextureWidth, ptr_506440->uTextureHeight, 1, 0, 0x71u, 0, 0, pGlobalTXT_LocalizationStrings[79], 0);
+  pBtn_CloseBook = CreateButton(0x231u, 0x1C2u, 0x30u, 0x20u, 1, 0, 0x71u, 0, 0, pGlobalTXT_LocalizationStrings[79], ptr_506440, 0);
 }
 // 50640C: using guessed type int dword_50640C[];
 
@@ -1798,7 +1796,6 @@
   int uWidtha; // [sp+14h] [bp+4h]@66
   int a4a; // [sp+20h] [bp+10h]@15
 
-  uNextFreeWindowID = 0;
   for (uNextFreeWindowID = 0; uNextFreeWindowID < 20; ++uNextFreeWindowID)
   {
     if (pWindowList[uNextFreeWindowID].eWindowType == WINDOW_null)
--- a/GUIWindow.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/GUIWindow.h	Sun Feb 17 11:41:44 2013 +0400
@@ -94,6 +94,12 @@
 #pragma pack(push, 1)
 struct GUIWindow
 {
+  inline GUIWindow()
+  {
+    pControlsHead = pControlsTail = nullptr;
+    eWindowType = WINDOW_null;
+  }
+
   GUIButton *CreateButton(unsigned int uX, unsigned int uY, unsigned int uWidth, unsigned int uHeight, int a6, int a7, 
 	         unsigned int uControlID, unsigned int uControlParam, unsigned __int8 uHotkey, const char *pName, Texture *pTextures, ...);
   void DrawFlashingInputCursor(signed int a3, int a4, struct GUIFont *a2);
@@ -103,7 +109,7 @@
 	            unsigned __int16 uDefaultColor, const char *pInString, unsigned int uLineSpacing);
   char *_4B1854(__int64 a2);
   void _4B3157();
-  GUIButton *OpenSpellBook();
+  void OpenSpellBook();
   void InitializeBookView();
   void DrawMessageBox(int arg0);
   GUIButton *GetControl(unsigned int uID);
@@ -222,8 +228,8 @@
   UIMSG_SetGraphicsMode = 0x83,
   UIMSG_Quit = 0x84,
   UIMSG_85 = 0x85,
-  UIMSG_86 = 0x86,
-  UIMSG_87 = 0x87,
+  UIMSG_StartHireling1Dialogue = 0x86,
+  UIMSG_StartHireling2Dialogue = 0x87,
   UIMSG_88 = 0x88,
   UIMSG_8C = 0x8C,
   UIMSG_8D = 0x8D,
@@ -292,7 +298,7 @@
   UIMSG_ToggleFlipOnExit = 0xE2,
   UIMSG_16F = 0x16F,
   UIMSG_170 = 0x170,
-  UIMSG_194 = 0x194,
+  UIMSG_Game_Action = 0x194,
   UIMSG_195 = 0x195,
   UIMSG_OpenRestUI = 0x199,
   UIMSG_19A = 0x19A,
--- a/Game.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/Game.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -16,12 +16,13 @@
 #include "GUIWindow.h"
 #include "Party.h"
 #include "TurnEngine.h"
-#include "stru157.h"
 #include "VideoPlayer.h"
 #include "Bink_Smacker.h"
 #include "Events.h"
 #include "Arcomage.h"
 #include "texts.h"
+#include "Actor.h"
+#include "Log.h"
 
 //#include "MM7.h"
 
@@ -583,69 +584,54 @@
 bool Game::_44EEA7()
 {
   //Game *v1; // esi@1
-  double v2; // st7@2
+  //double v2; // st7@2
   float depth; // ST00_4@9
-  bool result; // eax@9
+  //bool result; // eax@9
   unsigned int v5; // eax@14
   __int64 v6; // kr00_8@21
   unsigned int y; // [sp+4h] [bp-24h]@2
   unsigned int x; // [sp+8h] [bp-20h]@2
-  bool v9; // [sp+Ch] [bp-1Ch]@2
-  stru157 *v10; // [sp+10h] [bp-18h]@2
-  stru157 *v11; // [sp+14h] [bp-14h]@2
+  Vis_SelectionFilter *v10; // [sp+10h] [bp-18h]@2
+  Vis_SelectionFilter *v11; // [sp+14h] [bp-14h]@2
   POINT a2; // [sp+20h] [bp-8h]@1
 
   //v1 = this;
   ++qword_5C6DF0;
   pParticleEngine->UpdateParticles();
   pMouseInstance->GetCursorPos(&a2);
+
+  x = a2.y;
+  y = a2.x;
   if ( sub_4637E0_is_there_popup_onscreen() )
   {
-    v11 = &a5;
-    v10 = &stru_F93E30;
-    v9 = 0;
-    x = a2.y;
-    y = a2.x;
-    v2 = GetPickDepth();
+    v11 = &vis_face_filter;
+    v10 = &vis_sprite_filter_2;
+    depth = GetPickDepth();
   }
   else
   {
     if ( uFlags2 & 0x10 )
     {
-      v11 = &a5;
-      v10 = &stru_F93E1C;
+      v11 = &vis_face_filter;
+      v10 = &vis_sprite_filter_1;
     }
     else
     {
-      static bool __init_flag = false;
-      static stru157 static_sub_44EEA7_stru157;
-      if (!__init_flag)
-      {
-        __init_flag = true;
-        static_sub_44EEA7_stru157.field_8 = -1;
-        static_sub_44EEA7_stru157.field_0 = 0;
-        static_sub_44EEA7_stru157.field_4 = 2;
-        static_sub_44EEA7_stru157.field_C = 0;
-        static_sub_44EEA7_stru157.field_10 = 0;
-      }
-      v11 = &a5;
-      v10 = &static_sub_44EEA7_stru157;
+      v11 = &vis_face_filter;
+      v10 = &vis_sprite_filter_4;
     }
-    v2 = 5120.0;
-    v9 = 0;
-    x = a2.y;
-    y = a2.x;
+    depth = 5120.0;
   }
-  depth = v2;
+  //depth = v2;
 
-  PickMouse(depth, y, x, v9, v10, v11);
+  PickMouse(depth, y, x, true, v10, v11);
   pLightmapBuilder->std__vector_000004_size = 0;
   pLightmapBuilder->std__vector_183808_size = 0;
   pDecalBuilder->std__vector_pDecals_size = 0;
   pDecalBuilder->field_308008 = 0;
-  result = _44F07B();
-  if ( result )
-  {
+  if (!_44F07B())
+    return false;
+
     if ( uFlags & 8 )
       LOBYTE(pStru10Instance->field_4) = 0;
     if ( pRenderer->pRenderD3D && uCurrentlyLoadedLevelType == LEVEL_Outdoor)
@@ -669,9 +655,7 @@
       uNumStationaryLights_in_pStationaryLightsStack = pStationaryLightsStack->uNumLightsActive;
     }
     _44E904();
-    LOBYTE(result) = 1;
-  }
-  return result;
+    return true;
 }
 
 
@@ -1038,51 +1022,38 @@
 }
 
 //----- (0044EA5E) --------------------------------------------------------
-char Game::PickMouse(float fPickDepth, unsigned int uMouseX, unsigned int uMouseY, bool bOutline, stru157 *a5, stru157 *a6)
+bool Game::PickMouse(float fPickDepth, unsigned int uMouseX, unsigned int uMouseY, bool bOutline, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
 {
-  char result; // al@3
-  std::string v10; // [sp-4h] [bp-24h]@5
-  float v11; // [sp+4h] [bp-1Ch]@10
-  float v12; // [sp+8h] [bp-18h]@10
-  const char *v13; // [sp+Ch] [bp-14h]@5
-  int v14; // [sp+10h] [bp-10h]@5
-  std::string *v15; // [sp+18h] [bp-8h]@5
-  int a3; // [sp+1Fh] [bp-1h]@5
+  if (pCurrentScreen || !pRenderer->pRenderD3D)
+    return false;
 
-  auto v7 = this;
-  if (!pCurrentScreen && pRenderer->pRenderD3D)
+  if (!pVisInstance)
   {
-    if (!pVisInstance)
-    {
-      MessageBoxW(nullptr, L"The 'Vis' object pointer has not been instatiated, but CGame::Pick() is trying to call through it.", nullptr, 0);
-      ExitProcess(0);
-    }
+    MessageBoxW(nullptr, L"The 'Vis' object pointer has not been instatiated, but CGame::Pick() is trying to call through it.", nullptr, 0);
+    return false;
+  }
 
-    if ( (signed int)uMouseX >= (signed int)pViewport->uScreenX
-      && (signed int)uMouseX <= (signed int)pViewport->uScreenZ
-      && (signed int)uMouseY >= (signed int)pViewport->uScreenY
-      && (signed int)uMouseY <= (signed int)pViewport->uScreenW )
-    {
-      v14 = (int)a6;
-      v12 = (double)(signed int)uMouseY;
-      v11 = (double)(signed int)uMouseX;
-      pVisInstance->PickMouse(fPickDepth, v11, v12, a5, a6);
+  if (uMouseX >= (signed int)pViewport->uScreenX &&
+      uMouseX <= (signed int)pViewport->uScreenZ &&
+      uMouseY >= (signed int)pViewport->uScreenY &&
+      uMouseY <= (signed int)pViewport->uScreenW)
+  {
+    pVisInstance->PickMouse(fPickDepth, uMouseX, uMouseY, sprite_filter, face_filter);
 
-      if (bOutline)
-        OutlineSelection();
-    }
-    return true;
+    if (bOutline)
+      OutlineSelection();
   }
-  return false;
+
+  return true;
 }
 // 4E28F8: using guessed type int pCurrentScreen;
 
 //----- (0044EB12) --------------------------------------------------------
-bool Game::_44EB12(bool bOutline, stru157 *a3, stru157 *a4)
+bool Game::PickKeyboard(bool bOutline, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
 {
   if ( !pCurrentScreen && pVisInstance && pRenderer->pRenderD3D )
   {
-    bool r = pVisInstance->PickKeyboard(&pVisInstance->stru1, a3, a4);
+    bool r = pVisInstance->PickKeyboard(&pVisInstance->default_list, sprite_filter, face_filter);
 
     if (bOutline)
       OutlineSelection();
@@ -1107,58 +1078,47 @@
 //----- (0044EB5A) --------------------------------------------------------
 void Game::OutlineSelection()
 {
-  Vis *v1; // eax@1
-  Vis_stru1_stru0 *v2; // eax@3
-  void *v3; // edx@9
-  int v4; // eax@10
-  int v5; // eax@11
-  int v6; // eax@14
-  int v7; // eax@15
-  const char *v9; // [sp-8h] [bp-14h]@8
-  int v10; // [sp-4h] [bp-10h]@8
-  char v11; // [sp+0h] [bp-Ch]@18
-  int a3; // [sp+Ah] [bp-2h]@8
+  if (!pVisInstance)
+    return;
+
+  if (!pVisInstance->default_list.uNumPointers)
+    return;
 
-  v1 = this->pVisInstance;
-  if ( v1 )
-  {
-    v2 = (Vis_stru1_stru0 *)((signed int)v1->stru1.uNumPointers <= 0 ? 0 : v1->stru1.array_1804[0]);
-    if ( v2 )
+  auto object_info = pVisInstance->default_list.object_pointers[0];
+  if (object_info)
+    switch (object_info->object_type)
     {
-      if ( v2->uObjectType == 1 )
+      case VisObjectType_Sprite:
       {
-        MessageBoxW(nullptr, L"Sprite outline currently Unsupported", nullptr, 0);
-        ExitProcess(0);
+        Log::Warning(L"Sprite outline currently unsupported");
+        return;
       }
 
-        if ( v2->uObjectType == 2 )
+      case VisObjectType_Face:
+      {
+        if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
         {
-          v3 = v2->pObjectInfo;                 // TODO  2 objects for indoor/outdoor
-                                                // some clues in header for Vis_stru1_stru0
-          if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
-          {
-            v4 = *((int *)v3 + 11);
-            if ( v4 & 0x10000 )
-              v5 = v4 & 0xFFFEFFFF;
-            else
-              v5 = v4 | 0x10000;
-            *((int *)v3 + 11) = v5;
-          }
+          auto face = (ODMFace *)object_info->object;
+          if (face->uAttributes & FACE_OUTLINED)
+            face->uAttributes &= ~FACE_OUTLINED;
           else
-          {
-            v6 = *((int *)v3 + 7);
-            if ( v6 & 0x10000 )
-              v7 = v6 & 0xFFFEFFFF;
-            else
-              v7 = v6 | 0x10000;
-            *((int *)v3 + 7) = v7;
-          }
+            face->uAttributes |= FACE_OUTLINED;
+        }
+        else if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+        {
+          auto face = (BLVFace *)object_info->object;
+          if (face->uAttributes & FACE_OUTLINED)
+            face->uAttributes &= ~FACE_OUTLINED;
+          else
+            face->uAttributes |= FACE_OUTLINED;
         }
-        else
-        {
-          MessageBoxW(nullptr, L"Undefined CObjectInfo type requested in CGame::outline_selection()", nullptr, 0);
-          ExitProcess(0);
-        }
+        else assert(false);
+      }
+
+      default:
+      {
+        MessageBoxW(nullptr, L"Undefined CObjectInfo type requested in CGame::outline_selection()", nullptr, 0);
+        ExitProcess(0);
+      }
     }
-  }
 }
\ No newline at end of file
--- a/Game.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Game.h	Sun Feb 17 11:41:44 2013 +0400
@@ -87,8 +87,8 @@
 public:
   void _44E904();
   bool InitializeGammaController();
-  char PickMouse(float fPickDepth, unsigned int uMouseX, unsigned int uMouseY, bool bOutline, struct stru157 *a5, struct stru157 *a6);
-  bool _44EB12(bool bOutline, struct stru157 *a3, struct stru157 *a4);
+  bool PickMouse(float fPickDepth, unsigned int uMouseX, unsigned int uMouseY, bool bOutline, struct Vis_SelectionFilter *sprite_filter, struct Vis_SelectionFilter *face_filter);
+  bool PickKeyboard(bool bOutline, struct Vis_SelectionFilter *sprite_filter, struct Vis_SelectionFilter *face_filter);
   void OutlineSelection();
   signed int _44EC23(struct stru148 *a2, int *a3, signed int a4);
   signed int _44ED0A(struct BLVFace *a2, int *a3, signed int a4);
--- a/Indoor.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Indoor.h	Sun Feb 17 11:41:44 2013 +0400
@@ -255,6 +255,7 @@
 #define FACE_TEXTURE_ANIMATED 0x00000010 // like wavy water
 #define FACE_INVISIBLE        0x00002000
 #define FACE_TEXTURE_FRAME    0x00004000 // Texture ID is a frameset from TextureFrameTable, otherwise BitmapID
+#define FACE_OUTLINED         0x00010000 // outline face edges
 #define FACE_TEXTURE_FLOW     0x00040000 // The texture moves slowly. For horizontal facets only.
 #define FACE_CLICKABLE        0x02000000 // Event can be triggered by clicking on the facet.
 #define FACE_PRESSURE_PLATE   0x04000000 // Event can be triggered by stepping on the facet.
--- a/Mouse.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/Mouse.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -879,7 +879,7 @@
 void AsyncMouse::Suspend()
 {
   void *v1; // esi@1
-  Vis *v2; // eax@3
+  //Vis *v2; // eax@3
   std::string v3; // [sp-18h] [bp-24h]@2
   const char *v4; // [sp-8h] [bp-14h]@2
   int v5; // [sp-4h] [bp-10h]@2
@@ -889,9 +889,10 @@
   v1 = this;
   if ( *((int *)this + 33) )
   {
-    v2 = pGame->pVisInstance;
-    if ( v2 )
-      v2->stru1.uNumPointers = 0;
+    //v2 = pGame->pVisInstance;
+    if (pGame->pVisInstance)
+      pGame->pVisInstance->default_list.uNumPointers = 0;
+
     EnterCriticalSection(&pGame->pThreadWardInstance->cs3);
     SuspendThread(*((HANDLE *)v1 + 4));
     _46B0ED();
--- a/Party.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/Party.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -71,12 +71,9 @@
 //----- (004936E1) --------------------------------------------------------
 void Party::SetHoldingItem(ItemGen *pItem)
 {
-  Party *v2; // esi@1
-
-  v2 = this;
   sub_421B2C_PlaceInInventory_or_DropPickedItem();
-  memcpy(&v2->pPickedItem, pItem, sizeof(v2->pPickedItem));
-  pMouse->SetCursorBitmapFromItemID(v2->pPickedItem.uItemID);
+  memcpy(&pPickedItem, pItem, sizeof(pPickedItem));
+  pMouse->SetCursorBitmapFromItemID(pPickedItem.uItemID);
 }
 
 //----- (0049370F) --------------------------------------------------------
@@ -392,7 +389,7 @@
 	    if (pPlayers[uNumPlayers].pActiveSkills[12+i])
 			++uSpellBookPageCount;
     }
-    pCharacter->pNumSpellBookPage = uSpellBookPageCount;
+    pCharacter->lastOpenedSpellbookPage = uSpellBookPageCount;
 //LABEL_10:
     pCharacter->uExpressionTimePassed = 0;
     Dst.Reset();
--- a/Player.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/Player.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -576,7 +576,7 @@
   //Player *pPlayer; // edi@1
   //int v4; // eax@4
   signed int v5; // esi@4
-  char *v6; // ebx@4
+  unsigned char *v6; // ebx@4
   signed int v7; // ecx@5
   unsigned __int8 v8; // al@6
   int v9; // eax@10
@@ -608,8 +608,8 @@
   //v4 = a2;//102
   v5 = 0;
   pSoundId = 0;
-  v6 = (char *)&SoundSetAction[4 * speech];//byte_4ED280 &byte_4ED3D8[4 * v4] ???
-  if ( uVoicesVolumeMultiplier )
+  v6 = SoundSetAction[speech];//byte_4ED280 &byte_4ED3D8[4 * v4] ???
+  if (uVoicesVolumeMultiplier)
   {
     v7 = 0;
     do
@@ -625,17 +625,16 @@
       v9 = rand();
       //pVoiceID = uVoiceID;
       v11 = v20[v9 % v5];
-      if ( LOBYTE((&(&dlhu_texnames_by_face[19])[25 * v11 + 3])[uVoiceID]) )
-      {
-        pSoundId = rand() % SLOBYTE((&(&dlhu_texnames_by_face[19])[25 * v11 + 3])[uVoiceID])
-            + 2 * (v11 + 50 * uVoiceID)
-            + 4998;
-        v12 = 8 * pPlayerNum + 312;
-        LOBYTE(v12) = v12 | OBJECT_Player;
+
+      if (int _v1 = byte_4ECF08[v11 - 1][uVoiceID])
+      {
+        pSoundId = rand() % _v1 + 2 * (v11 + 50 * uVoiceID) + 4998;
+        v12 = (8 * pPlayerNum + 312) | OBJECT_Player;
         pAudioPlayer->PlaySound((SoundID)pSoundId, v12, 0, -1, 0, 0, (pSoundVolumeLevels[uVoicesVolumeMultiplier] * 128.0), 0);
       }
     }
   }
+
   v13 = 0;
   v14 = (int)(v6 + 3);
   do
@@ -1374,7 +1373,7 @@
 
   v11 = this;
   v3 = pIcons_LOD->LoadTexture(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE);
-  v4 = (Texture *)(v3 != -1 ? (int)&pIcons_LOD->pTextures[v3] : 0);
+  v4 = (Texture *)(v3 != -1 ? &pIcons_LOD->pTextures[v3] : 0);
   v5 = GetSizeInInventorySlots(v3 != -1 ? pIcons_LOD->pTextures[v3].uTextureWidth : 24);
   uItemIDa = GetSizeInInventorySlots(v4->uTextureHeight);
   if ( !areWeLoadingTexture )
@@ -1463,7 +1462,7 @@
   if ( v12 == -1 )
   {
     if ( uActiveCharacter )
-      pPlayers[uActiveCharacter]->PlaySound(SPEECH_15, 0);
+      pPlayers[uActiveCharacter]->PlaySound(SPEECH_NoRoom, 0);
     result = 0;
   }
   else
@@ -1761,6 +1760,8 @@
   unsigned int uSlota; // [sp+14h] [bp+4h]@1
 
   pIndices = &this->pInventoryIndices[uSlot];
+
+  __debugbreak();  // the following indexing is invalid
   v3 = (ItemGen *)&this->spellbook.pDarkSpellbook.bIsSpellAvailable[36 * *pIndices + 5];
   v4 = v3->uItemID;
   v3->Reset();
@@ -2315,6 +2316,8 @@
   field_FC = 0;
   field_100 = 0;
   field_104 = 0;
+
+  lastOpenedSpellbookPage = 0;
 }
 
 //----- (0048C6F6) --------------------------------------------------------
@@ -6534,15 +6537,15 @@
 
     switch (i)
     {
-      case PLAYER_SKILL_FIRE:   spellbook.pFireSpellbook.bIsSpellbookAvailable = true;   break;
-      case PLAYER_SKILL_AIR:    spellbook.pAirSpellbook.bIsSpellbookAvailable = true;    break;
-      case PLAYER_SKILL_WATER:  spellbook.pWaterSpellbook.bIsSpellbookAvailable = true;  break;
-      case PLAYER_SKILL_EARTH:  spellbook.pEarthSpellbook.bIsSpellbookAvailable = true;  break;
-      case PLAYER_SKILL_SPIRIT: spellbook.pSpiritSpellbook.bIsSpellbookAvailable = true; break;
-      case PLAYER_SKILL_MIND:   spellbook.pMindSpellbook.bIsSpellbookAvailable = 1; break;
-      case PLAYER_SKILL_BODY:   spellbook.pBodySpellbook.bIsSpellbookAvailable = 1; break;
-      case PLAYER_SKILL_LIGHT:  spellbook.pLightSpellbook.bIsSpellbookAvailable = 1; break;
-      case PLAYER_SKILL_DARK:   spellbook.pDarkSpellbook.bIsSpellbookAvailable = 1; break;
+      case PLAYER_SKILL_FIRE:   spellbook.pFireSpellbook.bIsSpellAvailable[0] = true;   break;
+      case PLAYER_SKILL_AIR:    spellbook.pAirSpellbook.bIsSpellAvailable[0] = true;    break;
+      case PLAYER_SKILL_WATER:  spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true;  break;
+      case PLAYER_SKILL_EARTH:  spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true;  break;
+      case PLAYER_SKILL_SPIRIT: spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true; break;
+      case PLAYER_SKILL_MIND:   spellbook.pMindSpellbook.bIsSpellAvailable[0] = true;   break;
+      case PLAYER_SKILL_BODY:   spellbook.pBodySpellbook.bIsSpellAvailable[0] = true;   break;
+      case PLAYER_SKILL_LIGHT:  spellbook.pLightSpellbook.bIsSpellAvailable[0] = true;  break;
+      case PLAYER_SKILL_DARK:   spellbook.pDarkSpellbook.bIsSpellAvailable[0] = true;   break;
     }
   }
 
--- a/Player.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Player.h	Sun Feb 17 11:41:44 2013 +0400
@@ -24,14 +24,14 @@
   SPEECH_11 = 11,
   SPEECH_12 = 12,
   SPEECH_14 = 14,
-  SPEECH_15 = 15,
+  SPEECH_NoRoom = 15,  // when placing to inventory
   SPEECH_16 = 16,
   SPEECH_17 = 17,
   SPEECH_18 = 18,
   SPEECH_19 = 19,
   SPEECH_20 = 20,
   SPEECH_21 = 21,
-  SPEECH_GoodDay = 22,
+  SPEECH_GoodDay = 22,     // greets on dialogue start
   SPEECH_GoodEvening = 23,
   SPEECH_24 = 24,
   SPEECH_25 = 25,
@@ -195,26 +195,28 @@
   PLAYER_SKILL_WATER = 14,
   PLAYER_SKILL_EARTH = 15,
   PLAYER_SKILL_SPIRIT = 16,
-  PLAYER_SKILL_MIND = 0x11,
+  PLAYER_SKILL_MIND = 17,
   PLAYER_SKILL_BODY = 18,
-  PLAYER_SKILL_LIGHT = 0x13,
-  PLAYER_SKILL_DARK = 0x14,
-  PLAYER_SKILL_ITEM_ID = 0x15,
-  PLAYER_SKILL_MERCHANT = 0x16,
-  PLAYER_SKILL_REPAIR = 0x17,
-  PLAYER_SKILL_BODYBUILDING = 0x18,
-  PLAYER_SKILL_MEDITATION = 0x19,
-  PLAYER_SKILL_PERCEPTION = 0x1A,
-  PLAYER_SKILL_DIPLOMACY = 0x1B,
-  PLAYER_SKILL_TIEVERY = 0x1C,
+  PLAYER_SKILL_LIGHT = 19,
+  PLAYER_SKILL_DARK = 20,
+  PLAYER_SKILL_ITEM_ID = 21,
+  PLAYER_SKILL_MERCHANT = 22,
+  PLAYER_SKILL_REPAIR = 23,
+  PLAYER_SKILL_BODYBUILDING = 24,
+  PLAYER_SKILL_MEDITATION = 25,
+  PLAYER_SKILL_PERCEPTION = 26,
+  PLAYER_SKILL_DIPLOMACY = 27,
+  PLAYER_SKILL_TIEVERY = 28,
   PLAYER_SKILL_TRAP_DISARM = 29,
-  PLAYER_SKILL_DODGE = 0x1E,
-  PLAYER_SKILL_UNARMED = 0x1F,
-  PLAYER_SKILL_MONSTER_ID = 0x20,
+  PLAYER_SKILL_DODGE = 30,
+  PLAYER_SKILL_UNARMED = 31,
+  PLAYER_SKILL_MONSTER_ID = 32,
   PLAYER_SKILL_ARMSMASTER = 33,
   PLAYER_SKILL_STEALING = 34,
   PLAYER_SKILL_ALCHEMY = 35,
-  PLAYER_SKILL_LEARNING = 0x24,
+  PLAYER_SKILL_LEARNING = 36,
+
+  PLAYER_SKILL_INVALID = -1
 };
 
 /*  329 */
@@ -255,8 +257,7 @@
 #pragma pack(push, 1)
 struct PlayerSpellbookChapter
 {
-  unsigned __int8 bIsSpellbookAvailable;
-  char bIsSpellAvailable[10];
+  char bIsSpellAvailable[11];
 };
 #pragma pack(pop)
 
@@ -666,7 +667,7 @@
   int field_1988[49];
   char field_1A4C;
   char field_1A4D;
-  char pNumSpellBookPage;
+  char lastOpenedSpellbookPage;
   unsigned __int8 uQuickSpell;
   char field_1A50[64];
   char _some_attack_bonus;
--- a/Render.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Render.h	Sun Feb 17 11:41:44 2013 +0400
@@ -56,7 +56,15 @@
   int _screenspace_y_scaler_packedfloat;
   float fov_x;
   float fov_y;
-  int sZValue;
+  union
+  {
+    int sZValue;
+    struct
+    {
+      unsigned __int16 object_pid;
+      signed __int16 actual_z;
+    };
+  };
   int field_14_actor_id;
   unsigned __int16 uHwSpriteID;
   __int16 uPalette;
@@ -73,7 +81,7 @@
 
    inline float GetFloatZ() const
  {
-  return LOWORD(sZValue) / 65535.0f + (float)HIWORD(sZValue);
+  return (float)object_pid / 65535.0f + (float)actual_z;
  }
 };
 #pragma pack(pop)
--- a/SaveLoad.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/SaveLoad.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -67,18 +67,18 @@
     }
 
 
-  if (byte_4ED498)
+  if (SoundSetAction[24][0])
     for (uint i = 0; i < 4; ++i)
     {
       for (uint j = 0; j < pSoundList->uNumSounds; ++j)
-        if (pSoundList->pSounds[j].uSoundID == 2 * (byte_4ED498 + 50 * pParty->pPlayers[i].uVoiceID) + 4998)
+        if (pSoundList->pSounds[j].uSoundID == 2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[i].uVoiceID) + 4998)
         {
           pSoundList->_4A9DCD(j, 1);
           break;
         }
 
         for (uint j = 0; j < pSoundList->uNumSounds; ++j)
-        if (pSoundList->pSounds[j].uSoundID == 2 * (byte_4ED498 + 50 * pParty->pPlayers[i].uVoiceID) + 4999)
+        if (pSoundList->pSounds[j].uSoundID == 2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[i].uVoiceID) + 4999)
         {
           pSoundList->_4A9DCD(j, 1);
           break;
--- a/Vis.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/Vis.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -1,45 +1,53 @@
+#include <assert.h>
+
 #include "Vis.h"
 #include "Outdoor.h"
 #include "Game.h"
 #include "Actor.h"
 #include "IndoorCamera.h"
 #include "Viewport.h"
-#include "stru157.h"
 
 #include "mm7_data.h"
 //#include "MM7.h"
 
 
-static Vis_stru1 Vis_static_sub_4C1944_stru_F8BDE8;
+static Vis_SelectionList Vis_static_sub_4C1944_stru_F8BDE8;
+
+Vis_SelectionFilter vis_sprite_filter_1 = {VisObjectType_Sprite, OBJECT_Decoration,  0, 0,         2}; // 00F93E1C
+Vis_SelectionFilter vis_sprite_filter_2 = {VisObjectType_Sprite, OBJECT_Decoration,  0, 0,         2}; // 00F93E30
+Vis_SelectionFilter vis_face_filter     = {VisObjectType_Face,   OBJECT_Any,        -1, 0,         0}; // 00F93E44
+Vis_SelectionFilter vis_door_filter     = {VisObjectType_Face,   OBJECT_BLVDoor,    -1, 0x100000,  0}; // 00F93E58
+Vis_SelectionFilter vis_sprite_filter_3 = {VisObjectType_Sprite, OBJECT_Decoration, -1, 0,         4}; // 00F93E6C
+Vis_SelectionFilter vis_sprite_filter_4 = {VisObjectType_Any,    OBJECT_Item,       -1, 0,         0}; // static to sub_44EEA7
 
 
 
 //----- (004C1026) --------------------------------------------------------
-Vis_stru1_stru0 *Vis::_4C1026(BLVFace *a2, unsigned int a3, float a4)
+Vis_ObjectInfo *Vis::_4C1026(BLVFace *face, unsigned int a3, float pick_depth)
 {
   char *v4; // eax@4
   signed int v5; // ecx@4
-  BLVFace *v6; // ecx@7
-  unsigned int v7; // edi@7
+  //BLVFace *v6; // ecx@7
+  //unsigned int v7; // edi@7
   Vec3_short_ *v8; // eax@9
   char *v9; // edx@9
   signed int v10; // esi@10
-  Vec3_int_ **v11; // edx@13
-  char *v12; // eax@13
-  double v13; // st7@14
-  signed int v14; // ebx@14
-  Vis *v15; // ebx@15
-  Vis_stru1_stru0 *result; // eax@21
-  Vis_stru1_stru0 *v17; // ecx@24
+  //Vec3_int_ **v11; // edx@13
+  //char *v12; // eax@13
+  //double v13; // st7@14
+  //signed int v14; // ebx@14
+  //Vis *v15; // ebx@15
+  //Vis_ObjectInfo *result; // eax@21
+  //Vis_ObjectInfo *v17; // ecx@24
   RenderVertexSoft pRay[2]; // [sp+20h] [bp-70h]@17
   int v20; // [sp+84h] [bp-Ch]@10
-  int v21; // [sp+88h] [bp-8h]@16
-  int v22; // [sp+8Ch] [bp-4h]@16
+  //int v21; // [sp+88h] [bp-8h]@16
+  //int v22; // [sp+8Ch] [bp-4h]@16
   signed int v23; // [sp+98h] [bp+8h]@7
 
-  auto ecx0 = this;
+  //auto ecx0 = this;
 
-  static Vis_stru1 static_sub_4C1026_stru_F8FE00;
+  static Vis_SelectionList static_sub_4C1026_stru_F8FE00;
   static_sub_4C1026_stru_F8FE00.uNumPointers = 0;
 
   static bool _init_flag = false;
@@ -51,138 +59,150 @@
       static_sub_4C1026_array_F8F200[i].flt_2C = 0.0f;
   }
 
-  v6 = a2;
+  //v6 = a2;
   v23 = 0;
-  v7 = v6->uNumVertices;
-  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
+  //v7 = face->uNumVertices;
+  if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
   {
-    if ( (signed int)v7 > 0 )
+    __debugbreak(); // refactor for BLV picking
+    if ( (signed int)face->uNumVertices > 0 )
     {
       v8 = pIndoor->pVertices;
       v9 = (char *)&static_sub_4C1026_array_F8F200[0].vWorldPosition.y;
       do
       {
         v10 = v23++;
-        v20 = v8[v6->pVertexIDs[v10]].x;
+        v20 = v8[face->pVertexIDs[v10]].x;
         *((float *)v9 - 1) = (double)v20;
-        v20 = v8[v6->pVertexIDs[v10]].y;
+        v20 = v8[face->pVertexIDs[v10]].y;
         *(float *)v9 = (double)v20;
         v9 += 48;
-        v20 = v8[v6->pVertexIDs[v10]].z;
+        v20 = v8[face->pVertexIDs[v10]].z;
         *((float *)v9 - 11) = (double)v20;
       }
-      while ( v23 < (signed int)v7 );
+      while ( v23 < (signed int)face->uNumVertices );
+    }
+  }
+  else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+  {
+    uint bmodel_id = a3 >> 9;
+    auto v = (Vec3_int_ *)pOutdoor->pBModels[bmodel_id].pVertices.pVertices;
+    for (uint i = 0; i < face->uNumVertices; ++i)
+    {
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.x = v[face->pVertexIDs[i]].x;
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.y = v[face->pVertexIDs[i]].y;
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.z = v[face->pVertexIDs[i]].z;
     }
   }
-  else
-  {
-    if ( (signed int)v7 > 0 )
-    {
-      v11 = &pOutdoor->pBModels[a3 >> 9].pVertices.pVertices;
-      v12 = (char *)&static_sub_4C1026_array_F8F200[0].vWorldPosition.y;
-      do
-      {
-        *((float *)v12 - 1) = (double)(*v11)[v6->pVertexIDs[v23]].x;
-        v13 = (double)(*v11)[v6->pVertexIDs[v23]].y;
-        v14 = v23++;
-        *(float *)v12 = v13;
-        v12 += 48;
-        *((float *)v12 - 11) = (double)(*v11)[v6->pVertexIDs[v14]].z;
-      }
-      while ( v23 < (signed int)v7 );
-    }
-  }
-  pGame->pIndoorCameraD3D->ViewTransform(static_sub_4C1026_array_F8F200, v7);
-  pGame->pIndoorCameraD3D->Project(static_sub_4C1026_array_F8F200, v7, 1);
-  v15 = this;
-  SortVectors_x(static_sub_4C1026_array_F8F200, 0, v7 - 1);
-  if ( static_sub_4C1026_array_F8F200[0].vWorldViewPosition.x > (double)a4
-    || (_4C1495(static_sub_4C1026_array_F8F200, v7, (float *)&v21, (float *)&v22),
-        _4C12C3_FindSomeBillboard(static_sub_4C1026_array_F8F200, v7, *(float *)&v21, *(float *)&v22))
-    || ((CastPickRay(pRay, *(float *)&v21, *(float *)&v22, a4), uCurrentlyLoadedLevelType != LEVEL_Indoor) ? PickOutdoor(a4, pRay, &static_sub_4C1026_stru_F8FE00, &a5, 1) : PickIndoor(a4, pRay, &static_sub_4C1026_stru_F8FE00, &a5),
-        (static_sub_4C1026_stru_F8FE00.create_object_pointers(0),
-         sort_object_pointers(
-           static_sub_4C1026_stru_F8FE00.array_1804,
-           0,
-           static_sub_4C1026_stru_F8FE00.uNumPointers - 1),
-         !static_sub_4C1026_stru_F8FE00.uNumPointers)
-     || (result = static_sub_4C1026_stru_F8FE00.sub_4C2551(2, a3)) == 0
-     || (signed int)static_sub_4C1026_stru_F8FE00.uNumPointers > 1
-     && ((signed int)static_sub_4C1026_stru_F8FE00.uNumPointers <= 0 ? (v17 = 0) : (v17 = static_sub_4C1026_stru_F8FE00.array_1804[0]),
-         result != v17)) )
-    result = 0;
-  return result;
+  else assert(false);
+
+  pGame->pIndoorCameraD3D->ViewTransform(static_sub_4C1026_array_F8F200, face->uNumVertices);
+  pGame->pIndoorCameraD3D->Project(static_sub_4C1026_array_F8F200, face->uNumVertices, 1);
+
+  //v15 = this;
+  SortVectors_x(static_sub_4C1026_array_F8F200, 0, face->uNumVertices - 1);
+  if (static_sub_4C1026_array_F8F200[0].vWorldViewPosition.x > pick_depth)
+    return nullptr;
+
+  float screenspace_center_x,
+        screenspace_center_y;
+  GetPolygonScreenSpaceCenter(static_sub_4C1026_array_F8F200, face->uNumVertices, &screenspace_center_x, &screenspace_center_y);
+  if (IsPolygonOccludedByBillboard(static_sub_4C1026_array_F8F200, face->uNumVertices, screenspace_center_x, screenspace_center_y))
+    return nullptr;
+
+  CastPickRay(pRay, screenspace_center_x, screenspace_center_y, pick_depth);
+
+  if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+    PickOutdoorFaces_Mouse(pick_depth, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter, true);
+  else if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+    PickIndoorFaces_Mouse(pick_depth, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter);
+  else assert(false);
+
+  static_sub_4C1026_stru_F8FE00.create_object_pointers();
+  sort_object_pointers(static_sub_4C1026_stru_F8FE00.object_pointers, 0, static_sub_4C1026_stru_F8FE00.uNumPointers - 1);
+  if (!static_sub_4C1026_stru_F8FE00.uNumPointers)
+    return nullptr;
+
+  if (!static_sub_4C1026_stru_F8FE00.sub_4C2551(2, a3))
+    return nullptr;
+
+  if (static_sub_4C1026_stru_F8FE00.uNumPointers)
+    return static_sub_4C1026_stru_F8FE00.object_pointers[0];
+  else return nullptr;
 }
 // F91E08: using guessed type char static_sub_4C1026_byte_F91E08__init_flags;
 
 //----- (004C12C3) --------------------------------------------------------
-char Vis::_4C12C3_FindSomeBillboard(RenderVertexSoft *a1, int a2, float a3, float a4)
+bool Vis::IsPolygonOccludedByBillboard(RenderVertexSoft *vertices, int num_vertices, float x, float y)
 {
-  signed int v5; // esi@1
-  RenderBillboardD3D *v6; // edi@2
-  double v7; // st7@9
-  int v8; // edx@9
-  RenderVertexSoft *v9; // ecx@10
-  char result; // al@24
-  Vis *thisa; // [sp+10h] [bp-8h]@1
-  float thisb; // [sp+10h] [bp-8h]@9
-  signed int v13; // [sp+14h] [bp-4h]@1
-  float a3a; // [sp+28h] [bp+10h]@9
-  float a4a; // [sp+2Ch] [bp+14h]@9
+  //signed int v5; // esi@1
+  //RenderBillboardD3D *v6; // edi@2
+  //double v7; // st7@9
+  //int v8; // edx@9
+  //RenderVertexSoft *v9; // ecx@10
+  //char result; // al@24
+  //Vis *thisa; // [sp+10h] [bp-8h]@1
+  //float thisb; // [sp+10h] [bp-8h]@9
+  //signed int v13; // [sp+14h] [bp-4h]@1
+  //float a3a; // [sp+28h] [bp+10h]@9
+  //float a4a; // [sp+2Ch] [bp+14h]@9
 
-  v13 = -1;
-  v5 = 0;
-  thisa = this;
-  if ( (signed int)pRenderer->uNumBillboardsToDraw <= 0 )
-  {
-    return 0;
-  }
-  v6 = pRenderer->pBillboardRenderListD3D;
-  do
-  {
-    if ( IsPointInsideD3DBillboard(v6, a3, a4)
-      && (v13 == -1
-	  || (unsigned int)pBillboardRenderList[v6->uParentBillboardID].sZValue < pBillboardRenderList[pRenderer->pBillboardRenderListD3D[v13].uParentBillboardID].sZValue) )
-      v13 = v5;
-    ++v5;
-    ++v6;
-  }
-  while ( v5 < (signed int)pRenderer->uNumBillboardsToDraw );
-  if ( v13 == -1 )
+  int v13 = -1;
+  //v5 = 0;
+  //thisa = this;
+
+  //v6 = pRenderer->pBillboardRenderListD3D;
+  for (uint i = 0; i < pRenderer->uNumBillboardsToDraw; ++i)
   {
-    return 0;
-  }
-  v7 = 3.4028235e38;
-  v8 = a2;
-  a4a = 3.4028235e38;
-  a3a = -3.4028235e38;
-  thisb = -3.4028235e38;
-  if ( a2 > 0 )
-  {
-    v9 = a1;
-    do
+    auto billboard = pRenderer->pBillboardRenderListD3D + i;
+    if (IsPointInsideD3DBillboard(billboard, x, y))
     {
-		if ( v9->vWorldViewProjX < v7 )
-			v7 = v9->vWorldViewProjX;
-		if ( v9->vWorldViewProjX > (double)a3a )
-        a3a = v9->vWorldViewProjX;
-		if ( v9->vWorldViewProjY < (double)a4a )
-        a4a = v9->vWorldViewProjY;
-      if ( v9->vWorldViewProjY > (double)thisb )
-        thisb = v9->vWorldViewProjY;
-      ++v9;
-      --v8;
+      if (v13 == -1)
+        v13 = i;
+      else  if ((unsigned int)pBillboardRenderList[billboard->uParentBillboardID].sZValue < pBillboardRenderList[pRenderer->pBillboardRenderListD3D[v13].uParentBillboardID].sZValue)
+        v13 = i;
     }
-    while ( v8 );
   }
-  if ( v7 < pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.x
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.y > (double)a4a
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[3].pos.x < (double)a3a
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[1].pos.y < (double)thisb )
-    result = 0;
-  else
-    result = 1;
-  return result;
+
+  if ( v13 == -1 )
+    return false;
+  
+  //v8 = num_vertices;
+  //v7 = 3.4028235e38;
+  float min_x = FLT_MAX;
+  //a4a = 3.4028235e38;
+  float min_y = FLT_MAX;
+  //a3a = -3.4028235e38;
+  float max_x = -FLT_MAX;
+  //thisb = -3.4028235e38;
+  float max_y = -FLT_MAX;
+  for (uint i = 0; i < num_vertices; ++i)
+  {
+    //v9 = a1;
+    //do
+    //{
+    auto v = vertices + i;
+
+    if (v->vWorldViewProjX < min_x)
+      min_x = v->vWorldViewProjX;
+    if (v->vWorldViewProjX > max_x)
+      max_x = v->vWorldViewProjX;
+
+    if (v->vWorldViewProjY < min_y)
+      min_y = v->vWorldViewProjY;
+    if (v->vWorldViewProjY > max_y)
+      max_y = v->vWorldViewProjY;
+      //++v9;
+      //--v8;
+    //}
+    //while ( v8 );
+  }
+
+  if (min_x < pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.x || pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.y > min_y ||
+      pRenderer->pBillboardRenderListD3D[v13].pQuards[3].pos.x < max_x || pRenderer->pBillboardRenderListD3D[v13].pQuards[1].pos.y < max_y)
+    return false;
+
+  return true;
 }
 
 //----- (004C1417) --------------------------------------------------------
@@ -200,81 +220,45 @@
 }
 
 //----- (004C1495) --------------------------------------------------------
-float *Vis::_4C1495(RenderVertexSoft *Src, int a2, float *a3, float *a4)
+void Vis::GetPolygonScreenSpaceCenter(RenderVertexSoft *vertices, int num_vertices, float *out_center_x, float *out_center_y)
 {
   char *v5; // eax@2
   signed int v6; // ecx@2
   float *result; // eax@5
-  Vis *thisa; // [sp+0h] [bp-4h]@1
 
-  thisa = this;
-
-  static bool static_sub_4C1495_byte_F8E9F8__init_flags = false; // weak
   static RenderVertexSoft static_sub_4C1495_array_F8DDF8[64];
-  if ( !static_sub_4C1495_byte_F8E9F8__init_flags )
-  {
-    static_sub_4C1495_byte_F8E9F8__init_flags = true;
 
-    for (uint i = 0; i < 64; ++i)
-      static_sub_4C1495_array_F8DDF8[i].flt_2C = 0.0f;
-  }
+  memcpy(static_sub_4C1495_array_F8DDF8, vertices, 48 * num_vertices);
 
-  memcpy(static_sub_4C1495_array_F8DDF8, Src, 48 * a2);
-  sort_objects_2(static_sub_4C1495_array_F8DDF8, 0, a2 - 1);
-  *a3 = (*(float *)&Vis_static_sub_4C1944_stru_F8BDE8.array_1804[12 * a2 + 509]
-       - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX)
-      * 0.5
-      + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX;
-  sort_objects_3(static_sub_4C1495_array_F8DDF8, 0, a2 - 1);
-  result = a4;
-  *a4 = (*(float *)&Vis_static_sub_4C1944_stru_F8BDE8.array_1804[12 * a2 + 510]
-       - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY)
-      * 0.5
-      + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY;
-  return result;
+  SortByScreenSpaceX(static_sub_4C1495_array_F8DDF8, 0, num_vertices - 1);
+  *out_center_x = (static_sub_4C1495_array_F8DDF8[num_vertices - 1].vWorldViewProjX - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX) * 0.5 + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX;
+
+  SortByScreenSpaceY(static_sub_4C1495_array_F8DDF8, 0, num_vertices - 1);
+  *out_center_y = (static_sub_4C1495_array_F8DDF8[num_vertices - 1].vWorldViewProjY - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY) * 0.5 + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY;
 }
 
 //----- (004C1542) --------------------------------------------------------
-void Vis::PickBillboards(float fPickDepth, float fX, float fY, Vis_stru1 *a4, stru157 *a2)
+void Vis::PickBillboards_Mouse(float fPickDepth, float fX, float fY, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
-  int v6; // ST1C_4@6
-  Vis_stru1_stru0 *v7; // edi@6
-  Vis *thisa; // [sp+20h] [bp-Ch]@1
-  RenderBillboardD3D *v9; // [sp+24h] [bp-8h]@2
-  unsigned int uD3DBillboardIdx; // [sp+28h] [bp-4h]@1
-
-  uD3DBillboardIdx = 0;
-  thisa = this;
-  if ( (signed int)pRenderer->uNumBillboardsToDraw > 0 )
+  for (uint i = 0; i < pRenderer->uNumBillboardsToDraw; ++i)
   {
-    v9 = pRenderer->pBillboardRenderListD3D;//[0].uParentBillboardID;
-    do
+    auto d3d_billboard = pRenderer->pBillboardRenderListD3D + i;
+    if (is_part_of_selection((void *)i, filter) && IsPointInsideD3DBillboard(d3d_billboard, fX, fY))
     {
-      if ( is_part_of_selection((BLVFace *)uD3DBillboardIdx, a2)
-        && IsPointInsideD3DBillboard((RenderBillboardD3D *)(v9 - 38), fX, fY) )
+      if (DoesRayIntersectBillboard(fPickDepth, i))
       {
-        if ( DoesRayIntersectBillboard(fPickDepth, uD3DBillboardIdx) )
-        {
-          v6 = pBillboardRenderList[v9->uParentBillboardID].sZValue;
-          v7 = &a4->array_0004[a4->uNumPointers];
-		  v7->pObjectInfo = (void *)v9->uParentBillboardID;
-          v7 = (Vis_stru1_stru0 *)((char *)v7 + 4);
-          v7->pObjectInfo = (void *)v6;
-          v7->sZValue = 1;
-          ++a4->uNumPointers;
-        }
+        auto billboard = &pBillboardRenderList[d3d_billboard->uParentBillboardID];
+
+        list->AddObject((void *)d3d_billboard->uParentBillboardID, VisObjectType_Sprite, billboard->sZValue);
       }
-      ++uD3DBillboardIdx;
-      ++v9;
     }
-    while ( (signed int)uD3DBillboardIdx < (signed int)pRenderer->uNumBillboardsToDraw );
   }
 }
 
 //----- (004C1607) --------------------------------------------------------
 bool Vis::IsPointInsideD3DBillboard(RenderBillboardD3D *a1, float x, float y)
 {
-  RenderBillboardD3D *result; // eax@1
+  //RenderBillboardD3D *result; // eax@1
   double v5; // st7@2
   float v6; // ecx@2
   float v7; // ST00_4@3
@@ -302,27 +286,28 @@
   float v29; // [sp+8h] [bp-4h]@2
   float a1a; // [sp+14h] [bp+8h]@2
 
-  result = a1;
   if ( a1->uParentBillboardID == -1 )
-    goto LABEL_14;
+    return false;
+
+  //result = a1;
   v5 = a1->pQuards[0].pos.x;
   a1a = a1->pQuards[3].pos.x;
-  v6 = result->pQuards[0].pos.y;
-  result = (RenderBillboardD3D *)LODWORD(result->pQuards[1].pos.y);
+  v6 = a1->pQuards[0].pos.y;
+  //result = (RenderBillboardD3D *)LODWORD(result->pQuards[1].pos.y);
   v29 = v6;
-  LODWORD(v28) = (int)result;
+  v28 = a1->pQuards[1].pos.y;
   if ( v5 > a1a )
   {
     v7 = v5;
-    HIWORD(result) = HIWORD(v7);
+    //HIWORD(result) = HIWORD(v7);
     v5 = a1a;
     a1a = v7;
   }
   if ( v6 > (double)v28 )
   {
-    result = (RenderBillboardD3D *)LODWORD(v28);
+    //result = (RenderBillboardD3D *)LODWORD(v28);
     v28 = v6;
-    LODWORD(v29) = (int)result;
+    v29 = v28;
   }
   v9 = x + 1.0;
   //UNDEF(v8);
@@ -330,19 +315,17 @@
   //v11 = 0;
   //v12 = v9 == v5;
   //BYTE1(result) = HIBYTE(v8);//crash
-  if ( v9 >= v5
-    && (v14 = x - 1.0, v14<=a1a)///*UNDEF(v13),*/ v15 = v14 < a1a, v16 = 0, v17 = v14 == a1a, BYTE1(result) = HIBYTE(v13), v15 | v17)
-    && (v19 = y + 1.0, v19>=v29)///*UNDEF(v18),*/ v20 = v19 < v29, v21 = 0, v22 = v19 == v29, BYTE1(result) = HIBYTE(v18), v19 >= v29)
-    && (v24 = y - 1.0, v24<=v28))///*UNDEF(v23),*/ v25 = v24 < v28, v26 = 0, v27 = v24 == v28, BYTE1(result) = HIBYTE(v23), v25 | v27) )
-    LOBYTE(result) = 1;
+  if (v9 >= v5 &&
+      (v14 = x - 1.0, v14<=a1a) &&///*UNDEF(v13),*/ v15 = v14 < a1a, v16 = 0, v17 = v14 == a1a, BYTE1(result) = HIBYTE(v13), v15 | v17)
+      (v19 = y + 1.0, v19>=v29) &&///*UNDEF(v18),*/ v20 = v19 < v29, v21 = 0, v22 = v19 == v29, BYTE1(result) = HIBYTE(v18), v19 >= v29)
+      (v24 = y - 1.0, v24<=v28))///*UNDEF(v23),*/ v25 = v24 < v28, v26 = 0, v27 = v24 == v28, BYTE1(result) = HIBYTE(v23), v25 | v27) )
+    return true;
   else
-LABEL_14:
-    LOBYTE(result) = 0;
-  return (bool)result;
+    return false;
 }
 
 //----- (004C16B4) --------------------------------------------------------
-void Vis::PickIndoor(float fDepth, RenderVertexSoft *pRay, Vis_stru1 *a4, stru157 *a5)
+void Vis::PickIndoorFaces_Mouse(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
   int v5; // eax@1
   signed int v6; // edi@2
@@ -351,7 +334,7 @@
   int v9; // eax@7
   unsigned int *pNumPointers; // eax@7
   unsigned int v11; // ecx@7
-  Vis_stru1_stru0 *v12; // edi@7
+  Vis_ObjectInfo *v12; // edi@7
   RenderVertexSoft a1; // [sp+Ch] [bp-44h]@1
   BLVFace *v14; // [sp+3Ch] [bp-14h]@7
   void *v15; // [sp+40h] [bp-10h]@7
@@ -359,6 +342,8 @@
   int v17; // [sp+48h] [bp-8h]@1
   Vis *thisa; // [sp+4Ch] [bp-4h]@1
 
+  __debugbreak(); // refactor for BLV picking
+
   v5 = 0;
   thisa = this;
   v17 = 0;
@@ -370,7 +355,7 @@
       if ( v6 < (signed int)pIndoor->uNumFaces )
       {
         v7 = v6;
-        if ( is_part_of_selection(&pIndoor->pFaces[v6], a5) )
+        if ( is_part_of_selection(&pIndoor->pFaces[v6], filter) )
         {
           if ( !pGame->pIndoorCameraD3D->IsCulled(&pIndoor->pFaces[v7]) )
           {
@@ -380,14 +365,14 @@
               v9 = _48B561_mess_with_scaling_along_z(/*v8, */a1.vWorldViewPosition.x);
               LOWORD(v9) = 0;
               v15 = (void *)((8 * v6 | 6) + v9);
-              pNumPointers = &a4->uNumPointers;
+              pNumPointers = &list->uNumPointers;
               v16 = 2;
-              v11 = a4->uNumPointers;
+              v11 = list->uNumPointers;
               v14 = &pIndoor->pFaces[v7];
-              v12 = &a4->array_0004[v11];
-              v12->pObjectInfo = &pIndoor->pFaces[v7];
-              v12 = (Vis_stru1_stru0 *)((char *)v12 + 4);
-              v12->pObjectInfo = v15;
+              v12 = &list->object_pool[v11];
+              v12->object = &pIndoor->pFaces[v7];
+              v12 = (Vis_ObjectInfo *)((char *)v12 + 4);
+              v12->object = v15;
               v12->sZValue = v16;
               ++*pNumPointers;
             }
@@ -400,99 +385,40 @@
 }
 
 //----- (004C17CF) --------------------------------------------------------
-void Vis::PickOutdoor(float fDepth, RenderVertexSoft *pRay, Vis_stru1 *a4, stru157 *a5, char a6)
-{
-  int v6; // esi@1
-  unsigned int v7; // ecx@1
-  BSPModel *v8; // ebx@3
-  bool v9; // eax@3
-  int v10; // eax@8
-  ODMFace *v11; // esi@10
-  int v12; // ecx@12
-  int v13; // eax@12
-  unsigned int *pNumPointers; // eax@12
-  Vis_stru1_stru0 *v15; // edi@12
-  BLVFace thisa; // [sp+10h] [bp-B8h]@1
-  RenderVertexSoft a1; // [sp+70h] [bp-58h]@1
-  void *v18; // [sp+A0h] [bp-28h]@12
-  void *v19; // [sp+A4h] [bp-24h]@12
-  int v20; // [sp+A8h] [bp-20h]@12
-  int v21; // [sp+ACh] [bp-1Ch]@8
-  Vis *v22; // [sp+B0h] [bp-18h]@1
-  int v23; // [sp+B4h] [bp-14h]@9
-  int v24; // [sp+B8h] [bp-10h]@1
-  unsigned int v25; // [sp+BCh] [bp-Ch]@2
-  unsigned int v26; // [sp+C0h] [bp-8h]@1
-  int v27; // [sp+C4h] [bp-4h]@8
-
-  v22 = this;
-  v6 = 0;
-  v7 = 0;
-  v24 = 0;
-  v26 = 0;
-  a1.flt_2C = 0.0;
+void Vis::PickOutdoorFaces_Mouse(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, bool one_sided)
+{  
   if (!pOutdoor)
     return;
-  if ( (signed int)pOutdoor->uNumBModels > 0 )
+
+  for (uint i = 0; i < pOutdoor->uNumBModels; ++i)
   {
-    v25 = 0;
-    do
+    int v24;
+    if (!IsBModelVisible(i, &v24))
+      continue;
+    if (one_sided && !v24)
+      continue;
+
+    auto bmodel = &pOutdoor->pBModels[i];
+
+    for (uint j = 0; j < bmodel->uNumFaces; ++j)
     {
-      v8 = &pOutdoor->pBModels[v25 / 0xBC];
-      v9 = IsBModelVisible(v7, &v24);
-      if ( a6 )
+      auto face = bmodel->pFaces + j;
+      if (is_part_of_selection(face, filter))
       {
-        if ( v9 && v24 != v6 )
+        BLVFace blv_face;
+        blv_face.FromODM(face);
+        
+        RenderVertexSoft intersection;
+        if (Intersect_Ray_Face(pRay, pRay + 1, &fDepth, &intersection, &blv_face, i))
         {
-LABEL_8:
-          v10 = v8->uNumFaces;
-          v27 = v6;
-          v21 = v10;
-          if ( v10 > v6 )
-          {
-            v23 = v6;
-            do
-            {
-              v11 = (ODMFace *)((char *)v8->pFaces + v23);
-              if ( is_part_of_selection((BLVFace *)((char *)v8->pFaces + v23), a5) )
-              {
-                thisa.FromODM(v11);
-                if ( Intersect_Ray_Face(pRay, pRay + 1, &fDepth, &a1, &thisa, v26) )
-                {
-                  pGame->pIndoorCameraD3D->ViewTransform(&a1, 1u);
-                  v18 = v11;
-                  v13 = _48B561_mess_with_scaling_along_z(/*v12, */a1.vWorldViewPosition.x);
-                  LOWORD(v13) = 0;
-                  v20 = 2;
-                  v19 = (void *)((8 * (v27 | (v26 << 6)) | 6) + v13);
-                  pNumPointers = &a4->uNumPointers;
-                  v15 = &a4->array_0004[a4->uNumPointers];
-                  v15->pObjectInfo = v18;
-                  v15 = (Vis_stru1_stru0 *)((char *)v15 + 4);
-                  v15->pObjectInfo = v19;
-                  v15->sZValue = v20;
-                  ++*pNumPointers;
-                }
-              }
-              ++v27;
-              v23 += 308;
-            }
-            while ( v27 < v21 );
-            v6 = 0;
-          }
-          goto LABEL_15;
+          pGame->pIndoorCameraD3D->ViewTransform(&intersection, 1u);
+          int v13 = _48B561_mess_with_scaling_along_z(/*v12, */intersection.vWorldViewPosition.x);
+          LOWORD(v13) = (8 * (j | (i << 6)) | OBJECT_BModel) + v13;
+
+          list->AddObject(face, VisObjectType_Face, v13);
         }
       }
-      else
-      {
-        if ( v9 )
-          goto LABEL_8;
-      }
-LABEL_15:
-      v25 += 188;
-      v7 = v26++ + 1;
     }
-    while ( (signed int)v26 < (signed int)pOutdoor->uNumBModels );
   }
 }
 
@@ -501,39 +427,38 @@
 //{return DoesRayIntersectBillboard(fDepth, uD3DBillboardIdx);}
 
 //----- (004C1944) --------------------------------------------------------
-int Vis::_4C1944(int a2, unsigned int a3, int a4, int a5, int a6)
+int Vis::_4C1944(int object_id, unsigned int a3, int a4, int a5, int a6)
 {
   float v6; // ST00_4@3
   int result; // eax@4
-  stru157 v8; // [sp+18h] [bp-20h]@3
+  Vis_SelectionFilter v8; // [sp+18h] [bp-20h]@3
   __int64 v9; // [sp+2Ch] [bp-Ch]@3
   Vis *v14; // [sp+34h] [bp-4h]@1
 
   v14 = this;
 
-  static Vis_stru1 Vis_static_sub_4C1944_stru_F8BDE8;
+  static Vis_SelectionList Vis_static_sub_4C1944_stru_F8BDE8;
 
-  v8.field_4 = a2;
+  v8.object_id = object_id;
   v8.field_8 = a6;
   v8.field_C = a5;
   v8.field_10 = a4;
   v9 = a3;
   Vis_static_sub_4C1944_stru_F8BDE8.uNumPointers = 0;
   v6 = (double)a3;
-  v8.field_0 = 1;
-  _4C06F8(v6, &Vis_static_sub_4C1944_stru_F8BDE8, &v8);
-  Vis_static_sub_4C1944_stru_F8BDE8.create_object_pointers(1u);
+  v8.object_type = VisObjectType_Sprite;
+  PickBillboards_Keyboard(v6, &Vis_static_sub_4C1944_stru_F8BDE8, &v8);
+  Vis_static_sub_4C1944_stru_F8BDE8.create_object_pointers(Vis_SelectionList::Unique);
   sort_object_pointers(
-    Vis_static_sub_4C1944_stru_F8BDE8.array_1804,
+    Vis_static_sub_4C1944_stru_F8BDE8.object_pointers,
     0,
     Vis_static_sub_4C1944_stru_F8BDE8.uNumPointers - 1);
   if ( (signed int)Vis_static_sub_4C1944_stru_F8BDE8.uNumPointers <= 0 )
     result = -1;
   else
-    result = Vis_static_sub_4C1944_stru_F8BDE8.array_1804[0]->sZValue;
+    result = Vis_static_sub_4C1944_stru_F8BDE8.object_pointers[0]->sZValue;
   return result;
 }
-// F8DDF0: using guessed type char Vis_static_sub_4C1944_byte_F8DDF0_init;
 
 //----- (004C1A02) --------------------------------------------------------
 void Vis::_4C1A02()
@@ -626,39 +551,27 @@
 }
 
 //----- (004C1BAA) --------------------------------------------------------
-int Vis::get_object_zbuf_val(Vis_stru1_stru0 *a2)
+int Vis::get_object_zbuf_val(Vis_ObjectInfo *info)
 {
-  unsigned int v2; // eax@1
-  int result; // eax@3
-  std::string v4; // [sp-18h] [bp-1Ch]@4
-  const char *v5; // [sp-8h] [bp-Ch]@4
-  int v6; // [sp-4h] [bp-8h]@4
-  Vis *v7; // [sp+0h] [bp-4h]@1
+  switch (info->object_type)
+  {
+    case VisObjectType_Sprite:
+    case VisObjectType_Face:
+      return info->sZValue;
 
-  v7 = this;
-  v2 = a2->uObjectType;
-  if ( (signed int)v2 <= 0 || (signed int)v2 > 2 )
-  {
-    MessageBoxW(nullptr, L"Undefined type requested for: CVis::get_object_zbuf_val()", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:1037", 0);
-    result = -1;
+    default:
+      MessageBoxW(nullptr, L"Undefined type requested for: CVis::get_object_zbuf_val()", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:1037", 0);
+      return -1;
   }
-  else
-  {
-    result = a2->sZValue;
-  }
-  return result;
 }
 
 //----- (004C1BF1) --------------------------------------------------------
 int Vis::get_picked_object_zbuf_val()
 {
-  int result; // eax@2
+  if (!default_list.uNumPointers)
+    return -1;
 
-  if ( (signed int)this->stru1.uNumPointers <= 0 )
-    result = -1;
-  else
-    result = get_object_zbuf_val(this->stru1.array_1804[0]);
-  return result;
+  return get_object_zbuf_val(default_list.object_pointers[0]);
 }
 
 //----- (004C1C0C) --------------------------------------------------------
@@ -1126,12 +1039,12 @@
 }
 
 //----- (004C2551) --------------------------------------------------------
-Vis_stru1_stru0 *Vis_stru1::sub_4C2551(int a2, int a3)
+Vis_ObjectInfo *Vis_SelectionList::sub_4C2551(int a2, int a3)
 {
   unsigned int v3; // esi@1
   signed int v4; // edx@1
   char *v5; // eax@2
-  Vis_stru1_stru0 *result; // eax@6
+  Vis_ObjectInfo *result; // eax@6
 
   v3 = this->uNumPointers;
   v4 = 0;
@@ -1142,7 +1055,7 @@
   }
   else
   {
-    v5 = (char *)&this->array_0004[0].sZValue;
+    v5 = (char *)&this->object_pool[0].sZValue;
     while ( *((int *)v5 + 1) != a2 || (*(int *)v5 & 0xFFFF) != a3 )
     {
       ++v4;
@@ -1150,92 +1063,51 @@
       if ( v4 >= (signed int)v3 )
         goto LABEL_6;
     }
-    result = &this->array_0004[v4];
+    result = &this->object_pool[v4];
   }
   return result;
 }
 
 //----- (004C2591) --------------------------------------------------------
-Vis_stru1_stru0 **Vis_stru1::create_object_pointers(unsigned int flag)
+void Vis_SelectionList::create_object_pointers(PointerCreationType type)
 {
-  Vis_stru1_stru0 **result; // eax@1
-  signed int v3; // esi@2
-  Vis_stru1_stru0 *v4; // edx@3
-  unsigned __int8 v5; // zf@7
-  unsigned __int8 v6; // sf@7
-  Vis_stru1_stru0 **v7; // ebx@8
-  Vis_stru1_stru0 *v8; // esi@8
-  signed int v9; // edi@9
-  Vis_stru1_stru0 **v10; // edx@10
-  std::string v11; // [sp-18h] [bp-28h]@19
-  const char *v12; // [sp-8h] [bp-18h]@19
-  int v13; // [sp-4h] [bp-14h]@19
-  char v14; // [sp+Ch] [bp-4h]@19
+  switch (type)
+  {
+    case All:
+    {
+      for (uint i = 0; i < uNumPointers; ++i)
+        object_pointers[i] = &object_pool[i];
+    }
+    break;
 
-  result = 0;
-  if ( flag )
-  {
-    if ( flag == 1 )
-    {
-      v5 = this->uNumPointers == 0;
-      v6 = (this->uNumPointers & 0x80000000u) != 0;
-      BYTE3(flag) = 1;
-      if ( !(v6 | v5) )
+    case Unique: // seems quite retarted; the inner if condition will never trigger, since we compare pointers, not values. pointers will always be unique
+    {            // but it may be decompilation error thou
+      bool create = true;
+ 
+      for (uint i = 0; i < uNumPointers; ++i)
       {
-        v7 = this->array_1804;
-        v8 = this->array_0004;
-        do
+        for (uint j = 0; j < i; ++j)
         {
-          v9 = 0;
-          if ( (signed int)result > 0 )
+          if (object_pointers[j] == &object_pool[i])
           {
-            v10 = this->array_1804;
-            while ( *v10 != v8 )
-            {
-              ++v9;
-              ++v10;
-              if ( v9 >= (signed int)result )
-                goto LABEL_15;
-            }
-            BYTE3(flag) = 0;
+            create = false;
+            break;
           }
-LABEL_15:
-          if ( BYTE3(flag) )
-            *v7 = v8;
-          result = (Vis_stru1_stru0 **)((char *)result + 1);
-          ++v7;
-          ++v8;
         }
-        while ( (signed int)result < (signed int)this->uNumPointers );
+
+        if (create)
+          object_pointers[i] = &object_pool[i];
       }
     }
-    else
-    {
+    break;
+
+    default:
       MessageBoxW(nullptr, L"Unknown pointer creation flag passed to ::create_object_pointers()", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:1358", 0);
-    }
   }
-  else
-  {
-    v3 = 0;
-    if ( (signed int)this->uNumPointers > 0 )
-    {
-      result = this->array_1804;
-      v4 = this->array_0004;
-      do
-      {
-        *result = v4;
-        ++v3;
-        ++result;
-        ++v4;
-      }
-      while ( v3 < (signed int)this->uNumPointers );
-    }
-  }
-  return result;
 }
 
 //----- (004C264A) --------------------------------------------------------
-void Vis::sort_object_pointers(Vis_stru1_stru0 **pPointers, int left, int right)
+void Vis::sort_object_pointers(Vis_ObjectInfo **pPointers, int left, int right)
 {
   int v4; // edx@1
   int v5; // ebx@1
@@ -1244,9 +1116,9 @@
   int v8; // eax@3
   int v9; // ebx@4
   int v10; // ebx@6
-  Vis_stru1_stru0 *v11; // eax@7
+  Vis_ObjectInfo *v11; // eax@7
   Vis *thisa; // [sp+4h] [bp-4h]@1
-  Vis_stru1_stru0 *a3a; // [sp+14h] [bp+Ch]@2
+  Vis_ObjectInfo *a3a; // [sp+14h] [bp+Ch]@2
 
   v4 = left;
   v5 = right;
@@ -1410,15 +1282,14 @@
     memcpy(&v12, &v5[v8], sizeof(v12));
     memcpy(&v5[v8], v15, sizeof(v5[v8]));
     memcpy(v15, &v12, 0x20u);
-    //__debugbreak();
-    SortVerticesByX(v5, uStart, v8 - 1);
-    SortVerticesByX(a2, v8 + 1, uEnd);
+    SortVerticesByY(v5, uStart, v8 - 1);
+    SortVerticesByY(a2, v8 + 1, uEnd);
   }
   return true;
 }
 
 //----- (004C288E) --------------------------------------------------------
-bool Vis::sort_objects_2(RenderVertexSoft *pArray, int sLeft, int sRight)
+bool Vis::SortByScreenSpaceX(RenderVertexSoft *pArray, int sLeft, int sRight)
 {
   bool result; // eax@1
   RenderVertexSoft *v5; // edx@2
@@ -1433,11 +1304,11 @@
   //float v13; // [sp+4Ch] [bp-24h]@4
   int v14; // [sp+64h] [bp-Ch]@7
   //Vis *thisa; // [sp+68h] [bp-8h]@1
-  void *thisa;
+  //void *thisa;
   //RenderVertexSoft *v16; // [sp+6Ch] [bp-4h]@2
   const void *v16;
 
-  thisa = this;
+  //thisa = this;
   if (sRight <= sLeft)
     return true;
   v5 = pArray;
@@ -1472,13 +1343,13 @@
   memcpy(&v11, &v5[v6], sizeof(v11));
   memcpy(&v5[v6], v16, sizeof(v5[v6]));
   memcpy((void *)v16, &v11, sizeof(0x30u));
-  sort_objects_2(v5, sLeft, v6 - 1);
-  sort_objects_2(pArray, v6 + 1, sRight);
+  SortByScreenSpaceX(v5, sLeft, v6 - 1);
+  SortByScreenSpaceX(pArray, v6 + 1, sRight);
   return true;
 }
 
 //----- (004C297E) --------------------------------------------------------
-bool Vis::sort_objects_3(RenderVertexSoft *pArray, int sLeft, int sRight)
+bool Vis::SortByScreenSpaceY(RenderVertexSoft *pArray, int sLeft, int sRight)
 {
   //bool result; // eax@1
   RenderVertexSoft *v5; // edx@2
@@ -1530,8 +1401,8 @@
   memcpy(&v11, &v5[v6], sizeof(0x30));
   memcpy(&v5[v6], v16, sizeof(v5[v6]));
   memcpy((void *)v16, &v11, sizeof(0x30));
-  sort_objects_3(v5, sLeft, v6 - 1);
-  sort_objects_3(pArray, v6 + 1, sRight);
+  SortByScreenSpaceY(v5, sLeft, v6 - 1);
+  SortByScreenSpaceY(pArray, v6 + 1, sRight);
   return true;
 }
 
@@ -1539,12 +1410,9 @@
 //----- (004C04AF) --------------------------------------------------------
 Vis::Vis()
 {
-  Vis *v1; // ebx@1
-  Vis *result; // eax@1
   RenderVertexSoft v3; // [sp+Ch] [bp-60h]@1
   RenderVertexSoft v4; // [sp+3Ch] [bp-30h]@1
 
-  v1 = this;
   v3.flt_2C = 0.0;
   v3.vWorldPosition.x = 0.0;
   v3.vWorldPosition.y = 65536.0;
@@ -1553,202 +1421,197 @@
   v4.vWorldPosition.x = 65536.0;
   v4.vWorldPosition.y = 0.0;
   v4.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_200C, &v4, sizeof(v1->stru_200C));
+  memcpy(&stru_200C, &v4, sizeof(stru_200C));
+
   v4.flt_2C = 0.0;
   v4.vWorldPosition.x = 0.0;
   v4.vWorldPosition.y = 65536.0;
   v4.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_203C, &v3, sizeof(v1->stru_203C));
+  memcpy(&stru_203C, &v3, sizeof(stru_203C));
+
   v3.flt_2C = 0.0;
   v3.vWorldPosition.x = 65536.0;
   v3.vWorldPosition.y = 0.0;
   v3.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_206C, &v3, sizeof(v1->stru_206C));
-  result = v1;
-  memcpy(&v1->stru_209C, &v4, sizeof(v1->stru_209C));
-  v1->field_20CC = 512;
+  memcpy(&stru_206C, &v3, sizeof(stru_206C));
+  memcpy(&stru_209C, &v4, sizeof(stru_209C));
+
+  keyboard_pick_depth = 512;
 }
 
 //----- (004C055C) --------------------------------------------------------
-Vis_stru1::Vis_stru1()
+Vis_SelectionList::Vis_SelectionList()
 {
   for (uint i = 0; i < 512; ++i)
   {
-    array_0004[i].pObjectInfo = 0;
-    array_0004[i].sZValue = -1;
-    array_0004[i].uObjectType = 0;
+    object_pool[i].object = nullptr;
+    object_pool[i].sZValue = -1;
+    object_pool[i].object_type = VisObjectType_Any;
   }
   uNumPointers = 0;
 }
 
 //----- (004C05CC) --------------------------------------------------------
-bool Vis::PickKeyboard(Vis_stru1 *a2, stru157 *a3, stru157 *a4)
+bool Vis::PickKeyboard(Vis_SelectionList *list, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
 {
-  Vis_stru1 *v4; // esi@1
-  Vis *v5; // ebx@1
-  char *v6; // edi@3
-  float v7; // ST00_4@3
-  bool result; // eax@6
-  float v9; // [sp+4h] [bp-14h]@3
+  if (!list)
+    list = &default_list;
+  list->uNumPointers = 0;
 
-  v4 = a2;
-  v5 = this;
-  if ( !a2 )
-    v4 = &this->stru1;
-  v4->uNumPointers = 0;
-  v6 = (char *)&this->field_20CC;
-  v7 = (double)this->field_20CC;
-  _4C06F8(v7, v4, a3);
-  v9 = (double)*(signed int *)v6;
-  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
-    _4C0D32_BLV(v9, v4, a4);
+  PickBillboards_Keyboard(keyboard_pick_depth, list, sprite_filter);
+  if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+    PickIndoorFaces_Keyboard(keyboard_pick_depth, list, face_filter);
+  else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+    PickOutdoorFaces_Keyboard(keyboard_pick_depth, list, face_filter);
   else
-    _4C0DEA_ODM(v9, v4, a4);
-  v4->create_object_pointers(1u);
-  sort_object_pointers(v4->array_1804, 0, v4->uNumPointers - 1);
+    assert(false);
+
+  list->create_object_pointers(Vis_SelectionList::Unique);
+  sort_object_pointers(list->object_pointers, 0, list->uNumPointers - 1);
+
   return true;
 }
 
 //----- (004C0646) --------------------------------------------------------
-bool Vis::PickMouse(float fDepth, float fMouseX, float fMouseY, stru157 *a5, stru157 *a6)
+bool Vis::PickMouse(float fDepth, float fMouseX, float fMouseY, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
 {
   RenderVertexSoft pMouseRay[2]; // [sp+1Ch] [bp-60h]@1
 
-  stru1.uNumPointers = 0;
+  default_list.uNumPointers = 0;
   CastPickRay(pMouseRay, fMouseX, fMouseY, fDepth);
-  //PickBillboards(fDepth, fMouseX, fMouseY, &stru1, a5);//Ritor1: do comment to test
+  PickBillboards_Mouse(fDepth, fMouseX, fMouseY, &default_list, sprite_filter);
   if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
-    PickIndoor(fDepth, pMouseRay, &stru1, a6);
+    PickIndoorFaces_Mouse(fDepth, pMouseRay, &default_list, face_filter);
   else
-    PickOutdoor(fDepth, pMouseRay, &stru1, a6, 0);
-  stru1.create_object_pointers(0);
-  sort_object_pointers(stru1.array_1804, 0, stru1.uNumPointers - 1);
+    PickOutdoorFaces_Mouse(fDepth, pMouseRay, &default_list, face_filter, false);
+  default_list.create_object_pointers(Vis_SelectionList::All);
+  sort_object_pointers(default_list.object_pointers, 0, default_list.uNumPointers - 1);
+
   return true;
 }
 
 //----- (004C06F8) --------------------------------------------------------
-void Vis::_4C06F8(float arg0, Vis_stru1 *a3, stru157 *a2)
+void Vis::PickBillboards_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
-  int v4; // ST18_4@5
-  Vis_stru1_stru0 *v5; // edi@5
-  void **v7; // [sp+24h] [bp-8h]@2
-  unsigned int uD3DBillboardIdx; // [sp+28h] [bp-4h]@1
+  for (int i = 0; i < pRenderer->uNumBillboardsToDraw; ++i)
+  {
+    auto d3d_billboard = &pRenderer->pBillboardRenderListD3D[i];
 
-  uD3DBillboardIdx = 0;
-  auto ecx0 = this;
-  if ( (signed int)pRenderer->uNumBillboardsToDraw > 0 )
-  {
-    v7 = (void **)&pRenderer->pBillboardRenderListD3D[0].uParentBillboardID;
-    do
+    if (is_part_of_selection((void *)i, filter))
     {
-      if ( is_part_of_selection((BLVFace *)uD3DBillboardIdx, a2) )
+      if (DoesRayIntersectBillboard(pick_depth, i))
       {
-        if ( DoesRayIntersectBillboard(arg0, uD3DBillboardIdx) )
-        {
-          v4 = pBillboardRenderList[(int)*v7].sZValue;
-          v5 = &a3->array_0004[a3->uNumPointers];
-          v5->pObjectInfo = *v7;
-          v5 = (Vis_stru1_stru0 *)((char *)v5 + 4);
-          v5->pObjectInfo = (void *)v4;
-          v5->sZValue = 1;
-          ++a3->uNumPointers;
-        }
+        auto billboard = &pBillboardRenderList[d3d_billboard->uParentBillboardID];
+
+        list->AddObject((void *)d3d_billboard->uParentBillboardID, VisObjectType_Sprite, billboard->sZValue);
       }
-      ++uD3DBillboardIdx;
-      v7 += 39;
     }
-    while ( (signed int)uD3DBillboardIdx < (signed int)pRenderer->uNumBillboardsToDraw );
   }
 }
 
+
+// tests the object against selection filter to determine whether it can be picked or not
 //----- (004C0791) --------------------------------------------------------
-bool Vis::is_part_of_selection(BLVFace *uD3DBillboardIdx_or_pBLVFace_or_pODMFace, stru157 *a2)
+bool Vis::is_part_of_selection(void *uD3DBillboardIdx_or_pBLVFace_or_pODMFace, Vis_SelectionFilter *filter)
 {
-  stru157 *v3; // esi@1
-  int result; // eax@1
+  //stru157 *v3; // esi@1
+  //int result; // eax@1
   int v5; // edx@2
-  int v6; // ecx@2
-  char v7; // zf@3
+  //int v6; // ecx@2
+  //char v7; // zf@3
   int v8; // esi@5
   std::string *v9; // ecx@7
   Actor *v10; // edi@18
-  char v11; // zf@26
-  const char *v12; // [sp-20h] [bp-2Ch]@7
+  //const char *v12; // [sp-20h] [bp-2Ch]@7
   int v13; // [sp-1Ch] [bp-28h]@7
-  std::string v14; // [sp-18h] [bp-24h]@7
-  const char *v15; // [sp-8h] [bp-14h]@7
+  //std::string v14; // [sp-18h] [bp-24h]@7
+  //const char *v15; // [sp-8h] [bp-14h]@7
   int v16; // [sp-4h] [bp-10h]@7
 
-  v3 = a2;
-  result = a2->field_0;
-  if ( a2->field_0 != 1 )
+  switch (filter->object_type)
   {
-    if ( result != 2
-      || (uCurrentlyLoadedLevelType != LEVEL_Indoor ? (v11 = LOWORD(uD3DBillboardIdx_or_pBLVFace_or_pODMFace[3].pFacePlane.vNormal.y) == 0,
-                                            result = uD3DBillboardIdx_or_pBLVFace_or_pODMFace->pFacePlane_old.dist) : (v11 = pIndoor->pFaceExtras[uD3DBillboardIdx_or_pBLVFace_or_pODMFace->uFaceExtraID].uEventID == 0, result = uD3DBillboardIdx_or_pBLVFace_or_pODMFace->uAttributes),
-          a2->field_4 != 1) )
-      goto LABEL_16;
-    if ( v11 || result & a2->field_C )
-      goto LABEL_33;
-    v7 = (result & a2->field_8) == 0;
-    goto LABEL_32;
-  }
-  v5 = a2->field_10;
-  result = (pBillboardRenderList[pRenderer->pBillboardRenderListD3D[(int)uD3DBillboardIdx_or_pBLVFace_or_pODMFace].uParentBillboardID].sZValue & 0xFFFF) >> 3;
-  v6 = pBillboardRenderList[pRenderer->pBillboardRenderListD3D[(int)uD3DBillboardIdx_or_pBLVFace_or_pODMFace].uParentBillboardID].sZValue & 7;
-  if ( v5 & 2 )
-  {
-    v7 = v6 == a2->field_4;
-    goto LABEL_32;
-  }
-  if ( v5 & 4 )
-  {
-    v8 = a2->field_4;
-    if ( v6 != v8 )
-      goto LABEL_16;
-    if ( v8 != 5 )
+    case VisObjectType_Any:
+      return true;
+
+    case VisObjectType_Sprite:
     {
-      v15 = "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:207";
-      v12 = "Unsupported \"exclusion if no event\" type in CVis::is_part_of_selection";
-LABEL_15:
-          MessageBoxA(nullptr, v12, v15, 0);
-      return true;
+      v5 = filter->field_10;
+      int object_idx = (pBillboardRenderList[pRenderer->pBillboardRenderListD3D[(int)uD3DBillboardIdx_or_pBLVFace_or_pODMFace].uParentBillboardID].object_pid & 0xFFFF) >> 3;
+      int object_type = pBillboardRenderList[pRenderer->pBillboardRenderListD3D[(int)uD3DBillboardIdx_or_pBLVFace_or_pODMFace].uParentBillboardID].object_pid & 7;
+      if ( v5 & 2 )
+      {
+        if (object_type == filter->object_id)
+          return false;
+        return true;
+      }
+      if ( v5 & 4 )
+      {
+        v8 = filter->object_id;
+        if ( object_type != filter->object_id)
+          return true;
+        if (v8 != OBJECT_Decoration)
+        {
+          MessageBoxA(nullptr, "Unsupported \"exclusion if no event\" type in CVis::is_part_of_selection", "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:207", 0);
+          return true;
+        }
+        if (pLevelDecorations[object_idx].uCog || pLevelDecorations[object_idx].field_16_event_id)
+          return true;
+        return pLevelDecorations[object_idx].IsInteractive();
+      }
+      if (object_type == filter->object_id)
+      {
+        if (object_type != OBJECT_Actor)
+        {
+          MessageBoxA(nullptr, "Default case reached in VIS", "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:245", 0);
+          return true;
+        }
+
+        v10 = &pActors[object_idx];
+        int result = 1 << LOBYTE(v10->uAIState);
+        if ( result & filter->field_C
+            || !(result & filter->field_8)
+            || v5 & 8 && (result = MonsterStats::BelongsToSupertype(v10->pMonsterInfo.uID, MONSTER_SUPERTYPE_UNDEAD)) == 0 )
+          return false;
+        if ( !(filter->field_10 & 1) )
+          return true;
+
+        result = v10->GetActorsRelation(nullptr);
+        if (result == 0)
+          return false;
+        return true;
+      }
+      return false;
     }
-    result *= 32;
-    if ( *(__int16 *)((char *)&pLevelDecorations[0].uCog + result)
-      || *(__int16 *)((char *)&pLevelDecorations[0].field_16_event_id + result) )
-      goto LABEL_16;
-    result = pLevelDecorations[result / sizeof(LevelDecoration)].IsInteractive();
-    goto LABEL_11;
-  }
-  if ( v6 == a2->field_4 )
-  {
-    if ( v6 != 3 )
+
+    case VisObjectType_Face:
     {
-      v15 = "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:245";
-      v12 = "Default case reached in VIS";
-      goto LABEL_15;
+      uint face_attrib = 0;
+      bool no_event = true;
+      if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+      {
+        auto face = (ODMFace *)uD3DBillboardIdx_or_pBLVFace_or_pODMFace;
+        no_event = face->sCogTriggeredID == 0;
+        face_attrib = face->uAttributes;
+      }
+      else if (uCurrentlyLoadedLevelType == LEVEL_Indoor) 
+      {
+        auto face = (BLVFace *)uD3DBillboardIdx_or_pBLVFace_or_pODMFace;
+        no_event = pIndoor->pFaceExtras[face->uFaceExtraID].uEventID == 0;
+        face_attrib = face->uAttributes;
+      }
+      else
+        assert(false);
+
+      if (filter->object_id != OBJECT_BLVDoor)
+        return true;
+      if (no_event || face_attrib & filter->field_C)
+        return false;
+      return (face_attrib & filter->field_8) != 0;
     }
-    v10 = &pActors[result];
-    result = 1 << LOBYTE(v10->uAIState);
-    if ( result & a2->field_C
-      || !(result & a2->field_8)
-      || v5 & 8 && (result = MonsterStats::BelongsToSupertype(v10->pMonsterInfo.uID, MONSTER_SUPERTYPE_UNDEAD)) == 0 )
-      goto LABEL_33;
-    if ( !(v3->field_10 & 1) )
-      goto LABEL_16;
-    result = v10->GetActorsRelation(nullptr);
-LABEL_11:
-    v7 = result == 0;
-LABEL_32:
-    if ( v7 )
-      goto LABEL_33;
-LABEL_16:
-    return true;
+
+    default:
+      assert(false);
   }
-LABEL_33:
-  LOBYTE(result) = 0;
-  return result;
 }
 
 //----- (004C091D) --------------------------------------------------------
@@ -1758,8 +1621,8 @@
   //signed int v5; // ecx@4
   //float v6; // ST04_4@6
   //float v7; // ST00_4@7
-  int v8; // eax@10
-  unsigned int v9; // eax@12
+  //int v8; // eax@10
+  //unsigned int v9; // eax@12
   int v10; // eax@17
   double v11; // st6@18
   double v12; // st7@18
@@ -1768,8 +1631,8 @@
   float v15; // ST08_4@22
   //float v16; // ST04_4@23
   //float v17; // ST00_4@24
-  signed int v18; // eax@27
-  unsigned int v19; // eax@29
+  //signed int v18; // eax@27
+  //unsigned int v19; // eax@29
   double v20; // st6@32
   double v21; // st7@32
   int v22; // eax@32
@@ -1789,13 +1652,13 @@
   float v34; // [sp+E4h] [bp-18h]@32
   int v35; // [sp+E8h] [bp-14h]@5
   int v36; // [sp+ECh] [bp-10h]@5
-  unsigned int v37; // [sp+F0h] [bp-Ch]@5
+  int v37; // [sp+F0h] [bp-Ch]@5
   float v38; // [sp+F4h] [bp-8h]@17
   //void *v39; // [sp+F8h] [bp-4h]@1
   signed int v40; // [sp+108h] [bp+Ch]@17
   float v41; // [sp+108h] [bp+Ch]@32
 
-  static Vis_stru1 Vis_static_stru_F91E10;
+  static Vis_SelectionList Vis_static_stru_F91E10;
   Vis_static_stru_F91E10.uNumPointers = 0;
   v3 = pRenderer->pBillboardRenderListD3D[uD3DBillboardIdx].uParentBillboardID;
   if (v3 == -1)
@@ -1805,26 +1668,20 @@
 LABEL_49:
     return false;
   }
-  else
-  {
+
     v37 = pBillboardRenderList[v3].sZValue & 0xFFFF0000;
     GetPolygonCenter(pRenderer->pBillboardRenderListD3D[v3].pQuards, 4, (float *)&v35, (float *)&v36);
-    this->CastPickRay(pPickingRay, *(float *)&v35, *(float *)&v36, fDepth);
-    if (uCurrentlyLoadedLevelType == 1)
-      PickIndoor(fDepth, pPickingRay, &Vis_static_stru_F91E10, &a5);
+    CastPickRay(pPickingRay, *(float *)&v35, *(float *)&v36, fDepth);
+    if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+      PickIndoorFaces_Mouse(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter);
     else
-      PickOutdoor(fDepth, pPickingRay, &Vis_static_stru_F91E10, &a5, 0);
-    Vis_static_stru_F91E10.create_object_pointers(0);
-    sort_object_pointers(Vis_static_stru_F91E10.array_1804, 0, Vis_static_stru_F91E10.uNumPointers - 1);
+      PickOutdoorFaces_Mouse(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter, false);
+    Vis_static_stru_F91E10.create_object_pointers();
+    sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1);
     if (Vis_static_stru_F91E10.uNumPointers)
     {
-     if (Vis_static_stru_F91E10.uNumPointers <= 0)
-       v8 = 0;
-     else v8 = (int)Vis_static_stru_F91E10.array_1804;
-     v9 = *(_DWORD *)(v8 + 4);
-     LOWORD(v9) = 0;
-     if (v9 > v37)
-       return 1;
+       if (Vis_static_stru_F91E10.object_pointers[0]->actual_z > pBillboardRenderList[v3].actual_z)
+         return 1;
     }
     else if ((double)(pViewport->uScreenX) <= *(float *)&v35 &&
              (double)pViewport->uScreenZ >= *(float *)&v35 &&
@@ -1852,18 +1709,21 @@
                 v15 = v12;
                 CastPickRay(local_80, SLODWORD(v15), v14, fDepth);
                 if ( uCurrentlyLoadedLevelType == 1 )
-                  PickIndoor(fDepth, local_80, &Vis_static_stru_F91E10, &a5);
+                  PickIndoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter);
                 else
-                  PickOutdoor(fDepth, local_80, &Vis_static_stru_F91E10, &a5, 0);
-                Vis_static_stru_F91E10.create_object_pointers(0);
-                sort_object_pointers(Vis_static_stru_F91E10.array_1804, 0, Vis_static_stru_F91E10.uNumPointers - 1);
+                  PickOutdoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, false);
+                Vis_static_stru_F91E10.create_object_pointers();
+                sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1);
                 if ( !Vis_static_stru_F91E10.uNumPointers )
                   break;
-                v18 = Vis_static_stru_F91E10.uNumPointers <= 0 ? 0 : (int)Vis_static_stru_F91E10.array_1804;
-                v19 = *(_DWORD *)(v18 + 4);
-                LOWORD(v19) = 0;
-                if ( v19 > v37 )
+                else
+                {
+                //v18 = Vis_static_stru_F91E10.uNumPointers <= 0 ? 0 : (int);
+                //v19 = *(_DWORD *)(v18 + 4);
+                //LOWORD(v19) = 0;
+                if (Vis_static_stru_F91E10.object_pointers[0]->actual_z > pBillboardRenderList[v3].actual_z)
                   break;
+                }
               }
             }
           }
@@ -1896,12 +1756,12 @@
             || (double)pViewport->uScreenY > v41
             || (double)pViewport->uScreenW < v41
             || ((v25 = v23, CastPickRay(local_80, SLODWORD(v25), v41, fDepth), uCurrentlyLoadedLevelType != 1) ? 
-             (PickOutdoor(fDepth, local_80, &Vis_static_stru_F91E10, &a5, 0)) : 
-             (PickIndoor(fDepth, local_80, &Vis_static_stru_F91E10, &a5)),
-             (Vis_static_stru_F91E10.create_object_pointers(0),
-              sort_object_pointers(Vis_static_stru_F91E10.array_1804, 0, Vis_static_stru_F91E10.uNumPointers - 1),
+             (PickOutdoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, false)) : 
+             (PickIndoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter)),
+             (Vis_static_stru_F91E10.create_object_pointers(),
+              sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1),
               Vis_static_stru_F91E10.uNumPointers)
-             && (Vis_static_stru_F91E10.uNumPointers <= 0 ? (v28 = 0) : (v28 = (int)Vis_static_stru_F91E10.array_1804),
+             && (Vis_static_stru_F91E10.uNumPointers <= 0 ? (v28 = 0) : (v28 = (int)Vis_static_stru_F91E10.object_pointers),
                  v29 = *(_DWORD *)(v28 + 4),
                  LOWORD(v29) = 0,
                  v29 <= v37)) )
@@ -1909,23 +1769,21 @@
           break;
         }
       }
-    result = 1;
-  }
-  return result;
+  return true;
 }
 // F93E18: using guessed type char static_byte_F93E18_init;
 
 //----- (004C0D32) --------------------------------------------------------
-int Vis::_4C0D32_BLV(float a1, Vis_stru1 *arg4, stru157 *a2)
+void Vis::PickIndoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
   int result; // eax@1
   signed int v5; // esi@2
   BLVFace *v6; // edi@4
   unsigned int v7; // eax@6
-  Vis_stru1_stru0 *v8; // eax@6
-  int v9; // ST18_4@7
-  unsigned int v10; // ST1C_4@7
-  unsigned int v11; // ecx@7
+  Vis_ObjectInfo *v8; // eax@6
+  //int v9; // ST18_4@7
+  //unsigned int v10; // ST1C_4@7
+  //unsigned int v11; // ecx@7
   signed int i; // [sp+18h] [bp-8h]@1
   Vis *thisa; // [sp+1Ch] [bp-4h]@1
 
@@ -1941,108 +1799,46 @@
         v6 = &pIndoor->pFaces[v5];
         if ( !pGame->pIndoorCameraD3D->IsCulled(&pIndoor->pFaces[v5]) )
         {
-          if ( is_part_of_selection(v6, a2) )
+          if ( is_part_of_selection(v6, filter) )
           {
             v7 = 8 * v5;
-            LOBYTE(v7) = 8 * v5 | 6;
-            v8 = _4C1026(v6, v7, a1);
+            LOBYTE(v7) = 8 * v5 | OBJECT_BModel;
+            v8 = _4C1026(v6, v7, pick_depth);
             if ( v8 )
-            {
-              v9 = v8->sZValue;
-              v10 = v8->uObjectType;
-              v11 = 3 * arg4->uNumPointers;
-              arg4->array_0004[arg4->uNumPointers].pObjectInfo = v8->pObjectInfo;
-              arg4->array_0004[4 * v11 / 0xC].sZValue = v9;
-              arg4->array_0004[4 * v11 / 0xC].uObjectType = v10;
-              ++arg4->uNumPointers;
-            }
+              list->AddObject(v8->object, v8->object_type, v8->sZValue);
           }
         }
       }
     }
     result = i + 1;
   }
-  return result;
 }
 
 //----- (004C0DEA) --------------------------------------------------------
-void Vis::_4C0DEA_ODM(float arg0, Vis_stru1 *a3, stru157 *a2)
+void Vis::PickOutdoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
-  int v4; // esi@1
-  BSPModel *v5; // ebx@3
-  unsigned __int8 v6; // zf@5
-  char v7; // sf@5
-  unsigned __int8 v8; // of@5
-  ODMFace *v9; // esi@7
-  unsigned int v10; // eax@8
-  Vis_stru1_stru0 *v11; // eax@8
-  unsigned int v12; // ecx@9
-  BLVFace f; // [sp+10h] [bp-84h]@1
-  void *v14; // [sp+70h] [bp-24h]@9
-  int v15; // [sp+74h] [bp-20h]@9
-  unsigned int v16; // [sp+78h] [bp-1Ch]@9
-  int v17; // [sp+7Ch] [bp-18h]@1
-  Vis *v18; // [sp+80h] [bp-14h]@1
-  int v19; // [sp+84h] [bp-10h]@6
-  unsigned int v20; // [sp+88h] [bp-Ch]@2
-  int v21; // [sp+8Ch] [bp-8h]@5
-  int a1; // [sp+90h] [bp-4h]@1
+  for (uint i = 0; i < pOutdoor->uNumBModels; ++i)
+  {
+    int v17;
+    if (!IsBModelVisible(i, &v17))
+      continue;
+    if (!v17)
+      continue;
 
-  auto ecx0 = this;
-  v18 = ecx0;
-  v4 = 0;
-  v17 = 0;
-  a1 = 0;
-  if ( (signed int)pOutdoor->uNumBModels > 0 )
-  {
-    v20 = 0;
-    do
+    auto bmodel = pOutdoor->pBModels + i;
+    for (uint j = 0; j < bmodel->uNumFaces; ++j)
     {
-      v5 = &pOutdoor->pBModels[v20 / 0xBC];
-      if ( IsBModelVisible(a1, &v17) )
+      auto face = bmodel->pFaces + j;
+
+      if (is_part_of_selection(face, filter) )
       {
-        if ( v17 != v4 )
-        {
-          v8 = __OFSUB__(v5->uNumFaces, v4);
-          v6 = v5->uNumFaces == v4;
-          v7 = ((v5->uNumFaces - v4) & 0x80000000u) != 0;
-          v21 = v4;
-          if ( !((unsigned __int8)(v7 ^ v8) | v6) )
-          {
-            v19 = v4;
-            do
-            {
-              v9 = (ODMFace *)((char *)v5->pFaces + v19);
-              if ( is_part_of_selection((BLVFace *)((char *)v5->pFaces + v19), a2) )
-              {
-                f.FromODM(v9);
-                v10 = 8 * (v21 | (a1 << 6));
-                LOBYTE(v10) = v10 | 6;
-                v11 = _4C1026(&f, v10, arg0);
-                if ( v11 )
-                {
-                  v14 = v11->pObjectInfo;
-                  v15 = v11->sZValue;
-                  v12 = a3->uNumPointers;
-                  v16 = v11->uObjectType;
-                  v12 *= 3;
-                  *((int *)&a3->array_0004[0].pObjectInfo + v12) = (int)v14;
-                  *(&a3->array_0004[0].sZValue + v12) = v15;
-                  *(&a3->array_0004[0].uObjectType + v12) = v16;
-                  ++a3->uNumPointers;
-                }
-              }
-              ++v21;
-              v19 += 308;
-            }
-            while ( v21 < (signed int)v5->uNumFaces );
-            v4 = 0;
-          }
-        }
+        BLVFace blv_face;
+        blv_face.FromODM(face);
+
+        int pid = 8 * (j | (i << 6)) | OBJECT_BModel;
+        if (auto object_info = _4C1026(&blv_face, pid, pick_depth))
+          list->AddObject(object_info->object, object_info->object_type, object_info->sZValue);
       }
-      ++a1;
-      v20 += 188;
     }
-    while ( a1 < (signed int)pOutdoor->uNumBModels );
   }
 }
\ No newline at end of file
--- a/Vis.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/Vis.h	Sun Feb 17 11:41:44 2013 +0400
@@ -3,31 +3,77 @@
 
 
 
+enum VisObjectType: unsigned __int32
+{
+  VisObjectType_Any = 0,
+  VisObjectType_Sprite = 1,
+  VisObjectType_Face = 2
+};
+
+/*  150 */
+#pragma pack(push, 1)
+struct Vis_SelectionFilter //stru157
+{
+  VisObjectType object_type;
+  int object_id;  // OBJECT_Actor, OBJECT_Player etc
+  int field_8;
+  int field_C;
+  int field_10;
+};
+#pragma pack(pop)
+extern Vis_SelectionFilter vis_sprite_filter_1; // 00F93E1C
+extern Vis_SelectionFilter vis_sprite_filter_2; // 00F93E30
+extern Vis_SelectionFilter vis_face_filter;     // 00F93E44
+extern Vis_SelectionFilter vis_door_filter;     // 00F93E58
+extern Vis_SelectionFilter vis_sprite_filter_3; // 00F93E6C
+extern Vis_SelectionFilter vis_sprite_filter_4; // static to sub_44EEA7
 
 
 
 #pragma pack(push, 1)
-struct Vis_stru1_stru0
+struct Vis_ObjectInfo
 {
-  void *pObjectInfo;
-  int sZValue;
-  unsigned int uObjectType;
+  void *object;
+  union
+  {
+    int sZValue;
+    struct
+    {
+      unsigned __int16 object_pid;
+      signed __int16 actual_z;
+    };
+  };
+  VisObjectType object_type;
 };
 #pragma pack(pop)
 
+
 #pragma pack(push, 1)
-struct Vis_stru1
+struct Vis_SelectionList
 {
-  Vis_stru1();
+  enum PointerCreationType
+  {
+    All = 0,
+    Unique = 1
+  };
+
+  Vis_SelectionList();
   //----- (004C0585) --------------------------------------------------------
-  ~Vis_stru1() {}
-  Vis_stru1_stru0 *sub_4C2551(int a2, int a3);
-  Vis_stru1_stru0 **create_object_pointers(unsigned int flag);
+  ~Vis_SelectionList() {}
+  Vis_ObjectInfo *sub_4C2551(int a2, int a3);
+  void            create_object_pointers(PointerCreationType type = All);
 
-  void (__thiscall ***vdestructor_ptr)(Vis_stru1 *, bool);
-  Vis_stru1_stru0 array_0004[512];
-  Vis_stru1_stru0 *array_1804[512];
-  unsigned int uNumPointers;
+  inline void AddObject(void *object, VisObjectType type, int packed_zval)
+  {
+    object_pool[uNumPointers].object = object;
+    object_pool[uNumPointers].object_type = type;
+    object_pool[uNumPointers++].sZValue = packed_zval;
+  }
+
+  void (__thiscall ***vdestructor_ptr)(Vis_SelectionList *, bool);
+  Vis_ObjectInfo  object_pool[512];
+  Vis_ObjectInfo *object_pointers[512];
+  unsigned int    uNumPointers;
 };
 #pragma pack(pop)
 
@@ -42,43 +88,45 @@
   //virtual ~Vis() {}
   //----- (004C05BE) --------------------------------------------------------
   ~Vis() {}
-  bool PickKeyboard(Vis_stru1 *a2, struct stru157 *a3, struct stru157 *a4);
-  bool PickMouse(float fDepth, float fMouseX, float fMouseY, struct stru157 *a5, struct stru157 *a6);
-  void _4C06F8(float arg0, Vis_stru1 *a3, struct stru157 *a2);
-  bool is_part_of_selection(struct BLVFace *uD3DBillboardIdx_or_pBLVFace_or_pODMFace, struct stru157 *a2);
+  bool PickKeyboard(Vis_SelectionList *list, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter);
+  void PickBillboards_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickIndoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickOutdoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+
+  bool PickMouse(float fDepth, float fMouseX, float fMouseY, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter);
+  void PickBillboards_Mouse(float fPickDepth, float fX, float fY, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickIndoorFaces_Mouse(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickOutdoorFaces_Mouse(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, bool one_sided);
+
+  bool is_part_of_selection(void *uD3DBillboardIdx_or_pBLVFace_or_pODMFace, Vis_SelectionFilter *filter);
   bool DoesRayIntersectBillboard(float fDepth, unsigned int uD3DBillboardIdx);
-  int _4C0D32_BLV(float a1, Vis_stru1 *arg4, struct stru157 *a2);
-  void _4C0DEA_ODM(float arg0, Vis_stru1 *a3, struct stru157 *a2);
-  Vis_stru1_stru0 *_4C1026(struct BLVFace *a2, unsigned int a3, float a4);
-  char _4C12C3_FindSomeBillboard(struct RenderVertexSoft *a1, int a2, float a3, float a4);
+  Vis_ObjectInfo *_4C1026(struct BLVFace *face, unsigned int a3, float pick_depth);
+  bool IsPolygonOccludedByBillboard(struct RenderVertexSoft *vertices, int num_vertices, float x, float y);
   void GetPolygonCenter(struct RenderVertexD3D3 *pVertices, unsigned int uNumVertices, float *pCenterX, float *pCenterY);
-  float *_4C1495(struct RenderVertexSoft *Src, int a2, float *a3, float *a4);
-  void PickBillboards(float fPickDepth, float fX, float fY, Vis_stru1 *a4, stru157 *a2);
+  void GetPolygonScreenSpaceCenter(struct RenderVertexSoft *vertices, int num_vertices, float *out_center_x, float *out_center_y);
   bool IsPointInsideD3DBillboard(struct RenderBillboardD3D *a1, float x, float y);
-  void PickIndoor(float fDepth, struct RenderVertexSoft *pRay, Vis_stru1 *a4, stru157 *a5);
-  void PickOutdoor(float fDepth, struct RenderVertexSoft *pRay, Vis_stru1 *a4, stru157 *a5, char a6);
-  int _4C1944(int a2, unsigned int a3, int a4, int a5, int a6);
+  int _4C1944(int object_id, unsigned int a3, int a4, int a5, int a6);
   void _4C1A02();
   bool SortVectors_x(RenderVertexSoft *a2, int a3, int a4);
-  int get_object_zbuf_val(Vis_stru1_stru0 *a2);
+  int get_object_zbuf_val(Vis_ObjectInfo *info);
   int get_picked_object_zbuf_val();
   bool Intersect_Ray_Face(struct RenderVertexSoft *pRayStart, struct RenderVertexSoft *pRayEnd, float *pDepth, RenderVertexSoft *a4, BLVFace *a5, unsigned int a6);
   int _4C1D2B(BLVFace *pFace, Vec3_short_ a2, unsigned int uModelID);
   bool _4C1EE5_BLV_IntersectBModel_2(int *a1, int *a2, __int16 *a3, __int16 *a4, Vec3_short_ *a5, BLVFace *pFace);
   bool _4C2186_BLV_IntersectBModel(int *a1, int *a2, __int16 *a3, __int16 *a4, Vec3_short_ *a5, BLVFace *a6, unsigned int uModelID);
   void CastPickRay(RenderVertexSoft *pRay, float fMouseX, float fMouseY, float fPickDepth);
-  void sort_object_pointers(Vis_stru1_stru0 **pPointers, int left, int right);
+  void sort_object_pointers(Vis_ObjectInfo **pPointers, int left, int right);
   bool SortVerticesByX(struct RenderVertexD3D3 *a2, unsigned int uStart, unsigned int uEnd);
   bool SortVerticesByY(struct RenderVertexD3D3 *a2, unsigned int uStart, unsigned int uEnd);
-  bool sort_objects_2(struct RenderVertexSoft *pArray, int sLeft, int sRight);
-  bool sort_objects_3(struct RenderVertexSoft *pArray, int sLeft, int sRight);
+  bool SortByScreenSpaceX(struct RenderVertexSoft *pArray, int sLeft, int sRight);
+  bool SortByScreenSpaceY(struct RenderVertexSoft *pArray, int sLeft, int sRight);
 
   void (__thiscall ***vdestructor_ptr)(Vis *, bool);
-  Vis_stru1 stru1;
-  RenderVertexSoft stru_200C;
-  RenderVertexSoft stru_203C;
-  RenderVertexSoft stru_206C;
-  RenderVertexSoft stru_209C;
-  int field_20CC;
+  Vis_SelectionList default_list;
+  RenderVertexSoft  stru_200C;
+  RenderVertexSoft  stru_203C;
+  RenderVertexSoft  stru_206C;
+  RenderVertexSoft  stru_209C;
+  int keyboard_pick_depth;
 };
 #pragma pack(pop)
--- a/mm7_1.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_1.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -3432,6 +3432,7 @@
   a4 = (char *)v106.uViewportY;
   if ( v119 )
   {
+    __debugbreak(); // following format strings are decompiled incorrectly
     sprintf(pTmpBuf, "%s", pGlobalTXT_LocalizationStrings[108], 0, v121->pMonsterInfo.uHP);
     a1->DrawText(v56, 150, (int)a4, a5, pTmpBuf, 0, 0, 0);
     a4 = &a4[LOBYTE(v56->uFontHeight) - 3];
@@ -3442,6 +3443,7 @@
   }
   else
   {
+    __debugbreak(); // following format strings are decompiled incorrectly
     sprintf(pTmpBuf, "%s", pGlobalTXT_LocalizationStrings[108], 0, pGlobalTXT_LocalizationStrings[630]);
     a1->DrawText(v56, 150, (int)a4, a5, pTmpBuf, 0, 0, 0);
     v79 = (unsigned int)pGlobalTXT_LocalizationStrings[630];
@@ -3466,6 +3468,7 @@
   v105 = pGlobalTXT_LocalizationStrings[54];
   if ( v116 )
   {
+    __debugbreak(); // following format strings are decompiled incorrectly
     sprintf(pTmpBuf, "%s", pGlobalTXT_LocalizationStrings[18], 0, (&v95)[4 * v121->pMonsterInfo.uAttack1Type]);
     a1->DrawText(v56, 150, (int)a4, a5, pTmpBuf, 0, 0, 0);
     a4 = &a4[LOBYTE(v56->uFontHeight) - 3];
@@ -3490,6 +3493,7 @@
   }
   else
   {
+    __debugbreak(); // following format strings are decompiled incorrectly
     sprintf(pTmpBuf, "%s", pGlobalTXT_LocalizationStrings[18], 0, pGlobalTXT_LocalizationStrings[630]);
     a1->DrawText(v56, 150, (int)a4, a5, pTmpBuf, 0, 0, 0);
     a4 = &a4[LOBYTE(v56->uFontHeight) - 3];
@@ -3597,7 +3601,8 @@
     i = 0;
     do
     {
-      sprintf(pTmpBuf, "%s", (&v85)[4 * i], 0, pGlobalTXT_LocalizationStrings[630]);
+      __debugbreak(); // string argument is decompiled incorrectry
+      sprintf(pTmpBuf, "%s", (&v85)[4 * i], 0, pGlobalTXT_LocalizationStrings[630]); // "?"
       a1->DrawText(v56, 170, (int)a4, a5, pTmpBuf, 0, 0, 0);
       v65 = LOBYTE(v56->uFontHeight);
       ++i;
@@ -4090,7 +4095,7 @@
     if ( v22 == v5 )
     {
       if ( uActiveCharacter )
-        pPlayers[uActiveCharacter]->PlaySound(SPEECH_15, 0);
+        pPlayers[uActiveCharacter]->PlaySound(SPEECH_NoRoom, 0);
       return 0;
     }
     v7 = pIcons_LOD->LoadTexture(pItemsTable->pItems[v4->uItemID].pIconName, TEXTURE_16BIT_PALETTE);
@@ -5729,46 +5734,46 @@
 //----- (00421D00) --------------------------------------------------------
 void __fastcall GameUI_OnPlayerPortraitLeftClick(unsigned int uPlayerID)
 {
-  unsigned int v1; // esi@1
-  int v2; // eax@2
-  Player *v3; // ecx@2
-  Player *v4; // ecx@5
+  //unsigned int v1; // esi@1
+  //int v2; // eax@2
+  //Player *v3; // ecx@2
+  //Player *v4; // ecx@5
   unsigned int v5; // [sp-4h] [bp-10h]@21
 
-  v1 = uPlayerID;
-  if ( pParty->pPickedItem.uItemID )
-  {
-    v2 = pPlayers[uPlayerID]->AddItem(0xFFFFFFFFu, pParty->pPickedItem.uItemID);
-    v3 = pPlayers[v1];
-    if ( v2 )
-    {
-      memcpy(&v3->spellbook.pDarkSpellbook.bIsSpellAvailable[36 * v2 + 5], &pParty->pPickedItem, 0x24u);
-      viewparams->bRedrawGameUI = 1;
+  //v1 = uPlayerID;
+  auto player = &pParty->pPlayers[uPlayerID - 1];
+  if (pParty->pPickedItem.uItemID)
+  {
+    //v3 = player;
+    if (auto slot = player->AddItem(0xFFFFFFFFu, pParty->pPickedItem.uItemID))
+    {
+      __debugbreak(); // invalid inventory indexing
+      memcpy(&player->spellbook.pDarkSpellbook.bIsSpellAvailable[36 * slot + 5], &pParty->pPickedItem, 0x24u);
+      viewparams->bRedrawGameUI = true;
       pMouse->RemoveHoldingItem();
       return;
     }
-    if ( v3->CanAct() )
-    {
-      v4 = pPlayers[v1];
-    }
-    else
-    {
-      if ( !pPlayers[uActiveCharacter]->CanAct() )
+
+    if (!player->CanAct())
+    {
+      if ( pPlayers[uActiveCharacter]->CanAct())
         goto LABEL_9;
-      v4 = pPlayers[uActiveCharacter];
-    }
-    v4->PlaySound(SPEECH_15, 0);
-  }
+      player = pPlayers[uActiveCharacter];
+    }
+    player->PlaySound(SPEECH_NoRoom, 0);
+  }
+
 LABEL_9:
-  if ( !pCurrentScreen )
-  {
-    viewparams->bRedrawGameUI = 1;
-    if ( uActiveCharacter != v1 )
+  if (pCurrentScreen == SCREEN_GAME)
+  {
+    viewparams->bRedrawGameUI = true;
+    if ( uActiveCharacter != uPlayerID )
       //goto LABEL_27;
     {
-      if ( pPlayers[v1]->uTimeToRecovery )
+      if ( pPlayers[uPlayerID]->uTimeToRecovery )
         return;
-      uActiveCharacter = v1;
+
+      uActiveCharacter = uPlayerID;
       return;
     }
     v5 = 7;
@@ -5781,20 +5786,20 @@
   if ( pCurrentScreen == SCREEN_CHEST )
   {
 //LABEL_23:
-    viewparams->bRedrawGameUI = 1;
-    if ( uActiveCharacter == v1 )
+    viewparams->bRedrawGameUI = true;
+    if ( uActiveCharacter == uPlayerID )
     {
       pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] = 103;
       pCurrentScreen = SCREEN_F;
       //goto LABEL_28;
-      uActiveCharacter = v1;
+      uActiveCharacter = uPlayerID;
       return;
     }
 //LABEL_27:
-    if ( pPlayers[v1]->uTimeToRecovery )
+    if ( pPlayers[uPlayerID]->uTimeToRecovery )
       return;
     //goto LABEL_28;
-    uActiveCharacter = v1;
+    uActiveCharacter = uPlayerID;
     return;
   }
   if ( pCurrentScreen != SCREEN_HOUSE )
@@ -5802,40 +5807,40 @@
     if ( pCurrentScreen == SCREEN_E )
     {
 //LABEL_28:
-      uActiveCharacter = v1;
+      uActiveCharacter = uPlayerID;
       return;
     }
     if ( pCurrentScreen != SCREEN_F )
     {
-      viewparams->bRedrawGameUI = 1;
-      uActiveCharacter = v1;
+      viewparams->bRedrawGameUI = true;
+      uActiveCharacter = uPlayerID;
       if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 102 )
         sub_419100();
       return;
     }
     //goto LABEL_23;
-    viewparams->bRedrawGameUI = 1;
-    if ( uActiveCharacter == v1 )
+    viewparams->bRedrawGameUI = true;
+    if ( uActiveCharacter == uPlayerID )
     {
       pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] = 103;
       pCurrentScreen = SCREEN_F;
       //goto LABEL_28;
-      uActiveCharacter = v1;
+      uActiveCharacter = uPlayerID;
       return;
     }
 //LABEL_27:
-    if ( pPlayers[v1]->uTimeToRecovery )
+    if ( pPlayers[uPlayerID]->uTimeToRecovery )
       return;
     //goto LABEL_28;
-    uActiveCharacter = v1;
+    uActiveCharacter = uPlayerID;
     return;
   }
   if ( ptr_507BC0->field_40 == 1 )
     return;
-  viewparams->bRedrawGameUI = 1;
-  if ( uActiveCharacter != v1 )
+  viewparams->bRedrawGameUI = true;
+  if ( uActiveCharacter != uPlayerID )
     //goto LABEL_28;
-    uActiveCharacter = v1;
+    uActiveCharacter = uPlayerID;
     return;
   if ( dword_F8B19C == 2 || dword_F8B19C == 6 )
   {
--- a/mm7_2.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_2.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -32,7 +32,6 @@
 #include "Time.h"
 #include "IconFrameTable.h"
 #include "GUIProgressBar.h"
-#include "stru157.h"
 #include "Bink_Smacker.h"
 #include "TileFrameTable.h"
 #include "PlayerFrameTable.h"
@@ -4600,7 +4599,7 @@
       memcpy(&v0->spellbook.pDarkSpellbook.bIsSpellAvailable[36 * v25 + 5], v20, 0x24u);
       goto LABEL_42;
     }
-    v0->PlaySound(SPEECH_15, 0);
+    v0->PlaySound(SPEECH_NoRoom, 0);
     v54 = 5;
 LABEL_70:
     v9 = pGlobalTXT_LocalizationStrings[563];   // "Pack is Full!"
@@ -4695,7 +4694,7 @@
       v27->PlaySound((PlayerSpeech)v51, v53);
       return;
     }
-    v0->PlaySound(SPEECH_15, 0);
+    v0->PlaySound(SPEECH_NoRoom, 0);
     v54 = 2;
     goto LABEL_70;
   }
@@ -11981,7 +11980,7 @@
         {
           if ( pAsyncMouse != (void *)v28 )
             goto _def_wnd_proc;
-          pGame->PickMouse(512.0, (unsigned __int16)lParam, lParam >> 16, v28, &a3, &a4);
+          pGame->PickMouse(512.0, (unsigned __int16)lParam, lParam >> 16, v28, &vis_sprite_filter_3, &vis_door_filter);
         }
         if ( pAsyncMouse == (void *)v28 )
         {
@@ -12003,7 +12002,7 @@
             if (pAsyncMouse)
               goto _def_wnd_proc;
             v33 = GetPickDepth();
-            pGame->PickMouse(v33, (unsigned __int16)lParam, lParam >> 16, v31, &stru_F93E30, &a4);
+            pGame->PickMouse(v33, (unsigned __int16)lParam, lParam >> 16, v31, &vis_sprite_filter_2, &vis_door_filter);
           }
           if (!pAsyncMouse)
           {
@@ -12022,7 +12021,7 @@
           if ( pGame && !pAsyncMouse )
           {
             v34 = GetPickDepth();
-            pGame->PickMouse(v34, (unsigned __int16)lParam, lParam >> 16, 1, &a3, &a5);
+            pGame->PickMouse(v34, (unsigned __int16)lParam, lParam >> 16, 1, &vis_sprite_filter_3, &vis_face_filter);
             return DefWindowProcA(hWnd, Msg, wParam, v4);
           }
           goto _def_wnd_proc;
@@ -13029,6 +13028,9 @@
   }
 }
 
+
+
+
 //----- (004651F4) --------------------------------------------------------
 bool MM7_Initialize()
 {
@@ -13048,7 +13050,6 @@
   }
 
 
-
   srand(GetTickCount());
   /*GetDiskFreeSpaceA(0, &SectorsPerCluster, &BytesPerSector, &hdc, &TotalNumberOfClusters);
   v4 = hdc * BytesPerSector * SectorsPerCluster;
@@ -13536,19 +13537,6 @@
       sprintf(pTmpBuf, "data\\lloyd%d%d.pcx", i, j);
       remove(pTmpBuf);
     }
-  /*do
-  {
-    v11 = 1;
-    do
-    {
-      sprintfex(pTmpBuf, "data\\lloyd%d%d.pcx", v10, v11);
-      remove(pTmpBuf);
-      ++v11;
-    }
-    while ( v11 < 6 );
-    ++v10;
-  }
-  while ( v10 < 5 );*/
 
   Initialize_GamesLOD_NewLOD();
   dword_576E2C = 512;
@@ -15206,9 +15194,9 @@
 }
 
 //----- (0046A14B) --------------------------------------------------------
-char __cdecl OnPressSpace()
-{
-  SHORT v0; // ax@2
+void OnPressSpace()
+{
+  //SHORT v0; // ax@2
   int *v1; // eax@2
   char *v2; // ebx@5
   unsigned int v3; // esi@5
@@ -15233,12 +15221,10 @@
 
   if ( pRenderer->pRenderD3D )
   {
-    v0 = GetAsyncKeyState(17);
-    pGame->_44EB12((v0 & 0x8001) != 0, &a3, &a4);
+    pGame->PickKeyboard(GetAsyncKeyState(VK_CONTROL) & 0x8001, &vis_sprite_filter_3, &vis_door_filter);
     v1 = (int *)pGame->pVisInstance->get_picked_object_zbuf_val();
     if ( v1 != (int *)-1 )
-      LOBYTE(v1) = DoInteractionWithTopmostZObject((unsigned __int16)v1, (signed int)(unsigned __int16)v1 >> 3);
-    return (char)v1;
+      DoInteractionWithTopmostZObject((unsigned __int16)v1, (signed int)(unsigned __int16)v1 >> 3);
   }
   v22 = 0;
   v1 = (int *)((signed int)(viewparams->uScreenZ + viewparams->uScreenX) >> 1);
@@ -15335,10 +15321,7 @@
     if ( !(char)v1 )
       break;
   }
-  return (char)v1;
-}
-// 72065C: using guessed type int dword_72065C[];
-// 7207EC: using guessed type int dword_7207EC[];
+}
 
 //----- (0046A334) --------------------------------------------------------
 char __fastcall DoInteractionWithTopmostZObject(int a1, int a2)
@@ -15615,7 +15598,7 @@
     {
       v3 = pRenderer->GetParentBillboardID(a1a);
       v4 = pBillboardRenderList[v3].sZValue;
-      v5 = (unsigned __int16)pBillboardRenderList[v3].sZValue;
+      v5 = (unsigned __int16)pBillboardRenderList[v3].object_pid;
       if ( (v5 & 7) == OBJECT_Actor)
       {
         if ( v4 <= (unsigned int)(a3 << 16) )
--- a/mm7_3.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_3.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -13436,10 +13436,14 @@
               v15->uScreenSpaceX = a5;
               v15->uScreenSpaceY = a6;
               v23 = 8 * v26;
-              LOBYTE(v23) = 8 * v26 | 5;
+              LOBYTE(v23) = 8 * v26 | OBJECT_Decoration;
               LOWORD(v22) = 0;
+
+              //v15->sZValue = v22 + v23;
+              v15->actual_z = HIWORD(x);
+              v15->object_pid = 8 * v26 | OBJECT_Decoration;
+
               v15->uTintColor = 0;
-              v15->sZValue = v22 + v23;
               v15->pSpriteFrame = v12;
             }
           }
@@ -13610,7 +13614,7 @@
               v3->uScreenSpaceY = v22;
               LOWORD(v21) = 0;
               v23 = 8 * i;
-              LOBYTE(v23) = 8 * i | 2;
+              LOBYTE(v23) = 8 * i | OBJECT_Item;
               v3->pSpriteFrame = v24;
               v12 = (p->uAttributes & 0x20) == 0;
               v3->sZValue = v21 + v23;
@@ -16420,19 +16424,8 @@
   GUIButton *v14; // eax@43
   GUIButton *v15; // edi@43
   signed int v16; // eax@44
-  int v17; // eax@46
-  int v18; // eax@47
-  int v19; // eax@48
-  int v20; // eax@49
-  int v21; // eax@50
-  int v22; // eax@51
   unsigned int v23; // eax@53
   const char *v24; // eax@59
-  int v25; // eax@65
-  int v26; // eax@66
-  int v27; // eax@67
-  int v28; // eax@68
-  int v29; // eax@69
   unsigned __int16 v30; // cx@83
   int v31; // ecx@86
   int v32; // ebx@93
@@ -16505,9 +16498,8 @@
       pRenderer->DrawTextureIndexed(8, 347 - v12, pTexture_591428);
       v13 = FitTextInAWindow(pGlobalTXT_LocalizationStrings[577], pFontArrus, &pWindow, 0xDu, 0);
       pDialogueWindow->DrawText(pFontArrus, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-    if ( uDialogueType == DIALOGUE_ARENA_REWARD )
+    }
+    else if ( uDialogueType == DIALOGUE_ARENA_REWARD )
     {
       sprintf(v4, pGlobalTXT_LocalizationStrings[576], dword_F8B1B4);// "Congratulations on your win: here's your stuff: %u gold."
       pInString = v4;
@@ -16525,9 +16517,8 @@
       pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
       v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
       pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-    if ( uDialogueType == DIALOGUE_ARENA_ALREADY_WON )
+    }
+    else if ( uDialogueType == DIALOGUE_ARENA_ALREADY_WON )
     {
       pInString = pGlobalTXT_LocalizationStrings[582]; // "You already won this trip to the Arena:"
       pWindow.uFrameWidth = 460;
@@ -16544,7 +16535,6 @@
       pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
       v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
       pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
     }
   }
   else
@@ -16567,9 +16557,8 @@
       pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
       v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
       pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-    if ( uDialogueType == DIALOGUE_13 )
+    }
+    else if ( uDialogueType == DIALOGUE_13 )
     {
       v5 = 5 * pNPC->uProfession;
       v6 = (char *)*(&pNPCStats->field_13A64 + v5);
@@ -16589,14 +16578,11 @@
       pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
       v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
       pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-    if ( (signed int)uDialogueType > DIALOGUE_18 )
-    {
-      if ( (signed int)uDialogueType > DIALOGUE_24 )
-      {
-        if ( uDialogueType == DIALOGUE_77 )
-        {
+    }
+    else if ( (signed int)uDialogueType > DIALOGUE_18 && !((signed int)uDialogueType > DIALOGUE_24 && uDialogueType != DIALOGUE_77 || byte_5B0938[0]) )
+    {
+      if ( (signed int)uDialogueType > DIALOGUE_24 && uDialogueType == DIALOGUE_77 )
+      {
           v5 = 5 * pNPC->uProfession;
           if ( byte_F8B1EC )
           {
@@ -16617,9 +16603,8 @@
             pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
             v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
             pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-            goto LABEL_42;
-          }
-          if ( pNPC->uFlags & 0x80 )
+          }
+          else if ( pNPC->uFlags & 0x80 )
           {
             v6 = (char *)*(&pNPCStats->field_13A68 + 5 * pNPC->uProfession);
             v7 = sub_495461(v6, uActiveCharacter - 1, 0, 0, 0, 0);
@@ -16638,92 +16623,106 @@
             pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
             v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
             pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-            goto LABEL_42;
-          }
-          v6 = (char *)*(&pNPCStats->field_13A64 + v5);
-          v7 = sub_495461(v6, uActiveCharacter - 1, 0, 0, 0, 0);
-          pInString = v7;
-          pWindow.uFrameWidth = 460;
-          pWindow.uFrameZ = 452;
-          pOutString = pFontArrus;
-          v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-          if ( 352 - v12 < 8 )
-          {
-            pOutString = pFontCreate;
-            v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-          }
-          pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
-                                     (uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
-          pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
-          v13 = FitTextInAWindow(pInString, pOutString,  &pWindow, 0xDu, 0);
-          pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-          goto LABEL_42;
-        }
-        goto LABEL_24;
-      }
-      if ( byte_5B0938[0] )
-        goto LABEL_24;
-      v7 = (char *)ptr_F8B1E8;
-      pInString = v7;
-      pWindow.uFrameWidth = 460;
-      pWindow.uFrameZ = 452;
-      pOutString = pFontArrus;
-      v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-      if ( 352 - v12 < 8 )
-      {
-        pOutString = pFontCreate;
-        v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-      }
-      pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
-        (uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
-      pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
-      v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
-      pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-  }
-LABEL_24:
-  if ( *(int *)v54 == 1 )
-  {
-    v11 = pNPC->greet;
-    v8 = 0;
-    if ( v11 )
-    {
-      v10 = (char *)*(&pNPCStats->field_17884 + ((pNPC->uFlags & 3) == 2) + 2 * v11);
-      goto LABEL_32;
-    }
-  }
-  else
-  {
-    if ( *(int *)v54 == 2 )
-    {
-      if ( pNPC->uFlags & 0x80 )
-        v9 = (char *)pNPCStats->pProfessions[pNPC->uProfession].pDismissText;
-      else
-        v9 = (char *)pNPCStats->pProfessions[pNPC->uProfession].pJoinText; //"Invalid String Passed"
-       pInString = sub_495461(v9, uActiveCharacter - 1, 0, 0, 0, 0);
-LABEL_32:
-
-      if (  pInString == NULL )
-        goto LABEL_42;
-      pWindow.uFrameWidth = 460;
-      pWindow.uFrameZ = 452;
-      pOutString = pFontArrus;
-      v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-      if ( 352 - v12 < 8 )
-      {
-        pOutString = pFontCreate;
-        v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
-      }
-      pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
-        (uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
-      pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
-      v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
-      pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
-      goto LABEL_42;
-    }
-  }
-LABEL_42:
+          }
+		  else
+		  {
+			v6 = (char *)*(&pNPCStats->field_13A64 + v5);
+			v7 = sub_495461(v6, uActiveCharacter - 1, 0, 0, 0, 0);
+			pInString = v7;
+			pWindow.uFrameWidth = 460;
+			pWindow.uFrameZ = 452;
+			pOutString = pFontArrus;
+			v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+			if ( 352 - v12 < 8 )
+			{
+			pOutString = pFontCreate;
+			v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+			}
+			pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
+										(uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
+			pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
+			v13 = FitTextInAWindow(pInString, pOutString,  &pWindow, 0xDu, 0);
+			pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
+		  }
+      }
+	  else
+	  {
+		  v7 = (char *)ptr_F8B1E8;
+		  pInString = v7;
+		  pWindow.uFrameWidth = 460;
+		  pWindow.uFrameZ = 452;
+		  pOutString = pFontArrus;
+		  v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+		  if ( 352 - v12 < 8 )
+		  {
+			pOutString = pFontCreate;
+			v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+		  }
+		  pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
+			(uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
+		  pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
+		  v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
+		  pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
+	  }
+    }
+	else
+	{    
+		if ( *(int *)v54 == 1 )
+		{
+			v11 = pNPC->greet;
+			v8 = 0;
+			if ( v11 )
+			{
+				v10 = (char *)*(&pNPCStats->field_17884 + ((pNPC->uFlags & 3) == 2) + 2 * v11);
+				if (  pInString != NULL )
+				{
+					pWindow.uFrameWidth = 460;
+					pWindow.uFrameZ = 452;
+					pOutString = pFontArrus;
+					v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+					if ( 352 - v12 < 8 )
+					{
+						pOutString = pFontCreate;
+						v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+					}
+					pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
+					(uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
+					pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
+					v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
+					pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
+				}
+			}
+		}
+		else
+		{
+			if ( *(int *)v54 == 2 )
+			{
+				if ( pNPC->uFlags & 0x80 )
+					v9 = (char *)pNPCStats->pProfessions[pNPC->uProfession].pDismissText;
+				else
+					v9 = (char *)pNPCStats->pProfessions[pNPC->uProfession].pJoinText; //"Invalid String Passed"
+				pInString = sub_495461(v9, uActiveCharacter - 1, 0, 0, 0, 0);
+				if (  pInString != NULL )
+				{
+					pWindow.uFrameWidth = 460;
+					pWindow.uFrameZ = 452;
+					pOutString = pFontArrus;
+					v12 = pFontArrus->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+					if ( 352 - v12 < 8 )
+					{
+						pOutString = pFontCreate;
+						v12 = pFontCreate->CalcTextHeight(pInString, &pWindow, 13, 0) + 7;
+					}
+					pRenderer->_4A6A68(8, 352 - v12, (Texture *)(uTextureID_Leather != -1 ? (int)&pIcons_LOD->pTextures[uTextureID_Leather] : 0),
+					(uTextureID_Leather != -1 ? pIcons_LOD->pTextures[uTextureID_Leather].uTextureHeight : 26) - v12);
+					pRenderer->DrawTextureIndexed(8u, 347 - v12, pTexture_591428);
+					v13 = FitTextInAWindow(pInString, pOutString, &pWindow, 0xDu, 0);
+					pDialogueWindow->DrawText(pOutString, 13, 354 - v12, 0, v13, 0, 0, 0);
+				}
+			}
+		}
+	}
+  }
   memcpy(&v52, pDialogueWindow, sizeof(v52));
   v52.uFrameX = 483;
   v52.uFrameWidth = 148;
@@ -16737,125 +16736,107 @@
     if ( !v14 )
       break;
     v16 = v14->uControlParam;
-    if ( v16 > 24 )
-    {
-      v25 = v16 - 76;
-      if ( v25 )
-      {
-        v26 = v25 - 1;
-        if ( v26 )
-        {
-          v27 = v26 - 8;
-          if ( v27 )
-          {
-            v28 = v27 - 1;
-            if ( v28 )
-            {
-              v29 = v28 - 1;
-              if ( v29 )
-              {
-                if ( v29 != 1 )
-                {
-                  v24 = "";
-                  goto LABEL_79;
-                }
-                v24 = pGlobalTXT_LocalizationStrings[581];
-              }
-              else
-              {
-                v24 = pGlobalTXT_LocalizationStrings[580];
-              }
-            }
-            else
-            {
-              v24 = pGlobalTXT_LocalizationStrings[579];
-            }
-          }
-          else
-          {
-            v24 = pGlobalTXT_LocalizationStrings[578];
-          }
-        }
-        else
-        {
-          v24 = pGlobalTXT_LocalizationStrings[407];
-        }
-      }
-      else
-      {
-        if ( pNPC->uFlags & 0x80 )
-        {
-          sprintf(pTmpBuf, (const char*)pGlobalTXT_LocalizationStrings[408], pNPC->pName);
-          v24 = pTmpBuf;
-          goto LABEL_79;
-        }
-        v24 = pGlobalTXT_LocalizationStrings[406];
-      }
-    }
-    else
-    {
-      if ( v16 == 24 )
-      {
-        v23 = pNPC->evtf;
-LABEL_63:
-        v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
-        if ( !v24 )
-        {
-          v24 = "";
-          v15->uControlParam = 0;
-        }
-        goto LABEL_79;
-      }
-      v17 = v16 - 9;
-      if ( !v17 )
-      {
-        v24 = (const char *)sub_445308(pNPC->uProfession);
-        goto LABEL_79;
-      }
-      v18 = v17 - 4;
-      if ( v18 )
-      {
-        v19 = v18 - 6;
-        if ( !v19 )
-        {
-          v23 = pNPC->bDrawSomeAnim;
-          goto LABEL_63;
-        }
-        v20 = v19 - 1;
-        if ( !v20 )
-        {
-          v23 = pNPC->_anim_current_time;
-          goto LABEL_63;
-        }
-        v21 = v20 - 1;
-        if ( !v21 )
-        {
-          v23 = pNPC->_anim_end_time;
-          goto LABEL_63;
-        }
-        v22 = v21 - 1;
-        if ( !v22 )
-        {
-          v23 = pNPC->evtd;
-          goto LABEL_63;
-        }
-        if ( v22 == 1 )
-        {
-          v23 = pNPC->evte;
-          goto LABEL_63;
-        }
+
+    if ( v16 > 88 )
+    {
         v24 = "";
-        goto LABEL_79;
-      }
-      if ( pNPC->uFlags & 0x80 )
-      {
-        sprintf(pTmpBuf, pGlobalTXT_LocalizationStrings[408], pNPC->pName);
-        v24 = pTmpBuf;
-        goto LABEL_79;
-      }
-      v24 = pGlobalTXT_LocalizationStrings[122];
-    }
-LABEL_79:
+    }
+	else if ( v16 == 88 )
+		v24 = pGlobalTXT_LocalizationStrings[581];
+    else if ( v16 == 87 )
+	    v24 = pGlobalTXT_LocalizationStrings[580];
+    else if ( v16 == 86 )
+	    v24 = pGlobalTXT_LocalizationStrings[579];
+    else if ( v16 == 85 )
+		v24 = pGlobalTXT_LocalizationStrings[578];
+    else if ( v16 == 77 )
+        v24 = pGlobalTXT_LocalizationStrings[407];
+    else if ( v16 == 76 )
+    {
+		if ( pNPC->uFlags & 0x80 )
+		{
+			sprintf(pTmpBuf, (const char*)pGlobalTXT_LocalizationStrings[408], pNPC->pName);
+			v24 = pTmpBuf;
+		}
+		else
+			v24 = pGlobalTXT_LocalizationStrings[406];
+    }
+	else if ( v16 == 24 )
+    {
+		v23 = pNPC->evtf;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+    }
+	else if ( v16 == 9 )
+		v24 = (const char *)sub_445308(pNPC->uProfession);
+	else if ( v16 == 19 )
+	{
+		v23 = pNPC->bDrawSomeAnim;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+	}
+	else if ( v16 == 20 )
+	{
+		v23 = pNPC->_anim_current_time;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+	}
+	else if ( v16 == 21 )
+	{
+		v23 = pNPC->_anim_end_time;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+	}
+	else if ( v16 == 22 )
+	{
+		v23 = pNPC->evtd;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+	}
+	else if ( v16 == 23 )
+	{
+		v23 = pNPC->evte;
+		v24 = pNPCTopics[v23-1].pTopic;//(&dword_721660)[8 * v23];
+		if ( !v24 )
+		{
+			v24 = "";
+			v15->uControlParam = 0;
+		}
+	}
+	else if ( v16 == 13 )
+	{
+		if ( pNPC->uFlags & 0x80 )
+		{
+			sprintf(pTmpBuf, pGlobalTXT_LocalizationStrings[408], pNPC->pName);
+			v24 = pTmpBuf;
+		}
+		else
+			v24 = pGlobalTXT_LocalizationStrings[122];
+	}
+	else
+		v24 = "";
+	
+
     if ( pParty->field_7B5_in_arena_quest && pParty->field_7B5_in_arena_quest != -1 )
     {
       pInString = 0;
--- a/mm7_4.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_4.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -1,5 +1,6 @@
 #include <io.h>
 #include <direct.h>
+#include <assert.h>
 
 #include "MapInfo.h"
 #include "Game.h"
@@ -31,7 +32,6 @@
 #include "Time.h"
 #include "IconFrameTable.h"
 #include "GUIProgressBar.h"
-#include "stru157.h"
 #include "Bink_Smacker.h"
 #include "TileFrameTable.h"
 #include "PlayerFrameTable.h"
@@ -2889,11 +2889,11 @@
   pTexture_PlayerFaceDead = pIcons_LOD->LoadTexturePtr("DEAD", TEXTURE_16BIT_PALETTE);
   pTexture_PlayerFaceMask = pIcons_LOD->LoadTexturePtr("FACEMASK", TEXTURE_16BIT_PALETTE);
   
-  if (byte_4ED498)
+  if (SoundSetAction[24][0])
     for (uint i = 0; i < 4; ++i)
     {
-      pSoundList->LoadSound(2 * (byte_4ED498 + 50 * pParty->pPlayers[i].uVoiceID) + 4998, 0);
-      pSoundList->LoadSound(2 * (byte_4ED498 + 50 * pParty->pPlayers[i].uVoiceID) + 4999, 0);
+      pSoundList->LoadSound(2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[i].uVoiceID) + 4998, 0);
+      pSoundList->LoadSound(2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[i].uVoiceID) + 4999, 0);
     }
 }
 
@@ -2941,7 +2941,7 @@
   v0 = pParty->pPlayers;
   do
   {
-    if ( byte_4ED498 )
+    if (SoundSetAction[24][0])
     {
       v1 = 0;
       if ( (signed int)pSoundList->uNumSounds <= 0 )
@@ -2952,7 +2952,7 @@
       else
       {
         v2 = (char *)&pSoundList->pSounds->uSoundID;
-        while ( *(int *)v2 != 2 * ((unsigned __int8)byte_4ED498 + 50 * v0->uVoiceID) + 4998 )
+        while ( *(int *)v2 != 2 * (SoundSetAction[24][0] + 50 * v0->uVoiceID) + 4998 )
         {
           ++v1;
           v2 += 120;
@@ -2971,7 +2971,7 @@
       else
       {
         v5 = (char *)&pSoundList->pSounds->uSoundID;
-        while ( *(int *)v5 != 2 * ((unsigned __int8)byte_4ED498 + 50 * v0->uVoiceID) + 4999 )
+        while ( *(int *)v5 != 2 * (SoundSetAction[24][0] + 50 * v0->uVoiceID) + 4999 )
         {
           ++v4;
           v5 += 120;
@@ -5862,7 +5862,7 @@
   signed int uSkillIdx; // eax@45
   int v15; // eax@70
   signed int v16; // ecx@70
-  unsigned int v18; // [sp-4h] [bp-84h]@48
+  //unsigned int v18; // [sp-4h] [bp-84h]@48
   ItemGen item; // [sp+Ch] [bp-74h]@37
   char v20[32]; // [sp+30h] [bp-50h]@29
   //char v21; // [sp+31h] [bp-4Fh]@29
@@ -6000,7 +6000,7 @@
       if ( pPlayer->pActiveSkills[12+i] )
         ++uSpellBookPageCount;
     }
-    pPlayer->pNumSpellBookPage = uSpellBookPageCount;
+    pPlayer->lastOpenedSpellbookPage = uSpellBookPageCount;
     pItemsTable->GenerateItem(2, 40, &item);
     pPlayer->AddItem2(-1, &item);
     uSkillIdx = 0;
@@ -6011,96 +6011,66 @@
       {
         switch ( uSkillIdx )
         {
-          case 0:
-            v18 = 61;
-            pPlayer->AddItem(-1, v18);
-            break;
-          case 1:
-            v18 = 1;
-            pPlayer->AddItem(-1, v18);
-            break;
-          case 2:
-            v18 = 15;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 3:
-            v18 = 23;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 4:
-            v18 = 31;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 5:
-            v18 = 47;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 6:
-            v18 = 50;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 8:
-            v18 = 84;
-  			pPlayer->AddItem(-1, v18);
-            break;
-          case 9:
-            v18 = 66;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 10:
-            v18 = 71;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 11:
-            v18 = 76;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 12:
+          case PLAYER_SKILL_STAFF:   pPlayer->AddItem(-1, 61); break;
+          case PLAYER_SKILL_SWORD:   pPlayer->AddItem(-1, 1); break;
+          case PLAYER_SKILL_DAGGER:  pPlayer->AddItem(-1, 15); break;
+          case PLAYER_SKILL_AXE:     pPlayer->AddItem(-1, 23); break;
+          case PLAYER_SKILL_SPEAR:   pPlayer->AddItem(-1, 31); break;
+          case PLAYER_SKILL_BOW:     pPlayer->AddItem(-1, 47); break;
+          case PLAYER_SKILL_MACE:    pPlayer->AddItem(-1, 50); break;
+          case PLAYER_SKILL_BLASTER: assert(false); break;
+          case PLAYER_SKILL_SHIELD:  pPlayer->AddItem(-1, 84); break;
+          case PLAYER_SKILL_LEATHER: pPlayer->AddItem(-1, 66); break;
+          case PLAYER_SKILL_CHAIN:   pPlayer->AddItem(-1, 71); break;
+          case PLAYER_SKILL_PLATE:   pPlayer->AddItem(-1, 76); break;
+          case PLAYER_SKILL_FIRE:
             pPlayer->AddItem(-1, 0x191);
-            pPlayer->spellbook.pFireSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 13:
+            pPlayer->spellbook.pFireSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_AIR:
             pPlayer->AddItem(-1, 0x19C);
-            pPlayer->spellbook.pAirSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 14:
+            pPlayer->spellbook.pAirSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_WATER:
             pPlayer->AddItem(-1, 0x1A7);
-			pPlayer->spellbook.pWaterSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 15:
+			pPlayer->spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_EARTH:
             pPlayer->AddItem(-1, 0x1B2);
-			pPlayer->spellbook.pEarthSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 16:
+			pPlayer->spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_SPIRIT:
             pPlayer->AddItem(-1, 0x1BD);
-			pPlayer->spellbook.pSpiritSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 17:
+			pPlayer->spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_MIND:
             pPlayer->AddItem(-1, 0x1C8);
-			pPlayer->spellbook.pMindSpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 18:
+			pPlayer->spellbook.pMindSpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_BODY:
             pPlayer->AddItem(-1, 0x1D3);
-			pPlayer->spellbook.pBodySpellbook.bIsSpellbookAvailable = 1;
-            break;
-          case 21:
-          case 23:
-          case 25:
-          case 26:
-          case 29:
-          case 36:
+			pPlayer->spellbook.pBodySpellbook.bIsSpellAvailable[0] = true;
+          break;
+          case PLAYER_SKILL_LIGHT:
+          case PLAYER_SKILL_DARK:
+          case PLAYER_SKILL_DIPLOMACY:
+            assert(false);
+          break;
+          case PLAYER_SKILL_ITEM_ID:
+          case PLAYER_SKILL_REPAIR:
+          case PLAYER_SKILL_MEDITATION:
+          case PLAYER_SKILL_PERCEPTION:
+          case PLAYER_SKILL_TRAP_DISARM:
+          case PLAYER_SKILL_LEARNING:
             pPlayer->AddItem(-1, 0xDC);
-            v18 = 5 * (rand() % 3 + 40);
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 30:
-            v18 = 115;
-			pPlayer->AddItem(-1, v18);
-            break;
-          case 31:
-            v18 = 110;
-            pPlayer->AddItem(-1, v18);
-            break;
+			pPlayer->AddItem(-1, 5 * (rand() % 3 + 40));
+          break;
+          case PLAYER_SKILL_DODGE:
+			pPlayer->AddItem(-1, 115);
+          break;
+          case PLAYER_SKILL_UNARMED:
+            pPlayer->AddItem(-1, 110);
+          break;
           default:
             break;
         }
@@ -14719,9 +14689,11 @@
     v0->uScreenSpaceY = a6;
     LOWORD(v25) = 0;
     LOBYTE(v26) = v41;
-    v0->sZValue = v25 + (8 * i | 3);
-    //v27 = pMonsterList->pMonsters;
-    //v28 = p->pMonsterInfo.uID;
+
+    //v0->sZValue = v25 + (8 * i | OBJECT_Actor);
+    v0->actual_z = HIWORD(x);
+    v0->object_pid = v8 * i | OBJECT_Actor;
+
     v29 = HIDWORD(p->pActorBuffs[5].uExpireTime) == 0;
     v30 = HIDWORD(p->pActorBuffs[5].uExpireTime) < 0;
     v0->field_1E = v41;
--- a/mm7_5.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_5.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -69,9 +69,9 @@
   unsigned int v2; // edx@7
   Actor *pActor; // ecx@13
   int v4; // ecx@18
-  NPCData *pNPCData0; // eax@18
-  int v6; // edx@20
-  int v7; // ecx@29
+  //NPCData *pNPCData0; // eax@18
+  //int v6; // edx@20
+  //int v7; // ecx@29
   unsigned int v8; // edx@59
   unsigned int v9; // ecx@60
   unsigned int v10; // ecx@73
@@ -244,7 +244,7 @@
   const char *v177; // [sp+0h] [bp-5FCh]@629
   char *v178; // [sp+0h] [bp-5FCh]@637
   int v179; // [sp+4h] [bp-5F8h]@0
-  signed int _this; // [sp+14h] [bp-5E8h]@22
+  //signed int _this; // [sp+14h] [bp-5E8h]@22
   signed int thisa; // [sp+14h] [bp-5E8h]@251
   signed int thisb; // [sp+14h] [bp-5E8h]@272
   Player *pPlayer7; // [sp+14h] [bp-5E8h]@373
@@ -333,50 +333,56 @@
           //goto _actor_init_dlg;
           pActor->InitializeDialogue(v0);
           continue;
-        case UIMSG_86:
-        case UIMSG_87:
-          if ( bNoNPCHiring != 1 && !pCurrentScreen )
-          {
+        case UIMSG_StartHireling1Dialogue:
+        case UIMSG_StartHireling2Dialogue:
+        {
+          if (bNoNPCHiring || pCurrentScreen)
+            continue;
+
             if ( pMessageQueue_50CBD0->uNumMessages )
               pMessageQueue_50CBD0->uNumMessages = pMessageQueue_50CBD0->pMessages[0].field_8 != 0;
             uAction = 0;
-            uNumSeconds = uMessage - 134;
+            int hireling_idx = uMessage - UIMSG_StartHireling1Dialogue;
             v4 = 0;
-            pNPCData0 = pParty->pHirelings;
-            do
-            {
-              if ( pNPCData0->pName )
-              {
-                v6 = uAction++;
-                pTmpBuf[v6] = v4;
-              }
-              ++pNPCData0;
-              ++v4;
-            }
-            while ( (signed int)pNPCData0 < (signed int)&pParty->pPickedItem );
-            _this = 0;
-            if ( (signed int)pNPCStats->uNumNewNPCs > 0 )
-            {
-              pNPCData4 = pNPCStats->pNewNPCData;
-              do
-              {
-                if ( pNPCData4->uFlags & 0x80
-                  && (!pParty->pHirelings[0].pName || strcmp(pNPCData4->pName, pParty->pHirelings[0].pName))
-                  && (!pParty->pHirelings[1].pName || strcmp(pNPCData4->pName, pParty->pHirelings[1].pName)) )
+
+            for (uint i = 0; i < 2; ++i)
+            //pNPCData0 = pParty->pHirelings;
+            //do
+            {
+              if (pParty->pHirelings[i].pName)
+              //{
+                //v6 = uAction++;
+                pTmpBuf[uAction++] = i;
+              //}
+              //++pNPCData0;
+              //++v4;
+            }
+            //while ( (signed int)pNPCData0 < (signed int)&pParty->pPickedItem );
+
+            //_this = 0;
+            for (uint i = 0; i < pNPCStats->uNumNewNPCs; ++i)
+            {
+              auto npc = pNPCStats->pNewNPCData + i;
+              //do
+              //{
+                if (npc->uFlags & 0x80 &&
+                    (!pParty->pHirelings[0].pName || strcmp(npc->pName, pParty->pHirelings[0].pName)) &&
+                    (!pParty->pHirelings[1].pName || strcmp(npc->pName, pParty->pHirelings[1].pName)) )
                 {
-                  v7 = uAction++;
-                  pTmpBuf[v7] = _this + 2;
+                  //v7 =;
+                  pTmpBuf[uAction++] = i + 2;
                 }
-                ++_this;
-                ++pNPCData4;
-              }
-              while ( _this < (signed int)pNPCStats->uNumNewNPCs );
-            }
-            if ( (signed int)(uNumSeconds + (unsigned __int8)pParty->field_709) < uAction )
+                //++_this;
+                //++pNPCData4;
+              //}
+              //while ( _this < (signed int)pNPCStats->uNumNewNPCs );
+            }
+
+            if ( (signed int)(hireling_idx + (unsigned __int8)pParty->field_709) < uAction )
             {
               //Actor::Actor(&actor);
               memset(&actor, 0, 0x344u);
-              actor.uNPC_ID += -1 - (unsigned __int8)pParty->field_709 - uNumSeconds;
+              actor.uNPC_ID += -1 - (unsigned __int8)pParty->field_709 - hireling_idx;
               pActor = &actor;
 //_actor_init_dlg:
               pActor->InitializeDialogue(v0);
@@ -2962,7 +2968,7 @@
         case UIMSG_4E:
           if ( dword_50654C && byte_506550 )
           {
-            v173 = pSpellStats->pInfos[dword_50654C + 11 * pPlayers[uActiveCharacter]->pNumSpellBookPage].pName;
+            v173 = pSpellStats->pInfos[dword_50654C + 11 * pPlayers[uActiveCharacter]->lastOpenedSpellbookPage].pName;
             v157 = pGlobalTXT_LocalizationStrings[483];
 _sprintex_2args_draw_status_and_continue:
             sprintf(pTmpBuf, v157, v173);
@@ -3019,7 +3025,7 @@
             v127 = 203;
             goto _play_sound_and_continue;
           }
-          v99 = dword_50654C + 11 * pPlayers[uActiveCharacter]->pNumSpellBookPage;
+          v99 = dword_50654C + 11 * pPlayers[uActiveCharacter]->lastOpenedSpellbookPage;
           pPlayers[uActiveCharacter]->uQuickSpell = v99;
           stru_A750F8[uActiveCharacter + 3]._494836(v99, uActiveCharacter);
           if ( uActiveCharacter )
@@ -3038,7 +3044,7 @@
           {
             if ( *(short *)thisl )
             {
-              if ( pPlayer3->pNumSpellBookPage == v101 )
+              if ( pPlayer3->lastOpenedSpellbookPage == v101 )
                 uAction = (int)pNPCData4;
               v102 = (int)pNPCData4;
               pNPCData4 = (NPCData *)((char *)pNPCData4 + 1);
@@ -3073,7 +3079,7 @@
               uAction = 0;
           }
           sub_41140B();
-          pPlayers[uActiveCharacter]->pNumSpellBookPage = LOBYTE(v217[uAction]);
+          pPlayers[uActiveCharacter]->lastOpenedSpellbookPage = LOBYTE(v217[uAction]);
           pGUIWindow_CurrentMenu->OpenSpellBook();
           v165 = 0;
           v151 = 0;
@@ -3085,10 +3091,10 @@
           v127 = rand() % 2 + 204;
           goto _play_sound_and_continue;
         case UIMSG_57:
-          if ( pTurnEngine->field_4 == 3 || !uActiveCharacter || uMessageParam == pPlayers[uActiveCharacter]->pNumSpellBookPage )
+          if ( pTurnEngine->field_4 == 3 || !uActiveCharacter || uMessageParam == pPlayers[uActiveCharacter]->lastOpenedSpellbookPage )
             continue;
           sub_41140B();
-          pPlayers[uActiveCharacter]->pNumSpellBookPage = uMessageParam;
+          pPlayers[uActiveCharacter]->lastOpenedSpellbookPage = uMessageParam;
           pGUIWindow_CurrentMenu->OpenSpellBook();
           v165 = 0;
           v151 = 0;
@@ -3619,7 +3625,7 @@
 //LABEL_733:
           GUIWindow::Create(v9, v8, v133, v137, pWindowType1, (int)pButton2, v163);
           continue;
-        case UIMSG_194:
+        case UIMSG_Game_Action:
           if ( pMessageQueue_50CBD0->uNumMessages )
             pMessageQueue_50CBD0->uNumMessages = pMessageQueue_50CBD0->pMessages[0].field_8 != 0;
           OnPressSpace();
@@ -12738,7 +12744,7 @@
 
   v1 = pPlayers[uActiveCharacter];
   v10 = _this;
-  v2 = &pSpellStats->pInfos[(signed int)((char *)_this + 11 * v1->pNumSpellBookPage) + 1];
+  v2 = &pSpellStats->pInfos[(signed int)((char *)_this + 11 * v1->lastOpenedSpellbookPage) + 1];
   if ( pMouse->GetCursorPos(&a2)->y <= 250 )
     v3 = pMouse->GetCursorPos(&a2)->y + 30;
   else
@@ -12797,14 +12803,14 @@
   a1.DrawText(pFontSmallnum, 120, 44, 0, pTmpBuf2, 0, 0, 0);
   a1.uFrameWidth = 108;
   a1.uFrameZ = a1.uFrameX + 107;
-  a1.DrawTitleText(pFontComic, 0xCu, 0x4Bu, 0, pSkillNames[v1->pNumSpellBookPage + 12], 3u);
+  a1.DrawTitleText(pFontComic, 0xCu, 0x4Bu, 0, pSkillNames[v1->lastOpenedSpellbookPage + 12], 3u);
   sprintf(
     pTmpBuf,
     "%s\n%d",
     pGlobalTXT_LocalizationStrings[522],
     *(&pSpellDatas[0].field_12 //temp_fix field_14
-    + ((unsigned int)LOBYTE(v1->pActiveSkills[v1->pNumSpellBookPage + 12]) >> 6)
-    + 10 * (int)((char *)v10 + 11 * v1->pNumSpellBookPage)));
+    + ((unsigned int)LOBYTE(v1->pActiveSkills[v1->lastOpenedSpellbookPage + 12]) >> 6)
+    + 10 * (int)((char *)v10 + 11 * v1->lastOpenedSpellbookPage)));
   a1.DrawTitleText(pFontComic, 0xCu, a1.uFrameHeight - LOBYTE(pFontComic->uFontHeight) - 16, 0, pTmpBuf, 3u);
   dword_507B00_spell_info_to_draw_in_popup = 0;
 }
@@ -13130,56 +13136,44 @@
 // 4E1D3A: using guessed type __int16 word_4E1D3A[];
 
 //----- (00411300) --------------------------------------------------------
-Texture *__fastcall LoadSpellbook(unsigned int uID)
-{
-  unsigned int v1; // esi@1
+void LoadSpellbook(unsigned int school)
+{
+  //unsigned int v1; // esi@1
   Player *pPlayer; // ecx@1
   char v3; // al@1
-  int v4; // edi@5
-  Texture *result; // eax@6
-  char *v6; // edi@7
-  unsigned int v7; // eax@7
-  unsigned __int8 v8; // sf@8
-  unsigned __int8 v9; // of@8
+  //int v4; // edi@5
+  //Texture *result; // eax@6
+  //unsigned char *v6; // edi@7
+  //unsigned int v7; // eax@7
+  //unsigned __int8 v8; // sf@8
+  //unsigned __int8 v9; // of@8
   char pContainer[20]; // [sp+Ch] [bp-1Ch]@7
-  Texture *v11; // [sp+20h] [bp-8h]@5
-  int v12; // [sp+24h] [bp-4h]@5
+  //Texture *v11; // [sp+20h] [bp-8h]@5
+  //int v12; // [sp+24h] [bp-4h]@5
 
   byte_506550 = 0;
-  v1 = uID;
+  //v1 = uID;
   pPlayer = pPlayers[uActiveCharacter];
   v3 = pPlayer->uQuickSpell;
-  if ( v3 && (unsigned __int8)v3 / 11 == v1 )
-    dword_50654C = (unsigned __int8)v3 - 11 * v1;
+  if ( v3 && (unsigned __int8)v3 / 11 == school )
+    dword_50654C = (unsigned __int8)v3 - 11 * school;
   else
     dword_50654C = 0;
-  v4 = 1;
-  v12 = 1;
-  v11 = (Texture *)&pPlayer->field_152[11 * v1 + 63];
-  do
-  {
-    result = v11;
-    if ( v11->pName[v4] )
-    {
-      v6 = &byte_4E2430[12 * v1] + v4;
-      sprintf(pContainer, "SB%sS%02d", spellbook_texture_filename_suffices[v1], (unsigned __int8)*v6);
-      v7 = pIcons_LOD->LoadTexture(pContainer, TEXTURE_16BIT_PALETTE);
-      dword_506408[v12] = &pIcons_LOD->pTextures[v7];
-      sprintf(pContainer, "SB%sC%02d", spellbook_texture_filename_suffices[v1], (unsigned __int8)*v6);
-      result = &pIcons_LOD->pTextures[pIcons_LOD->LoadTexture(pContainer, TEXTURE_16BIT_PALETTE)];
-      dword_5063D8[v12] = result;
-    }
-    v4 = v12 + 1;
-    v9 = v12++ > 12;//v9 = __OFSUB__(v12 + 1, 12);
-    v8 = v12++ - 11 < 0;
-  }
-  while ( v8 ^ v9 );
-  return result;
-}
-// 4E1D18: using guessed type char *spellbook_texture_filename_suffices[8];
-// 506408: using guessed type int dword_506408[];
-// 50654C: using guessed type int dword_50654C;
-// 506550: using guessed type char byte_506550;
+
+  char *v11 = &pPlayer->field_152[11 * school + 63];
+
+  for (uint i = 1; i < 12; ++i)
+  {
+    if (v11[i])
+    {
+      sprintf(pContainer, "SB%sS%02d", spellbook_texture_filename_suffices[school], pSpellbookSpellIndices[school][i]);
+      dword_506408[i] = pIcons_LOD->LoadTexturePtr(pContainer, TEXTURE_16BIT_PALETTE);
+
+      sprintf(pContainer, "SB%sC%02d", spellbook_texture_filename_suffices[school], pSpellbookSpellIndices[school][i]);
+      dword_5063D8[i] = pIcons_LOD->LoadTexturePtr(pContainer, TEXTURE_16BIT_PALETTE);
+    }
+  }
+}
 
 //----- (0041140B) --------------------------------------------------------
 GUIWindow *__cdecl sub_41140B()
@@ -13279,7 +13273,7 @@
 
   v0 = 0;
   if ( uActiveCharacter )
-	  v0 = pParty->pPlayers[uActiveCharacter-1].pNumSpellBookPage;//*((char *)&pParty->pPartyBuffs[5].uExpireTime + 6972 * uActiveCharacter + 2);
+	  v0 = pParty->pPlayers[uActiveCharacter-1].lastOpenedSpellbookPage;//*((char *)&pParty->pPartyBuffs[5].uExpireTime + 6972 * uActiveCharacter + 2);
   pRenderer->DrawTextureIndexed(8u, 8u, pTextures_5064A0[v0]);
   pRenderer->DrawTextureIndexed(0x1DCu, 0x1C2u, pTexture_50643C);
   pRenderer->DrawTextureIndexed(0x231u, 0x1C2u, pTexture_506448);
@@ -13318,7 +13312,7 @@
 
   sub_412AF9();
   v0 = pPlayers[uActiveCharacter];
-  v1 = 11 * v0->pNumSpellBookPage;
+  v1 = 11 * v0->lastOpenedSpellbookPage;
   v2 = pIcons_LOD->FindTextureByName("Pending");
   v3 = (Texture *)(v2 != -1 ? (int)&pIcons_LOD->pTextures[v2] : 0);
   pRenderer->ClearZBuffer(0, 479);
@@ -13344,14 +13338,14 @@
           }
           if ( v6->pLevelOfDetail0 )
           {
-            v7 = 2 * (12 * v0->pNumSpellBookPage + (unsigned __int8)*(&byte_4E2430[12 * v0->pNumSpellBookPage + v4]));
+            v7 = 2 * (12 * v0->lastOpenedSpellbookPage + pSpellbookSpellIndices[v0->lastOpenedSpellbookPage][v4]);
             v19 = pViewport->uViewportY + dword_4E20D0[v7 + 1];
             v17 = pViewport->uViewportX + dword_4E20D0[v7];
             if ( BYTE1(v6->pBits) & 2 )
               pRenderer->DrawTextureTransparent(v17, v19, v6);
             else
               pRenderer->DrawTextureIndexed(v17, v19, v6);
-            v8 = 2 * (12 * v0->pNumSpellBookPage + (unsigned __int8)*(&byte_4E2430[12 * v0->pNumSpellBookPage] + v4));
+            v8 = 2 * (12 * v0->lastOpenedSpellbookPage + pSpellbookSpellIndices[v0->lastOpenedSpellbookPage][v4]);
             pRenderer->_4A612A(dword_4E20D0[v8], dword_4E20D0[v8 + 1], v23, v4);
           }
         }
@@ -13368,7 +13362,7 @@
     if ( v11->pLevelOfDetail0 )
     {
       v21 = dword_5063D8[v10];
-      v12 = 2 * (12 * v0->pNumSpellBookPage + (unsigned __int8)*(&byte_4E2430[12 * v0->pNumSpellBookPage] + v10));
+      v12 = 2 * (12 * v0->lastOpenedSpellbookPage + pSpellbookSpellIndices[v0->lastOpenedSpellbookPage][v10]);
       v20 = pViewport->uViewportY + dword_4E20D0[v12 + 1];
       v18 = pViewport->uViewportX + dword_4E20D0[v12];
       if ( BYTE1(v11->pBits) & 2 )
@@ -13386,7 +13380,7 @@
   {
     if ( *(short *)a2.x )
     {
-      if ( v0->pNumSpellBookPage == v13 )
+      if ( v0->lastOpenedSpellbookPage == v13 )
       {
         pPageTexture = pTextures_tabs[v13][1];
         switch ( v13 )
@@ -16179,6 +16173,7 @@
       return;
     }
   }
+
   if ( pParty->pPickedItem.uItemID )//нажатие на портрет перса правой кнопкой мыши с раствором
   {
     //v1 = 0;
@@ -16195,6 +16190,7 @@
     }
     //while ( v1 < 4 );
   }
+
   pEventTimer->Pause();
   if ( pCurrentScreen <= SCREEN_CHEST )
   {
--- a/mm7_6.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_6.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -8148,7 +8148,7 @@
     v6 = a3 != 0;
     if ( a4 )
       LOBYTE(v6) = v6 | 8;
-    v7 = pGame->pVisInstance->_4C1944(3, a2, v6, 657456, -1);
+    v7 = pGame->pVisInstance->_4C1944(OBJECT_Actor, a2, v6, 657456, -1);
     if ( v7 != -1 )
       return (unsigned __int16)v7;
   }
--- a/mm7_data.cpp	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_data.cpp	Sun Feb 17 11:41:44 2013 +0400
@@ -1,7 +1,7 @@
 #include "mm7_data.h"
 
 #include "NPC.h"
-
+#include "Actor.h"
 
 
 
@@ -47,13 +47,6 @@
 #include "stru279.h"
 stru279 stru_51076C;
 
-#include "stru157.h"
-stru157 stru_F93E1C; // weak
-stru157 stru_F93E30; // weak
-stru157 a5; // idb
-stru157 a4; // idb
-stru157 a3; // idb
-
 #include "stru179.h"
 stru179 pStru179;
 
@@ -391,9 +384,19 @@
 __int16 pTownPortalBook_ws[6];
 __int16 pTownPortalBook_hs[6];
 int dword_4E20D0[777]; // idb
-char byte_4E2430[777]; // weak
-char byte_4E2431[777]; // weak
-unsigned int pLloydsBeaconsPreviewXs[5] = {61, 281,  61, 281, 171};
+unsigned char pSpellbookSpellIndices[9][12] = // 4E2430
+{
+   {0,  3,  1,  8, 11,  7,  4, 10,  6,  2,  5,  9},
+   {0, 11,  2,  9,  6,  8,  5, 10,  3,  7,  1,  4},
+   {0,  4,  8,  9,  1, 10,  3, 11,  7,  6,  2,  5}, 
+   {0,  7, 10,  8,  2, 11,  1,  5,  3,  6,  4,  9},
+   {0,  5, 10, 11,  7,  2,  8,  1,  4,  9,  3,  6},
+   {0,  5,  9,  8,  3,  7,  6,  4,  1, 11,  2, 10}, 
+   {0,  1,  6,  9,  3,  5,  8, 11,  7, 10,  4,  2},
+   {0,  1, 10, 11,  9,  4,  3,  6,  5,  7,  8,  2},
+   {0,  9,  3,  7,  1,  5,  2, 10, 11,  8,  6,  4}
+};
+unsigned int pLloydsBeaconsPreviewXs[5] = {61, 281,  61, 281, 171}; // 004E249C
 unsigned int pLloydsBeaconsPreviewYs[5] = {84,  84, 228, 228, 155};
 unsigned int pLloydsBeacons_SomeXs[5] = {59, 279, 59, 279, 169};
 unsigned int pLloydsBeacons_SomeYs[5] = {82, 82, 226, 226, 153};
@@ -1094,16 +1097,128 @@
   "pc19lhu", "pc20lhu", "pc21lhu", "pc22lhu", "pc23lhu", "pc24lhu",
   "pc25lhu"
 };
-short SoundSetAction[192]= // 4ED3D8
+
+unsigned char byte_4ECF08[48][25] =      // 4ECF08
+{
+  {2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1},
+  {2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, // IMCOMPLETE
+  {2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+  {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+  {2, 2, 2, 2, 2, 1, 2, 2}
+};
+unsigned char SoundSetAction[110][8] = // 4ED3D8
 {
-	0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 37, 38, 45, 0, 0, 37, 0, 0, 47, 53, 0, 0, 0, 2, 0, 0, 25, 0, 0, 0, 0, 1, 0, 0, 47, 0,
-	0, 0, 0, 3, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 5, 0, 0, 21, 22, 23, 24, 45, 6, 0, 0, 47, 0, 0, 0, 0, 7, 0,
-	0, 43, 48, 0, 0, 0, 8, 0, 0, 38, 0, 0, 0, 0, 9, 0, 0, 39, 0, 0, 0, 0, 13, 0, 0, 37, 38, 0, 0, 0, 23, 0, 0, 25, 0, 0, 0,
-	0, 0, 0, 0, 37, 38, 45, 0, 0, 25, 0, 0, 25, 0, 0, 0, 0, 26, 0, 0, 38, 47, 0, 0, 0, 27, 0, 0, 41, 42, 0, 0, 0, 28, 0, 0,
-	25, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 30, 0, 0, 25, 0, 0, 0, 0, 29, 0, 0, 27, 0, 0, 0, 0, 32, 33, 0, 37, 38, 0, 0, 0,
-	34, 0, 0, 53, 0, 0, 0, 0
-}; // weak
-unsigned char byte_4ED498 = 15; // weak
+  { 0,  0,  0,  0,  0,  0,  0,  0},
+  {38,  0,  0, 37, 38, 45,  0,  0},
+  {37,  0,  0, 47, 53,  0,  0,  0},
+  { 2,  0,  0, 25,  0,  0,  0,  0},
+  { 1,  0,  0, 47,  0,  0,  0,  0},
+  { 3,  0,  0, 41, 42,  0,  0,  0},
+  { 0,  0,  0, 33,  0,  0,  0,  0},
+  { 5,  0,  0, 21, 22, 23, 24, 45},
+  { 6,  0,  0, 47,  0,  0,  0,  0},
+  { 7,  0,  0, 43, 48,  0,  0,  0},
+  { 8,  0,  0, 38,  0,  0,  0,  0},
+  { 9,  0,  0, 39,  0,  0,  0,  0},
+  {13,  0,  0, 37, 38,  0,  0,  0},
+  {23,  0,  0, 25,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38, 45,  0,  0},
+  {25,  0,  0, 25,  0,  0,  0,  0},
+  {26,  0,  0, 38, 47,  0,  0,  0},
+  {27,  0,  0, 41, 42,  0,  0,  0},
+  {28,  0,  0, 25,  0,  0,  0,  0},
+  { 0,  0,  0, 51,  0,  0,  0,  0},
+  {30,  0,  0, 25,  0,  0,  0,  0},
+  {29,  0,  0, 27,  0,  0,  0,  0},
+  {32, 33,  0, 37, 38,  0,  0,  0},
+  {34,  0,  0, 53,  0,  0,  0,  0},
+  {15,  0,  0, 34, 35, 36,  0,  0},
+  { 0,  0,  0,  3,  0,  0,  0,  0},
+  {22,  0,  0,  5,  0,  0,  0,  0},
+  {20,  0,  0,  8,  0,  0,  0,  0},
+  {20,  0,  0,  9,  0,  0,  0,  0},
+  {19,  0,  0,  7,  0,  0,  0,  0},
+  {21,  0,  0,  2,  0,  0,  0,  0},
+  {18,  0,  0,  6,  0,  0,  0,  0},
+  { 0,  0,  0, 11,  0,  0,  0,  0},
+  {17,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0, 12,  0,  0,  0,  0},
+  {17,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0, 37,  0,  0,  0,  0},
+  { 0,  0,  0, 49,  0,  0,  0,  0},
+  {24,  0,  0, 25,  0,  0,  0,  0},
+  {31,  0,  0, 25,  0,  0,  0,  0},
+  { 0,  0,  0, 41, 42,  0,  0,  0},
+  { 0,  0,  0, 39, 48,  0,  0,  0},
+  { 0,  0,  0, 46,  0,  0,  0,  0}, 
+  { 0,  0,  0, 39, 48,  0,  0,  0},
+  { 0,  0,  0, 41, 42,  0,  0,  0},
+  { 0,  0,  0, 39, 48,  0,  0,  0},
+  {41,  0,  0, 21,  0,  0,  0,  0},
+  {40,  0,  0, 21,  0,  0,  0,  0},
+  {16,  0,  0, 46,  0,  0,  0,  0},
+  { 0,  0,  0, 40,  0,  0,  0,  0},
+  { 0,  0,  0, 39,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 48, 49, 50,  0,  0},
+  { 0,  0,  0, 44,  0,  0,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38, 45,  0,  0},
+  { 0,  0,  0, 41, 42,  0,  0,  0},
+  { 0,  0,  0, 47,  0,  0,  0,  0},
+  { 0,  0,  0, 39, 48,  0,  0,  0},
+  { 0,  0,  0, 39, 48,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 31,  0,  0,  0,  0},
+  { 0,  0,  0, 32,  0,  0,  0,  0},
+  {47,  0,  0, 46,  0,  0,  0,  0},
+  {22,  0,  0,  5,  0,  0,  0,  0},
+  { 0,  0,  0, 25,  0,  0,  0,  0},
+  { 0,  0,  0, 37,  0,  0,  0,  0},
+  { 0,  0,  0, 52,  0,  0,  0,  0},
+  { 0,  0,  0, 45,  0,  0,  0,  0},
+  { 0,  0,  0, 27,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 49,  0,  0,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38, 45,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38, 45,  0,  0},
+  { 0,  0,  0, 47,  0,  0,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  {44,  0,  0, 39, 48,  0,  0,  0},
+  { 0,  0,  0, 48, 49,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0, 31,  0,  0,  0,  0},
+  {32, 33,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 47,  0,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  { 0,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0, 47,  0,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0, 38,  0,  0,  0,  0},
+  { 0,  0,  0,  5,  0,  0,  0,  0},
+  { 0,  0,  0, 37, 38,  0,  0,  0},
+  { 0,  0,  0, 44,  0,  0,  0,  0},
+  { 0,  0,  0, 48,  0,  0,  0,  0},
+  { 4,  0,  0,  0,  0,  0,  0,  0},
+  { 0,  0,  0, 58,  0,  0,  0,  0},
+  {10,  0,  0, 45,  0,  0,  0,  0},
+  {11,  0,  0, 47,  0,  0,  0,  0},
+  {12,  0,  0, 43, 48,  0,  0,  0},
+  {39,  0,  0, 48,  0,  0,  0,  0},
+  {14,  0,  0, 48,  0,  0,  0,  0},
+  {17,  0,  0,  0,  0,  0,  0,  0}
+};
 __int16 pPlayerPortraitsXCoords_For_PlayerBuffAnimsDrawing[4] = {34, 149, 264, 379};
 char byte_4ED970_skill_learn_ability_by_class_table[32][37];
 int dword_4EDEA0[777]; // weak
--- a/mm7_data.h	Sun Feb 17 11:29:10 2013 +0400
+++ b/mm7_data.h	Sun Feb 17 11:41:44 2013 +0400
@@ -374,9 +374,8 @@
 extern __int16 pTownPortalBook_ws[6];
 extern __int16 pTownPortalBook_hs[6];
 extern int dword_4E20D0[]; // idb
-extern char byte_4E2430[]; // weak
-extern char byte_4E2431[]; // weak
-extern unsigned int pLloydsBeaconsPreviewXs[5];
+extern unsigned char pSpellbookSpellIndices[9][12]; // 4E2430
+extern unsigned int pLloydsBeaconsPreviewXs[5]; // 004E249C
 extern unsigned int pLloydsBeaconsPreviewYs[5];
 extern unsigned int pLloydsBeacons_SomeXs[5];
 extern unsigned int pLloydsBeacons_SomeYs[5]; // idb
@@ -979,8 +978,9 @@
 extern const char *drh_texnames_by_face[25];
 extern const char *dlh_texnames_by_face[25];
 extern const char *dlhu_texnames_by_face[25];
-extern short SoundSetAction[192]; // weak
-extern unsigned char byte_4ED498; // weak
+extern unsigned char byte_4ECF08[48][25];
+extern unsigned char SoundSetAction[110][8]; // weak
+//extern unsigned char byte_4ED498; // weak
 extern __int16 pPlayerPortraitsXCoords_For_PlayerBuffAnimsDrawing[4];
 extern char byte_4ED970_skill_learn_ability_by_class_table[32][37];
 extern int dword_4EDEA0[]; // weak
@@ -1154,7 +1154,6 @@
 extern __int64 qword_506350; // weak
 extern char byte_506360; // weak
 extern int dword_506364; // weak
-extern Texture *dword_506408[]; // weak
 extern Texture *dword_50640C[]; // weak
 extern unsigned int uTextureID_506438;
 extern int dword_50651C; // weak
@@ -1374,7 +1373,7 @@
 extern int dword_5C35D4; // weak
 extern char *aAMPMNames[2];
 extern char byte_5C45AF[]; // weak
-extern char pTmpBuf3[2048];
+extern char pTmpBuf3[];
 extern char pFinalMessage[4096]; // idb
 extern char pTmpBuf[2000];
 extern char pTmpBuf2[2000];
@@ -1827,7 +1826,7 @@
 signed int __fastcall sub_410D99_get_map_index(int a1);
 unsigned int __cdecl DrawLloydBeaconsScreen();
 char *__cdecl DrawTownPortalScreen();
-struct Texture *__fastcall LoadSpellbook(unsigned int uID); // idb
+void LoadSpellbook(unsigned int uID); // idb
 struct GUIWindow *__cdecl sub_41140B();
 void __cdecl sub_411473();
 void __cdecl OnCloseSpellook();
@@ -2145,7 +2144,7 @@
 void __cdecl OnPaperdollLeftClick();
 int __thiscall UnprojectX(int x);
 int __thiscall UnprojectY(int _this);
-char __cdecl OnPressSpace();
+void OnPressSpace();
 char __fastcall DoInteractionWithTopmostZObject(int a1, int a2);
 int __fastcall sub_46A6AC(int a1, int a2, int a3);
 int __fastcall sub_46A7C8(int a1, int a2, signed int a3);
--- a/stru157.h	Sun Feb 17 11:29:10 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-#pragma once
-
-
-/*  150 */
-#pragma pack(push, 1)
-struct stru157
-{
-  int field_0;
-  int field_4;
-  int field_8;
-  int field_C;
-  int field_10;
-};
-#pragma pack(pop)
-extern stru157 stru_F93E1C; // weak
-extern stru157 stru_F93E30; // weak
-extern stru157 a5; // idb
-extern stru157 a4; // idb
-extern stru157 a3; // idb
\ No newline at end of file