Mercurial > mm7
view Engine/Objects/NPC.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 "../texts.h" #include "../LOD.h" #include "../Autonotes.h" #include "../Awards.h" #include "../Party.h" #include "NPC.h" #include "GUI/GUIWindow.h" #include "../Events.h" #include "..\..\GUI\UI\UIHouses.h" #include "../Graphics/Indoor.h" #include "../MapInfo.h" #include "Actor.h" #include "Media/Audio/AudioPlayer.h" #include "../Spells/CastSpellInfo.h" #include "../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_fizzle, 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_21fly03, 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_WaterWalk, 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; }