view GUI/UI/UIPopup.cpp @ 2541:a902abdfc7f2

1. Renamed class Game to class Engine. 2. Separated game logic as state of FSM from game logic as engine. 3. Found out that many UI screen initializers were optimized away, intially they all returned newly created window as separate object like it is done in CharacterUI_Initialize.
author a.parshin
date Sun, 10 May 2015 01:29:11 +0200
parents 1bcadc6dd203
children c674d547cc7c
line wrap: on
line source
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define _CRT_SECURE_NO_WARNINGS

#include "Engine/Engine.h"

#include "UIPopup.h"
#include "Books\UIMapBook.h"
#include "UIShops.h"

#include "..\../IO/Mouse.h"

#include "..\../Engine/Graphics/Sprites.h"
#include "..\../Engine/Graphics/Vis.h"
#include "..\../GUI/GUIWindow.h"
#include "..\../GUI/GUIFont.h"
#include "..\../Engine/Party.h"
#include "..\../Media/Audio/AudioPlayer.h"
#include "..\../Engine/LOD.h"
#include "..\../Engine/Objects/Actor.h"
#include "..\../Engine/Graphics/Viewport.h"
#include "..\../Engine/Objects/SpriteObject.h"
#include "..\../Engine/Objects/ObjectList.h"
#include "..\../Engine/Objects/Chest.h"
#include "..\../Engine/Graphics/PaletteManager.h"
#include "..\../Engine/Timer.h"
#include "..\../Engine/texts.h"
#include "..\../Engine/Events.h"

static char static_sub_417BB5_out_string[1200]; // static to a file, not sub actually


//----- (004179BC) --------------------------------------------------------
void CharacterUI_DrawTooltip(const char *Title, const char *content)
{
  GUIWindow popup_window; // [sp+Ch] [bp-5Ch]@1
  POINT v6; // [sp+60h] [bp-8h]@1

  memset(&popup_window, 0, 0x54u);
  popup_window.uFrameWidth = 384;
  popup_window.uFrameHeight = 256;
  popup_window.uFrameX = 128;
  popup_window.uFrameY = pMouse->GetCursorPos(&v6)->y + 30;
  popup_window.uFrameHeight = pFontSmallnum->CalcTextHeight(content, &popup_window, 24, 0) + 2 * LOBYTE(pFontLucida->uFontHeight) + 24;
  popup_window.uFrameZ = popup_window.uFrameX + popup_window.uFrameWidth - 1;
  popup_window.uFrameW = popup_window.uFrameY + popup_window.uFrameHeight - 1;
  popup_window.DrawMessageBox(0);

  popup_window.uFrameX += 12;
  popup_window.uFrameWidth -= 24;
  popup_window.uFrameY += 12;
  popup_window.uFrameHeight -= 12;
  popup_window.uFrameZ = popup_window.uFrameX + popup_window.uFrameWidth - 1;
  popup_window.uFrameW = popup_window.uFrameY + popup_window.uFrameHeight - 1;
  sprintf(pTmpBuf.data(), "\f%05d%s\f00000\n", ui_character_tooltip_header_default_color, Title);
  popup_window.DrawTitleText(pFontCreate, 0, 0, 0, pTmpBuf.data(), 3);
  popup_window.DrawText(pFontSmallnum, 1, LOBYTE(pFontLucida->uFontHeight), 0, content, 0, 0, 0);
}

//----- (004151D9) --------------------------------------------------------
void __fastcall DrawPopupWindow(unsigned int uX, unsigned int uY, unsigned int uWidth, unsigned int uHeight)
{
  unsigned int uNumTiles; // [sp+2Ch] [bp-Ch]@6
  unsigned int coord_x; // [sp+2Ch] [bp-Ch]@3
  unsigned int coord_y; // [sp+34h] [bp-4h]@5

  auto parchment = pIcons_LOD->GetTexture(uTextureID_Parchment);

  if ( parchment->uTextureWidth && parchment->uTextureHeight)
  {
    pRenderer->SetUIClipRect(uX, uY, uX + uWidth, uY + uHeight);

    uNumTiles = uWidth / parchment->uTextureWidth;
    if ( uWidth % parchment->uTextureWidth )
      ++uNumTiles;
    coord_y = uY;
    for ( uint j = 0; j <= uHeight / parchment->uTextureHeight; j++ )
    {
      coord_x = uX - parchment->uTextureWidth;
      for ( uint i = uNumTiles + 1; i; --i )
      {
        coord_x += parchment->uTextureWidth;
        pRenderer->DrawTextureIndexed(coord_x, coord_y, parchment);
      }
      coord_y += parchment->uTextureHeight;
    }
    pRenderer->DrawTextureIndexedAlpha(uX,               uY,                pIcons_LOD->GetTexture(uTextureID_5076AC));
    pRenderer->DrawTextureIndexedAlpha(uX,               uY + uHeight - 32, pIcons_LOD->GetTexture(uTextureID_5076B4));
    pRenderer->DrawTextureIndexedAlpha(uX + uWidth - 32, uY,                pIcons_LOD->GetTexture(uTextureID_5076A8));
    pRenderer->DrawTextureIndexedAlpha(uX + uWidth - 32, uY + uHeight - 32, pIcons_LOD->GetTexture(uTextureID_5076B0));
    if ( uWidth > 64 )
    {
      pRenderer->SetUIClipRect(uX + 32, uY, uX + uWidth - 32, uY + uHeight);
      pRenderer->DrawTextureIndexedAlpha(uX + 32, uY,                pIcons_LOD->GetTexture(uTextureID_507698));
      pRenderer->DrawTextureIndexedAlpha(uX + 32, uY + uHeight - 10, pIcons_LOD->GetTexture(uTextureID_5076A4));
      if ( uWidth > 512 )
      {
        pRenderer->DrawTextureIndexedAlpha(uX + 544, uY,                pIcons_LOD->GetTexture(uTextureID_507698));
        pRenderer->DrawTextureIndexedAlpha(uX + 544, uY + uHeight - 10, pIcons_LOD->GetTexture(uTextureID_5076A4));
      }
    }
    if ( uHeight > 64 )
    {
      pRenderer->SetUIClipRect(uX, uY + 32, uX + uWidth, uY + uHeight - 32);
      pRenderer->DrawTextureIndexedAlpha(uX,               uY + 32, pIcons_LOD->GetTexture(uTextureID_5076A0));
      pRenderer->DrawTextureIndexedAlpha(uX + uWidth - 10, uY + 32, pIcons_LOD->GetTexture(uTextureID_50769C));
    }
    pRenderer->ResetUIClipRect();
  }
}

//----- (0041D895) --------------------------------------------------------
void GameUI_DrawItemInfo( struct ItemGen* inspect_item )
{
  unsigned int v2; // eax@3
  const char *v28; // edi@69
  int v34; // esi@81
  const char *pText; // [sp-14h] [bp-28Ch]@110
  char out_text[300]; // [sp+8h] [bp-270h]@40
  char v65[120]; // [sp+134h] [bp-144h]@92
  stru351_summoned_item v67;
  int v77; // [sp+200h] [bp-78h]@12
  int v78; // [sp+204h] [bp-74h]@5
  GUIWindow iteminfo_window; // [sp+208h] [bp-70h]@2
  POINT a2; // [sp+25Ch] [bp-1Ch]@2
  int v81; // [sp+264h] [bp-14h]@5
  PlayerSpeech v83; // [sp+26Ch] [bp-Ch]@18
  char* v84;
  int v85;
  char *Str; // [sp+270h] [bp-8h]@65

  int r_mask = 0xF800;
  int g_mask = 0x7E0;
  int b_mask = 0x1F;

  if (!inspect_item->uItemID)
    return;
  iteminfo_window.Hint = nullptr;
  iteminfo_window.uFrameWidth = 384;
  iteminfo_window.uFrameHeight = 180;
  iteminfo_window.uFrameY = 40;
  if ( pMouse->GetCursorPos(&a2)->x <= 320 )
    v2 = pMouse->GetCursorPos(&a2)->x + 30;
  else
    v2 = pMouse->GetCursorPos(&a2)->x - iteminfo_window.uFrameWidth - 30;
  iteminfo_window.uFrameX = v2;
  v78 = 100 - pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->uTextureWidth;
  v81 = 144 - pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->uTextureHeight;
  if ( v78 > 0 )
    v78 = v78 / 2;
  if ( v81 <= 0 )
    v81 = 0;
  else
    v81 = v81 / 2;
  if ( !pItemsTable->pItems[inspect_item->uItemID].uItemID_Rep_St )
    inspect_item->SetIdentified();
  v77 = 0;
  if (inspect_item->GetItemEquipType() == EQUIP_GOLD)
    v77 = inspect_item->uSpecEnchantmentType;
  if ( uActiveCharacter )
  {
  //try to identify
    if (!inspect_item->IsIdentified())
    {
      if ( pPlayers[uActiveCharacter]->CanIdentify(inspect_item) == 1 )
        inspect_item->SetIdentified();
      v83 = SPEECH_9;
      if ( !inspect_item->IsIdentified() )
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[446], 2);//"Identify Failed"
      else
      {
        v83 = SPEECH_8;
        if ( inspect_item->GetValue() < 100 * (pPlayers[uActiveCharacter]->uLevel + 5) )
          v83 = SPEECH_7;
      }
      if ( dword_4E455C )
      {
        pPlayers[uActiveCharacter]->PlaySound((PlayerSpeech)(int)v83, 0);
        dword_4E455C = 0;
      }
    }
    inspect_item->UpdateTempBonus(pParty->uTimePlayed);
    if (inspect_item->IsBroken())
    {
      if ( pPlayers[uActiveCharacter]->CanRepair(inspect_item) == 1 )
        inspect_item->uAttributes = inspect_item->uAttributes & 0xFFFFFFFD | 1;
      v83 = SPEECH_11;
      if ( !inspect_item->IsBroken() )
        v83 = SPEECH_10;
      else
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[448], 2);//"Repair Failed"
      if ( dword_4E455C )
      {
        pPlayers[uActiveCharacter]->PlaySound(v83, 0);
        dword_4E455C = 0;
      }
    }
  }
  if (inspect_item->IsBroken())
  {
    iteminfo_window.DrawMessageBox(0);
    pRenderer->SetUIClipRect(iteminfo_window.uFrameX + 12, iteminfo_window.uFrameY + 12,
    iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 12, 
    iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 12);
    iteminfo_window.uFrameWidth -= 24;
    iteminfo_window.uFrameHeight -= 12;
    iteminfo_window.uFrameZ = iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 1;
    iteminfo_window.uFrameW = iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 1;
    pRenderer->DrawTransparentRedShade(iteminfo_window.uFrameX + v78, v81 + iteminfo_window.uFrameY + 30, pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE));
    if ( inspect_item->IsIdentified())
      pText = (char *)inspect_item->GetIdentifiedName();
    else
      pText = pItemsTable->pItems[inspect_item->uItemID].pUnidentifiedName;
    iteminfo_window.DrawTitleText(pFontArrus, 0, 0xCu, Color16(0xFFu, 0xFFu, 0x9Bu), pText, 3);
    iteminfo_window.DrawTitleText(pFontArrus, 0x64u, ((signed int)iteminfo_window.uFrameHeight >> 1) - pFontArrus->CalcTextHeight(pGlobalTXT_LocalizationStrings[32], &iteminfo_window, 0, 0) / 2,
                   Color16(0xFFu, 0x19u, 0x19u), pGlobalTXT_LocalizationStrings[32], 3); //"Broken Item"
    pRenderer->ResetUIClipRect();
    if ( !areWeLoadingTexture )
    {
      pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->Release();
      pIcons_LOD->SyncLoadedFilesCount();
    }
    return;
  }
  if (!inspect_item->IsIdentified())
  {
    iteminfo_window.DrawMessageBox(0);
    pRenderer->SetUIClipRect(iteminfo_window.uFrameX + 12,  iteminfo_window.uFrameY + 12,
          iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 12,  iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 12);
    iteminfo_window.uFrameWidth -= 24;
    iteminfo_window.uFrameHeight -= 12;
    iteminfo_window.uFrameZ = iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 1;
    iteminfo_window.uFrameW = iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 1;
    pRenderer->DrawTextureIndexedAlpha(iteminfo_window.uFrameX + v78, v81 + iteminfo_window.uFrameY + 30, pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE));
    iteminfo_window.DrawTitleText(pFontArrus, 0, 0xCu, Color16(0xFFu, 0xFFu, 0x9Bu), pItemsTable->pItems[inspect_item->uItemID].pUnidentifiedName, 3);
    iteminfo_window.DrawTitleText(pFontArrus, 0x64u, ((signed int)iteminfo_window.uFrameHeight >> 1) - pFontArrus->CalcTextHeight(pGlobalTXT_LocalizationStrings[232], &iteminfo_window, 0, 0) / 2,
                        Color16(0xFFu, 0x19u, 0x19u), pGlobalTXT_LocalizationStrings[232], 3);//"Not Identified"
    pRenderer->ResetUIClipRect();
    if ( !areWeLoadingTexture )
    {
      pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->Release();
      pIcons_LOD->SyncLoadedFilesCount();
    }
    return;
  }
  sprintfex(out_text, pGlobalTXT_LocalizationStrings[463], pItemsTable->pItems[inspect_item->uItemID].pUnidentifiedName); //"Type: %s"
  out_text[100] = 0;
  out_text[200] = 0;
  switch (inspect_item->GetItemEquipType())
  {
    case EQUIP_SINGLE_HANDED:
    case EQUIP_TWO_HANDED:
      sprintfex(out_text + 100, "%s: +%d   %s: %dd%d", pGlobalTXT_LocalizationStrings[LOCSTR_ATTACK],
          (int)inspect_item->GetDamageMod(), pGlobalTXT_LocalizationStrings[53],
          (int)inspect_item->GetDamageDice(), (int)inspect_item->GetDamageRoll()); //"Damage"
      if (inspect_item->GetDamageMod())
      {
        char mod[16];
        sprintf(mod, "+%d", (int)inspect_item->GetDamageMod());
        strcat(out_text + 100, mod);
      }
      break;

    case EQUIP_BOW:
      sprintfex(out_text + 100, "%s: +%d   %s: %dd%d", pGlobalTXT_LocalizationStrings[203], //"Shoot"
          (int)inspect_item->GetDamageMod(), pGlobalTXT_LocalizationStrings[53], //"Damage"
          (int)inspect_item->GetDamageDice(), (int)inspect_item->GetDamageRoll());
      if (inspect_item->GetDamageMod())
      {
        char mod[16];
        sprintf(mod, "+%d", (int)inspect_item->GetDamageMod());
        strcat(out_text + 100, mod);
      }
      break;

    case EQUIP_ARMOUR:
    case EQUIP_SHIELD:
    case EQUIP_HELMET:
    case EQUIP_BELT:
    case EQUIP_CLOAK:
    case EQUIP_GAUNTLETS:
    case EQUIP_BOOTS:
    case EQUIP_RING:
    case EQUIP_AMULET:
      if (inspect_item->GetDamageDice()) //"Armor"	
          sprintfex(out_text + 100, "%s: +%d", pGlobalTXT_LocalizationStrings[11],
                    inspect_item->GetDamageDice() + inspect_item->GetDamageMod());
      break;
  }

  if ( !v77 )
  {
    if (inspect_item->GetItemEquipType() ==EQUIP_POTION)  //this is CORRECT! do not move to switch!
    {
      if ( inspect_item->uEnchantmentType )
           sprintf(out_text + 200,  "%s: %d",pGlobalTXT_LocalizationStrings[449] , inspect_item->uEnchantmentType); //"Power"
    }
    else if (inspect_item->GetItemEquipType() == EQUIP_REAGENT)
      sprintf(out_text + 200, "%s: %d", pGlobalTXT_LocalizationStrings[449], inspect_item->GetDamageDice()); //"Power"
    else if ( inspect_item->uEnchantmentType )
      sprintf(out_text + 200, "%s: %s +%d", pGlobalTXT_LocalizationStrings[210], pItemsTable->pEnchantments[inspect_item->uEnchantmentType-1].pBonusStat, inspect_item->m_enchantmentStrength); //"Special"
    else  if ( inspect_item->uSpecEnchantmentType )
      sprintf(out_text + 200, "%s: %s", pGlobalTXT_LocalizationStrings[210], pItemsTable->pSpecialEnchantments[inspect_item->uSpecEnchantmentType-1].pBonusStatement);
    else if ( inspect_item->uNumCharges )
      sprintf(out_text + 200, "%s: %lu", pGlobalTXT_LocalizationStrings[464], inspect_item->uNumCharges); //"Charges"
  }
  iteminfo_window.uFrameWidth -= 12;
  iteminfo_window.uFrameZ = iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 1;
  iteminfo_window.uFrameW = iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 1;
  Str = (char *)(3 * (LOBYTE(pFontArrus->uFontHeight) + 8));
  v84 = &out_text[0];
  for ( uint i = 1; i <= 3; i++ )
  {
    if ( *v84 )
      Str += pFontComic->CalcTextHeight(v84, &iteminfo_window, 100, 0) + 3;
    v84 += 100;
  }
  v28 = pItemsTable->pItems[inspect_item->uItemID].pDescription;
  if ( *v28 )
    Str += pFontSmallnum->CalcTextHeight(pItemsTable->pItems[inspect_item->uItemID].pDescription, &iteminfo_window, 100, 0);
  iteminfo_window.uFrameHeight = pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(),
                                     TEXTURE_16BIT_PALETTE)->uTextureHeight + v81 + 54;
  if ( (signed int)Str > (signed int)iteminfo_window.uFrameHeight )
    iteminfo_window.uFrameHeight = (unsigned int)Str;
  if ( inspect_item->uAttributes & ITEM_TEMP_BONUS && (inspect_item->uSpecEnchantmentType || inspect_item->uEnchantmentType) )
    iteminfo_window.uFrameHeight += LOBYTE(pFontComic->uFontHeight);
  v85 = 0;
  if ( pFontArrus->uFontHeight )
  {
    iteminfo_window.uFrameWidth -= 24;
    if ( pFontArrus->CalcTextHeight(inspect_item->GetIdentifiedName(), &iteminfo_window, 0, 0) / (signed int)pFontArrus->uFontHeight )
      v85 = pFontArrus->uFontHeight;
    iteminfo_window.uFrameWidth += 24;
  }
  iteminfo_window.uFrameWidth += 12;
  iteminfo_window.uFrameHeight += (unsigned int)v85;
  iteminfo_window.uFrameW = iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 1;
  iteminfo_window.uFrameZ = iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 1;
  iteminfo_window.DrawMessageBox(0);
  pRenderer->SetUIClipRect(iteminfo_window.uFrameX + 12, iteminfo_window.uFrameY + 12,
         iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 12, iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 12);
  iteminfo_window.uFrameWidth -= 12;
  iteminfo_window.uFrameHeight -= 12;
  iteminfo_window.uFrameZ = iteminfo_window.uFrameX + iteminfo_window.uFrameWidth - 1;
  iteminfo_window.uFrameW = iteminfo_window.uFrameY + iteminfo_window.uFrameHeight - 1;
  pRenderer->DrawTextureIndexedAlpha(iteminfo_window.uFrameX + v78,
      iteminfo_window.uFrameY + (signed int)(iteminfo_window.uFrameHeight - pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->uTextureHeight) / 2,
      pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE));

  v34 = (int)(v85 + 35);
  Str = out_text;
  for ( uint i = 1; i <= 3; i++ )
  {
    if ( *Str )
    {
      iteminfo_window.DrawText(pFontComic, 100, v34, 0, Str, 0, 0, 0);
      v34 += pFontComic->CalcTextHeight(Str, &iteminfo_window, 100, 0) + 3;
    }
    Str += 100;
  }
  v28 = pItemsTable->pItems[inspect_item->uItemID].pDescription;
  if ( *v28 )
    iteminfo_window.DrawText(pFontSmallnum, 100, v34, 0, v28, 0, 0, 0);
  iteminfo_window.uFrameX += 12;
  iteminfo_window.uFrameWidth -= 24;
  iteminfo_window.DrawTitleText(pFontArrus, 0, 0xCu, Color16(0xFFu, 0xFFu, 0x9Bu), inspect_item->GetIdentifiedName(), 3);
  iteminfo_window.uFrameWidth += 24;
  iteminfo_window.uFrameX -= 12;
  if ( v77 )
  {
    sprintf(pTmpBuf.data(), "%s: %lu", pGlobalTXT_LocalizationStrings[465], v77);//"Value"
    iteminfo_window.DrawText(pFontComic, 100, iteminfo_window.uFrameHeight - LOBYTE(pFontComic->uFontHeight), 0, pTmpBuf.data(), 0, 0, 0);
    pRenderer->ResetUIClipRect();
  }
  else
  {
    if ( (inspect_item->uAttributes & ITEM_TEMP_BONUS) && (inspect_item->uSpecEnchantmentType || inspect_item->uEnchantmentType) )
    {
      init_summoned_item(&v67, inspect_item->uExpireTime - pParty->uTimePlayed);
      strcpy(pTmpBuf.data(), "Duration:");
      Str = (char *)(v67.field_18_expire_year - game_starting_year);
      if (v67.field_18_expire_year != 1168 )
      {
        sprintf(v65, " %d:yr", v67.field_18_expire_year - game_starting_year);
        strcat(pTmpBuf.data(), v65);
      }
      if ( (((v67.field_14_exprie_month || Str) && 
           ((sprintf(v65, " %d:mo", v67.field_14_exprie_month), strcat(pTmpBuf.data(), v65), v67.field_14_exprie_month) || Str) 
         || v67.field_C_expire_day)
         && ((sprintf(v65, " %d:dy", v67.field_C_expire_day), strcat(pTmpBuf.data(), v65), v67.field_14_exprie_month) || Str || 
             v67.field_C_expire_day)
         || v67.field_8_expire_hour)
         && ((sprintf(v65, " %d:hr", v67.field_8_expire_hour), strcat(pTmpBuf.data(), v65), v67.field_14_exprie_month) || Str || 
             v67.field_C_expire_day || v67.field_8_expire_hour)
         || v67.field_4_expire_minute )
      {
        sprintf(v65, " %d:mn", v67.field_4_expire_minute);
        strcat(pTmpBuf.data(), v65);
      }
      iteminfo_window.DrawText(pFontComic, 100, iteminfo_window.uFrameHeight - 2 * LOBYTE(pFontComic->uFontHeight), 0, pTmpBuf.data(), 0, 0, 0);
    }
    sprintf(pTmpBuf.data(), "%s: %lu", pGlobalTXT_LocalizationStrings[465], inspect_item->GetValue());
    iteminfo_window.DrawText(pFontComic, 100, iteminfo_window.uFrameHeight - LOBYTE(pFontComic->uFontHeight), 0, pTmpBuf.data(), 0, 0, 0);
    if ( inspect_item->uAttributes & ITEM_STOLEN )
      pText = pGlobalTXT_LocalizationStrings[187]; //"Stolen"
    else
    {
      if ( !(inspect_item->uAttributes & ITEM_HARDENED) )
      {
        pRenderer->ResetUIClipRect();
        if ( !areWeLoadingTexture )
        {
          pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->Release();
          pIcons_LOD->SyncLoadedFilesCount();
        }
        return;
      }
      pText = pGlobalTXT_LocalizationStrings[651]; //"Hardened"
    }
    LOWORD(inspect_item->uAttributes) = r_mask;
    iteminfo_window.DrawText(pFontComic, pFontComic->GetLineWidth(pTmpBuf.data()) + 132,
          iteminfo_window.uFrameHeight - LOBYTE(pFontComic->uFontHeight), inspect_item->uAttributes, pText, 0, 0, 0);
    pRenderer->ResetUIClipRect();
  }
  if ( !areWeLoadingTexture )
  {
    pIcons_LOD->LoadTexturePtr(inspect_item->GetIconName(), TEXTURE_16BIT_PALETTE)->Release();
    pIcons_LOD->SyncLoadedFilesCount();
  }
  return;
}
// 4E455C: using guessed type int dword_4E455C;
// 506128: using guessed type int areWeLoadingTexture;

//----- (0041E360) --------------------------------------------------------
void MonsterPopup_Draw(unsigned int uActorID, GUIWindow *pWindow)
{
  unsigned __int16 v9; // dx@4
  SpriteFrame *v10; // edi@17
  unsigned int v18; // ecx@19
  unsigned int v19; // eax@21
  int skill_points; // edi@61
  unsigned int skill_level; // eax@61
  int pTextHeight; // edi@90
  PlayerSpeech speech; // [sp-8h] [bp-1F4h]@79
  DDBLTFX Dst; // [sp+Ch] [bp-1E0h]@18
  DDSURFACEDESC2 pDesc; // [sp+70h] [bp-17Ch]@18
  RECT dest_rect; // [sp+ECh] [bp-100h]@26
  const char *string_name[10]; // [sp+FCh] [bp-F0h]@145
  const char *content[11]; // [sp+124h] [bp-C8h]@127
  unsigned char resistances[11]; // [sp+124h] [bp-C8h]@127
  RenderBillboardTransform_local0 v106; // [sp+150h] [bp-9Ch]@3
  unsigned int v107; // [sp+1A0h] [bp-4Ch]@18
  bool for_effects; // [sp+1C0h] [bp-2Ch]@3
  bool normal_level; // [sp+1D0h] [bp-1Ch]@18
  bool expert_level; // [sp+1C4h] [bp-28h]@18
  bool master_level; // [sp+1C8h] [bp-24h]@18
  bool grandmaster_level; // [sp+1B4h] [bp-38h]@3
  const char *pText; // [sp+1D4h] [bp-18h]@18
  int pTextColorID; // [sp+1E4h] [bp-8h]@18
  int v115;

  bool monster_full_informations = false;
  static Actor pMonsterInfoUI_Doll;
  if ( !uActiveCharacter ) //
    uActiveCharacter = 1;

  /*if ( !(bMonsterInfoUI_bDollInitialized & 1) )
  {
    bMonsterInfoUI_bDollInitialized |= 1u;
    Actor::Actor(&pMonsterInfoUI_Doll);
    atexit(nullsub_3);
  }*/
  v106.sParentBillboardID = -1;
  v115 = monster_popup_y_offsets[((signed __int16)pActors[uActorID].pMonsterInfo.uID - 1) / 3] - 40;
  if ( pActors[uActorID].pMonsterInfo.uID == pMonsterInfoUI_Doll.pMonsterInfo.uID )
    v9 = pMonsterInfoUI_Doll.uCurrentActionLength;
  else
  {
    memcpy(&pMonsterInfoUI_Doll, &pActors[uActorID], sizeof(pMonsterInfoUI_Doll));
    pMonsterInfoUI_Doll.uCurrentActionAnimation = ANIM_Bored;
    pMonsterInfoUI_Doll.uCurrentActionTime = 0;
    v9 = rand() % 256 + 128;
    pMonsterInfoUI_Doll.uCurrentActionLength = v9;
  }

  if ( (signed int)pMonsterInfoUI_Doll.uCurrentActionTime > (signed __int16)v9 )
  {
    pMonsterInfoUI_Doll.uCurrentActionTime = 0;
    if ( pMonsterInfoUI_Doll.uCurrentActionAnimation == ANIM_Bored || pMonsterInfoUI_Doll.uCurrentActionAnimation == ANIM_AtkMelee)
    {
      pMonsterInfoUI_Doll.uCurrentActionAnimation = ANIM_Standing;
      pMonsterInfoUI_Doll.uCurrentActionLength = rand() % 128 + 128;
    }
    else
    {
      //rand();
      pMonsterInfoUI_Doll.uCurrentActionAnimation = ANIM_Bored;
      if ( (pMonsterInfoUI_Doll.pMonsterInfo.uID < 115 || pMonsterInfoUI_Doll.pMonsterInfo.uID > 186) &&
           (pMonsterInfoUI_Doll.pMonsterInfo.uID < 232 || pMonsterInfoUI_Doll.pMonsterInfo.uID > 249) && rand() % 30 < 100 )
        pMonsterInfoUI_Doll.uCurrentActionAnimation = ANIM_AtkMelee;
      pMonsterInfoUI_Doll.uCurrentActionLength = 8 * pSpriteFrameTable->pSpriteSFrames[pActors[uActorID].pSpriteIDs[(signed __int16)pMonsterInfoUI_Doll.uCurrentActionAnimation]].uAnimLength;
    }
  }
  v10 = pSpriteFrameTable->GetFrame( pActors[uActorID].pSpriteIDs[pMonsterInfoUI_Doll.uCurrentActionAnimation], pMonsterInfoUI_Doll.uCurrentActionTime);
  v106.pTarget = pRenderer->pTargetSurface;
  v106.pTargetZ = pRenderer->pActiveZBuffer;
  v106.uTargetPitch = pRenderer->uTargetSurfacePitch;
  v106.uViewportX = pWindow->uFrameX + 13;
  v106.uViewportY = pWindow->uFrameY + 52;
  v106.uViewportW = (pWindow->uFrameY + 52) + 128;
  v106.uViewportZ = v106.uViewportX + 128;
  v106.uScreenSpaceX = (signed int)(v106.uViewportX + 128 + v106.uViewportX) / 2;
  v106._screenspace_x_scaler_packedfloat = 65536;
  v106._screenspace_y_scaler_packedfloat = 65536;
  v106.uScreenSpaceY = v115 + (pWindow->uFrameY + 52) + pSprites_LOD->pSpriteHeaders[v10->pHwSpriteIDs[0]].uHeight;
  v106.pPalette = PaletteManager::Get_Dark_or_Red_LUT(v10->uPaletteIndex, 0, 1);
  v106.sZValue = 0;
  v106.uFlags = 0;
  pRenderer->SetRasterClipRect(0, 0, window->GetWidth() - 1, window->GetHeight() - 1);
  pRenderer->RasterLine2D(v106.uViewportX - 1, v106.uViewportY - 1, v106.uViewportX + 129, v106.uViewportY - 1, Color16(0xE1u, 255, 0x9Bu));//�������������� ������� �����
  pRenderer->RasterLine2D(v106.uViewportX - 1, v106.uViewportW + 1, v106.uViewportX - 1, v106.uViewportY - 1, Color16(0xE1u, 255, 0x9Bu));//�������������� ������ �����
  pRenderer->RasterLine2D(v106.uViewportX + 129, v106.uViewportW + 1, v106.uViewportX - 1, v106.uViewportW + 1, Color16(0xE1u, 255, 0x9Bu));//����� ������������ �����
  pRenderer->RasterLine2D(v106.uViewportX + 129, v106.uViewportY - 1, v106.uViewportX + 129, v106.uViewportW + 1, Color16(0xE1u, 255, 0x9Bu));//������ ������������ �����
  //if ( pRenderer->pRenderD3D )
  {
    v106.uScreenSpaceY = v115 + v106.uViewportY + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferHeight;

    memset(&Dst, 0, sizeof(Dst));
    Dst.dwSize = sizeof(Dst);
    Dst.dwFillColor = 0;

    memset(&pDesc, 0, sizeof(pDesc));
    pDesc.dwSize = sizeof(pDesc);

    pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].pTextureSurface->GetSurfaceDesc(&pDesc);
    v107 = 0;
    uint i = 0;
    int dst_x = v106.uScreenSpaceX + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaX - pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferWidth / 2;
    int dst_y = v106.uScreenSpaceY + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaY - pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferHeight;
    uint dst_z = v106.uScreenSpaceX + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaX + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaWidth + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferWidth / 2 - pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferWidth;
    uint dst_w = v106.uScreenSpaceY + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaY + pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaHeight - pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uBufferHeight;
    if (dst_x < v106.uViewportX)
    {
      v18 = v106.uViewportX - dst_x;
      dst_x = v106.uViewportX;
      v107 = v18;
    }
    if (dst_y < v106.uViewportY)
    {
      v19 = v106.uViewportY - dst_y;
      dst_y = v106.uViewportY;
      i = v19;
    }
    if (dst_z > v106.uViewportZ)
      dst_z = v106.uViewportZ;
    if (dst_w > v106.uViewportW)
      dst_w = v106.uViewportW;
    pRenderer->FillRectFast(v106.uViewportX, v106.uViewportY, v106.uViewportZ - v106.uViewportX, v106.uViewportW - v106.uViewportY, 0x7FF);
    pRenderer->FillRectFast(v106.uViewportX, v106.uViewportY, v106.uViewportZ - v106.uViewportX, v106.uViewportW - v106.uViewportY, 0x7FF);
    dest_rect.left = v106.uViewportX;
    dest_rect.top = v106.uViewportY;
    dest_rect.right = v106.uViewportZ;
    dest_rect.bottom = v106.uViewportW;

    ErrD3D(pRenderer->pBackBuffer4->Blt(&dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &Dst));
    /*if ( pRenderer->uTargetGBits == 5 )
    {
      __debugbreak(); // no monster popup for r5g5b5 will be
      memset(&pDesc, 0, 0x7Cu);
      pDesc.dwSize = 124;
      if ( pRenderer->LockSurface_DDraw4(pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].pTextureSurface, &pDesc, DDLOCK_WAIT))
      {
        v20 = (char *)dst_y;
        v110 = pDesc.lpSurface;
        if (dst_y < dst_w)
        {
          v21 = dst_x;
          //v22 = &pRenderer->pTargetSurface[dst_y * pRenderer->uTargetSurfacePitch + dst_x];
          ushort* _v22_2 = v22;
          v23 = i - dst_y;
          v115 = i - dst_y;
          while ( 1 )
          {
            dst_y = v21;
            if ( v21 < dst_z )
            {
              v25 = v107 - v21;
              v109 = (int)&v20[v23];
              for ( i = v107 - v21; ; v25 = i )
              {
                v108 = (unsigned __int16 *)((pDesc.lPitch >> 1) * pDesc.dwHeight * v109 / pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaHeight);
                v26 = (char *)v108 + pDesc.dwWidth * (v25 + dst_y++) / pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaWidth;
                *v22 = *((short *)v110 + (int)v26);
                ++v22;
                if ( dst_y >= dst_z )
                  break;
              }
              v23 = v115;
            }
            v22 = (unsigned __int16 *)((char *)_v22_2 + 2 * pRenderer->uTargetSurfacePitch);
            _v22_2 = v22;
            v20 = (char *)(dst_y + 1);
            v28 = __OFSUB__(dst_y + 1, dst_w);
            v27 = (signed int)(dst_y++ + 1 - dst_w) < 0;
            if ( !(v27 ^ v28) )
              break;
            v21 = dst_x;
          }
        }
        pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].pTextureSurface->Unlock(0);
      }
    }
    else*/
    {
      memset(&pDesc, 0, sizeof(pDesc));
      pDesc.dwSize = sizeof(pDesc);
      if ( pRenderer->LockSurface_DDraw4(pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].pTextureSurface, &pDesc, DDLOCK_WAIT) )
      {
        ushort* src = (unsigned __int16 *)pDesc.lpSurface;
        uint num_top_scanlines_above_frame_y = i - dst_y;
        for (uint y = dst_y; y < dst_w; ++y)
        {
          //ushort* dst = &pRenderer->pTargetSurface[y * pRenderer->uTargetSurfacePitch + dst_x];

          uint src_y = num_top_scanlines_above_frame_y + y;
          for (uint x = dst_x; x < dst_z; ++x)
          {
            uint src_x  = v107 - dst_x + x; // num scanlines left to frame_x  + current x

            uint idx = pDesc.dwHeight * src_y / pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaHeight * (pDesc.lPitch / sizeof(short)) +
                       pDesc.dwWidth  * src_x / pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].uAreaWidth;
            uint b = src[idx] & 0x1F;
            //*dst++ = b | 2 * (src[idx] & 0xFFE0);
            pRenderer->WritePixel16(x, y, b | 2 * (src[idx] & 0xFFE0));
          }
        }
        pSprites_LOD->pHardwareSprites[v10->pHwSpriteIDs[0]].pTextureSurface->Unlock(NULL);
      }
    }
  }
  /*else
  {
    pRenderer->FillRectFast(v106.uViewportX, v106.uViewportY, v106.uViewportZ - v106.uViewportX, v106.uViewportW - v106.uViewportY, 0);
    if ( v10->pHwSpriteIDs[0] >= 0 )
      pSprites_LOD->pSpriteHeaders[v10->pHwSpriteIDs[0]].DrawSprite_sw(&v106, 0);
  }*/
//name and profession
  if ( pActors[uActorID].sNPC_ID )
  {
    if (GetNPCData(pActors[uActorID].sNPC_ID)->uProfession)
      sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[429], GetNPCData(pActors[uActorID].sNPC_ID)->pName, aNPCProfessionNames[GetNPCData(pActors[uActorID].sNPC_ID)->uProfession]); // "%s the %s"   /   ^Pi[%s] %s
    else
      strncpy(pTmpBuf.data(), GetNPCData(pActors[uActorID].sNPC_ID)->pName, 2000);
  }
  else
  {
    if ( pActors[uActorID].dword_000334_unique_name )
      strncpy(pTmpBuf.data(), pMonsterStats->pPlaceStrings[pActors[uActorID].dword_000334_unique_name], 2000);
    else
      strncpy(pTmpBuf.data(), pMonsterStats->pInfos[pActors[uActorID].pMonsterInfo.uID].pName, 2000);
  }
  pWindow->DrawTitleText(pFontComic, 0, 0xCu, Color16(0xFFu, 0xFFu, 0x9Bu), pTmpBuf.data(), 3);
  //health bar
  Actor::DrawHealthBar(&pActors[uActorID], pWindow);

  normal_level = 0;
  expert_level = 0;
  master_level = 0;
  grandmaster_level = 0;
  for_effects = 0;
  pMonsterInfoUI_Doll.uCurrentActionTime += pMiscTimer->uTimeElapsed;
  if ( pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_MONSTER_ID) )
  {
    skill_points = (unsigned __int8)pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_MONSTER_ID) & 0x3F;
    skill_level = SkillToMastery(pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_MONSTER_ID)) - 1;
    if ( skill_level == 0 )//(normal)
    {
      if ( skill_points + 10 >= pActors[uActorID].pMonsterInfo.uLevel )
        normal_level = 1;
    }
    else if ( skill_level == 1 )//(expert)
    {
      if ( 2 * skill_points + 10 >= pActors[uActorID].pMonsterInfo.uLevel )
      {
        normal_level = 1;
        expert_level = 1;
      }
    }
    else if ( skill_level  == 2 )//(master)
    {
      if ( 3 * skill_points + 10 >= pActors[uActorID].pMonsterInfo.uLevel )
      {
        normal_level = 1;
        expert_level = 1;
        master_level = 1;
      }
    }
    else if ( skill_level == 3 )//grandmaster
    {
      normal_level = 1;
      expert_level = 1;
      master_level = 1;
      grandmaster_level = 1;
    }
  }
  if ( pActors[uActorID].uAIState != Dead
    && pActors[uActorID].uAIState != Dying
    && !dword_507BF0_is_there_popup_onscreen && pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_MONSTER_ID) )
  {
    if ( normal_level | expert_level | master_level | grandmaster_level )
    {
      if ( pActors[uActorID].pMonsterInfo.uLevel >= pPlayers[uActiveCharacter]->uLevel - 5 )
        speech = SPEECH_IDENTIFY_MONSTER_STRONGER;
      else
        speech = SPEECH_IDENTIFY_MONSTER_WEAKER;
    }
    else
      speech = SPEECH_IDENTIFY_MONSTER_106;
    pPlayers[uActiveCharacter]->PlaySound(speech, 0);
  }

  if ( (signed int)SkillToMastery(pParty->pPlayers[uActiveCharacter - 1].GetActualSkillLevel(PLAYER_SKILL_MONSTER_ID)) >= 3 )
    for_effects = 1;

  if ( monster_full_informations == true )
  {
    normal_level = 1;//
    expert_level = 1;//
    master_level = 1;//
    grandmaster_level = 1;//
    for_effects = 1;
  }

  pWindow->DrawText(pFontSmallnum, 12, 196, Color16(0xE1u, 255, 0x9Bu), pGlobalTXT_LocalizationStrings[631], 0, 0, 0);//Effects
  if ( !for_effects && false)
    pWindow->DrawText(pFontSmallnum, 28, LOBYTE(pFontSmallnum->uFontHeight) + 193, Color16(0xE1u, 255, 0x9Bu), pGlobalTXT_LocalizationStrings[630], 0, 0, 0);//?
  else
  {
    pText = "";
    pTextHeight = LOBYTE(pFontSmallnum->uFontHeight) + 193;
    for ( uint i = 1; i <= 21; ++i )
    {
      if ( pActors[uActorID].pActorBuffs[i].uExpireTime > 0 )
      {
        switch ( i )
        {
          case ACTOR_BUFF_CHARM:
            pTextColorID = 60;
            pText = pGlobalTXT_LocalizationStrings[591];//Charmed
            break;
          case ACTOR_BUFF_SUMMONED:
            pTextColorID = 82;
            pText = pGlobalTXT_LocalizationStrings[649];//Summoned
            break;
          case ACTOR_BUFF_SHRINK:
            pTextColorID = 92;
            pText = pGlobalTXT_LocalizationStrings[592];//Shrunk
            break;
          case ACTOR_BUFF_AFRAID:
            pTextColorID = 63;
            pText = pGlobalTXT_LocalizationStrings[4];//Afraid
            break;
          case ACTOR_BUFF_STONED:
            pText = pGlobalTXT_LocalizationStrings[220];//Stoned
            pTextColorID = 81;
            break;
          case ACTOR_BUFF_PARALYZED:
            pText = pGlobalTXT_LocalizationStrings[162];//Paralyzed
            pTextColorID = 81;
            break;
          case ACTOR_BUFF_SLOWED:
            pText = pGlobalTXT_LocalizationStrings[593];//Slowed
            pTextColorID = 35;
            break;
          case ACTOR_BUFF_BERSERK:
            pText = pGlobalTXT_LocalizationStrings[608];//Berserk
            pTextColorID = 62;
            break;
          case ACTOR_BUFF_SOMETHING_THAT_HALVES_AC:
          case ACTOR_BUFF_MASS_DISTORTION:
            pText = "";
            pTextColorID = 0;
            continue;
          case ACTOR_BUFF_FATE:
            pTextColorID = 47;
            pText = pGlobalTXT_LocalizationStrings[221];//Fate
            break;
          case ACTOR_BUFF_ENSLAVED:
            pTextColorID = 66;
            pText = pGlobalTXT_LocalizationStrings[607];//Enslaved
            break;
          case ACTOR_BUFF_DAY_OF_PROTECTION:
            pTextColorID = 85;
            pText = pGlobalTXT_LocalizationStrings[610];//Day of Protection
            break;
          case ACTOR_BUFF_HOUR_OF_POWER:
            pTextColorID = 86;
            pText = pGlobalTXT_LocalizationStrings[609];//Hour of Power
            break;
          case ACTOR_BUFF_SHIELD:
            pTextColorID = 17;
            pText = pGlobalTXT_LocalizationStrings[279];//Shield
            break;
          case ACTOR_BUFF_STONESKIN:
            pTextColorID = 38;
            pText = pGlobalTXT_LocalizationStrings[442];//Stoneskin
            break;
          case ACTOR_BUFF_BLESS:
            pTextColorID = 46;
            pText = pGlobalTXT_LocalizationStrings[443];//Bless
            break;
          case ACTOR_BUFF_HEROISM:
            pTextColorID = 51;
            pText = pGlobalTXT_LocalizationStrings[440];//Heroism
            break;
          case ACTOR_BUFF_HASTE:
            pTextColorID = 5;
            pText = pGlobalTXT_LocalizationStrings[441];//Haste
            break;
          case ACTOR_BUFF_PAIN_REFLECTION:
            pTextColorID = 95;
            pText = pGlobalTXT_LocalizationStrings[229];//Pain Reflection
            break;
          case ACTOR_BUFF_PAIN_HAMMERHANDS:
            pTextColorID = 73;
            pText = pGlobalTXT_LocalizationStrings[228];//Hammerhands
            break;
          default:
            pText = "";
            break;
        }
        if ( _stricmp(pText, "" ))
        {
          pWindow->DrawText(pFontSmallnum, 28, pTextHeight, GetSpellColor(pTextColorID), pText, 0, 0, 0);
          pTextHeight = pTextHeight + *(char *)((int)pFontSmallnum + 5) - 3;
        }
      }
    }
    if ( !_stricmp(pText,"" ))
      pWindow->DrawText(pFontSmallnum, 28, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pGlobalTXT_LocalizationStrings[153], 0, 0, 0);//���
  }

  if ( normal_level )
  {
    sprintf(pTmpBuf.data(), "%s\f%05u\t100%d\n", pGlobalTXT_LocalizationStrings[108], 0, pActors[uActorID].pMonsterInfo.uHP);
    pWindow->DrawText(pFontSmallnum, 150, (int)v106.uViewportY, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
    pTextHeight = v106.uViewportY + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    sprintf(pTmpBuf.data(), "%s\f%05u\t100%d\n", pGlobalTXT_LocalizationStrings[12], 0, pActors[uActorID].pMonsterInfo.uAC);//Armor Class
  }
  else
  {
    sprintf(pTmpBuf.data(), "%s\f%05u\t100%s\n", pGlobalTXT_LocalizationStrings[108], 0, pGlobalTXT_LocalizationStrings[630]);//?   - [630] actually displays a question mark
    pWindow->DrawText(pFontSmallnum, 150, (int)v106.uViewportY, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
    pTextHeight = v106.uViewportY + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    sprintf(pTmpBuf.data(), "%s\f%05u\t100%s\n", pGlobalTXT_LocalizationStrings[12], 0, pGlobalTXT_LocalizationStrings[630]);//?   - [630] actually displays a question mark
  }
  pWindow->DrawText(pFontSmallnum, 150, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
  pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 6 + LOBYTE(pFontSmallnum->uFontHeight);

  content[0] = pGlobalTXT_LocalizationStrings[87];
  content[1] = pGlobalTXT_LocalizationStrings[6];
  content[2] = pGlobalTXT_LocalizationStrings[240];
  content[3] = pGlobalTXT_LocalizationStrings[70];
  content[4] = pGlobalTXT_LocalizationStrings[624];
  content[5] = pGlobalTXT_LocalizationStrings[138];
  content[6] = pGlobalTXT_LocalizationStrings[214];
  content[7] = pGlobalTXT_LocalizationStrings[142];
  content[8] = pGlobalTXT_LocalizationStrings[29];
  content[9] = pGlobalTXT_LocalizationStrings[133];
  content[10] = pGlobalTXT_LocalizationStrings[54];

  if ( expert_level )
  {
    sprintf(pTmpBuf.data(), "%s\f%05u\t080%s\n", pGlobalTXT_LocalizationStrings[18], 0, content[pActors[uActorID].pMonsterInfo.uAttack1Type]);//Attack
    pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
    pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    if ( pActors[uActorID].pMonsterInfo.uAttack1DamageBonus )
      sprintf(pTmpBuf.data(), "%s\f%05u\t080%dd%d+%d\n", pGlobalTXT_LocalizationStrings[53],
        0, pActors[uActorID].pMonsterInfo.uAttack1DamageDiceRolls, pActors[uActorID].pMonsterInfo.uAttack1DamageDiceSides, pActors[uActorID].pMonsterInfo.uAttack1DamageBonus);
    else
      sprintf(pTmpBuf.data(), "%s\f%05u\t080%dd%d\n", pGlobalTXT_LocalizationStrings[53],
        0, pActors[uActorID].pMonsterInfo.uAttack1DamageDiceRolls, pActors[uActorID].pMonsterInfo.uAttack1DamageDiceSides);
  }
  else
  {
    sprintf(pTmpBuf.data(), "%s\f%05u\t080%s\n", pGlobalTXT_LocalizationStrings[18], 0, pGlobalTXT_LocalizationStrings[630]);
    pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
    pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    sprintf(pTmpBuf.data(), "%s\f%05u\t080%s\n", pGlobalTXT_LocalizationStrings[53], 0, pGlobalTXT_LocalizationStrings[630]);
  }
  pWindow->DrawText(pFontSmallnum, 150, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
  pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 6 + LOBYTE(pFontSmallnum->uFontHeight);

  if ( !master_level )
  {
    sprintf(pTmpBuf.data(), "%s\f%05u\t080%s\n", pGlobalTXT_LocalizationStrings[628], 0, pGlobalTXT_LocalizationStrings[630]);//"Spell" "?"
    pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
    pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
  }
  else
  {
    pText = pGlobalTXT_LocalizationStrings[628];//Spell
    if ( pActors[uActorID].pMonsterInfo.uSpell1ID && pActors[uActorID].pMonsterInfo.uSpell2ID )
      pText = pGlobalTXT_LocalizationStrings[629];//Spells
    if ( pActors[uActorID].pMonsterInfo.uSpell1ID )
    {
      sprintf(pTmpBuf.data(), "%s\f%05u\t070%s\n", pText, 0, pSpellStats->pInfos[pActors[uActorID].pMonsterInfo.uSpell1ID].pShortName);//"%s\f%05u\t060%s\n"
      pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
      pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    }
    if ( pActors[uActorID].pMonsterInfo.uSpell2ID )
    {
      sprintf(pTmpBuf.data(), "\f%05u\t070%s\n", 0, pSpellStats->pInfos[pActors[uActorID].pMonsterInfo.uSpell2ID].pShortName);//"%s\f%05u\t060%s\n"
      pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
      pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    }
    if ( !pActors[uActorID].pMonsterInfo.uSpell1ID && !pActors[uActorID].pMonsterInfo.uSpell2ID )
    {
      sprintf(pTmpBuf.data(), "%s\f%05u\t070%s\n", pGlobalTXT_LocalizationStrings[628], 0, pGlobalTXT_LocalizationStrings[153]);//"%s\f%05u\t060%s\n"
      pWindow->DrawText(pFontSmallnum, 150, (int)pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
      pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    }
  }
  pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
  pWindow->DrawText(pFontSmallnum, 150, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pGlobalTXT_LocalizationStrings[626], 0, 0, 0);//Immune
  pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;

  string_name[0] = pGlobalTXT_LocalizationStrings[87];//Fire
  string_name[1] = pGlobalTXT_LocalizationStrings[6];//Air
  string_name[2] = pGlobalTXT_LocalizationStrings[240];
  string_name[3] = pGlobalTXT_LocalizationStrings[70];
  string_name[4] = pGlobalTXT_LocalizationStrings[142];
  string_name[5] = pGlobalTXT_LocalizationStrings[214];
  string_name[6] = pGlobalTXT_LocalizationStrings[29];
  string_name[7] = pGlobalTXT_LocalizationStrings[133];
  string_name[8] = pGlobalTXT_LocalizationStrings[54];
  string_name[9] = pGlobalTXT_LocalizationStrings[624];

  resistances[0] = pActors[uActorID].pMonsterInfo.uResFire;
  resistances[1] = pActors[uActorID].pMonsterInfo.uResAir;
  resistances[2] = pActors[uActorID].pMonsterInfo.uResWater;
  resistances[3] = pActors[uActorID].pMonsterInfo.uResEarth;
  resistances[4] = pActors[uActorID].pMonsterInfo.uResMind;
  resistances[5] = pActors[uActorID].pMonsterInfo.uResSpirit;
  resistances[6] = pActors[uActorID].pMonsterInfo.uResBody;
  resistances[7] = pActors[uActorID].pMonsterInfo.uResLight;
  resistances[8] = pActors[uActorID].pMonsterInfo.uResPhysical;
  resistances[9] = pActors[uActorID].pMonsterInfo.uResDark;

  if ( grandmaster_level )
  {
    for ( uint i = 0; i < 10; i++ )
    {
      if ( resistances[i] == 200 )
      {
        pText = pGlobalTXT_LocalizationStrings[625];//Immune
      }
      else
      {
        if ( resistances[i] )
          pText = pGlobalTXT_LocalizationStrings[627];//Resistant
        else
          pText = pGlobalTXT_LocalizationStrings[153];//None
      }
      sprintf(pTmpBuf.data(), "%s\f%05u\t070%s\n", string_name[i], 0, pText);
      pWindow->DrawText(pFontSmallnum, 170, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
      pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    }
  }
  else
  {
    for ( uint i = 0; i < 10; ++i )
    {
      sprintf(pTmpBuf.data(), "%s\f%05u\t070%s\n", string_name[i], 0, pGlobalTXT_LocalizationStrings[630]); // "?"
      pWindow->DrawText(pFontSmallnum, 170, pTextHeight, Color16(0xE1u, 255, 0x9Bu), pTmpBuf.data(), 0, 0, 0);
      pTextHeight = pTextHeight + LOBYTE(pFontSmallnum->uFontHeight) - 3;
    }
  }
  //cast spell: Detect life
  if ( (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_DETECT_LIFE].uExpireTime > 0 )
  {
    sprintf(pTmpBuf.data(), "%s: %d", pGlobalTXT_LocalizationStrings[650], pActors[uActorID].sCurrentHP);//Current Hit Points
    pFontSmallnum->GetLineWidth(pTmpBuf.data());
    pWindow->DrawTitleText(pFontSmallnum, 0, pWindow->uFrameHeight - LOBYTE(pFontSmallnum->uFontHeight) - 12, 0, pTmpBuf.data(), 3);
  }
}

//----- (00417BB5) --------------------------------------------------------
const char *CharacterUI_GetSkillDescText(unsigned int uPlayerID, PLAYER_SKILL_TYPE uPlayerSkillType)
{
  char a2[1200]; // [sp+Ch] [bp-538h]@7
  char Source[120]; // [sp+4BCh] [bp-88h]@7
  int v35; // [sp+53Ch] [bp-8h]@1

  v35 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[431]);// Normal
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[433]) > (signed int)v35 )
    v35 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[433]);// Expert
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[432]) > (signed int)v35 )
    v35 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[432]);// Master
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[96]) > (signed int)v35 )
    v35 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[96]);// Grand

  a2[0] = 0;
  Source[0] = 0;
  strcpy(a2, "%s\n\n");
  sprintf(Source, "\f%05d", GetSkillColor(pParty->pPlayers[uPlayerID].classType, uPlayerSkillType, 1));
  strcat(a2, Source);
  strcat(a2, "%s\t%03d:\t%03d%s\t000\n");
  sprintf(Source, "\f%05d", GetSkillColor(pParty->pPlayers[uPlayerID].classType, uPlayerSkillType, 2));
  strcat(a2, Source);
  strcat(a2, "%s\t%03d:\t%03d%s\t000\n");
  sprintf(Source, "\f%05d", GetSkillColor(pParty->pPlayers[uPlayerID].classType, uPlayerSkillType, 3));
  strcat(a2, Source);
  strcat(a2, "%s\t%03d:\t%03d%s\t000\n");
  sprintf(Source, "\f%05d", GetSkillColor(pParty->pPlayers[uPlayerID].classType, uPlayerSkillType, 4));
  strcat(a2, Source);
  strcat(a2, "%s\t%03d:\t%03d%s\t000\n");
  if ( (pParty->pPlayers[uPlayerID].pActiveSkills[uPlayerSkillType] & 0x3F) == (pParty->pPlayers[uPlayerID].GetActualSkillLevel(uPlayerSkillType) & 0x3F) )
  {
    sprintf(static_sub_417BB5_out_string, a2, pSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[431], v35 + 3, v35 + 5, pNormalSkillDesc[uPlayerSkillType],     // Normal
            pGlobalTXT_LocalizationStrings[433], v35 + 3, v35 + 5, pExpertSkillDesc[uPlayerSkillType],     // Expert
            pGlobalTXT_LocalizationStrings[432], v35 + 3, v35 + 5, pMasterSkillDesc[uPlayerSkillType],     // Master
            pGlobalTXT_LocalizationStrings[96],  v35 + 3, v35 + 5, pGrandSkillDesc[uPlayerSkillType]);      // Grand
  }
  else
  {
    sprintf(Source, "\f%05d", Color16(0xFFu, 0xFFu, 0xFFu));
    strcat(a2, Source);
    strcat(a2, "%s: +%d");
    sprintf(static_sub_417BB5_out_string, a2, pSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[431], v35 + 3, v35 + 5, pNormalSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[433], v35 + 3, v35 + 5, pExpertSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[432], v35 + 3, v35 + 5, pMasterSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[96],  v35 + 3, v35 + 5, pGrandSkillDesc[uPlayerSkillType],
            pGlobalTXT_LocalizationStrings[623], //Bonus
            (pParty->pPlayers[uPlayerID].GetActualSkillLevel(uPlayerSkillType) & 0x3F) - (pParty->pPlayers[uPlayerID].pActiveSkills[uPlayerSkillType] & 0x3F));
  }
  return static_sub_417BB5_out_string;
}

//----- (00417FE5) --------------------------------------------------------
void CharacterUI_SkillsTab_ShowHint()
{
  GUIButton *pButton; // esi@6
  unsigned int pX; // [sp+4h] [bp-8h]@1
  unsigned int pY; // [sp+8h] [bp-4h]@1

  pMouse->GetClickPos(&pX, &pY);
  if ( (signed int)pX < 24 || (signed int)pX > 455 || (signed int)pY < 18 || (signed int)pY > 36 )
  {
    for ( pButton = pGUIWindow_CurrentMenu->pControlsHead; pButton; pButton = pButton->pNext )
    {
      if ( pButton->msg == UIMSG_SkillUp
        && (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 )
      {
        CharacterUI_DrawTooltip(pSkillNames[pButton->msg_param], CharacterUI_GetSkillDescText(uActiveCharacter - 1, (PLAYER_SKILL_TYPE)pButton->msg_param));
      }
    }
  }
  else
    CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[207], pSkillPointsAttributeDescription);//���� �������
}

//----- (00418083) --------------------------------------------------------
void  CharacterUI_StatsTab_ShowHint()
{
  int pStringNum; // edi@1
  signed int pTextColor; // eax@15
  const char *pHourWord; // ecx@17
  const char *pDayWord; // eax@20
  int v15; // ebx@28
  POINT a2; // [sp+Ch] [bp-24h]@1
  int pHour; // [sp+14h] [bp-1Ch]@15
  unsigned int pDay; // [sp+24h] [bp-Ch]@15

  pMouse->GetCursorPos(&a2);
  for ( pStringNum = 0; pStringNum < stat_string_coord.size(); ++pStringNum )
  {
    if (a2.x >= stat_string_coord[pStringNum].x && a2.x <= stat_string_coord[pStringNum].x + stat_string_coord[pStringNum].width )
    {
      if (a2.y >= stat_string_coord[pStringNum].y && a2.y <= stat_string_coord[pStringNum].y + stat_string_coord[pStringNum].height )
        break;
    }
  }

  switch ( pStringNum )
  {
    case 0:// Attributes
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
      if ( aAttributeNames[pStringNum] && pAttributeDescriptions[pStringNum] )
        CharacterUI_DrawTooltip(aAttributeNames[pStringNum], pAttributeDescriptions[pStringNum]);
      break;
    case 7:// Health Points
      if ( pGlobalTXT_LocalizationStrings[108] && pHealthPointsAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[108], pHealthPointsAttributeDescription);
      break;
    case 8:// Spell Points
      if ( pGlobalTXT_LocalizationStrings[212] && pSpellPointsAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[212], pSpellPointsAttributeDescription);
      break;
    case 9:// Armor Class
      if ( pGlobalTXT_LocalizationStrings[12] && pArmourClassAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[12], pArmourClassAttributeDescription);
      break;
    case 10:// Player Condition
      strcpy(pTmpBuf2.data(), pPlayerConditionAttributeDescription);
      strcat(pTmpBuf2.data(), "\n");
      extern std::array<unsigned int, 18> pConditionImportancyTable;
      for ( uint i = 0; i < 18; ++i )
      {
        if ( pPlayers[uActiveCharacter]->pConditions[pConditionImportancyTable[i]] )
        {
          strcat(pTmpBuf2.data(), " \n");
          pHour = pParty->uTimePlayed - pPlayers[uActiveCharacter]->pConditions[pConditionImportancyTable[i]];
          pHour = (unsigned int)((pHour * 0.234375) / 60 / 60);
          pDay = (unsigned int)pHour / 24;
          pHour %= 24i64;
          pTextColor = GetConditionDrawColor(pConditionImportancyTable[i]);
          sprintfex(pTmpBuf.data(), format_4E2DE8, pTextColor, aCharacterConditionNames[pConditionImportancyTable[i]]);
          strcat(pTmpBuf2.data(), pTmpBuf.data());
          if ( pHour && pHour <= 1 )
            pHourWord = pGlobalTXT_LocalizationStrings[109];
          else
            pHourWord = pGlobalTXT_LocalizationStrings[110];
          if ( !pDay || (pDayWord = pGlobalTXT_LocalizationStrings[56], pDay > 1) )
            pDayWord = pGlobalTXT_LocalizationStrings[57];
          sprintfex(pTmpBuf.data(), "%lu %s, %lu %s", pDay, pDayWord, pHour, pHourWord);
          strcat(pTmpBuf2.data(), pTmpBuf.data());
        }
      }
      if ( pGlobalTXT_LocalizationStrings[47] && pTmpBuf2.data() )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[47], pTmpBuf2.data());
      break;
    case 11:// Fast Spell
      if ( pGlobalTXT_LocalizationStrings[172] && pFastSpellAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[172], pFastSpellAttributeDescription);
      break;
    case 12:// Player Age
      if ( pGlobalTXT_LocalizationStrings[5] && pPlayerAgeAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[5], pPlayerAgeAttributeDescription);
      break;
    case 13:// Player Level
      if ( pGlobalTXT_LocalizationStrings[131] && pPlayerLevelAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[131], pPlayerLevelAttributeDescription);
      break;
    case 14://Experience
      v15 = pPlayers[uActiveCharacter]->uLevel;
      do
      {
        if ( (signed __int64)pPlayers[uActiveCharacter]->uExperience < (unsigned int)GetExperienceRequiredForLevel(v15) )
          break;
        ++v15;
      }
      while ( v15 <= 10000 );
      pTmpBuf[0] = 0;
      pTmpBuf2[0] = 0;
      if ( v15 > pPlayers[uActiveCharacter]->uLevel )
        sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[147], v15);
      sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[538], GetExperienceRequiredForLevel(v15) - LODWORD(pPlayers[uActiveCharacter]->uExperience), v15 + 1);
      strcat(pTmpBuf.data(), "\n");
      strcat(pTmpBuf.data(), pTmpBuf2.data());
      sprintf(pTmpBuf2.data(), "%s\n \n%s", pPlayerExperienceAttributeDescription, pTmpBuf.data());
      if ( pGlobalTXT_LocalizationStrings[83] && pTmpBuf2.data() )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[83], pTmpBuf2.data());
      break;
    case 15:// Attack Bonus
      if ( pGlobalTXT_LocalizationStrings[587] && pAttackBonusAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[587], pAttackBonusAttributeDescription);
      break;
    case 16:// Attack Damage
      if ( pGlobalTXT_LocalizationStrings[588] && pAttackDamageAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[588], pAttackDamageAttributeDescription);
      break;
    case 17:// Missle Bonus
      if ( pGlobalTXT_LocalizationStrings[589] && pMissleBonusAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[589], pMissleBonusAttributeDescription);
      break;
    case 18:// Missle Damage
      if ( pGlobalTXT_LocalizationStrings[590] && pMissleDamageAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[590], pMissleDamageAttributeDescription);
      break;
    case 19:// Fire Resistance
      if ( pGlobalTXT_LocalizationStrings[87] && pFireResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[87], pFireResistanceAttributeDescription);
      break;
    case 20:// Air Resistance
      if ( pGlobalTXT_LocalizationStrings[6] && pAirResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[6], pAirResistanceAttributeDescription);
      break;
    case 21:// Water Resistance
      if ( pGlobalTXT_LocalizationStrings[240] && pWaterResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[240], pWaterResistanceAttributeDescription);
      break;
    case 22:// Earth Resistance
      if ( pGlobalTXT_LocalizationStrings[70] && pEarthResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[70], pEarthResistanceAttributeDescription);
      break;
    case 23:// Mind Resistance
      if ( pGlobalTXT_LocalizationStrings[142] && pMindResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[142], pMindResistanceAttributeDescription);
      break;
    case 24:// Body Resistance
      if ( pGlobalTXT_LocalizationStrings[29] && pBodyResistanceAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[29], pBodyResistanceAttributeDescription);
      break;
    case 25: // Skill Points
      if ( pGlobalTXT_LocalizationStrings[207] && pSkillPointsAttributeDescription )
        CharacterUI_DrawTooltip(pGlobalTXT_LocalizationStrings[207], pSkillPointsAttributeDescription);
      break;
    case 26: // Class description
    {
      if (pClassDescriptions[pPlayers[uActiveCharacter]->classType] && pClassNames[pPlayers[uActiveCharacter]->classType])
        CharacterUI_DrawTooltip(pClassNames[pPlayers[uActiveCharacter]->classType], pClassDescriptions[pPlayers[uActiveCharacter]->classType]);
    }
    break;

    default:
      break;
  }
}

//----- (00410B28) --------------------------------------------------------
void  DrawSpellDescriptionPopup(int spell_index)
{
  SpellInfo *spell; // esi@1
  unsigned int v3; // eax@2
  LONG v5; // ecx@4
  GUIWindow spell_info_window; // [sp+Ch] [bp-68h]@4
  POINT mouse; // [sp+64h] [bp-10h]@1

  spell = &pSpellStats->pInfos[spell_index + 11 * pPlayers[uActiveCharacter]->lastOpenedSpellbookPage + 1];
  if ( pMouse->GetCursorPos(&mouse)->y <= 250 )
    v3 = pMouse->GetCursorPos(&mouse)->y + 30;
  else
    v3 = 30;
  spell_info_window.uFrameY = v3;
  spell_info_window.uFrameWidth = 328;
  spell_info_window.uFrameHeight = 68;
  spell_info_window.uFrameX = 90;
  spell_info_window.uFrameZ = 417;
  spell_info_window.uFrameW = v3 + 67;
  spell_info_window.Hint = nullptr;
  v5 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_NORMAL]);
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_MASTER]) > v5 )
    v5 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_MASTER]);
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_EXPERT]) > v5 )
    v5 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_EXPERT]);
  if ( pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_GRAND]) > v5 )
    v5 = pFontSmallnum->GetLineWidth(pGlobalTXT_LocalizationStrings[LOCSTR_GRAND]);
  sprintf(pTmpBuf2.data(),
            "%s\n\n%s\t%03d:\t%03d%s\t000\n%s\t%03d:\t%03d%s\t000\n%s\t%03d:\t%03d%s\t000\n%s\t%03d:\t%03d%s",
            spell->pDescription,
            pGlobalTXT_LocalizationStrings[LOCSTR_NORMAL], v5 + 3, v5 + 10, spell->pBasicSkillDesc,
            pGlobalTXT_LocalizationStrings[LOCSTR_EXPERT], v5 + 3, v5 + 10, spell->pExpertSkillDesc,
            pGlobalTXT_LocalizationStrings[LOCSTR_MASTER], v5 + 3, v5 + 10, spell->pMasterSkillDesc,
            pGlobalTXT_LocalizationStrings[LOCSTR_GRAND], v5 + 3,  v5 + 10, spell->pGrandmasterSkillDesc);
  spell_info_window.uFrameHeight += pFontSmallnum->CalcTextHeight(pTmpBuf2.data(), &spell_info_window, 0, 0);
  if ( (signed int)spell_info_window.uFrameHeight < 150 )
    spell_info_window.uFrameHeight = 150;
  spell_info_window.uFrameWidth = game_viewport_width;
  spell_info_window.DrawMessageBox(0);
  spell_info_window.uFrameWidth -= 12;
  spell_info_window.uFrameHeight -= 12;
  spell_info_window.uFrameZ = spell_info_window.uFrameX + spell_info_window.uFrameWidth - 1;
  spell_info_window.uFrameW = spell_info_window.uFrameHeight + spell_info_window.uFrameY - 1;
  spell_info_window.DrawTitleText(pFontArrus, 0x78u, 0xCu, Color16(0xFFu, 0xFFu, 0x9Bu), spell->pName, 3);
  spell_info_window.DrawText(pFontSmallnum, 120, 44, 0, pTmpBuf2.data(), 0, 0, 0);
  spell_info_window.uFrameWidth = 108;
  spell_info_window.uFrameZ = spell_info_window.uFrameX + 107;
  int skill_level = SkillToMastery(pPlayers[uActiveCharacter]->pActiveSkills[pPlayers[uActiveCharacter]->lastOpenedSpellbookPage + 12]);
  spell_info_window.DrawTitleText(pFontComic, 12, 75, 0, pSkillNames[pPlayers[uActiveCharacter]->lastOpenedSpellbookPage + 12], 3);
  sprintf( pTmpBuf.data(),  "%s\n%d",    pGlobalTXT_LocalizationStrings[LOCSTR_SP_COST],
       pSpellDatas[spell_index + 11 * pPlayers[uActiveCharacter]->lastOpenedSpellbookPage + 1].mana_per_skill[skill_level - 1]);
  spell_info_window.DrawTitleText(pFontComic, 12, spell_info_window.uFrameHeight - LOBYTE(pFontComic->uFontHeight) - 16, 0, pTmpBuf.data(), 3);
  dword_507B00_spell_info_to_draw_in_popup = 0;
}
    // 507B00: using guessed type int dword_507B00_spell_info_to_draw_in_popup;

//----- (00416D62) --------------------------------------------------------
void UI_OnMouseRightClick(Vec2_int_ *_this)
{
  int v5; // esi@62
  GUIButton *pButton; // esi@84
  const char *pStr; // edi@85
  const char *pHint; // edx@113
  GUIWindow popup_window; // [sp+4h] [bp-74h]@32
  struct tagPOINT Point; // [sp+60h] [bp-18h]@6
  unsigned int pX; // [sp+70h] [bp-8h]@3
  unsigned int pY; // [sp+74h] [bp-4h]@3

  if ( current_screen_type == SCREEN_VIDEO || GetCurrentMenuID() == MENU_MAIN )
    return;
  if ( _this )
  {
    pX = _this->x;
    pY = _this->y;
  }
  else
  {
    pMouse->GetClickPos(&pX, &pY);
  }
  //if ( pRenderer->bWindowMode )
  {
    GetCursorPos(&Point);
    ScreenToClient(window->GetApiHandle(), &Point);
    if ( Point.x < 1 || Point.y < 1 || Point.x > 638 || Point.y > 478 )
    {
      back_to_game();
      return;
    }
  }
  if ( pParty->pPickedItem.uItemID )//������� �� ������� ����� ������ ������� ���� � ���������
  {
    for ( uint i = 0; i < 4; ++i )
    {
      if ( (signed int)pX > RightClickPortraitXmin[i] && (signed int)pX < RightClickPortraitXmax[i]
        && (signed int)pY > 375 && (signed int)pY < 466 )
      {
        pPlayers[uActiveCharacter]->UseItem_DrinkPotion_etc(i + 1, 1);
        return;
      }
    }
  }

  pEventTimer->Pause();
  switch(current_screen_type)
  {
    case SCREEN_CASTING:
    {
      Inventory_ItemPopupAndAlchemy();
      break;
    }
    case SCREEN_CHEST:
    {
      if ( !pPlayers[uActiveCharacter]->CanAct() )
      {
        sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[427], pPlayers[uActiveCharacter]->pName, pGlobalTXT_LocalizationStrings[541]);//%s �� � ��������� %s �������� ��������
        popup_window.Hint = pTmpBuf.data();
        popup_window.uFrameWidth = 384;
        popup_window.uFrameHeight = 180;
        popup_window.uFrameY = 40;
        if ( (signed int)pX <= 320 )
          popup_window.uFrameX = pX + 30;
        else
          popup_window.uFrameX = pX - 414;
        popup_window.DrawMessageBox(0);
      }
      else
      {
        if ( pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]] & 0xFFFF )
          GameUI_DrawItemInfo(&pChests[pChestWindow->par1C].igChestItems[pChests[pChestWindow->par1C].pInventoryIndices[(pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]] & 0xFFFF) - 1] - 1]);
      }
      break;
    }
    case SCREEN_GAME://In the main menu displays a pop-up window(� ������� ���� ���������� ����������� ����)
    {
      if (GetCurrentMenuID() > 0)
        break;
      if ( (signed int)pY > (signed int)pViewport->uViewportBR_Y )
      {
        popup_window.ptr_1C = (void *)((signed int)pX / 118);
        if ( (signed int)pX / 118 < 4 )//portaits zone
        {
          popup_window.Hint = nullptr;
          popup_window.uFrameWidth = 400;
          popup_window.uFrameHeight = 200;
          popup_window.uFrameX = 38;
          popup_window.uFrameY = 60;
          pAudioPlayer->StopChannels(-1, -1);
          GameUI_CharacterQuickRecord_Draw(&popup_window, pPlayers[(int)popup_window.ptr_1C + 1]);
        }
      }
      else if ( (signed int)pX > (signed int)pViewport->uViewportBR_X )
      {
        if ( (signed int)pY >= 130 )
        {
          if ( (signed int)pX >= 476 && (signed int)pX <= 636 && (signed int)pY >= 240 && (signed int)pY <= 300 )//buff_tooltip zone
          {
            popup_window.Hint = nullptr;
            popup_window.uFrameWidth = 400;
            popup_window.uFrameHeight = 200;
            popup_window.uFrameX = 38;
            popup_window.uFrameY = 60;
            pAudioPlayer->StopChannels(-1, -1);
            popup_window._41D73D_draw_buff_tooltip();
          }
          else if ( (signed int)pX < 485 || (signed int)pX > 548 || (signed int)pY < 156 || (signed int)pY > 229 )//NPC zone
          {
            if (!( (signed int)pX < 566 || (signed int)pX > 629 || (signed int)pY < 156 || (signed int)pY > 229 ))
            {
              pAudioPlayer->StopChannels(-1, -1);
              GameUI_DrawNPCPopup((void *)1);//NPC 2
            }
          }
          else
          {
            pAudioPlayer->StopChannels(-1, -1);
            GameUI_DrawNPCPopup(0);//NPC 1
          }
        }
        else//minimap zone
        {
          popup_window.Hint = (char *)GameUI_GetMinimapHintText();
          popup_window.uFrameWidth = 256;
          popup_window.uFrameX = 130;
          popup_window.uFrameY = 140;
          popup_window.uFrameHeight = 64;
          pAudioPlayer->StopChannels(-1, -1);
          popup_window.DrawMessageBox(0);
        }
      }
      else//game zone
      {
        popup_window.Hint = nullptr;
        popup_window.uFrameWidth = 320;
        popup_window.uFrameHeight = 320;
        popup_window.uFrameX = pX - 350;
        if ( (signed int)pX <= 320 )
          popup_window.uFrameX = pX + 30;
        popup_window.uFrameY = 40;
        //if ( pRenderer->pRenderD3D )
          v5 = pEngine->pVisInstance->get_picked_object_zbuf_val();
        /*else
          v5 = pRenderer->pActiveZBuffer[pX + pSRZBufferLineOffsets[pY]];*/
        if (PID_TYPE((unsigned __int16)v5) == OBJECT_Actor)
        {
          /*if ( pRenderer->uNumSceneBegins )
          {
            popup_window.DrawMessageBox(1);
            MonsterPopup_Draw(PID_ID((unsigned __int16)v5), &popup_window);
          }
          else*/
          {
            pRenderer->BeginScene();
            popup_window.DrawMessageBox(1);
            MonsterPopup_Draw(PID_ID((unsigned __int16)v5), &popup_window);
            pRenderer->EndScene();
          }
        }
        if (PID_TYPE((unsigned __int16)v5) == OBJECT_Item)
        {
          if ( !(pObjectList->pObjects[pSpriteObjects[PID_ID((unsigned __int16)v5)].uObjectDescID].uFlags & 0x10 ) )
          {
            GameUI_DrawItemInfo(&pSpriteObjects[PID_ID((unsigned __int16)v5)].stru_24);
          }
        }
      }
      break;
    }
    case SCREEN_BOOKS:
    {
      if ( !dword_506364
        || (signed int)pX < (signed int)pViewport->uViewportTL_X || (signed int)pX > (signed int)pViewport->uViewportBR_X
        || (signed int)pY < (signed int)pViewport->uViewportTL_Y || (signed int)pY > (signed int)pViewport->uViewportBR_Y
        || ((popup_window.Hint = (char *)GetMapBookHintText()) == 0) )
        break;
      popup_window.uFrameWidth = (pFontArrus->GetLineWidth(popup_window.Hint) + 32) + 0.5f;
      popup_window.uFrameX = pX + 5;
      popup_window.uFrameY = pY + 5;
      popup_window.uFrameHeight = 64;
      pAudioPlayer->StopChannels(-1, -1);
      popup_window.DrawMessageBox(0);
      break;
    }
    case SCREEN_CHARACTERS:
    case SCREEN_E:
    case SCREEN_CHEST_INVENTORY:
    {
      if ( (signed int)pX > 467 && current_screen_type != SCREEN_E )
        Inventory_ItemPopupAndAlchemy();
      else if ( (signed int)pY >= 345 )
        break;
      else if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 100 )//2DEvent - CharacerScreenStats
        CharacterUI_StatsTab_ShowHint();
      else if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 101 )//2DEvent - CharacerScreenSkills
        CharacterUI_SkillsTab_ShowHint();
      else if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 103 )//2DEvent - CharacerScreenInventory
          Inventory_ItemPopupAndAlchemy();
      break;
    }
    case SCREEN_SPELL_BOOK:
    {
      if ( dword_507B00_spell_info_to_draw_in_popup )
        DrawSpellDescriptionPopup(dword_507B00_spell_info_to_draw_in_popup - 1);
      break;
    }
    case SCREEN_HOUSE:
    {
      if ( (signed int)pY < 345 && (signed int)pX < 469 )
        ShowPopupShopItem();
      break;
    }
    case SCREEN_PARTY_CREATION:
    {
      popup_window.Hint = nullptr;
      pStr = 0;
      for ( pButton = pGUIWindow_CurrentMenu->pControlsHead; pButton; pButton = pButton->pNext)
      {
        if ( pButton->uButtonType == 1 && pButton->uButtonType != 3 && (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 )
        {
          switch ( pButton->msg )
          {
            case UIMSG_0: //stats info
              popup_window.Hint = pAttributeDescriptions[(signed int)pButton->msg_param % 7];
              pStr = aAttributeNames[(signed int)pButton->msg_param % 7];
              break;
            case UIMSG_PlayerCreationClickPlus: //Plus button info 
              pStr = pGlobalTXT_LocalizationStrings[670];//��������
              popup_window.Hint = pGlobalTXT_LocalizationStrings[671];//"��������� ���� � ����������� ������, ������� ��� �� ���������� �����"
              break;
            case UIMSG_PlayerCreationClickMinus: //Minus button info
              pStr = pGlobalTXT_LocalizationStrings[668];//�������
              popup_window.Hint = pGlobalTXT_LocalizationStrings[669];//"�������� ���� �� ����������� ������, ��������� ��� � ���������� �����"
              break;
            case UIMSG_PlayerCreationSelectActiveSkill: //Available skill button info
              pStr = pSkillNames[pParty->pPlayers[uPlayerCreationUI_SelectedCharacter].GetSkillIdxByOrder(pButton->msg_param + 4)];
              popup_window.Hint = pSkillDesc[pParty->pPlayers[uPlayerCreationUI_SelectedCharacter].GetSkillIdxByOrder(pButton->msg_param + 4)];
              break;
            case UIMSG_PlayerCreationSelectClass: //Available Class Info
              popup_window.Hint = pClassDescriptions[pButton->msg_param];
              pStr = pClassNames[pButton->msg_param];
              break;
            case UIMSG_PlayerCreationClickOK: //OK Info
              popup_window.Hint = pGlobalTXT_LocalizationStrings[664];//�������� ����� ��� ����������� ������� ������ � ����������� ����.
              pStr = pGlobalTXT_LocalizationStrings[665];//������ ��
              break;
            case UIMSG_PlayerCreationClickReset: //Clear info
              popup_window.Hint = pGlobalTXT_LocalizationStrings[666];//���������� ��� ��������� � ������ ������.
              pStr = pGlobalTXT_LocalizationStrings[667];//������ ��������
              break;
            case UIMSG_PlayerCreation_SelectAttribute: // Character info
              pStr = pParty->pPlayers[pButton->msg_param].pName;
              popup_window.Hint = pClassDescriptions[pParty->pPlayers[pButton->msg_param].classType];
              break;
          }
          if ( pButton->msg > UIMSG_44 && pButton->msg <= UIMSG_PlayerCreationRemoveDownSkill ) //Sellected skills info
          {
            pY = 0;
            if ( (signed int)pParty->pPlayers[pButton->msg_param].GetSkillIdxByOrder(pButton->msg - UIMSG_48) < 37 )
            {
              strcpy(pTmpBuf2.data(), CharacterUI_GetSkillDescText(pButton->msg_param, (PLAYER_SKILL_TYPE)pParty->pPlayers[pButton->msg_param].GetSkillIdxByOrder(pButton->msg - UIMSG_48)));
              popup_window.Hint = pTmpBuf2.data();
              pStr = pSkillNames[pParty->pPlayers[pButton->msg_param].GetSkillIdxByOrder(pButton->msg - UIMSG_48)];
            }
          }
        }
      }
      if ( popup_window.Hint )
      {
        pHint = popup_window.Hint;
        popup_window.Hint = nullptr;
        popup_window.uFrameWidth = 384;
        popup_window.uFrameHeight = 256;
        popup_window.uFrameX = 128;
        popup_window.uFrameY = 40;
        popup_window.uFrameHeight = pFontSmallnum->CalcTextHeight(pHint, &popup_window, 24, 0) + 2 * LOBYTE(pFontLucida->uFontHeight) + 24;
        popup_window.uFrameZ = popup_window.uFrameX + popup_window.uFrameWidth - 1;
        popup_window.uFrameW = popup_window.uFrameY + popup_window.uFrameHeight - 1;
        popup_window.DrawMessageBox(0);
        popup_window.uFrameX += 12;
        popup_window.uFrameWidth -= 24;
        popup_window.uFrameY += 12;
        popup_window.uFrameHeight -= 12;
        popup_window.uFrameZ = popup_window.uFrameX + popup_window.uFrameWidth - 1;
        popup_window.uFrameW = popup_window.uFrameY + popup_window.uFrameHeight - 1;
        sprintf(pTmpBuf.data(), "\f%05d%s\f00000\n", Color16(0xFF, 0xFF, 0x9B), pStr);
        popup_window.DrawTitleText(pFontCreate, 0, 0, 0, pTmpBuf.data(), 3);
        popup_window.DrawText(pFontSmallnum, 1, pFontLucida->uFontHeight, 0, pHint, 0, 0, 0);
      }
      break;
    }
    default:
      break;
  }
  dword_507BF0_is_there_popup_onscreen = 1;
  viewparams->bRedrawGameUI = 1;
}
int no_rightlick_in_inventory = false; // 0050CDCC
//----- (00416196) --------------------------------------------------------
void Inventory_ItemPopupAndAlchemy()
{
  int potion1_id; // edx@25
  unsigned int potion2_id; // edi@25
  signed int potionID; // edx@27
  unsigned int pOut_y; // edx@57
  double v31; // st7@112
  Vec3_int_ v39; // [sp-18h] [bp-A8h]@83
  GUIWindow message_window; // [sp+Ch] [bp-84h]@137
  POINT cursor; // [sp+78h] [bp-18h]@2
  unsigned int damage_level; // [sp+8Ch] [bp-4h]@23

  if (no_rightlick_in_inventory)
    return;

  pMouse->GetCursorPos(&cursor);
  int item_pid = (pRenderer->pActiveZBuffer[cursor.x + pSRZBufferLineOffsets[cursor.y]] & 0xFFFF) - 1;
  if (item_pid == -1) //added here to avoid crash
    return;
  ItemGen* item = &pPlayers[uActiveCharacter]->pInventoryItemList[item_pid];

  if (cursor.x <= 13 || cursor.x >= 462)//items out of inventory(���� ��� ���������)
  {
    GameUI_DrawItemInfo(item);
    return;
  }

  if (!item_pid)
  {
    int inventory_mouse_x = cursor.x - 14;
    int inventory_mouse_y = cursor.y - 17;

    int mouse_cell_x = inventory_mouse_x / 32;
    int mouse_cell_y = inventory_mouse_y / 32;

    if (mouse_cell_x + mouse_cell_y < 0)
      return;

    int inventory_idx = mouse_cell_x + 14 * mouse_cell_y;
    if (inventory_idx > 126)
      return;

    if (pPlayers[uActiveCharacter]->GetItemIDAtInventoryIndex(&inventory_idx) == 0)
      return;

    item_pid = pPlayers[uActiveCharacter]->GetItemIDAtInventoryIndex(&inventory_idx);
  }
//check character condition(�������� ��������� ���������)
  if (!pPlayers[uActiveCharacter]->CanAct())
  {
    sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[427], pPlayers[uActiveCharacter]->pName, pGlobalTXT_LocalizationStrings[541]);//%s �� � ��������� %s �������� ��������
    message_window.Hint = pTmpBuf.data();
    message_window.uFrameWidth = 384;
    message_window.uFrameHeight = 180;
    if (cursor.x <= 320 )
      message_window.uFrameX = cursor.x + 30;
    else
      message_window.uFrameX = cursor.x - 414;
    message_window.uFrameY = 40;
    message_window.DrawMessageBox(0);
    return;
  }

  int alchemy_skill_points = (int8_t)pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_ALCHEMY) & 0x3F;
  int alchemy_skill_level = SkillToMastery(pPlayers[uActiveCharacter]->GetActualSkillLevel(PLAYER_SKILL_ALCHEMY));

// for potion bottle(������� �������)
  if (pParty->pPickedItem.uItemID == ITEM_POTION_BOTTLE)
  {
    GameUI_DrawItemInfo(item);
    return;
  }
//for recharge potion(����� �����������)
  if (pParty->pPickedItem.uItemID == ITEM_POTION_RECHARGE_ITEM)
  {
    if (item->uItemID < ITEM_POTION_BOTTLE || item->uItemID > ITEM_POTION_REJUVENATION)// all potions
    {
      if (item->GetItemEquipType() != EQUIP_WAND) // can recharge only wands
      {
        pAudioPlayer->PlaySound(SOUND_error, 0, 0, -1, 0, 0, 0, 0);
        return;
      }

      v31 = (70.0 - (double)pParty->pPickedItem.uEnchantmentType) * 0.01;
      if ( v31 < 0.0 )
        v31 = 0.0;
      item->uMaxCharges = (signed __int64)((double)item->uMaxCharges - v31 * (double)item->uMaxCharges);
      item->uNumCharges = (signed __int64)((double)item->uMaxCharges - v31 * (double)item->uMaxCharges);

      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = 1;
      return;
    }
    GameUI_DrawItemInfo(item);
    return;
  }
// for harden potion(����� �������)
  else if (pParty->pPickedItem.uItemID == ITEM_POTION_HARDEN_ITEM)
  {
    if (item->uItemID < ITEM_POTION_BOTTLE || item->uItemID > ITEM_POTION_REJUVENATION) // bottle and all potions
    {
      if (item->IsBroken() ||                         // cant harden broken items
          item->uItemID >= ITEM_ARTIFACT_PUCK ||      // cant harden artifacts
          item->GetItemEquipType() < EQUIP_SINGLE_HANDED ||
          item->GetItemEquipType() > EQUIP_WAND)
      {
        pMouse->RemoveHoldingItem();
        no_rightlick_in_inventory = true;
        return;
      }

      item->uAttributes |= ITEM_AURA_EFFECT_RED | ITEM_HARDENED;

      _50C9A8_item_enchantment_timer = 256;
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = true;
      return;
    }
    GameUI_DrawItemInfo(item);
    return;
  }
// several potions(��������� �����)
  else if (pParty->pPickedItem.uItemID >= ITEM_POTION_FLAMING_POTION && pParty->pPickedItem.uItemID <= ITEM_POTION_SWIFT_POTION ||
           pParty->pPickedItem.uItemID == ITEM_POTION_SLAYING_POTION)
  {
    if ( item->uItemID < ITEM_POTION_BOTTLE || item->uItemID > ITEM_POTION_REJUVENATION) // all potions
    {
      if (item->uItemID >= ITEM_BLASTER && item->uItemID <= ITEM_LASER_RIFLE ||
          item->uItemID >= ITEM_ARTIFACT_PUCK ||
          item->IsBroken() ||
          item->uSpecEnchantmentType ||
          item->uEnchantmentType ||
          item->GetItemEquipType() >= EQUIP_ARMOUR)  // only melee weapons and bows
      {
        pMouse->RemoveHoldingItem();
        no_rightlick_in_inventory = true;
        return;
      }
      
      item->UpdateTempBonus(pParty->uTimePlayed);
      if (pParty->pPickedItem.uItemID == ITEM_POTION_SLAYING_POTION)
      {
        item->uSpecEnchantmentType = 40; // of Slaying
        v31 = (double)(1800 * pParty->pPickedItem.uEnchantmentType * 128);
      }
      else
      {
        static int _4E2904_enchantment_by_potion_lut[] =
        {
          164, 93, 22,
          164, 93, 22,
          11, 5, 13, 7, 59
        };
        item->uSpecEnchantmentType = _4E2904_enchantment_by_potion_lut[pParty->pPickedItem.uItemID - 240];
        v31 = (double)(1800 * pParty->pPickedItem.uEnchantmentType * 128);
      }

      item->uExpireTime = pParty->uTimePlayed + v31 * 0.033333335;
      item->uAttributes = alchemy_skill_level | 0x18;

      _50C9A8_item_enchantment_timer = 256;
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = true;
      return;
    }
    GameUI_DrawItemInfo(item);
    return;
  }
  // use reagents(���������� ���������)
  if (pParty->pPickedItem.uItemID >= ITEM_REAGENT_WIDOWSWEEP_BERRIES && pParty->pPickedItem.uItemID <= ITEM_REAGENT_PHILOSOPHERS_STONE &&
      pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID == ITEM_POTION_BOTTLE)
  {
    pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uEnchantmentType = alchemy_skill_points + pParty->pPickedItem.GetDamageDice();
    switch ( pParty->pPickedItem.uItemID )
    {
      case 200:
      case 201:
      case 202:
      case 203:
      case 204:
        pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = 222;
        break;
      case 205:
      case 206:
      case 207:
      case 208:
      case 209:
        pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = 223;
        break;
      case 210:
      case 211:
      case 212:
      case 213:
      case 214:
        pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = 224;
        break;
      case 215:
      case 216:
      case 217:
      case 218:
      case 219:
        pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = 221;
        break;
      default:
        break;
    }
    pMouse->RemoveHoldingItem();
    no_rightlick_in_inventory = 1;
    if ( dword_4E455C )
    {
      pPlayers[uActiveCharacter]->PlaySound(SPEECH_DO_POTION_FINE, 0);
      dword_4E455C = 0;
    }
    return;
  }
//potions mixing(���������� ���� �����)
  if (pParty->pPickedItem.uItemID >= ITEM_POTION_CATALYST && pParty->pPickedItem.uItemID <= ITEM_POTION_REJUVENATION &&
      pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID >= ITEM_POTION_CATALYST &&
      pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID <= ITEM_POTION_REJUVENATION)
  {
    potion1_id = item->uItemID - ITEM_POTION_CURE_WOUNDS;
    potion2_id = pParty->pPickedItem.uItemID - ITEM_POTION_CURE_WOUNDS;

    if ( pParty->pPickedItem.uItemID == ITEM_POTION_CATALYST || item->uItemID == ITEM_POTION_CATALYST )
      potionID = 5;
    else
      potionID = pItemsTable->potion_data[potion2_id][potion1_id];
    damage_level = 0;
    if ( alchemy_skill_points )
    {
      if ( potionID < ITEM_POTION_CURE_DISEASE || potionID > ITEM_POTION_AWAKEN )//< 225 >227
      {
        if ( potionID >= ITEM_POTION_HASTE && potionID <= ITEM_POTION_CURE_INSANITY && alchemy_skill_level == 1)//228 >= potionID <= 239
          damage_level = 2;
        if ( potionID >= ITEM_POTION_MIGHT_BOOST && potionID <= ITEM_POTION_BODY_RESISTANE && alchemy_skill_level <= 2)//240 >= potionID <= 261
          damage_level = 3;
        if ( potionID >= ITEM_POTION_STONE_TO_FLESH && alchemy_skill_level <= 3 )// 262 < potionID
          damage_level = 4;
      }
    }
    else//no skill(��� ������)
    {
      if ( potionID >= ITEM_POTION_CURE_DISEASE && potionID <= ITEM_POTION_AWAKEN )//225 <= v16 <= 227
        damage_level = 1;
      if ( potionID >= ITEM_POTION_HASTE && potionID <= ITEM_POTION_CURE_INSANITY )//228 <= v16 <= 239
        damage_level = 2;
      if ( potionID >= ITEM_POTION_MIGHT_BOOST && potionID <= ITEM_POTION_BODY_RESISTANE )//240 <= v16 <= 261
        damage_level = 3;
      if ( potionID >= ITEM_POTION_STONE_TO_FLESH )//262 <= v16
        damage_level = 4;
    }
    
    int pOut_x = item_pid + 1;
    for ( uint i = 0; i < 126; ++i )
    {
      if ( pPlayers[uActiveCharacter]->pInventoryMatrix[i] == pOut_x )
      {
        pOut_y = i;
        break;
      }
    }
    if ( !potionID )
    {
      GameUI_DrawItemInfo(item);
      return;
    }
    if ( damage_level == 1 )
    {
      pPlayers[uActiveCharacter]->RemoveItemAtInventoryIndex(pOut_y);
      pPlayers[uActiveCharacter]->ReceiveDamage(rand() % 11 + 10, DMGT_FIRE);
      pAudioPlayer->PlaySound(SOUND_fireBall, 0, 0, -1, 0, 0, 0, 0);
      pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);
      v39.z = pParty->vPosition.z + pParty->sEyelevel;
      v39.x = pParty->vPosition.x;
      v39.y = pParty->vPosition.y;

      int rot_x, rot_y, rot_z;
      Vec3_int_::Rotate(64, pParty->sRotationY, pParty->sRotationX, v39, &rot_x, &rot_y, &rot_z);
      SpriteObject::sub_42F7EB_DropItemAt(0x41Bu, rot_x, rot_y, rot_z, 0, 1, 0, 0, 0);
      if ( dword_4E455C )
      {
        if ( pPlayers[uActiveCharacter]->CanAct() )
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_17, 0);
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[444], 2);//��!
        dword_4E455C = 0;
      }
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = 1;
      return;
    }
    if ( damage_level == 2 )
    {
      pPlayers[uActiveCharacter]->RemoveItemAtInventoryIndex(pOut_y);
      pPlayers[uActiveCharacter]->ReceiveDamage(rand() % 71 + 30, DMGT_FIRE);
      pPlayers[uActiveCharacter]->ItemsEnchant(1);
      pAudioPlayer->PlaySound(SOUND_fireBall, 0, 0, -1, 0, 0, 0, 0);
      pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);

      v39.z = pParty->vPosition.z + pParty->sEyelevel;
      v39.x = pParty->vPosition.x;
      v39.y = pParty->vPosition.y;

      int rot_x, rot_y, rot_z;
      Vec3_int_::Rotate(64, pParty->sRotationY, pParty->sRotationX, v39, &rot_x, &rot_y, &rot_z);
      SpriteObject::sub_42F7EB_DropItemAt(0x41Bu, rot_x, rot_y, rot_z, 0, 1, 0, 0, 0);
      if ( dword_4E455C )
      {
        if ( pPlayers[uActiveCharacter]->CanAct() )
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_17, 0);
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[444], 2);//��!
        dword_4E455C = 0;
      }
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = 1;
      return;
    }
    if ( damage_level == 3 )
    {
      pPlayers[uActiveCharacter]->RemoveItemAtInventoryIndex(pOut_y);
      pPlayers[uActiveCharacter]->ReceiveDamage(rand() % 201 + 50, DMGT_FIRE);
      pPlayers[uActiveCharacter]->ItemsEnchant(5);
      pAudioPlayer->PlaySound(SOUND_fireBall, 0, 0, -1, 0, 0, 0, 0);

      pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);

      v39.z = pParty->vPosition.z + pParty->sEyelevel;
      v39.x = pParty->vPosition.x;
      v39.y = pParty->vPosition.y;

      int rot_x, rot_y, rot_z;
      Vec3_int_::Rotate(64, pParty->sRotationY, pParty->sRotationX, v39, &rot_x, &rot_y, &rot_z);
      SpriteObject::sub_42F7EB_DropItemAt(0x41Bu, rot_x, rot_y, rot_z, 0, 1, 0, 0, 0);
      if ( dword_4E455C )
      {
        if ( pPlayers[uActiveCharacter]->CanAct() )
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_17, 0);
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[444], 2);//��!
        dword_4E455C = 0;
      }
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = 1;
      return;
    }
    if ( damage_level == 4 )
    {
      pPlayers[uActiveCharacter]->RemoveItemAtInventoryIndex(pOut_y);
      pPlayers[uActiveCharacter]->SetCondition(Condition_Eradicated, 0);
      pPlayers[uActiveCharacter]->ItemsEnchant(0);
      pAudioPlayer->PlaySound(SOUND_fireBall, 0, 0, -1, 0, 0, 0, 0);

      pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);

      v39.z = pParty->vPosition.z + pParty->sEyelevel;
      v39.x = pParty->vPosition.x;
      v39.y = pParty->vPosition.y;

      int rot_x, rot_y, rot_z;
      Vec3_int_::Rotate(64, pParty->sRotationY, pParty->sRotationX, v39, &rot_x, &rot_y, &rot_z);
      SpriteObject::sub_42F7EB_DropItemAt(0x41Bu, rot_x, rot_y, rot_z, 0, 1, 0, 0, 0);
      if ( dword_4E455C )
      {
        if ( pPlayers[uActiveCharacter]->CanAct() )
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_17, 0);
        ShowStatusBarString(pGlobalTXT_LocalizationStrings[444], 2);//��!
        dword_4E455C = 0;
      }
      pMouse->RemoveHoldingItem();
      no_rightlick_in_inventory = 1;
      return;
    }
    if ( damage_level == 0 )
    {
      if ( alchemy_skill_points )
      {
        if ( pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID == 221 || pParty->pPickedItem.uItemID == 221 )//catalyst(�����������)
        {
          if ( pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID == 221 )
            pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = pParty->pPickedItem.uItemID;
          if ( pParty->pPickedItem.uItemID == 221 )
            pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uEnchantmentType = pParty->pPickedItem.uEnchantmentType;
        }
        else
        {
          pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID = potionID;
          pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uEnchantmentType = (pParty->pPickedItem.uEnchantmentType
                                            + pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uEnchantmentType) / 2;
          pPlayers[uActiveCharacter]->SetVariable(VAR_AutoNotes, pItemsTable->potion_note[potion1_id][potion2_id]);
        }
        int bottle = pPlayers[uActiveCharacter]->AddItem(-1, 220);//�������
        if ( bottle )
          pPlayers[uActiveCharacter]->pOwnItems[bottle - 1].uAttributes = ITEM_IDENTIFIED;
        if ( !(pItemsTable->pItems[pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uItemID].uItemID_Rep_St) )
          pPlayers[uActiveCharacter]->pInventoryItemList[item_pid].uAttributes |= 1;
        if ( !dword_4E455C )
        {
          pMouse->RemoveHoldingItem();
          no_rightlick_in_inventory = 1;
          return;
        }
        pPlayers[uActiveCharacter]->PlaySound(SPEECH_DO_POTION_FINE, 0);
        dword_4E455C = 0;
        pMouse->RemoveHoldingItem();
        no_rightlick_in_inventory = 1;
        return;
      }
      GameUI_DrawItemInfo(item);
      return;
    }
  }
  GameUI_DrawItemInfo(item);
  return;
}


//----- (0045828B) --------------------------------------------------------
unsigned int __fastcall GetSpellColor(signed int a1)
{
  if ( a1 == 0 )
    return Color16(0, 0, 0);
  if ( a1 < 12 )
    return Color16(255, 85, 0);
  if ( a1 < 23 )
    return Color16(150, 212, 255);
  if ( a1 < 34 )
    return Color16(0, 128, 255);
  if ( a1 < 45 )
    return Color16(128, 128, 128);
  if ( a1 < 56 )
    return Color16(225, 225, 225);
  if ( a1 < 67 )
    return Color16(235, 15, 255);
  if ( a1 < 78 )
    return Color16(255, 128, 0);
  if ( a1 < 89 )
    return Color16(255, 255, 155);
  if ( a1 < 100 )
    return Color16(192, 192, 240);
  else
    __debugbreak();
}

//----- (004B46F8) --------------------------------------------------------
__int64 GetExperienceRequiredForLevel(int level)
{
	__int64 v1; // eax@1
	int i; // edx@1

	v1 = 0;
	for (i = 0; i < level; ++i)
		v1 += i + 1;
	return 1000 * v1;
}