changeset 2397:eff78dab2142

Fixing GameUI_WritePointedObjectStatusString conditions
author Grumpy7
date Thu, 10 Jul 2014 00:58:45 +0200
parents 56f87a5c402b
children 79e750ba00b9
files UI/UiGame.cpp
diffstat 1 files changed, 281 insertions(+), 274 deletions(-) [+]
line wrap: on
line diff
--- a/UI/UiGame.cpp	Sat Jun 21 00:42:34 2014 +0200
+++ b/UI/UiGame.cpp	Thu Jul 10 00:58:45 2014 +0200
@@ -1152,32 +1152,31 @@
   GUIButton *pButton; // ecx@11
   int v7; // ecx@19
   enum UIMessageType pMessageType1; // esi@24
-//  int v14; // eax@41
+  int v14; // eax@41
   ItemGen *pItemGen; // ecx@44
   int v16; // ecx@46
   signed int v18; // eax@55
   signed int v18b;
   signed int v19; // ecx@63
+  BLVFace *pFace; // eax@69
   const char *pText; // ecx@79
-//  char *v28; // esi@82
-//  enum UIMessageType pMessageType2; // esi@110
-//  enum UIMessageType pMessageType3; // edx@117
+  char *v28; // esi@82
+  enum UIMessageType pMessageType2; // esi@110
+  enum UIMessageType pMessageType3; // edx@117
   char Str1[200]; // [sp+Ch] [bp-D4h]@129
   unsigned int pX; // [sp+D4h] [bp-Ch]@1
   unsigned int pY; // [sp+D8h] [bp-8h]@1
-//  unsigned int v45; // [sp+DCh] [bp-4h]@21
+  unsigned int v45; // [sp+DCh] [bp-4h]@21
 
   int interaction_distance_limit = 512;
-  int monster_info_distance_limit = 5120;
 
   pMouse->uPointingObjectID = 0;
   pMouse->GetClickPos(&pX, &pY);
-  if ( pX < 0 || pX > window->GetWidth() - 1 || pY < 0 || pY > window->GetHeight() - 1 )//границы окна игры
+  if ( pX < 0 || pX > 639 || pY < 0 || pY > 479 )
     return;
-  if ( pX <= 467 && pY <= 351 )//пределы основной области
+  if ( pCurrentScreen == SCREEN_GAME )
   {
-    //окно(область) игры----------------------------------
-    if ( pCurrentScreen == SCREEN_GAME )
+    if ( pX <= 467 && pY <= 351 ) 
     {
       //if ( pRenderer->pRenderD3D )  // inlined mm8::4C1E01
       {
@@ -1201,27 +1200,44 @@
         }
       }
       /*else
-        v18 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]];*/
+      {
+        v18 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]];
+      }*/
       pMouse->uPointingObjectID = (unsigned __int16)v18;
       v19 = (signed)PID_ID(v18);
-      //For Items------------------------------------
-      if (PID_TYPE(v18) == OBJECT_Item)
+      if ( PID_TYPE(v18) == OBJECT_Item )
       {
         if ( pObjectList->pObjects[pSpriteObjects[v19].uObjectDescID].uFlags & 0x10 )
         {
           pMouse->uPointingObjectID = 0;
-          pFooterString[0] = 0;
-          bForceDrawFooter = 1;
-          uLastPointedObjectID = 0;
+          uLastPointedObjectID = 1;
+          if ( pMouse->uPointingObjectID == 0 )
+          {
+            if ( uLastPointedObjectID != 0 )
+            {
+              pFooterString[0] = 0;
+              bForceDrawFooter = 1;
+            }
+          }
+          uLastPointedObjectID = pMouse->uPointingObjectID;
           return;
         }
-        if ( HIWORD(v18) < interaction_distance_limit && !pParty->pPickedItem.uItemID )
+        if ( v18 >= 0x2000000u || pParty->pPickedItem.uItemID )
         {
-          sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[470], pSpriteObjects[v19].stru_24.GetDisplayName());// "Get %s"
-          GameUI_SetFooterString(pTmpBuf.data());
+          GameUI_SetFooterString(pSpriteObjects[v19].stru_24.GetDisplayName());
+          if ( pMouse->uPointingObjectID == 0 )
+          {
+            if ( uLastPointedObjectID != 0 )
+            {
+              pFooterString[0] = 0;
+              bForceDrawFooter = 1;
+            }
+          }
+          uLastPointedObjectID = pMouse->uPointingObjectID;
           return;
         }
-        GameUI_SetFooterString(pSpriteObjects[v19].stru_24.GetDisplayName());
+        sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[470], pSpriteObjects[v19].stru_24.GetDisplayName());// "Get %s"
+        GameUI_SetFooterString(pTmpBuf.data());
         if ( pMouse->uPointingObjectID == 0 )
         {
           if ( uLastPointedObjectID != 0 )
@@ -1233,22 +1249,40 @@
         uLastPointedObjectID = pMouse->uPointingObjectID;
         return;
       }
-      //For Decorations----------------------------------
-      if (PID_TYPE(v18) == OBJECT_Decoration)
+      else if ( PID_TYPE(v18) == OBJECT_Decoration )
       {
         if ( !pLevelDecorations[v19].uEventID )
         {
           if ( pLevelDecorations[v19].IsInteractive() )
-            pText = pNPCTopics[stru_5E4C90_MapPersistVars._decor_events[pLevelDecorations[v19]._idx_in_stru123 - 75] + 380].pTopic;//-379
+            pText = pNPCTopics[stru_5E4C90_MapPersistVars._decor_events[pLevelDecorations[v19]._idx_in_stru123 - 75] + 379].pTopic;//неверно для костра
           else
             pText = pDecorationList->pDecorations[pLevelDecorations[v19].uDecorationDescID].field_20;
           GameUI_SetFooterString(pText);
+          if ( pMouse->uPointingObjectID == 0 )
+          {
+            if ( uLastPointedObjectID != 0 )
+            {
+              pFooterString[0] = 0;
+              bForceDrawFooter = 1;
+            }
+          }
+          uLastPointedObjectID = pMouse->uPointingObjectID;
+          return;
         }
-        else
+        if (  !GetEventHintString(pLevelDecorations[v19].uEventID) )
         {
-        if ( GetEventHintString(pLevelDecorations[v19].uEventID) )
-          GameUI_SetFooterString(GetEventHintString(pLevelDecorations[v19].uEventID));
+          if ( pMouse->uPointingObjectID == 0 )
+          {
+            if ( uLastPointedObjectID != 0 )
+            {
+              pFooterString[0] = 0;
+              bForceDrawFooter = 1;
+            }
+          }
+          uLastPointedObjectID = pMouse->uPointingObjectID;
+          return;
         }
+        GameUI_SetFooterString(GetEventHintString(pLevelDecorations[v19].uEventID));
         if ( pMouse->uPointingObjectID == 0 )
         {
           if ( uLastPointedObjectID != 0 )
@@ -1260,21 +1294,27 @@
         uLastPointedObjectID = pMouse->uPointingObjectID;
         return;
       }
-      //For 3D Model-------------------------------------
-      if (PID_TYPE(v18) == OBJECT_BModel)
+      else if ( PID_TYPE(v18) == OBJECT_BModel )
       {
-        if ( HIWORD(v18) < interaction_distance_limit )
+        if ( v18 < 0x2000000u )
         {
-          if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+          if ( uCurrentlyLoadedLevelType != LEVEL_Indoor )
           {
             v18b = (signed int)(unsigned __int16)v18 >> 9;
             if ( !pOutdoor->pBModels[v18b].pFaces[v19 & 0x3F].sCogTriggeredID
               || !GetEventHintString(pOutdoor->pBModels[v18b].pFaces[v19 & 0x3F].sCogTriggeredID) )
             {
               pMouse->uPointingObjectID = 0;
-              pFooterString[0] = 0;
-              bForceDrawFooter = 1;
-              uLastPointedObjectID = 0;
+              uLastPointedObjectID = 1;
+              if ( pMouse->uPointingObjectID == 0 )
+              {
+                if ( uLastPointedObjectID != 0 )
+                {
+                  pFooterString[0] = 0;
+                  bForceDrawFooter = 1;
+                }
+              }
+              uLastPointedObjectID = pMouse->uPointingObjectID;
               return;
             }
             GameUI_SetFooterString(GetEventHintString(pOutdoor->pBModels[v18b].pFaces[v19 & 0x3F].sCogTriggeredID));
@@ -1289,20 +1329,14 @@
             uLastPointedObjectID = pMouse->uPointingObjectID;
             return;
           }
-          if ( uCurrentlyLoadedLevelType == LEVEL_Indoor)
+          pFace = &pIndoor->pFaces[v19];
+          if ( BYTE3(pFace->uAttributes) & 6 )
           {
-            if ( pIndoor->pFaces[v19].uAttributes & FACE_INDICATE )
+            if ( !pIndoor->pFaceExtras[pFace->uFaceExtraID].uEventID
+              || !GetEventHintString(pIndoor->pFaceExtras[pFace->uFaceExtraID].uEventID) )
             {
-              if ( !pIndoor->pFaceExtras[pIndoor->pFaces[v19].uFaceExtraID].uEventID
-               || !GetEventHintString(pIndoor->pFaceExtras[pIndoor->pFaces[v19].uFaceExtraID].uEventID) )
-              {
-                pMouse->uPointingObjectID = 0;
-                pFooterString[0] = 0;
-                bForceDrawFooter = 1;
-                uLastPointedObjectID = 0;
-                return;
-              }
-              GameUI_SetFooterString(GetEventHintString(pIndoor->pFaceExtras[pIndoor->pFaces[v19].uFaceExtraID].uEventID));
+              pMouse->uPointingObjectID = 0;
+              uLastPointedObjectID = 1;
               if ( pMouse->uPointingObjectID == 0 )
               {
                 if ( uLastPointedObjectID != 0 )
@@ -1314,23 +1348,65 @@
               uLastPointedObjectID = pMouse->uPointingObjectID;
               return;
             }
+            GameUI_SetFooterString(GetEventHintString(pIndoor->pFaceExtras[pFace->uFaceExtraID].uEventID));
+            if ( pMouse->uPointingObjectID == 0 )
+            {
+              if ( uLastPointedObjectID != 0 )
+              {
+                pFooterString[0] = 0;
+                bForceDrawFooter = 1;
+              }
+            }
+            uLastPointedObjectID = pMouse->uPointingObjectID;
+            return;
           }
         }
         pMouse->uPointingObjectID = 0;
-        pFooterString[0] = 0;
-        bForceDrawFooter = 1;
-        uLastPointedObjectID = 0;
+        uLastPointedObjectID = 1;
+        if ( pMouse->uPointingObjectID == 0 )
+        {
+          if ( uLastPointedObjectID != 0 )
+          {
+            pFooterString[0] = 0;
+            bForceDrawFooter = 1;
+          }
+        }
+        uLastPointedObjectID = pMouse->uPointingObjectID;
         return;
       }
-      if (PID_TYPE(v18) == OBJECT_Actor && HIWORD(v18) < monster_info_distance_limit )
-      {
+      else if ( PID_TYPE(v18) == OBJECT_Actor )
+      {          
+        if ( v18 >= 0x2000000u )
+        {
+          pMouse->uPointingObjectID = 0;
+          if ( pMouse->uPointingObjectID == 0 )
+          {
+            if ( uLastPointedObjectID != 0 )
+            {
+              pFooterString[0] = 0;
+              bForceDrawFooter = 1;
+            }
+          }
+          uLastPointedObjectID = pMouse->uPointingObjectID;
+          return;
+        }
         if ( pActors[v19].dword_000334_unique_name )
           pText = pMonsterStats->pPlaceStrings[pActors[v19].dword_000334_unique_name];
         else
           pText = pMonsterStats->pInfos[pActors[v19].pMonsterInfo.uID].pName;
-        strncpy(pTmpBuf.data(), pText, 2000);
-        GameUI_SetFooterString(pTmpBuf.data());
+        GameUI_SetFooterString(pText);
+        if ( pMouse->uPointingObjectID == 0 )
+        {
+          if ( uLastPointedObjectID != 0 )
+          {
+            pFooterString[0] = 0;
+            bForceDrawFooter = 1;
+          }
+        }
+        uLastPointedObjectID = pMouse->uPointingObjectID;
+        return;
       }
+      pMouse->uPointingObjectID = 0;
       if ( pMouse->uPointingObjectID == 0 )
       {
         if ( uLastPointedObjectID != 0 )
@@ -1342,7 +1418,76 @@
       uLastPointedObjectID = pMouse->uPointingObjectID;
       return;
     }
-    //окно(область) ящика-------------------------------------------
+  }
+  else
+  {    
+    for (v1 = uNumVisibleWindows; v1 > 0; --v1)
+    {
+      pWindow = &pWindowList[pVisibleWindowsIdxs[v1] - 1];
+      if ( (signed int)pX >= (signed int)pWindow->uFrameX && (signed int)pX <= (signed int)pWindow->uFrameZ
+        && (signed int)pY >= (signed int)pWindow->uFrameY && (signed int)pY <= (signed int)pWindow->uFrameW )
+      {
+        for ( pButton = pWindow->pControlsHead; pButton != nullptr; pButton = pButton->pNext )
+        {
+          switch ( pButton->uButtonType )
+          {
+          case 1://for dialogue window
+            if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
+              && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
+            {
+              pMessageType1 = (UIMessageType)pButton->field_1C;
+              if ( pMessageType1 )
+                pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
+              GameUI_SetFooterString(pButton->pButtonName);
+              uLastPointedObjectID = 1;
+              return;
+            }
+            break;
+          case 2://hovering over portraits
+            if (pButton->uWidth != 0 && pButton->uHeight != 0)
+            {
+              uint distW = pX - pButton->uX;
+              uint distY = pY - pButton->uY;
+
+              double ratioX = 1.0 * (distW*distW) / (pButton->uWidth*pButton->uWidth);
+              double ratioY = 1.0 * (distY*distY) / (pButton->uHeight*pButton->uHeight);
+
+              if (ratioX + ratioY < 1.0)
+              {
+                pMessageType2 = (UIMessageType)pButton->field_1C;
+                if ( pMessageType2 != 0 )
+                  pMessageQueue_50CBD0->AddMessage(pMessageType2, pButton->msg_param, 0);
+                GameUI_SetFooterString(pButton->pButtonName); // for character name
+                uLastPointedObjectID = 1;
+                return;
+              }
+            }
+            break;
+          case 3:// click on skill
+            if ( pX >= pButton->uX && pX <= pButton->uZ
+              && pY >= pButton->uY && pY <= pButton->uW )
+            {
+              v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
+              if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
+                sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
+              else
+                sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
+              GameUI_SetFooterString(Str1);
+              uLastPointedObjectID = 1;
+              return;
+            }
+            break;
+          }
+        }
+      }
+      if ( pWindow->uFrameHeight == 480 )
+      {
+        //DebugBreak(); //Why is this condition here (in the original too)? Might check fullscreen windows. Let Silvo know if you find out
+        return;
+      }
+    }
+    //The game never gets to this point even in the original. It's also bugged(neither branch displays anything). 
+    //TODO fix these and move them up before the window check loop.
     if ( pCurrentScreen == SCREEN_CHEST )
     {
       Chest::ChestUI_WritePointedObjectStatusString();
@@ -1357,31 +1502,26 @@
       uLastPointedObjectID = pMouse->uPointingObjectID;
       return;
     }
-    //окно(область) магазина-----------------------------------------
-    if ( pCurrentScreen == SCREEN_HOUSE )
+    else if ( pCurrentScreen == SCREEN_HOUSE )
     {
-      v16 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]];
-      if ( v16 != 0 && v16 != -65536 )
+      if ( dialog_menu_id != HOUSE_DIALOGUE_SHOP_BUY_STANDARD
+        || (v16 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]], v16 == 0)
+        || v16 == -65536 )
       {
-        if ( dialog_menu_id == HOUSE_DIALOGUE_SHOP_BUY_STANDARD )
+        if ( pMouse->uPointingObjectID == 0 )
         {
-          pItemGen = &pParty->StandartItemsInShops[(unsigned int)window_SpeakInHouse->ptr_1C][v16-1];
-          GameUI_SetFooterString(pItemGen->GetDisplayName());
-          uLastPointedObjectID = 1;
+          if ( uLastPointedObjectID != 0 )
+          {
+            pFooterString[0] = 0;
+            bForceDrawFooter = 1;
+          }
         }
-        if ( dialog_menu_id == HOUSE_DIALOGUE_SHOP_BUY_SPECIAL )
-        {
-          pItemGen = &pParty->SpecialItemsInShops[(unsigned int)window_SpeakInHouse->ptr_1C][v16-1];
-          GameUI_SetFooterString(pItemGen->GetDisplayName());
-          uLastPointedObjectID = 1;
-        }
-        if ( dialog_menu_id == HOUSE_DIALOGUE_SHOP_SELL )
-        {
-          pItemGen = &pPlayers[uActiveCharacter]->pInventoryItemList[v16-1];
-          GameUI_SetFooterString(pItemGen->GetDisplayName());
-          uLastPointedObjectID = 1;
-        }
+        uLastPointedObjectID = pMouse->uPointingObjectID;
+        return;
       }
+      pItemGen = (ItemGen *)((char *)&pParty->pPickedItem + 36 * (v16 + 12 * (unsigned int)window_SpeakInHouse->ptr_1C) + 4);
+      GameUI_SetFooterString(pItemGen->GetDisplayName());
+      uLastPointedObjectID = 1;
       if ( pMouse->uPointingObjectID == 0 )
       {
         if ( uLastPointedObjectID != 0 )
@@ -1393,227 +1533,94 @@
       uLastPointedObjectID = pMouse->uPointingObjectID;
       return;
     }
-    //-----------------------------------------
-    for ( v1 = uNumVisibleWindows; v1 >= 0; --v1 ) // some other fullscreen ui
+    if ( pY < 350 )
     {
-      pWindow = &pWindowList[pVisibleWindowsIdxs[v1] - 1];
-      if ( (signed int)pX >= (signed int)pWindow->uFrameX && (signed int)pX <= (signed int)pWindow->uFrameZ
-        && (signed int)pY >= (signed int)pWindow->uFrameY && (signed int)pY <= (signed int)pWindow->uFrameW )
+      v14 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]];
+      if ( v14 == 0 || v14 == -65536 || v14 >= 5000 )
       {
-        for ( pButton = pWindow->pControlsHead; ; pButton = pButton->pNext )
+        if ( pMouse->uPointingObjectID == 0 )
         {
-          if ( !pButton )
-            break;
-          switch ( pButton->uButtonType )
+          if ( uLastPointedObjectID != 0 )
           {
-            case 1://for dialogue window
-              if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
-                && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
-              {
-                pMessageType1 = (UIMessageType)pButton->field_1C;
-                if ( pMessageType1 )
-                  pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                GameUI_SetFooterString(pButton->pButtonName);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
-            case 2:
-              if ( pX >= pButton->uX && pX <= pButton->uZ
-                && pY >= pButton->uY && pY <= pButton->uW )
-              {
-                pMessageType1 = (UIMessageType)pButton->field_1C;
-                if ( pMessageType1 )
-                  pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                GameUI_SetFooterString(pButton->pButtonName);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
-            case 3:// click on skill
-              if ( pX >= pButton->uX && pX <= pButton->uZ
-                && pY >= pButton->uY && pY <= pButton->uW )
-              {
-                v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
-                if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
-                  sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
-                else
-                  sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
-                GameUI_SetFooterString(Str1);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
+            pFooterString[0] = 0;
+            bForceDrawFooter = 1;
           }
         }
+        uLastPointedObjectID = pMouse->uPointingObjectID;
+        return;
       }
-    }
-  }//конец пределов основного экрана------------------------
-  if ( pX > 467 && pX <= window->GetWidth() - 1 && pY <= window->GetHeight() - 1 )//пределы правой области
-  {
-    if ( pCurrentScreen == SCREEN_GAME )
-    {
-      pWindow = &pWindowList[0];
-      if ( (signed int)pX >= (signed int)pWindow->uFrameX && (signed int)pX <= (signed int)pWindow->uFrameZ
-        && (signed int)pY >= (signed int)pWindow->uFrameY && (signed int)pY <= (signed int)pWindow->uFrameW )
+      pItemGen = (ItemGen *)&pPlayers[uActiveCharacter]->pInventoryItemList[v14-1];
+      GameUI_SetFooterString(pItemGen->GetDisplayName());
+      uLastPointedObjectID = 1;
+      if ( pMouse->uPointingObjectID == 0 )
       {
-        for ( pButton = pWindow->pControlsHead; ; pButton = pButton->pNext )
+        if ( uLastPointedObjectID != 0 )
         {
-          if ( !pButton )
-            break;
-          switch ( pButton->uButtonType )
-          {
-            case 1://for dialogue window
-              if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
-                && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
-              {
-                pMessageType1 = (UIMessageType)pButton->field_1C;
-                if ( pMessageType1 )
-                  pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                GameUI_SetFooterString(pButton->pButtonName);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
-            case 2:
-              if ( pX >= pButton->uX && pX <= pButton->uZ
-                && pY >= pButton->uY && pY <= pButton->uW )
-              {
-                pMessageType1 = (UIMessageType)pButton->field_1C;
-                if ( pMessageType1 )
-                  pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                GameUI_SetFooterString(pButton->pButtonName);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
-            case 3:// click on skill
-              if ( pX >= pButton->uX && pX <= pButton->uZ
-                && pY >= pButton->uY && pY <= pButton->uW )
-              {
-                v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
-                if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
-                  sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
-                else
-                  sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
-                GameUI_SetFooterString(Str1);
-                uLastPointedObjectID = 1;
-                return;
-              }
-              break;
-          }
+          pFooterString[0] = 0;
+          bForceDrawFooter = 1;
         }
       }
+      uLastPointedObjectID = pMouse->uPointingObjectID;
+      return;
     }
-    else
+  }
+  if ( (signed int)pX >= (signed int)pWindowList[0].uFrameX && (signed int)pX <= (signed int)pWindowList[0].uFrameZ
+    && (signed int)pY >= (signed int)pWindowList[0].uFrameY && (signed int)pY <= (signed int)pWindowList[0].uFrameW )
+  {
+    for ( pButton = pWindowList[0].pControlsHead; pButton != nullptr; pButton = pButton->pNext )
     {
-      for ( v1 = uNumVisibleWindows; v1 > 0; --v1 )
+      switch (pButton->uButtonType)
       {
-        pWindow = &pWindowList[pVisibleWindowsIdxs[v1] - 1];
-        if ( (signed int)pX >= (signed int)pWindow->uFrameX && (signed int)pX <= (signed int)pWindow->uFrameZ
-          && (signed int)pY >= (signed int)pWindow->uFrameY && (signed int)pY <= (signed int)pWindow->uFrameW )
+      case 1:
+        if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
+          && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
         {
-          for ( pButton = pWindow->pControlsHead; ; pButton = pButton->pNext )
+          pMessageType3 = (UIMessageType)pButton->field_1C;
+          if ( pMessageType3 == 0 ) // For books
           {
-            if ( !pButton )
-              break;
-            switch ( pButton->uButtonType )
-            {
-              case 1://for dialogue window
-                if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
-                  && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
-                {
-                  pMessageType1 = (UIMessageType)pButton->field_1C;
-                  if ( pMessageType1 )
-                    pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                  GameUI_SetFooterString(pButton->pButtonName);
-                  uLastPointedObjectID = 1;
-                  return;
-                }
-                break;
-              case 2:
-                if ( pX >= pButton->uX && pX <= pButton->uZ
-                  && pY >= pButton->uY && pY <= pButton->uW )
-                {
-                  pMessageType1 = (UIMessageType)pButton->field_1C;
-                  if ( pMessageType1 )
-                    pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-                  GameUI_SetFooterString(pButton->pButtonName);
-                  uLastPointedObjectID = 1;
-                  return;
-                }
-                break;
-              case 3:// click on skill
-                if ( pX >= pButton->uX && pX <= pButton->uZ
-                  && pY >= pButton->uY && pY <= pButton->uW )
-                {
-                  v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
-                  if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
-                    sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
-                  else
-                    sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
-                  GameUI_SetFooterString(Str1);
-                  uLastPointedObjectID = 1;
-                  return;
-                }
-                break;
-            }
+            GameUI_SetFooterString(pButton->pButtonName);
+            uLastPointedObjectID = 1;
+            return;
+          }
+          pMessageQueue_50CBD0->AddMessage(pMessageType3, pButton->msg_param, 0);
+          uLastPointedObjectID = 1;
+          return;
+        }
+        break;
+      case 2://hovering over portraits
+        if (pButton->uWidth != 0 && pButton->uHeight != 0)
+        {
+          uint distW = pX - pButton->uX;
+          uint distY = pY - pButton->uY;
+
+          double ratioX = 1.0 * (distW*distW) / (pButton->uWidth*pButton->uWidth);
+          double ratioY = 1.0 * (distY*distY) / (pButton->uHeight*pButton->uHeight);
+
+          if (ratioX + ratioY < 1.0)
+          {
+            pMessageType2 = (UIMessageType)pButton->field_1C;
+            if ( pMessageType2 != 0 )
+              pMessageQueue_50CBD0->AddMessage(pMessageType2, pButton->msg_param, 0);
+            GameUI_SetFooterString(pButton->pButtonName); // for character name
+            uLastPointedObjectID = 1;
+            return;
           }
         }
-      }
-    }
-  }
-  if ( pX <= 467 && pY > 351 && pY <= 479 )//пределы нижней области
-  {
-    pWindow = &pWindowList[0];
-    if ( (signed int)pX >= (signed int)pWindow->uFrameX && (signed int)pX <= (signed int)pWindow->uFrameZ
-      && (signed int)pY >= (signed int)pWindow->uFrameY && (signed int)pY <= (signed int)pWindow->uFrameW )
-    {
-      for ( pButton = pWindow->pControlsHead; ; pButton = pButton->pNext )
-      {
-        if ( !pButton )
-          break;
-        switch ( pButton->uButtonType )
+        break;
+      case 3:
+        if ( pX >= pButton->uX && pX <= pButton->uZ
+          && pY >= pButton->uY && pY <= pButton->uW )
         {
-          case 1://for dialogue window
-            if ( (signed int)pX >= (signed int)pButton->uX && (signed int)pX <= (signed int)pButton->uZ
-              && (signed int)pY >= (signed int)pButton->uY && (signed int)pY <= (signed int)pButton->uW )
-            {
-              pMessageType1 = (UIMessageType)pButton->field_1C;
-              if ( pMessageType1 )
-                pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-              GameUI_SetFooterString(pButton->pButtonName);
-              uLastPointedObjectID = 1;
-              return;
-            }
-            break;
-          case 2:
-            if ( pX >= pButton->uX && pX <= pButton->uZ
-              && pY >= pButton->uY && pY <= pButton->uW )
-            {
-              pMessageType1 = (UIMessageType)pButton->field_1C;
-              if ( pMessageType1 )
-                pMessageQueue_50CBD0->AddMessage(pMessageType1, pButton->msg_param, 0);
-              GameUI_SetFooterString(pButton->pButtonName);
-              uLastPointedObjectID = 1;
-              return;
-            }
-            break;
-           case 3:// click on skill
-             if ( pX >= pButton->uX && pX <= pButton->uZ
-               && pY >= pButton->uY && pY <= pButton->uW )
-             {
-               v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
-               if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
-                 sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
-               else
-                 sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
-               GameUI_SetFooterString(Str1);
-               uLastPointedObjectID = 1;
-               return;
-             }
-             break;
+          v7 = (LOBYTE(pPlayers[uActiveCharacter]->pActiveSkills[pButton->msg_param]) & 0x3F) + 1;
+          if ( pPlayers[uActiveCharacter]->uSkillPoints < v7 )
+            sprintf(Str1, pGlobalTXT_LocalizationStrings[469], v7 - pPlayers[uActiveCharacter]->uSkillPoints);// "You need %d more Skill Points to advance here"
+          else
+            sprintf(Str1, pGlobalTXT_LocalizationStrings[468], v7);// "Clicking here will spend %d Skill Points"
+          GameUI_SetFooterString(Str1);
+          uLastPointedObjectID = 1;
+          return;
         }
+        break;
       }
     }
   }