diff Engine/Objects/NPC.cpp @ 2498:92eeeb5200f2

.
author Ritor1
date Fri, 19 Sep 2014 00:03:04 +0600
parents
children 68cdef6879a0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Engine/Objects/NPC.cpp	Fri Sep 19 00:03:04 2014 +0600
@@ -0,0 +1,1762 @@
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#define _CRT_SECURE_NO_WARNINGS
+#include "texts.h"
+#include "LOD.h"
+#include "Autonotes.h"
+#include "Awards.h"
+#include "Party.h"
+#include "NPC.h"
+#include "GUIWindow.h"
+#include "Events.h"
+#include "UI\UIHouses.h"
+#include "Engine/Graphics/Indoor.h"
+#include "MapInfo.h"
+#include "Actor.h"
+#include "AudioPlayer.h"
+#include "CastSpellInfo.h"
+#include "Engine/Graphics/Overlays.h"
+
+int pDialogueNPCCount;
+std::array<struct Texture *, 6> pDialogueNPCPortraits;
+int uNumDialogueNPCPortraits; // weak
+struct NPCStats *pNPCStats = nullptr;
+
+int NPCStats::dword_AE336C_LastMispronouncedNameFirstLetter = -1;
+int NPCStats::dword_AE3370_LastMispronouncedNameResult = -1;
+
+void  InitializeAwards();
+void  InitializeScrolls();
+void  InitializeMerchants();
+void  InitializeTransitions();
+void  InitializeAutonotes();
+void  InitializeQuests();
+bool   CheckPortretAgainstSex(int portret_num, int sex); 
+
+//----- (004459F9) --------------------------------------------------------
+NPCData *__fastcall GetNPCData(signed int npcid)
+{
+  unsigned int v1; // esi@1
+  NPCData *result; // eax@5
+  int v3; // esi@9
+  int v4; // ecx@9
+  //int v5; // edx@9
+  //NPCData *v6; // eax@9
+//  char *v7; // ebx@14
+//  NPCData *v8; // edi@14
+  char v9; // al@22
+//  char v10;
+  //std::string v10; // [sp-18h] [bp-2Ch]@4
+//  int v11;
+  //const char *v11; // [sp-8h] [bp-1Ch]@4
+//  int v12; // [sp-4h] [bp-18h]@4
+//  int v13; 
+//  char *v14;
+  //std::string *v13; // [sp+Ch] [bp-8h]@4
+//  int a3; // [sp+13h] [bp-1h]@4
+  int i;
+
+  /*v1 = npcid;
+  if ( (npcid & 0x80000000u) == 0 )
+  {
+    if ( (signed int)npcid < 5000 )
+    {
+      if ( (signed int)npcid >= 501 )
+      {
+    MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0);
+      }
+      return &pNPCStats->pNewNPCData[v1];
+    }
+    return &pNPCStats->array_13EF4[npcid - 5000];
+  }
+  if ( (signed int)npcid >= 5000 )
+    return &pNPCStats->array_13EF4[npcid - 5000];
+  if ( (sDialogue_SpeakingActorNPC_ID & 0x80000000u) == 0 )
+  {
+    result = 0;
+  }
+  else
+  {
+    v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1;
+    v4 = 0;
+    v5 = 0;
+    v6 = pParty->pHirelings;
+    do
+    {
+      if ( v6->pName )
+        pTmpBuf[v4++] = v5;
+      ++v6;
+      ++v5;
+    }
+    while ( (signed int)v6 < (signed int)&pParty->pPickedItem );
+    v13 = 0;
+    if ( (signed int)pNPCStats->uNumNewNPCs > 0 )
+    {
+      v7 = &pTmpBuf[v4];
+      v8 = pNPCStats->pNewNPCData;
+      do
+      {
+        if ( v8->uFlags & 0x80
+          && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName))
+          && (!pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName)) )
+          *v7++ = (char)v13 + 2;
+        v13 = (std::string *)((char *)v13 + 1);
+        ++v8;
+      }
+      while ( (signed int)v13 < (signed int)pNPCStats->uNumNewNPCs );
+    }
+    v9 = pTmpBuf[v3];
+    if ( (unsigned __int8)v9 >= 2u )
+      result = &pNPCStats->pNPCData[(unsigned __int8)v9 + 499];
+    else
+      result = &pParty->pHirelings[(unsigned __int8)v9];
+  }
+  return result;*/
+  v1 = npcid;
+  if ( npcid >= 0 )
+  {
+    if ( npcid < 5000 )
+    {
+      if ( npcid >= 501 )
+      {
+        MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0);
+      }
+      return &pNPCStats->pNewNPCData[v1];// - 1];
+    }
+    return &pNPCStats->pAdditionalNPC[npcid - 5000];
+  }
+
+
+  if ( npcid >= 5000 )
+    return &pNPCStats->pAdditionalNPC[npcid - 5000];
+  if (sDialogue_SpeakingActorNPC_ID >= 0)
+  {
+    result = 0;
+  }
+  else
+  {
+    v3 = abs(sDialogue_SpeakingActorNPC_ID) - 1;
+    v4 = 0;
+
+    for (i = 0; i < 2; ++i)
+    {
+      if (pParty->pHirelings[i].pName)
+        pTmpBuf[v4++] = i;
+    }
+
+    if (pNPCStats->uNumNewNPCs > 0)
+    {
+      for (i = 0; i < pNPCStats->uNumNewNPCs; ++i)
+      {
+        if (pNPCStats->pNewNPCData[i].Hired())
+        {
+          if (!pParty->pHirelings[0].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[0].pName))
+          {
+            if (!pParty->pHirelings[1].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[1].pName))
+              pTmpBuf[v4++] = i + 2;
+          }
+        }
+      }
+    }
+
+    v9 = pTmpBuf[v3];
+    if ( v9 >= 2 )
+     result = &pNPCStats->pNPCData[499 + v9];
+    else
+      result = &pParty->pHirelings[v9];
+  }
+  return result;
+}
+
+//----- (00445B2C) --------------------------------------------------------
+struct NPCData * GetNewNPCData( signed int npcid, int* npc_indx )
+    {
+
+  int* v3; // edi@1
+  NPCData *result; // eax@5
+  int v5; // esi@9
+  int v6; // ecx@9
+  char v11; // al@23
+
+  v3 = npc_indx;
+  if ( npcid >= 0 )
+  {
+    if ( npcid < 5000 )
+    {
+      if ( npcid >= 501 )
+      {
+        MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:2040", 0);
+      }
+      *v3 = npcid;
+      return &pNPCStats->pNewNPCData[npcid];
+    }
+    *npc_indx = npcid - 5000;
+    return &pNPCStats->pAdditionalNPC[npcid - 5000];
+  }
+  if ( npcid >= 5000 )
+      {
+      *npc_indx = npcid - 5000;
+      return &pNPCStats->pAdditionalNPC[npcid - 5000];
+      }
+  if ( sDialogue_SpeakingActorNPC_ID >= 0 )
+  {
+    *npc_indx = 0;
+    result = nullptr;
+  }
+  else
+  {
+    v5 = abs(sDialogue_SpeakingActorNPC_ID) - 1;
+    v6 = 0;
+    for (int i=0; i<2; ++i)
+    {
+      if ( pParty->pHirelings[i].pName )
+        pTmpBuf[v6++] = i;
+     
+    }     
+    for (int i=0; i< pNPCStats->uNumNewNPCs; ++i)
+        {
+        if ( pNPCStats->pNewNPCData[i].Hired()
+            && (!pParty->pHirelings[0].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[0].pName))
+            && (!pParty->pHirelings[1].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[1].pName)) )
+            {
+                pTmpBuf[v6++]=i+2;
+            }
+        }
+    v11 = pTmpBuf[v5];
+
+    if ( v11 >= 2u )
+    {
+      *v3 = v11 - 2;
+      result = &pNPCStats->pNewNPCData[v11 - 2];
+    }
+    else
+    {
+      *v3 = v11;
+      result = &pParty->pHirelings[v11];
+    }
+  }
+  return result;
+}
+
+//----- (00476977) --------------------------------------------------------
+void NPCStats::InitializeNPCText()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pNPCTextTXT_Raw);
+	pNPCTextTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctext.txt", 0);
+	strtok(pNPCTextTXT_Raw, "\r");
+
+	for (i=0; i<789; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ( decode_step == 1)
+					pNPCTopics[i].pText =RemoveQuotes(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+	free(pNPCTopicTXT_Raw);
+	pNPCTopicTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctopic.txt", 0);
+	strtok(pNPCTopicTXT_Raw, "\r");
+
+	for ( i = 1; i <= 579; ++i )//NPC topics count limit
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ( decode_step == 1)
+					pNPCTopics[i].pTopic = RemoveQuotes(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+
+	free(pNPCDistTXT_Raw);
+	pNPCDistTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdist.txt", 0);
+	strtok(pNPCDistTXT_Raw, "\r");
+	strtok(NULL, "\r");
+
+	for (i=1; i<59; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ((decode_step>0)&&(decode_step<77))
+					{
+					pProfessionChance[decode_step].professionChancePerArea[i]=atoi(test_string);
+					}
+				else if (decode_step==0)
+					{
+					pProfessionChance[0].professionChancePerArea[i]=10;
+					}
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<78)&&!break_loop);
+		}
+
+	for ( i = 0; i < 77; ++i )
+		{
+		pProfessionChance[i].uTotalprofChance=0;
+		for ( int ii = 1; ii < 59; ++ii )
+			{
+			pProfessionChance[i].uTotalprofChance+=pProfessionChance[i].professionChancePerArea[ii];
+			}
+		pProfessionChance[i].professionChancePerArea[0]=0;
+		pProfessionChance[i].professionChancePerArea[59]=0;
+		}
+
+	free(pNPCDistTXT_Raw);
+	pNPCDistTXT_Raw = nullptr;
+	}
+
+//----- (00476C60) --------------------------------------------------------
+void NPCStats::_476C60()
+	{
+	for (unsigned int i = 1; i < uNumNewNPCs; ++i)
+		pNewNPCData[i].pName = pNPCUnicNames[i - 1];
+
+	if (pParty->pHirelings[0].pName)
+		pParty->pHirelings[0].pName = pParty->pHireling1Name;
+	if (pParty->pHirelings[1].pName)
+		pParty->pHirelings[1].pName = pParty->pHireling2Name;
+	}
+
+//----- (00476CB5) --------------------------------------------------------
+void NPCStats::InitializeNPCData()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	pNPCDataTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdata.txt", 0);
+	strtok(pNPCDataTXT_Raw, "\r");
+	strtok(NULL, "\r");
+
+	for (i=0; i<500; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{  //i+1
+				switch (decode_step)
+					{
+				case 1:
+					pNPCUnicNames[i] = RemoveQuotes(test_string);
+					pNPCData[i+1].pName=pNPCUnicNames[i];
+					break;
+				case 2:
+					pNPCData[i+1].uPortraitID = atoi(test_string);
+					break;
+				case 6:
+					pNPCData[i+1].Location2D = atoi(test_string);
+					break;
+				case 7:
+					pNPCData[i+1].uProfession = atoi(test_string);
+					break;
+				case 8:
+					pNPCData[i+1].greet = atoi(test_string);
+					break;
+				case 9:
+					pNPCData[i+1].joins = (*test_string == 'y')?1:0;
+					break;
+				case 10:
+					pNPCData[i+1].evt_A = atoi(test_string);
+					break;
+				case 11:
+					pNPCData[i+1].evt_B = atoi(test_string);
+					break;
+				case 12:
+					pNPCData[i+1].evt_C = atoi(test_string);
+					break;
+				case 13:
+					pNPCData[i+1].evt_D = atoi(test_string);
+					break;
+				case 14:
+					pNPCData[i+1].evt_E = atoi(test_string);
+					break;
+				case 15:
+					pNPCData[i+1].evt_F = atoi(test_string);
+					break;
+					}
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<16)&&!break_loop);
+		}
+	uNumNewNPCs = 501;
+	pNPCGreetTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgreet.txt", 0);
+	strtok(pNPCGreetTXT_Raw, "\r");
+	for ( i = 1; i <= 205; ++i )
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{  //i+1
+				switch (decode_step)
+					{
+				case 1:
+					pNPCGreetings[i].pGreetings[0] = RemoveQuotes(test_string);
+					break;
+				case 2:
+					pNPCGreetings[i].pGreetings[1] = RemoveQuotes(test_string);
+					break;
+					}
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<3)&&!break_loop);
+		}
+
+	pNCPGroupTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgroup.txt", 0);
+	strtok(pNCPGroupTXT_Raw, "\r");
+
+	for (i=0; i<51; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{  //i+1
+				if (decode_step==1)
+					{
+					pGroups[i] = atoi(test_string);
+					}
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+
+	pNPCNewsTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcnews.txt", 0);
+	strtok(pNPCNewsTXT_Raw, "\r");
+
+
+	for (i=0; i<51; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{  //i+1
+				if (decode_step==1)
+					pCatchPhrases[i] = RemoveQuotes(test_string);
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+	}
+
+//----- (0047702F) --------------------------------------------------------
+void NPCStats::Initialize()
+		{
+		int i;
+		char* test_string;
+		unsigned char c;
+		bool break_loop;
+		unsigned int temp_str_len;
+		char* tmp_pos;
+		int decode_step;
+
+		InitializeNPCData();
+		InitializeNPCText();
+		InitializeQuests();
+		InitializeAutonotes();
+		InitializeAwards();
+		InitializeTransitions();
+		InitializeMerchants();
+		InitializeScrolls();
+
+		pNPCNamesTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcnames.txt", 0);
+		strtok(pNPCNamesTXT_Raw, "\r");
+
+		uNewlNPCBufPos = 0;
+
+		for (i=0; i<540; ++i)
+			{
+			test_string = strtok(NULL, "\r") + 1;
+			break_loop = false;
+			decode_step=0;
+			do 
+				{
+				c = *(unsigned char*)test_string;
+				temp_str_len = 0;
+				if (c=='\t')
+					{
+					if ( (decode_step == 1)&&(!uNumNPCNames[1]))
+						uNumNPCNames[1]=i;
+					}
+				else
+					{
+					while((c!='\n')&&(c!='\t')&&(c>0))
+						{
+						++temp_str_len;
+						c=test_string[temp_str_len];
+						}		
+					tmp_pos=test_string+temp_str_len;
+					if (*tmp_pos == 0)
+						break_loop = true;
+
+					if (temp_str_len)
+						{
+						*tmp_pos = 0;
+						if ( decode_step == 0)
+							pNPCNames[i][0] =RemoveQuotes(test_string);
+						else if ( decode_step == 1)
+							pNPCNames[i][1] =RemoveQuotes(test_string);
+						}
+					else
+						{ 
+						if ( (decode_step == 1)&&(!uNumNPCNames[1]))
+							uNumNPCNames[1]=i;
+						}
+					}
+				++decode_step;
+				test_string=tmp_pos+1;
+				} while ((decode_step<2)&&!break_loop);
+			}
+		uNumNPCNames[0] = i;
+
+		pNPCProfTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcprof.txt", 0);
+		strtok(pNPCProfTXT_Raw, "\r");
+		strtok(NULL, "\r");
+		strtok(NULL, "\r");
+		strtok(NULL, "\r");
+
+		for (i=1; i<59; ++i)
+			{
+			test_string = strtok(NULL, "\r") + 1;
+			break_loop = false;
+			decode_step=0;
+			do 
+				{
+                //while (*test_string == '\t')  // some steps are separated by multiple \t's
+                  //++test_string;
+                
+				c = *(unsigned char*)test_string;
+				temp_str_len = 0;
+				while((c!='\t')&&(c>0))
+					{
+					++temp_str_len;
+					c=test_string[temp_str_len];
+					}		
+				tmp_pos=test_string+temp_str_len;
+				if (*tmp_pos == 0)
+					break_loop = true;
+				*tmp_pos = 0;
+				if (temp_str_len)
+					{
+					switch(decode_step)
+						{
+					case 2:
+						pProfessions[i].uHirePrice = atoi(test_string);
+						break;
+					case 3:
+						pProfessions[i].pActionText = RemoveQuotes(test_string);
+						break;
+					case 4:
+						pProfessions[i].pBenefits= RemoveQuotes(test_string);
+						break;
+					case 5:
+						pProfessions[i].pJoinText = RemoveQuotes(test_string);
+						break;
+					case 6:
+						pProfessions[i].pDismissText = RemoveQuotes(test_string);
+						}
+					}
+				else
+					{ 
+					if (!decode_step)
+						break_loop = true;
+					}
+				++decode_step;
+				test_string=tmp_pos+1;
+				} while ((decode_step<7)&&!break_loop);
+			}
+		uNumNPCProfessions = 59;
+		}
+
+//----- (00477266) --------------------------------------------------------
+void NPCStats::Release()
+	{
+	free(pNPCTopicTXT_Raw);
+	pNPCTopicTXT_Raw = nullptr;
+	free(pNPCTextTXT_Raw);
+	pNPCTextTXT_Raw = nullptr;
+	free(pNPCNewsTXT_Raw);
+	pNPCNewsTXT_Raw = nullptr;
+	free(pNPCProfTXT_Raw);
+	pNPCProfTXT_Raw = nullptr;
+	free(pNPCNamesTXT_Raw);
+	pNPCNamesTXT_Raw = nullptr;
+	free(pNPCDataTXT_Raw);
+	pNPCDataTXT_Raw = nullptr;
+	free(pNPCDistTXT_Raw);
+	pNPCDistTXT_Raw = nullptr;
+	free(pNPCGreetTXT_Raw);
+	pNPCGreetTXT_Raw = nullptr;
+	free(pNCPGroupTXT_Raw);
+	pNCPGroupTXT_Raw = nullptr;
+	}
+
+//----- (0047730C) --------------------------------------------------------
+bool  CheckPortretAgainstSex(int a1, int)
+	{
+	return true;
+	}
+// 47730C: using guessed type int __stdcall const_1(int);
+
+//----- (0047732C) --------------------------------------------------------
+void NPCStats::InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId)
+	{
+	int rep_gen;
+	int uNPCSex; // esi@1
+	int uGeneratedPortret; // ecx@23
+	int test_prof_summ; // ecx@37
+	int gen_profession; // eax@37
+	int max_prof_cap; // edx@37
+//	signed int result; // eax@39
+	int uRace; // [sp+Ch] [bp-Ch]@1
+	bool break_gen; // [sp+10h] [bp-8h]@1
+	signed int gen_attempts; // [sp+14h] [bp-4h]@1
+	int uPortretMin; // [sp+24h] [bp+Ch]@1
+	int uPortretMax;
+
+	static const unsigned __int8 NPCSexGenTable[86] ={
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                          
+		1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+		1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 };
+	static const unsigned __int8 NPCRaceGenTable[86] ={
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0};
+
+	unsigned __int8 seed = (unsigned __int8)((double)(npc_uid - 1)/3.0);
+	uNPCSex = NPCSexGenTable[seed];
+	uRace = NPCRaceGenTable[seed];
+	pNPCDataBuff->uSex = uNPCSex;
+	pNPCDataBuff->pName = pNPCNames[rand() % uNumNPCNames[uNPCSex]][uNPCSex];
+
+	gen_attempts = 0;
+	break_gen = false;
+
+	do
+		{
+		switch ( uRace )
+			{
+		case 0:
+			if ( uNPCSex == 0 )
+				{
+				uPortretMin = 2;
+				uPortretMax = 100;
+				}
+			else
+				{
+				uPortretMin = 201;
+				uPortretMax =  250;
+				}
+		case 1:
+			if ( uNPCSex == 0 )
+				{
+				uPortretMin = 400;
+				uPortretMax = 430;
+				}
+			else
+				{
+				uPortretMin = 460;
+				uPortretMax =  490;
+				}
+			break;
+		case 2:
+			if ( uNPCSex == 0 )
+				{
+				uPortretMin = 500;
+				uPortretMax =  520;
+				}
+			else
+				{
+				uPortretMin = 530;
+				uPortretMax = 550;	
+				}
+			break;
+		case 3:
+			if ( uNPCSex == 0 )
+				{
+				uPortretMin = 300;
+				uPortretMax = 330;
+				}
+			else
+				{
+				uPortretMin = 360;
+				uPortretMax = 387;
+				}
+
+			break;
+			}
+
+		uGeneratedPortret = uPortretMin + rand() % (uPortretMax - uPortretMin + 1);
+		if ( CheckPortretAgainstSex(uGeneratedPortret, uNPCSex))
+			break_gen = true;
+		++gen_attempts;
+		if ( gen_attempts >= 4 )
+			{
+			uGeneratedPortret = uPortretMin;
+			break_gen = true;
+			}
+		}
+		while(!break_gen);
+
+		pNPCDataBuff->uPortraitID = uGeneratedPortret;
+		pNPCDataBuff->uFlags = 0;
+		pNPCDataBuff->fame = 0;
+		//generate reputation
+		rep_gen = rand() % 100 + 1;
+
+		if ( rep_gen >= 60 )
+			{
+			if ( rep_gen >= 90 )
+				{
+				if ( rep_gen >= 95 )
+					{
+					if ( rep_gen >= 98 )
+						pNPCDataBuff->rep = -600;
+					else
+						pNPCDataBuff->rep = 400;
+					}
+				else
+					pNPCDataBuff->rep = -300;
+				}
+			else
+				pNPCDataBuff->rep = 200;
+			}
+		else
+			pNPCDataBuff->rep = 0;
+
+		max_prof_cap = rand() % pProfessionChance[uMapId].uTotalprofChance+1;
+		test_prof_summ = 0;
+		gen_profession = 0;
+
+		if ( max_prof_cap > 0 )
+			{
+			do
+				test_prof_summ += pProfessionChance[uMapId].professionChancePerArea[gen_profession++];
+			while ( test_prof_summ < max_prof_cap );
+			}
+		pNPCDataBuff->uProfession = gen_profession - 1;
+		pNPCDataBuff->Location2D = uLocation2D;
+		pNPCDataBuff->field_24 = 1;
+		pNPCDataBuff->joins = 1;
+		pNPCDataBuff->evt_A = 0;
+		pNPCDataBuff->evt_B = 0;
+		pNPCDataBuff->evt_C = 0;
+		pNPCDataBuff->evt_D = 0;
+		pNPCDataBuff->evt_E = 0;
+		pNPCDataBuff->evt_F = 0;
+	}
+
+
+//----- (00495366) --------------------------------------------------------
+char *NPCStats::sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId)
+{
+  int pickedName; // edx@2
+
+  if ( firstLetter == dword_AE336C_LastMispronouncedNameFirstLetter)
+    pickedName = dword_AE3370_LastMispronouncedNameResult;
+  else
+  {
+    dword_AE336C_LastMispronouncedNameFirstLetter = firstLetter;
+    if ( this->uNumNPCNames[genderId] == 0 )
+      pickedName = rand() % this->uNumNPCNames[(genderId + 1) % 2];  //originally without " + 1) % 2", but that would yield a div by zero
+    else
+    {
+      int rangeBottom = 0;
+      int rangeTop = 0;
+      for ( uint i = 0; i < this->uNumNPCNames[genderId]; ++i )
+      {
+        if (tolower(this->pNPCNames[i][genderId][0]))
+        {
+          if ( rangeBottom )
+            rangeTop = i;
+          else
+            rangeBottom = i;
+        }
+      }
+      if ( rangeTop != 0 )
+        pickedName = rangeBottom + rand() % (rangeTop - rangeBottom);
+      else
+        pickedName = rand() % this->uNumNPCNames[genderId];
+    }
+  }
+  dword_AE3370_LastMispronouncedNameResult = pickedName;
+  return this->pNPCNames[pickedName][genderId];
+}
+
+//----- (00476387) --------------------------------------------------------
+bool PartyHasDragon()
+{
+  return pNPCStats->pNewNPCData[57].Hired();
+}
+
+//----- (00476395) --------------------------------------------------------
+//0x26 Wizard eye at skill level 2
+bool  CheckHiredNPCSpeciality(unsigned int uProfession)
+    {
+
+    if ( bNoNPCHiring == 1 )
+        return 0;
+
+    for (uint i=0; i<pNPCStats->uNumNewNPCs; ++i )
+        {
+        if ( pNPCStats->pNewNPCData[i].uProfession == uProfession && 
+            (pNPCStats->pNewNPCData[i].uFlags & 0x80) )//Uninitialized memory access
+            return true;
+        }
+    if ( pParty->pHirelings[0].uProfession == uProfession ||
+         pParty->pHirelings[1].uProfession == uProfession)
+        return true;
+    else
+        return false;
+
+    }
+
+//----- (004763E0) --------------------------------------------------------
+void  InitializeAwards()
+{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pAwardsTXT_Raw);
+	pAwardsTXT_Raw = (char *)pEvents_LOD->LoadRaw("awards.txt", 0);
+	strtok(pAwardsTXT_Raw, "\r");
+
+	for (i=1; i<105; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if (decode_step==1)
+					pAwards[i].pText=RemoveQuotes(test_string);
+				else if (decode_step==2)
+					pAwards[i].uPriority = atoi(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<3)&&!break_loop);
+		}
+	}
+// 7241C8: using guessed type int dword_7241C8;
+
+//----- (004764C2) --------------------------------------------------------
+void  InitializeScrolls()
+	{
+
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pScrollsTXT_Raw);
+	pScrollsTXT_Raw = (char *)pEvents_LOD->LoadRaw("scroll.txt", 0);
+	strtok(pScrollsTXT_Raw, "\r");
+	for (i=0; i<82; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ( decode_step == 1)
+					pScrolls[i]=RemoveQuotes(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+	}
+
+//----- (00476590) --------------------------------------------------------
+void  InitializeMerchants()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pMerchantsTXT_Raw);
+	pMerchantsTXT_Raw = (char *)pEvents_LOD->LoadRaw("merchant.txt", 0);
+	strtok(pMerchantsTXT_Raw, "\r");
+
+	for (i=0; i<7; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				switch (decode_step)
+					{
+				case 1:
+					pMerchantsBuyPhrases[i]=RemoveQuotes(test_string);
+					break;
+				case 2:
+					pMerchantsSellPhrases[i]=RemoveQuotes(test_string);
+					break;
+				case 3:
+					pMerchantsRepairPhrases[i]=RemoveQuotes(test_string); 
+					break;
+				case 4:
+					pMerchantsIdentifyPhrases[i]=RemoveQuotes(test_string); 
+					break;
+					}
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<5)&&!break_loop);
+		}
+
+	}
+
+//----- (00476682) --------------------------------------------------------
+void InitializeTransitions()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pTransitionsTXT_Raw);
+	pTransitionsTXT_Raw = (char *)pEvents_LOD->LoadRaw("trans.txt", 0);
+	strtok(pTransitionsTXT_Raw, "\r");
+
+	for (i=0; i<464; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ( decode_step == 1)
+					pTransitionStrings[i + 1]=RemoveQuotes(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+	}
+
+//----- (00476750) --------------------------------------------------------
+void  InitializeAutonotes()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pAutonoteTXT_Raw);
+	pAutonoteTXT_Raw = (char *)pEvents_LOD->LoadRaw("autonote.txt", 0);
+	strtok(pAutonoteTXT_Raw, "\r");
+
+	for (i=0; i<195; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				switch (decode_step)
+					{
+				case  1:
+					pAutonoteTxt[i+1].pText=RemoveQuotes(test_string);
+					break;
+				case  2:
+					{
+					if ( !_stricmp(test_string, "potion"))
+						{
+						pAutonoteTxt[i+1].eType = AUTONOTE_POTION_RECEPIE;
+						break;
+						}
+					if ( !_stricmp(test_string, "stat") )
+						{
+						pAutonoteTxt[i+1].eType = AUTONOTE_STAT_HINT;
+						break;
+						}
+					if ( !_stricmp(test_string, "seer") )
+						{
+						pAutonoteTxt[i+1].eType = AUTONOTE_SEER;
+						break;
+						}
+					if ( !_stricmp(test_string, "obelisk") )
+						{
+						pAutonoteTxt[i+1].eType = AUTONOTE_OBELISK;
+						break;
+						}
+					if ( !_stricmp(test_string, "teacher") )
+						{
+						pAutonoteTxt[i+1].eType = AUTONOTE_TEACHER;
+						break;
+						}
+					pAutonoteTxt[i+1].eType =AUTONOTE_MISC;
+					break;
+					}
+					}
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<3)&&!break_loop);
+		}
+	}
+
+
+//----- (004768A9) --------------------------------------------------------
+void  InitializeQuests()
+	{
+	int i;
+	char* test_string;
+	unsigned char c;
+	bool break_loop;
+	unsigned int temp_str_len;
+	char* tmp_pos;
+	int decode_step;
+
+	free(pQuestsTXT_Raw);
+	pQuestsTXT_Raw = (char *)pEvents_LOD->LoadRaw("quests.txt", 0);
+	strtok(pQuestsTXT_Raw, "\r");
+    memset(pQuestTable.data(),0, sizeof(pQuestTable));
+	for (i=0; i<512; ++i)
+		{
+		test_string = strtok(NULL, "\r") + 1;
+		break_loop = false;
+		decode_step=0;
+		do 
+			{
+			c = *(unsigned char*)test_string;
+			temp_str_len = 0;
+			while((c!='\t')&&(c>0))
+				{
+				++temp_str_len;
+				c=test_string[temp_str_len];
+				}		
+			tmp_pos=test_string+temp_str_len;
+			if (*tmp_pos == 0)
+				break_loop = true;
+			*tmp_pos = 0;
+			if (temp_str_len)
+				{
+				if ( decode_step == 1)
+					pQuestTable[i+1] =RemoveQuotes(test_string);
+				}
+			else
+				{ 
+				break_loop = true;
+				}
+			++decode_step;
+			test_string=tmp_pos+1;
+			} while ((decode_step<2)&&!break_loop);
+		}
+	}
+
+//----- (004B29F2) --------------------------------------------------------
+const char * ContractSelectText( int pEventCode )
+{
+  static const int dialogue_base=110;
+  contract_approved = 0;
+  dword_F8B1AC_award_bit_number = pEventCode + 50;
+  gold_transaction_amount = price_for_membership[pEventCode];
+  if ( pPlayers[uActiveCharacter]->CanAct() )
+  {
+    if ( (unsigned __int16)_449B57_test_bit((unsigned __int8 *)pPlayers[uActiveCharacter]->_achieved_awards_bits, dword_F8B1AC_award_bit_number) )
+      return pNPCTopics[dialogue_base+13].pText;
+    else
+    {
+      if ( (unsigned int)gold_transaction_amount <= pParty->uNumGold )
+      {
+        contract_approved = 1;
+        return pNPCTopics[pEventCode + dialogue_base].pText;
+      }
+      else
+        return pNPCTopics[dialogue_base+14].pText; 
+    }
+  }
+  else
+    return pNPCTopics[dialogue_base+12].pText; 
+}
+//----- (004B40E6) --------------------------------------------------------
+void NPCHireableDialogPrepare()
+    {
+  signed int v0; // ebx@1
+  NPCData *v1; // edi@1
+
+  v0 = 0;
+  v1 = HouseNPCData[(unsigned int)((char *)pDialogueNPCCount + -(dword_591080 != 0) )];//- 1
+  pDialogueWindow->Release();
+  pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 350, WINDOW_MainMenu, 0, 0);
+  pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 0x1BDu,  0xA9u,   0x23u,  1,  0,  UIMSG_Escape,  0,   0,
+                 pGlobalTXT_LocalizationStrings[34], //"Cancel"
+                 pIcons_LOD->GetTexture(uExitCancelTextureId),
+                 0);
+  pDialogueWindow->CreateButton(0, 0, 0, 0, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0);
+  if ( pNPCStats->pProfessions[v1->uProfession].pBenefits)//*(&pNPCStats->field_13A5C + 5 * v1->uProfession) )
+  {
+    pDialogueWindow->CreateButton( 480,  0xA0u,  0x8Cu,  0x1Eu,   1,  0,  UIMSG_ClickNPCTopic,  0x4Du,   0,
+      pGlobalTXT_LocalizationStrings[407], 0);//"More Information"   
+    v0 = 1;
+  }
+  pDialogueWindow->CreateButton(  0x1E0u,  30 * v0 + 160,  0x8Cu,  0x1Eu,  1,  0,  UIMSG_ClickNPCTopic,  0x4Cu,  0,
+    pGlobalTXT_LocalizationStrings[406],  0); //"Hire"
+  pDialogueWindow->_41D08F_set_keyboard_control_group(v0 + 1, 1, 0, 2);
+  dialog_menu_id = HOUSE_DIALOGUE_OTHER;
+}
+
+//----- (004B4224) --------------------------------------------------------
+void _4B4224_UpdateNPCTopics( int _this )
+	{
+  int num_menu_buttons; // ebx@1
+  int i; // ebp@5
+ // signed int v4; // ebp@9
+  int v6; // eax@16
+  int v8; // eax@21
+  int v10; // eax@26
+  int v12; // eax@31
+  int v14; // eax@36
+  int v16; // eax@41
+  NPCData *v17; // [sp+10h] [bp-4h]@4
+
+  num_menu_buttons = 0;
+  pDialogueNPCCount = (_this + 1);
+  if ( _this + 1 == uNumDialogueNPCPortraits && uHouse_ExitPic )
+  {
+    pDialogueWindow->Release();
+    pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_MainMenu, 0, 0);
+    sprintfex(sHouseName.data(), pGlobalTXT_LocalizationStrings[LOCSTR_ENTER_S], pMapStats->pInfos[uHouse_ExitPic].pName);
+    pBtn_ExitCancel = pDialogueWindow->CreateButton(566, 445, 75, 33, 1, 0, UIMSG_Escape, 0, 'N', pGlobalTXT_LocalizationStrings[34], pIcons_LOD->GetTexture(uTextureID_BUTTDESC2), 0);// "Cancel"
+    pBtn_YES        = pDialogueWindow->CreateButton(486, 445, 75, 33, 1, 0, UIMSG_BF,     1, 'Y', sHouseName.data(), pIcons_LOD->GetTexture(uTextureID_BUTTYES2), 0);
+    pDialogueWindow->CreateButton( pNPCPortraits_x[0][0], pNPCPortraits_y[0][0], 63u, 73u, 1, 0,  UIMSG_BF, 1u, 0x20u,  sHouseName.data(), 0);
+    pDialogueWindow->CreateButton(8, 8, 460, 344, 1, 0, UIMSG_BF, 1, 0x59u, sHouseName.data(), 0);
+  }
+  else
+  {
+    v17 = HouseNPCData[_this + 1 - ((dword_591080 != 0)?1:0 )];//+ 1
+    if ( dialog_menu_id == HOUSE_DIALOGUE_OTHER )
+    {
+      pDialogueWindow->Release();
+    }
+    else
+    {
+      for ( i = 0; i < uNumDialogueNPCPortraits; ++i )
+        HouseNPCPortraitsButtonsList[i]->Release();
+    }
+    pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 345, WINDOW_MainMenu, 0, 0);
+    pBtn_ExitCancel = pDialogueWindow->CreateButton(  471,  445,  169, 35,  1,   0, UIMSG_Escape,  0,  0,
+                   pGlobalTXT_LocalizationStrings[74],// "End Conversation"
+                   pIcons_LOD->GetTexture(uExitCancelTextureId),   0);
+    pDialogueWindow->CreateButton(8, 8, 450, 320, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0);
+    if ( pDialogueNPCCount == 1 && dword_591080 )
+    {
+      InitializaDialogueOptions(in_current_building_type);
+    }
+    else
+    {
+      if ( v17->joins )
+      {
+        num_menu_buttons = 1;
+        pDialogueWindow->CreateButton(480u, 160u, 140u, 30, 1, 0, UIMSG_ClickNPCTopic, 0xDu, 0, "", 0);
+      }
+      if ( v17->evt_A)
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v6 = NPC_EventProcessor(v17->evt_A);
+          if ( v6 == 1 || v6 == 2 )
+            pDialogueWindow->CreateButton(  480u, 30 * num_menu_buttons++ + 160,  140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x13u,  0, "",  0);
+        }
+      }
+      if ( v17->evt_B )
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v8 = NPC_EventProcessor(v17->evt_B);
+          if ( v8 == 1 || v8 == 2 )
+            pDialogueWindow->CreateButton( 480u,  30 * num_menu_buttons++ + 160,  140u, 30u,  1, 0,  UIMSG_ClickNPCTopic,  0x14u,  0, "",  0);
+        }
+      }
+      if ( v17->evt_C )
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v10 = NPC_EventProcessor(v17->evt_C);
+          if ( v10 == 1 || v10 == 2 )
+            pDialogueWindow->CreateButton(  480u,  30 * num_menu_buttons++ + 160,  140u, 30u,  1,  0, UIMSG_ClickNPCTopic, 0x15u, 0, "",  0);
+        }
+      }
+ 
+      if ( v17->evt_D )
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v12 = NPC_EventProcessor(v17->evt_D);
+          if ( v12 == 1 || v12 == 2 )
+            pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160,  0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x16u,  0, "",  0);
+        }
+      }
+      if ( v17->evt_E )
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v14 = NPC_EventProcessor(v17->evt_E);
+          if ( v14 == 1 || v14 == 2 )
+            pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160,  0x8Cu,  0x1Eu,  1,  0,  UIMSG_ClickNPCTopic, 0x17u,  0, "",  0);
+        }
+      }
+      if ( v17->evt_F )
+      {
+        if ( num_menu_buttons < 4 )
+        {
+          v16 = NPC_EventProcessor(v17->evt_F);
+          if ( v16 == 1 || v16 == 2 )
+            pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160,  0x8Cu,  0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x18u, 0, "",  0);
+        }
+      }
+      pDialogueWindow->_41D08F_set_keyboard_control_group(num_menu_buttons, 1, 0, 2);
+      dword_F8B1E0 = pDialogueWindow->pNumPresenceButton;
+    }
+    dialog_menu_id = HOUSE_DIALOGUE_MAIN;
+  }
+ 
+}
+//----- (004466C4) --------------------------------------------------------
+int NPC_EventProcessor(int npc_event_id, int entry_line)
+	{
+  signed int event_index; // ebp@1
+  int evt_seq_num; // esi@3
+  bool ready_to_exit; // [sp+Ch] [bp-Ch]@3
+  signed int npc_activity; // [sp+10h] [bp-8h]@3
+  int result;
+
+  event_index = 0;
+  if ( !npc_event_id )
+    return 0;
+  evt_seq_num = entry_line;
+  pSomeOtherEVT = pGlobalEVT.data();
+  uSomeOtherEVT_NumEvents = uGlobalEVT_NumEvents;
+  memcpy(pSomeOtherEVT_Events.data(), pGlobalEVT_Index.data(), sizeof(EventIndex)*4400);
+  npc_activity = 1;
+  ready_to_exit = false;
+  if ( uSomeOtherEVT_NumEvents <= 0 )
+    return 2;
+  do
+  {
+    if ( (pSomeOtherEVT_Events[event_index].uEventID == npc_event_id) && (pSomeOtherEVT_Events[event_index].event_sequence_num == evt_seq_num) )
+    {
+	  _evt_raw *_evt = (_evt_raw *)&pSomeOtherEVT[pSomeOtherEVT_Events[event_index].uEventOffsetInEVT];
+	  switch(_evt->_e_type)
+		  {
+	  case EVENT_Exit:
+		   //exit
+		  if ( ready_to_exit )
+			  result = npc_activity != 0;
+		  else
+			   result = 2;
+		  return result;
+		  break;
+	  case EVENT_OnCanShowDialogItemCmp:
+		  ready_to_exit = true;
+		  //v8 = (unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + (((unsigned __int8)v7[9] + ((unsigned __int8)v7[10] << 8)) << 8)) << 8);
+		  for(int i=0; i<4; ++i)
+			  {  
+			//  if (pParty->pPlayers[i].CompareVariable((enum VariableType)((unsigned __int8)pSomeOtherEVT[v6 + 5] + ((unsigned __int8)pSomeOtherEVT[v6 + 6] << 8)),
+				//  v8))
+			  if (pParty->pPlayers[i].CompareVariable((enum VariableType)EVT_WORD(_evt->v5), EVT_DWORD(_evt->v7)))
+				  {
+				  event_index = -1;
+				  evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1;
+				  break;
+				  }
+			}
+		  break;
+	  case EVENT_EndCanShowDialogItem :
+		  if ( ready_to_exit )
+			  result = npc_activity != 0;
+		  else
+			  result = 2;
+		  return result;
+		  break;
+	  case EVENT_SetCanShowDialogItem :
+		  ready_to_exit = true;
+		  npc_activity = EVT_BYTE(_evt->v5); //(unsigned __int8)v7[5];
+		  break;
+	  case EVENT_IsActorAssasinated :
+		//  if (IsActorAlive( (unsigned __int8)v7[5], 
+		//	  (unsigned __int8)v7[6] + (((unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + ((unsigned __int8)v7[9] << 8)) << 8)) << 8),
+			//  (unsigned __int8)v7[10]) )
+			if (IsActorAlive( EVT_BYTE(_evt->v5),  EVT_DWORD(_evt->v6), EVT_BYTE(_evt->v10)))
+			  {  // drop linear sequense, going to new seq
+				event_index = -1;
+				evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1;
+			  }
+		  break;	  
+		  }
+		++evt_seq_num;
+    }
+    ++event_index;
+  }
+  while ( event_index < uSomeOtherEVT_NumEvents );
+  if ( ready_to_exit )
+    result = npc_activity != 0;
+  else
+    result = 2;
+  return result;
+}
+//----- (00445C8B) --------------------------------------------------------
+int __fastcall GetGreetType(signed int SpeakingNPC_ID)
+{
+  signed int v1; // ebx@1
+  int v3; // edi@6
+  int v4; // ecx@6
+  int v5; // edx@6
+  NPCData *v6; // eax@6
+  char *v7; // ebp@11
+  NPCData *v8; // esi@11
+
+  v1 = 0;
+  if ( SpeakingNPC_ID >= 0 )
+  {
+    if ( SpeakingNPC_ID < 5000 )
+      return 1;//QuestNPC_greet
+    return 2;//HiredNPC_greet
+  }
+  if ( SpeakingNPC_ID >= 5000 )
+    return 2;
+  v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1;
+  v4 = 0;
+  v5 = 0;
+  v6 = pParty->pHirelings.data();
+  do
+  {
+    if ( v6->pName )
+      pTmpBuf[v4++] = v5;
+    ++v6;
+    ++v5;
+  }
+  while ( (signed int)v6 < (signed int)&pParty->pPickedItem );
+  if ( (signed int)pNPCStats->uNumNewNPCs > 0 )
+  {
+    v7 = &pTmpBuf[v4];
+    v8 = pNPCStats->pNewNPCData;
+    do
+    {
+      if (v8->Hired() && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) )
+      {
+        if ( !pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName) )
+          *v7++ = v1 + 2;
+      }
+      ++v1;
+      ++v8;
+    }
+    while ( v1 < (signed int)pNPCStats->uNumNewNPCs );
+  }
+  return ((unsigned __int8)pTmpBuf[v3] < 2) + 1;
+}
+//----- (00445308) --------------------------------------------------------
+const char *GetProfessionActionText(int a1)
+{
+  if ( a1 == 10
+    || a1 == 11
+    || a1 == 12
+    || a1 == 33
+    || a1 == 34
+    || a1 == 39
+    || a1 == 40
+    || a1 == 41
+    || a1 == 42
+    || a1 == 43
+    || a1 == 52 )
+    return pNPCStats->pProfessions[a1 - 1].pActionText;
+  else
+    return pNPCTopics[407].pTopic;
+}
+
+//----- (004BB756) --------------------------------------------------------
+int UseNPCSkill(NPCProf profession)
+{
+  switch (profession)
+  {
+    case Healer:
+    {
+      for (int i = 0; i < 4; ++i)
+        pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
+    }
+    break;
+
+    case ExpertHealer:
+    {
+      for (int i = 0; i < 4; ++i)
+      {
+        __debugbreak();
+        pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
+
+        for (int j = 0; j < 14; ++j)
+          pParty->pPlayers[i].pConditions[j] = 0;
+        pParty->pPlayers[i].pConditions[Condition_Good] = 0;
+      }
+    }
+    break;
+
+    case MasterHealer:
+    {
+      for (int i = 0; i < 4; ++i)
+      {
+        __debugbreak();	//Ritor1:needed cleaned(Необходимо почистить)
+        Player* player = &pParty->pPlayers[i];
+        pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
+
+        int v5 = LODWORD(player->pConditions[19]);//*((int *)v4 - 32);
+        int v6 = HIDWORD(player->pConditions[19]);//*((int *)v4 - 31);
+        memset(&pParty->pPlayers[i].pConditions, 0, sizeof(pParty->pPlayers[i].pConditions));
+
+        *(int *)&player->pActiveSkills[PLAYER_SKILL_SHIELD] = v5;
+        *(int *)&player->pActiveSkills[PLAYER_SKILL_CHAIN] = v6;
+      }
+    }
+    break;
+
+    case Cook://Повар
+    {
+      if (pParty->uNumFoodRations >= 13)
+        return 1;
+
+      Party::GiveFood(1);
+    }
+    break;
+
+    case Chef:
+    {
+      if (pParty->uNumFoodRations >= 13)
+        return 1;
+
+      if (pParty->uNumFoodRations == 13)
+        Party::GiveFood(1);
+      else
+        Party::GiveFood(2);
+    }
+    break;
+
+    case WindMaster:
+    {
+      if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+      {
+        ShowStatusBarString(pGlobalTXT_LocalizationStrings[494], 2);//Нельзя применить знание Полет в помещении!
+        pAudioPlayer->PlaySound(SOUND_203, 0, 0, -1, 0, 0, 0, 0);
+      }
+      else
+      {
+        int v19 = pOtherOverlayList->_4418B1(10008, 203, 0, 65536);
+        pParty->pPartyBuffs[PARTY_BUFF_FLY].Apply(pParty->uTimePlayed + 60 * (256 * 2), 3, 1, v19, 0);
+        pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags |= 1;
+        pAudioPlayer->PlaySound(SOUND_11090, 0, 0, -1, 0, 0, 0, 0);
+      }
+    }
+    break;
+
+    case WaterMaster:
+    {
+      int v20 = pOtherOverlayList->_4418B1(10005, 201, 0, 65536);
+      pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].Apply(pParty->uTimePlayed + 60 * (256 * (2 + 1)), 3, 0, v20, 0);
+      pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags |= 1;
+      pAudioPlayer->PlaySound(SOUND_12040, 0, 0, -1, 0, 0, 0, 0);
+    }
+    break;
+
+    case GateMaster:
+    {
+      pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);
+      dword_50C9DC = 195;
+      ptr_50C9E0 = GetNPCData(sDialogue_SpeakingActorNPC_ID);
+    }
+    break;
+
+    case Acolyte:      _42777D_CastSpell_UseWand_ShootArrow(46, 0, 133, 0, 0); break;
+    case Piper:        _42777D_CastSpell_UseWand_ShootArrow(51, 0, 133, 0, 0); break;
+    case FallenWizard: _42777D_CastSpell_UseWand_ShootArrow(86, 0, 133, 0, 0); break;
+      
+    case Teacher:
+    case Instructor:
+    case Armsmaster:
+    case Weaponsmaster:
+    case Apprentice:
+    case Mystic:
+    case Spellmaster:
+    case Trader:
+    case Merchant:
+    case Scout:
+    case Herbalist:
+    case Apothecary:
+    case Tinker:
+    case Locksmith:
+    case Fool:
+    case ChimneySweep:
+    case Porter:
+    case QuarterMaster:
+    case Factor:
+    case Banker:
+    case Horseman:
+    case Bard:
+    case Enchanter:
+    case Cartographer:
+    case Explorer:
+    case Pirate:
+    case Squire:
+    case Psychic:
+    case Gypsy:
+    case Diplomat:
+    case Duper:
+    case Burglar:
+    case Acolyte2:
+    case Initiate:
+    case Prelate:
+    case Monk:
+    case Sage:
+    case Hunter:
+      break;
+
+    default:
+      assert(false && "Invalid enum value");
+  }
+  return 0;
+}
\ No newline at end of file