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

.
author Ritor1
date Fri, 19 Sep 2014 00:03:04 +0600
parents
children 68cdef6879a0
comparison
equal deleted inserted replaced
2497:82d5d92a097c 2498:92eeeb5200f2
1 #define _CRTDBG_MAP_ALLOC
2 #include <stdlib.h>
3 #include <crtdbg.h>
4
5 #define _CRT_SECURE_NO_WARNINGS
6 #include "texts.h"
7 #include "LOD.h"
8 #include "Autonotes.h"
9 #include "Awards.h"
10 #include "Party.h"
11 #include "NPC.h"
12 #include "GUIWindow.h"
13 #include "Events.h"
14 #include "UI\UIHouses.h"
15 #include "Engine/Graphics/Indoor.h"
16 #include "MapInfo.h"
17 #include "Actor.h"
18 #include "AudioPlayer.h"
19 #include "CastSpellInfo.h"
20 #include "Engine/Graphics/Overlays.h"
21
22 int pDialogueNPCCount;
23 std::array<struct Texture *, 6> pDialogueNPCPortraits;
24 int uNumDialogueNPCPortraits; // weak
25 struct NPCStats *pNPCStats = nullptr;
26
27 int NPCStats::dword_AE336C_LastMispronouncedNameFirstLetter = -1;
28 int NPCStats::dword_AE3370_LastMispronouncedNameResult = -1;
29
30 void InitializeAwards();
31 void InitializeScrolls();
32 void InitializeMerchants();
33 void InitializeTransitions();
34 void InitializeAutonotes();
35 void InitializeQuests();
36 bool CheckPortretAgainstSex(int portret_num, int sex);
37
38 //----- (004459F9) --------------------------------------------------------
39 NPCData *__fastcall GetNPCData(signed int npcid)
40 {
41 unsigned int v1; // esi@1
42 NPCData *result; // eax@5
43 int v3; // esi@9
44 int v4; // ecx@9
45 //int v5; // edx@9
46 //NPCData *v6; // eax@9
47 // char *v7; // ebx@14
48 // NPCData *v8; // edi@14
49 char v9; // al@22
50 // char v10;
51 //std::string v10; // [sp-18h] [bp-2Ch]@4
52 // int v11;
53 //const char *v11; // [sp-8h] [bp-1Ch]@4
54 // int v12; // [sp-4h] [bp-18h]@4
55 // int v13;
56 // char *v14;
57 //std::string *v13; // [sp+Ch] [bp-8h]@4
58 // int a3; // [sp+13h] [bp-1h]@4
59 int i;
60
61 /*v1 = npcid;
62 if ( (npcid & 0x80000000u) == 0 )
63 {
64 if ( (signed int)npcid < 5000 )
65 {
66 if ( (signed int)npcid >= 501 )
67 {
68 MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0);
69 }
70 return &pNPCStats->pNewNPCData[v1];
71 }
72 return &pNPCStats->array_13EF4[npcid - 5000];
73 }
74 if ( (signed int)npcid >= 5000 )
75 return &pNPCStats->array_13EF4[npcid - 5000];
76 if ( (sDialogue_SpeakingActorNPC_ID & 0x80000000u) == 0 )
77 {
78 result = 0;
79 }
80 else
81 {
82 v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1;
83 v4 = 0;
84 v5 = 0;
85 v6 = pParty->pHirelings;
86 do
87 {
88 if ( v6->pName )
89 pTmpBuf[v4++] = v5;
90 ++v6;
91 ++v5;
92 }
93 while ( (signed int)v6 < (signed int)&pParty->pPickedItem );
94 v13 = 0;
95 if ( (signed int)pNPCStats->uNumNewNPCs > 0 )
96 {
97 v7 = &pTmpBuf[v4];
98 v8 = pNPCStats->pNewNPCData;
99 do
100 {
101 if ( v8->uFlags & 0x80
102 && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName))
103 && (!pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName)) )
104 *v7++ = (char)v13 + 2;
105 v13 = (std::string *)((char *)v13 + 1);
106 ++v8;
107 }
108 while ( (signed int)v13 < (signed int)pNPCStats->uNumNewNPCs );
109 }
110 v9 = pTmpBuf[v3];
111 if ( (unsigned __int8)v9 >= 2u )
112 result = &pNPCStats->pNPCData[(unsigned __int8)v9 + 499];
113 else
114 result = &pParty->pHirelings[(unsigned __int8)v9];
115 }
116 return result;*/
117 v1 = npcid;
118 if ( npcid >= 0 )
119 {
120 if ( npcid < 5000 )
121 {
122 if ( npcid >= 501 )
123 {
124 MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0);
125 }
126 return &pNPCStats->pNewNPCData[v1];// - 1];
127 }
128 return &pNPCStats->pAdditionalNPC[npcid - 5000];
129 }
130
131
132 if ( npcid >= 5000 )
133 return &pNPCStats->pAdditionalNPC[npcid - 5000];
134 if (sDialogue_SpeakingActorNPC_ID >= 0)
135 {
136 result = 0;
137 }
138 else
139 {
140 v3 = abs(sDialogue_SpeakingActorNPC_ID) - 1;
141 v4 = 0;
142
143 for (i = 0; i < 2; ++i)
144 {
145 if (pParty->pHirelings[i].pName)
146 pTmpBuf[v4++] = i;
147 }
148
149 if (pNPCStats->uNumNewNPCs > 0)
150 {
151 for (i = 0; i < pNPCStats->uNumNewNPCs; ++i)
152 {
153 if (pNPCStats->pNewNPCData[i].Hired())
154 {
155 if (!pParty->pHirelings[0].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[0].pName))
156 {
157 if (!pParty->pHirelings[1].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[1].pName))
158 pTmpBuf[v4++] = i + 2;
159 }
160 }
161 }
162 }
163
164 v9 = pTmpBuf[v3];
165 if ( v9 >= 2 )
166 result = &pNPCStats->pNPCData[499 + v9];
167 else
168 result = &pParty->pHirelings[v9];
169 }
170 return result;
171 }
172
173 //----- (00445B2C) --------------------------------------------------------
174 struct NPCData * GetNewNPCData( signed int npcid, int* npc_indx )
175 {
176
177 int* v3; // edi@1
178 NPCData *result; // eax@5
179 int v5; // esi@9
180 int v6; // ecx@9
181 char v11; // al@23
182
183 v3 = npc_indx;
184 if ( npcid >= 0 )
185 {
186 if ( npcid < 5000 )
187 {
188 if ( npcid >= 501 )
189 {
190 MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:2040", 0);
191 }
192 *v3 = npcid;
193 return &pNPCStats->pNewNPCData[npcid];
194 }
195 *npc_indx = npcid - 5000;
196 return &pNPCStats->pAdditionalNPC[npcid - 5000];
197 }
198 if ( npcid >= 5000 )
199 {
200 *npc_indx = npcid - 5000;
201 return &pNPCStats->pAdditionalNPC[npcid - 5000];
202 }
203 if ( sDialogue_SpeakingActorNPC_ID >= 0 )
204 {
205 *npc_indx = 0;
206 result = nullptr;
207 }
208 else
209 {
210 v5 = abs(sDialogue_SpeakingActorNPC_ID) - 1;
211 v6 = 0;
212 for (int i=0; i<2; ++i)
213 {
214 if ( pParty->pHirelings[i].pName )
215 pTmpBuf[v6++] = i;
216
217 }
218 for (int i=0; i< pNPCStats->uNumNewNPCs; ++i)
219 {
220 if ( pNPCStats->pNewNPCData[i].Hired()
221 && (!pParty->pHirelings[0].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[0].pName))
222 && (!pParty->pHirelings[1].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[1].pName)) )
223 {
224 pTmpBuf[v6++]=i+2;
225 }
226 }
227 v11 = pTmpBuf[v5];
228
229 if ( v11 >= 2u )
230 {
231 *v3 = v11 - 2;
232 result = &pNPCStats->pNewNPCData[v11 - 2];
233 }
234 else
235 {
236 *v3 = v11;
237 result = &pParty->pHirelings[v11];
238 }
239 }
240 return result;
241 }
242
243 //----- (00476977) --------------------------------------------------------
244 void NPCStats::InitializeNPCText()
245 {
246 int i;
247 char* test_string;
248 unsigned char c;
249 bool break_loop;
250 unsigned int temp_str_len;
251 char* tmp_pos;
252 int decode_step;
253
254 free(pNPCTextTXT_Raw);
255 pNPCTextTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctext.txt", 0);
256 strtok(pNPCTextTXT_Raw, "\r");
257
258 for (i=0; i<789; ++i)
259 {
260 test_string = strtok(NULL, "\r") + 1;
261 break_loop = false;
262 decode_step=0;
263 do
264 {
265 c = *(unsigned char*)test_string;
266 temp_str_len = 0;
267 while((c!='\t')&&(c>0))
268 {
269 ++temp_str_len;
270 c=test_string[temp_str_len];
271 }
272 tmp_pos=test_string+temp_str_len;
273 if (*tmp_pos == 0)
274 break_loop = true;
275 *tmp_pos = 0;
276 if (temp_str_len)
277 {
278 if ( decode_step == 1)
279 pNPCTopics[i].pText =RemoveQuotes(test_string);
280 }
281 else
282 {
283 break_loop = true;
284 }
285 ++decode_step;
286 test_string=tmp_pos+1;
287 } while ((decode_step<2)&&!break_loop);
288 }
289 free(pNPCTopicTXT_Raw);
290 pNPCTopicTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctopic.txt", 0);
291 strtok(pNPCTopicTXT_Raw, "\r");
292
293 for ( i = 1; i <= 579; ++i )//NPC topics count limit
294 {
295 test_string = strtok(NULL, "\r") + 1;
296 break_loop = false;
297 decode_step=0;
298 do
299 {
300 c = *(unsigned char*)test_string;
301 temp_str_len = 0;
302 while((c!='\t')&&(c>0))
303 {
304 ++temp_str_len;
305 c=test_string[temp_str_len];
306 }
307 tmp_pos=test_string+temp_str_len;
308 if (*tmp_pos == 0)
309 break_loop = true;
310 *tmp_pos = 0;
311 if (temp_str_len)
312 {
313 if ( decode_step == 1)
314 pNPCTopics[i].pTopic = RemoveQuotes(test_string);
315 }
316 else
317 {
318 break_loop = true;
319 }
320 ++decode_step;
321 test_string=tmp_pos+1;
322 } while ((decode_step<2)&&!break_loop);
323 }
324
325 free(pNPCDistTXT_Raw);
326 pNPCDistTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdist.txt", 0);
327 strtok(pNPCDistTXT_Raw, "\r");
328 strtok(NULL, "\r");
329
330 for (i=1; i<59; ++i)
331 {
332 test_string = strtok(NULL, "\r") + 1;
333 break_loop = false;
334 decode_step=0;
335 do
336 {
337 c = *(unsigned char*)test_string;
338 temp_str_len = 0;
339 while((c!='\t')&&(c>0))
340 {
341 ++temp_str_len;
342 c=test_string[temp_str_len];
343 }
344 tmp_pos=test_string+temp_str_len;
345 if (*tmp_pos == 0)
346 break_loop = true;
347 *tmp_pos = 0;
348 if (temp_str_len)
349 {
350 if ((decode_step>0)&&(decode_step<77))
351 {
352 pProfessionChance[decode_step].professionChancePerArea[i]=atoi(test_string);
353 }
354 else if (decode_step==0)
355 {
356 pProfessionChance[0].professionChancePerArea[i]=10;
357 }
358 }
359 else
360 {
361 break_loop = true;
362 }
363 ++decode_step;
364 test_string=tmp_pos+1;
365 } while ((decode_step<78)&&!break_loop);
366 }
367
368 for ( i = 0; i < 77; ++i )
369 {
370 pProfessionChance[i].uTotalprofChance=0;
371 for ( int ii = 1; ii < 59; ++ii )
372 {
373 pProfessionChance[i].uTotalprofChance+=pProfessionChance[i].professionChancePerArea[ii];
374 }
375 pProfessionChance[i].professionChancePerArea[0]=0;
376 pProfessionChance[i].professionChancePerArea[59]=0;
377 }
378
379 free(pNPCDistTXT_Raw);
380 pNPCDistTXT_Raw = nullptr;
381 }
382
383 //----- (00476C60) --------------------------------------------------------
384 void NPCStats::_476C60()
385 {
386 for (unsigned int i = 1; i < uNumNewNPCs; ++i)
387 pNewNPCData[i].pName = pNPCUnicNames[i - 1];
388
389 if (pParty->pHirelings[0].pName)
390 pParty->pHirelings[0].pName = pParty->pHireling1Name;
391 if (pParty->pHirelings[1].pName)
392 pParty->pHirelings[1].pName = pParty->pHireling2Name;
393 }
394
395 //----- (00476CB5) --------------------------------------------------------
396 void NPCStats::InitializeNPCData()
397 {
398 int i;
399 char* test_string;
400 unsigned char c;
401 bool break_loop;
402 unsigned int temp_str_len;
403 char* tmp_pos;
404 int decode_step;
405
406 pNPCDataTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdata.txt", 0);
407 strtok(pNPCDataTXT_Raw, "\r");
408 strtok(NULL, "\r");
409
410 for (i=0; i<500; ++i)
411 {
412 test_string = strtok(NULL, "\r") + 1;
413 break_loop = false;
414 decode_step=0;
415 do
416 {
417 c = *(unsigned char*)test_string;
418 temp_str_len = 0;
419 while((c!='\t')&&(c>0))
420 {
421 ++temp_str_len;
422 c=test_string[temp_str_len];
423 }
424 tmp_pos=test_string+temp_str_len;
425 if (*tmp_pos == 0)
426 break_loop = true;
427 *tmp_pos = 0;
428 if (temp_str_len)
429 { //i+1
430 switch (decode_step)
431 {
432 case 1:
433 pNPCUnicNames[i] = RemoveQuotes(test_string);
434 pNPCData[i+1].pName=pNPCUnicNames[i];
435 break;
436 case 2:
437 pNPCData[i+1].uPortraitID = atoi(test_string);
438 break;
439 case 6:
440 pNPCData[i+1].Location2D = atoi(test_string);
441 break;
442 case 7:
443 pNPCData[i+1].uProfession = atoi(test_string);
444 break;
445 case 8:
446 pNPCData[i+1].greet = atoi(test_string);
447 break;
448 case 9:
449 pNPCData[i+1].joins = (*test_string == 'y')?1:0;
450 break;
451 case 10:
452 pNPCData[i+1].evt_A = atoi(test_string);
453 break;
454 case 11:
455 pNPCData[i+1].evt_B = atoi(test_string);
456 break;
457 case 12:
458 pNPCData[i+1].evt_C = atoi(test_string);
459 break;
460 case 13:
461 pNPCData[i+1].evt_D = atoi(test_string);
462 break;
463 case 14:
464 pNPCData[i+1].evt_E = atoi(test_string);
465 break;
466 case 15:
467 pNPCData[i+1].evt_F = atoi(test_string);
468 break;
469 }
470 }
471 ++decode_step;
472 test_string=tmp_pos+1;
473 } while ((decode_step<16)&&!break_loop);
474 }
475 uNumNewNPCs = 501;
476 pNPCGreetTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgreet.txt", 0);
477 strtok(pNPCGreetTXT_Raw, "\r");
478 for ( i = 1; i <= 205; ++i )
479 {
480 test_string = strtok(NULL, "\r") + 1;
481 break_loop = false;
482 decode_step=0;
483 do
484 {
485 c = *(unsigned char*)test_string;
486 temp_str_len = 0;
487 while((c!='\t')&&(c>0))
488 {
489 ++temp_str_len;
490 c=test_string[temp_str_len];
491 }
492 tmp_pos=test_string+temp_str_len;
493 if (*tmp_pos == 0)
494 break_loop = true;
495 *tmp_pos = 0;
496 if (temp_str_len)
497 { //i+1
498 switch (decode_step)
499 {
500 case 1:
501 pNPCGreetings[i].pGreetings[0] = RemoveQuotes(test_string);
502 break;
503 case 2:
504 pNPCGreetings[i].pGreetings[1] = RemoveQuotes(test_string);
505 break;
506 }
507 }
508 ++decode_step;
509 test_string=tmp_pos+1;
510 } while ((decode_step<3)&&!break_loop);
511 }
512
513 pNCPGroupTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgroup.txt", 0);
514 strtok(pNCPGroupTXT_Raw, "\r");
515
516 for (i=0; i<51; ++i)
517 {
518 test_string = strtok(NULL, "\r") + 1;
519 break_loop = false;
520 decode_step=0;
521 do
522 {
523 c = *(unsigned char*)test_string;
524 temp_str_len = 0;
525 while((c!='\t')&&(c>0))
526 {
527 ++temp_str_len;
528 c=test_string[temp_str_len];
529 }
530 tmp_pos=test_string+temp_str_len;
531 if (*tmp_pos == 0)
532 break_loop = true;
533 *tmp_pos = 0;
534 if (temp_str_len)
535 { //i+1
536 if (decode_step==1)
537 {
538 pGroups[i] = atoi(test_string);
539 }
540 }
541 ++decode_step;
542 test_string=tmp_pos+1;
543 } while ((decode_step<2)&&!break_loop);
544 }
545
546 pNPCNewsTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcnews.txt", 0);
547 strtok(pNPCNewsTXT_Raw, "\r");
548
549
550 for (i=0; i<51; ++i)
551 {
552 test_string = strtok(NULL, "\r") + 1;
553 break_loop = false;
554 decode_step=0;
555 do
556 {
557 c = *(unsigned char*)test_string;
558 temp_str_len = 0;
559 while((c!='\t')&&(c>0))
560 {
561 ++temp_str_len;
562 c=test_string[temp_str_len];
563 }
564 tmp_pos=test_string+temp_str_len;
565 if (*tmp_pos == 0)
566 break_loop = true;
567 *tmp_pos = 0;
568 if (temp_str_len)
569 { //i+1
570 if (decode_step==1)
571 pCatchPhrases[i] = RemoveQuotes(test_string);
572 }
573 ++decode_step;
574 test_string=tmp_pos+1;
575 } while ((decode_step<2)&&!break_loop);
576 }
577 }
578
579 //----- (0047702F) --------------------------------------------------------
580 void NPCStats::Initialize()
581 {
582 int i;
583 char* test_string;
584 unsigned char c;
585 bool break_loop;
586 unsigned int temp_str_len;
587 char* tmp_pos;
588 int decode_step;
589
590 InitializeNPCData();
591 InitializeNPCText();
592 InitializeQuests();
593 InitializeAutonotes();
594 InitializeAwards();
595 InitializeTransitions();
596 InitializeMerchants();
597 InitializeScrolls();
598
599 pNPCNamesTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcnames.txt", 0);
600 strtok(pNPCNamesTXT_Raw, "\r");
601
602 uNewlNPCBufPos = 0;
603
604 for (i=0; i<540; ++i)
605 {
606 test_string = strtok(NULL, "\r") + 1;
607 break_loop = false;
608 decode_step=0;
609 do
610 {
611 c = *(unsigned char*)test_string;
612 temp_str_len = 0;
613 if (c=='\t')
614 {
615 if ( (decode_step == 1)&&(!uNumNPCNames[1]))
616 uNumNPCNames[1]=i;
617 }
618 else
619 {
620 while((c!='\n')&&(c!='\t')&&(c>0))
621 {
622 ++temp_str_len;
623 c=test_string[temp_str_len];
624 }
625 tmp_pos=test_string+temp_str_len;
626 if (*tmp_pos == 0)
627 break_loop = true;
628
629 if (temp_str_len)
630 {
631 *tmp_pos = 0;
632 if ( decode_step == 0)
633 pNPCNames[i][0] =RemoveQuotes(test_string);
634 else if ( decode_step == 1)
635 pNPCNames[i][1] =RemoveQuotes(test_string);
636 }
637 else
638 {
639 if ( (decode_step == 1)&&(!uNumNPCNames[1]))
640 uNumNPCNames[1]=i;
641 }
642 }
643 ++decode_step;
644 test_string=tmp_pos+1;
645 } while ((decode_step<2)&&!break_loop);
646 }
647 uNumNPCNames[0] = i;
648
649 pNPCProfTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcprof.txt", 0);
650 strtok(pNPCProfTXT_Raw, "\r");
651 strtok(NULL, "\r");
652 strtok(NULL, "\r");
653 strtok(NULL, "\r");
654
655 for (i=1; i<59; ++i)
656 {
657 test_string = strtok(NULL, "\r") + 1;
658 break_loop = false;
659 decode_step=0;
660 do
661 {
662 //while (*test_string == '\t') // some steps are separated by multiple \t's
663 //++test_string;
664
665 c = *(unsigned char*)test_string;
666 temp_str_len = 0;
667 while((c!='\t')&&(c>0))
668 {
669 ++temp_str_len;
670 c=test_string[temp_str_len];
671 }
672 tmp_pos=test_string+temp_str_len;
673 if (*tmp_pos == 0)
674 break_loop = true;
675 *tmp_pos = 0;
676 if (temp_str_len)
677 {
678 switch(decode_step)
679 {
680 case 2:
681 pProfessions[i].uHirePrice = atoi(test_string);
682 break;
683 case 3:
684 pProfessions[i].pActionText = RemoveQuotes(test_string);
685 break;
686 case 4:
687 pProfessions[i].pBenefits= RemoveQuotes(test_string);
688 break;
689 case 5:
690 pProfessions[i].pJoinText = RemoveQuotes(test_string);
691 break;
692 case 6:
693 pProfessions[i].pDismissText = RemoveQuotes(test_string);
694 }
695 }
696 else
697 {
698 if (!decode_step)
699 break_loop = true;
700 }
701 ++decode_step;
702 test_string=tmp_pos+1;
703 } while ((decode_step<7)&&!break_loop);
704 }
705 uNumNPCProfessions = 59;
706 }
707
708 //----- (00477266) --------------------------------------------------------
709 void NPCStats::Release()
710 {
711 free(pNPCTopicTXT_Raw);
712 pNPCTopicTXT_Raw = nullptr;
713 free(pNPCTextTXT_Raw);
714 pNPCTextTXT_Raw = nullptr;
715 free(pNPCNewsTXT_Raw);
716 pNPCNewsTXT_Raw = nullptr;
717 free(pNPCProfTXT_Raw);
718 pNPCProfTXT_Raw = nullptr;
719 free(pNPCNamesTXT_Raw);
720 pNPCNamesTXT_Raw = nullptr;
721 free(pNPCDataTXT_Raw);
722 pNPCDataTXT_Raw = nullptr;
723 free(pNPCDistTXT_Raw);
724 pNPCDistTXT_Raw = nullptr;
725 free(pNPCGreetTXT_Raw);
726 pNPCGreetTXT_Raw = nullptr;
727 free(pNCPGroupTXT_Raw);
728 pNCPGroupTXT_Raw = nullptr;
729 }
730
731 //----- (0047730C) --------------------------------------------------------
732 bool CheckPortretAgainstSex(int a1, int)
733 {
734 return true;
735 }
736 // 47730C: using guessed type int __stdcall const_1(int);
737
738 //----- (0047732C) --------------------------------------------------------
739 void NPCStats::InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId)
740 {
741 int rep_gen;
742 int uNPCSex; // esi@1
743 int uGeneratedPortret; // ecx@23
744 int test_prof_summ; // ecx@37
745 int gen_profession; // eax@37
746 int max_prof_cap; // edx@37
747 // signed int result; // eax@39
748 int uRace; // [sp+Ch] [bp-Ch]@1
749 bool break_gen; // [sp+10h] [bp-8h]@1
750 signed int gen_attempts; // [sp+14h] [bp-4h]@1
751 int uPortretMin; // [sp+24h] [bp+Ch]@1
752 int uPortretMax;
753
754 static const unsigned __int8 NPCSexGenTable[86] ={
755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
756 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
757 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
758 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
759 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 };
760 static const unsigned __int8 NPCRaceGenTable[86] ={
761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 1,
762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
763 0, 0, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
764 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
765 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0};
766
767 unsigned __int8 seed = (unsigned __int8)((double)(npc_uid - 1)/3.0);
768 uNPCSex = NPCSexGenTable[seed];
769 uRace = NPCRaceGenTable[seed];
770 pNPCDataBuff->uSex = uNPCSex;
771 pNPCDataBuff->pName = pNPCNames[rand() % uNumNPCNames[uNPCSex]][uNPCSex];
772
773 gen_attempts = 0;
774 break_gen = false;
775
776 do
777 {
778 switch ( uRace )
779 {
780 case 0:
781 if ( uNPCSex == 0 )
782 {
783 uPortretMin = 2;
784 uPortretMax = 100;
785 }
786 else
787 {
788 uPortretMin = 201;
789 uPortretMax = 250;
790 }
791 case 1:
792 if ( uNPCSex == 0 )
793 {
794 uPortretMin = 400;
795 uPortretMax = 430;
796 }
797 else
798 {
799 uPortretMin = 460;
800 uPortretMax = 490;
801 }
802 break;
803 case 2:
804 if ( uNPCSex == 0 )
805 {
806 uPortretMin = 500;
807 uPortretMax = 520;
808 }
809 else
810 {
811 uPortretMin = 530;
812 uPortretMax = 550;
813 }
814 break;
815 case 3:
816 if ( uNPCSex == 0 )
817 {
818 uPortretMin = 300;
819 uPortretMax = 330;
820 }
821 else
822 {
823 uPortretMin = 360;
824 uPortretMax = 387;
825 }
826
827 break;
828 }
829
830 uGeneratedPortret = uPortretMin + rand() % (uPortretMax - uPortretMin + 1);
831 if ( CheckPortretAgainstSex(uGeneratedPortret, uNPCSex))
832 break_gen = true;
833 ++gen_attempts;
834 if ( gen_attempts >= 4 )
835 {
836 uGeneratedPortret = uPortretMin;
837 break_gen = true;
838 }
839 }
840 while(!break_gen);
841
842 pNPCDataBuff->uPortraitID = uGeneratedPortret;
843 pNPCDataBuff->uFlags = 0;
844 pNPCDataBuff->fame = 0;
845 //generate reputation
846 rep_gen = rand() % 100 + 1;
847
848 if ( rep_gen >= 60 )
849 {
850 if ( rep_gen >= 90 )
851 {
852 if ( rep_gen >= 95 )
853 {
854 if ( rep_gen >= 98 )
855 pNPCDataBuff->rep = -600;
856 else
857 pNPCDataBuff->rep = 400;
858 }
859 else
860 pNPCDataBuff->rep = -300;
861 }
862 else
863 pNPCDataBuff->rep = 200;
864 }
865 else
866 pNPCDataBuff->rep = 0;
867
868 max_prof_cap = rand() % pProfessionChance[uMapId].uTotalprofChance+1;
869 test_prof_summ = 0;
870 gen_profession = 0;
871
872 if ( max_prof_cap > 0 )
873 {
874 do
875 test_prof_summ += pProfessionChance[uMapId].professionChancePerArea[gen_profession++];
876 while ( test_prof_summ < max_prof_cap );
877 }
878 pNPCDataBuff->uProfession = gen_profession - 1;
879 pNPCDataBuff->Location2D = uLocation2D;
880 pNPCDataBuff->field_24 = 1;
881 pNPCDataBuff->joins = 1;
882 pNPCDataBuff->evt_A = 0;
883 pNPCDataBuff->evt_B = 0;
884 pNPCDataBuff->evt_C = 0;
885 pNPCDataBuff->evt_D = 0;
886 pNPCDataBuff->evt_E = 0;
887 pNPCDataBuff->evt_F = 0;
888 }
889
890
891 //----- (00495366) --------------------------------------------------------
892 char *NPCStats::sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId)
893 {
894 int pickedName; // edx@2
895
896 if ( firstLetter == dword_AE336C_LastMispronouncedNameFirstLetter)
897 pickedName = dword_AE3370_LastMispronouncedNameResult;
898 else
899 {
900 dword_AE336C_LastMispronouncedNameFirstLetter = firstLetter;
901 if ( this->uNumNPCNames[genderId] == 0 )
902 pickedName = rand() % this->uNumNPCNames[(genderId + 1) % 2]; //originally without " + 1) % 2", but that would yield a div by zero
903 else
904 {
905 int rangeBottom = 0;
906 int rangeTop = 0;
907 for ( uint i = 0; i < this->uNumNPCNames[genderId]; ++i )
908 {
909 if (tolower(this->pNPCNames[i][genderId][0]))
910 {
911 if ( rangeBottom )
912 rangeTop = i;
913 else
914 rangeBottom = i;
915 }
916 }
917 if ( rangeTop != 0 )
918 pickedName = rangeBottom + rand() % (rangeTop - rangeBottom);
919 else
920 pickedName = rand() % this->uNumNPCNames[genderId];
921 }
922 }
923 dword_AE3370_LastMispronouncedNameResult = pickedName;
924 return this->pNPCNames[pickedName][genderId];
925 }
926
927 //----- (00476387) --------------------------------------------------------
928 bool PartyHasDragon()
929 {
930 return pNPCStats->pNewNPCData[57].Hired();
931 }
932
933 //----- (00476395) --------------------------------------------------------
934 //0x26 Wizard eye at skill level 2
935 bool CheckHiredNPCSpeciality(unsigned int uProfession)
936 {
937
938 if ( bNoNPCHiring == 1 )
939 return 0;
940
941 for (uint i=0; i<pNPCStats->uNumNewNPCs; ++i )
942 {
943 if ( pNPCStats->pNewNPCData[i].uProfession == uProfession &&
944 (pNPCStats->pNewNPCData[i].uFlags & 0x80) )//Uninitialized memory access
945 return true;
946 }
947 if ( pParty->pHirelings[0].uProfession == uProfession ||
948 pParty->pHirelings[1].uProfession == uProfession)
949 return true;
950 else
951 return false;
952
953 }
954
955 //----- (004763E0) --------------------------------------------------------
956 void InitializeAwards()
957 {
958 int i;
959 char* test_string;
960 unsigned char c;
961 bool break_loop;
962 unsigned int temp_str_len;
963 char* tmp_pos;
964 int decode_step;
965
966 free(pAwardsTXT_Raw);
967 pAwardsTXT_Raw = (char *)pEvents_LOD->LoadRaw("awards.txt", 0);
968 strtok(pAwardsTXT_Raw, "\r");
969
970 for (i=1; i<105; ++i)
971 {
972 test_string = strtok(NULL, "\r") + 1;
973 break_loop = false;
974 decode_step=0;
975 do
976 {
977 c = *(unsigned char*)test_string;
978 temp_str_len = 0;
979 while((c!='\t')&&(c>0))
980 {
981 ++temp_str_len;
982 c=test_string[temp_str_len];
983 }
984 tmp_pos=test_string+temp_str_len;
985 if (*tmp_pos == 0)
986 break_loop = true;
987 *tmp_pos = 0;
988 if (temp_str_len)
989 {
990 if (decode_step==1)
991 pAwards[i].pText=RemoveQuotes(test_string);
992 else if (decode_step==2)
993 pAwards[i].uPriority = atoi(test_string);
994 }
995 else
996 {
997 break_loop = true;
998 }
999 ++decode_step;
1000 test_string=tmp_pos+1;
1001 } while ((decode_step<3)&&!break_loop);
1002 }
1003 }
1004 // 7241C8: using guessed type int dword_7241C8;
1005
1006 //----- (004764C2) --------------------------------------------------------
1007 void InitializeScrolls()
1008 {
1009
1010 int i;
1011 char* test_string;
1012 unsigned char c;
1013 bool break_loop;
1014 unsigned int temp_str_len;
1015 char* tmp_pos;
1016 int decode_step;
1017
1018 free(pScrollsTXT_Raw);
1019 pScrollsTXT_Raw = (char *)pEvents_LOD->LoadRaw("scroll.txt", 0);
1020 strtok(pScrollsTXT_Raw, "\r");
1021 for (i=0; i<82; ++i)
1022 {
1023 test_string = strtok(NULL, "\r") + 1;
1024 break_loop = false;
1025 decode_step=0;
1026 do
1027 {
1028 c = *(unsigned char*)test_string;
1029 temp_str_len = 0;
1030 while((c!='\t')&&(c>0))
1031 {
1032 ++temp_str_len;
1033 c=test_string[temp_str_len];
1034 }
1035 tmp_pos=test_string+temp_str_len;
1036 if (*tmp_pos == 0)
1037 break_loop = true;
1038 *tmp_pos = 0;
1039 if (temp_str_len)
1040 {
1041 if ( decode_step == 1)
1042 pScrolls[i]=RemoveQuotes(test_string);
1043 }
1044 else
1045 {
1046 break_loop = true;
1047 }
1048 ++decode_step;
1049 test_string=tmp_pos+1;
1050 } while ((decode_step<2)&&!break_loop);
1051 }
1052 }
1053
1054 //----- (00476590) --------------------------------------------------------
1055 void InitializeMerchants()
1056 {
1057 int i;
1058 char* test_string;
1059 unsigned char c;
1060 bool break_loop;
1061 unsigned int temp_str_len;
1062 char* tmp_pos;
1063 int decode_step;
1064
1065 free(pMerchantsTXT_Raw);
1066 pMerchantsTXT_Raw = (char *)pEvents_LOD->LoadRaw("merchant.txt", 0);
1067 strtok(pMerchantsTXT_Raw, "\r");
1068
1069 for (i=0; i<7; ++i)
1070 {
1071 test_string = strtok(NULL, "\r") + 1;
1072 break_loop = false;
1073 decode_step=0;
1074 do
1075 {
1076 c = *(unsigned char*)test_string;
1077 temp_str_len = 0;
1078 while((c!='\t')&&(c>0))
1079 {
1080 ++temp_str_len;
1081 c=test_string[temp_str_len];
1082 }
1083 tmp_pos=test_string+temp_str_len;
1084 if (*tmp_pos == 0)
1085 break_loop = true;
1086 *tmp_pos = 0;
1087 if (temp_str_len)
1088 {
1089 switch (decode_step)
1090 {
1091 case 1:
1092 pMerchantsBuyPhrases[i]=RemoveQuotes(test_string);
1093 break;
1094 case 2:
1095 pMerchantsSellPhrases[i]=RemoveQuotes(test_string);
1096 break;
1097 case 3:
1098 pMerchantsRepairPhrases[i]=RemoveQuotes(test_string);
1099 break;
1100 case 4:
1101 pMerchantsIdentifyPhrases[i]=RemoveQuotes(test_string);
1102 break;
1103 }
1104 }
1105 else
1106 {
1107 break_loop = true;
1108 }
1109 ++decode_step;
1110 test_string=tmp_pos+1;
1111 } while ((decode_step<5)&&!break_loop);
1112 }
1113
1114 }
1115
1116 //----- (00476682) --------------------------------------------------------
1117 void InitializeTransitions()
1118 {
1119 int i;
1120 char* test_string;
1121 unsigned char c;
1122 bool break_loop;
1123 unsigned int temp_str_len;
1124 char* tmp_pos;
1125 int decode_step;
1126
1127 free(pTransitionsTXT_Raw);
1128 pTransitionsTXT_Raw = (char *)pEvents_LOD->LoadRaw("trans.txt", 0);
1129 strtok(pTransitionsTXT_Raw, "\r");
1130
1131 for (i=0; i<464; ++i)
1132 {
1133 test_string = strtok(NULL, "\r") + 1;
1134 break_loop = false;
1135 decode_step=0;
1136 do
1137 {
1138 c = *(unsigned char*)test_string;
1139 temp_str_len = 0;
1140 while((c!='\t')&&(c>0))
1141 {
1142 ++temp_str_len;
1143 c=test_string[temp_str_len];
1144 }
1145 tmp_pos=test_string+temp_str_len;
1146 if (*tmp_pos == 0)
1147 break_loop = true;
1148 *tmp_pos = 0;
1149 if (temp_str_len)
1150 {
1151 if ( decode_step == 1)
1152 pTransitionStrings[i + 1]=RemoveQuotes(test_string);
1153 }
1154 else
1155 {
1156 break_loop = true;
1157 }
1158 ++decode_step;
1159 test_string=tmp_pos+1;
1160 } while ((decode_step<2)&&!break_loop);
1161 }
1162 }
1163
1164 //----- (00476750) --------------------------------------------------------
1165 void InitializeAutonotes()
1166 {
1167 int i;
1168 char* test_string;
1169 unsigned char c;
1170 bool break_loop;
1171 unsigned int temp_str_len;
1172 char* tmp_pos;
1173 int decode_step;
1174
1175 free(pAutonoteTXT_Raw);
1176 pAutonoteTXT_Raw = (char *)pEvents_LOD->LoadRaw("autonote.txt", 0);
1177 strtok(pAutonoteTXT_Raw, "\r");
1178
1179 for (i=0; i<195; ++i)
1180 {
1181 test_string = strtok(NULL, "\r") + 1;
1182 break_loop = false;
1183 decode_step=0;
1184 do
1185 {
1186 c = *(unsigned char*)test_string;
1187 temp_str_len = 0;
1188 while((c!='\t')&&(c>0))
1189 {
1190 ++temp_str_len;
1191 c=test_string[temp_str_len];
1192 }
1193 tmp_pos=test_string+temp_str_len;
1194 if (*tmp_pos == 0)
1195 break_loop = true;
1196 *tmp_pos = 0;
1197 if (temp_str_len)
1198 {
1199 switch (decode_step)
1200 {
1201 case 1:
1202 pAutonoteTxt[i+1].pText=RemoveQuotes(test_string);
1203 break;
1204 case 2:
1205 {
1206 if ( !_stricmp(test_string, "potion"))
1207 {
1208 pAutonoteTxt[i+1].eType = AUTONOTE_POTION_RECEPIE;
1209 break;
1210 }
1211 if ( !_stricmp(test_string, "stat") )
1212 {
1213 pAutonoteTxt[i+1].eType = AUTONOTE_STAT_HINT;
1214 break;
1215 }
1216 if ( !_stricmp(test_string, "seer") )
1217 {
1218 pAutonoteTxt[i+1].eType = AUTONOTE_SEER;
1219 break;
1220 }
1221 if ( !_stricmp(test_string, "obelisk") )
1222 {
1223 pAutonoteTxt[i+1].eType = AUTONOTE_OBELISK;
1224 break;
1225 }
1226 if ( !_stricmp(test_string, "teacher") )
1227 {
1228 pAutonoteTxt[i+1].eType = AUTONOTE_TEACHER;
1229 break;
1230 }
1231 pAutonoteTxt[i+1].eType =AUTONOTE_MISC;
1232 break;
1233 }
1234 }
1235 }
1236 else
1237 {
1238 break_loop = true;
1239 }
1240 ++decode_step;
1241 test_string=tmp_pos+1;
1242 } while ((decode_step<3)&&!break_loop);
1243 }
1244 }
1245
1246
1247 //----- (004768A9) --------------------------------------------------------
1248 void InitializeQuests()
1249 {
1250 int i;
1251 char* test_string;
1252 unsigned char c;
1253 bool break_loop;
1254 unsigned int temp_str_len;
1255 char* tmp_pos;
1256 int decode_step;
1257
1258 free(pQuestsTXT_Raw);
1259 pQuestsTXT_Raw = (char *)pEvents_LOD->LoadRaw("quests.txt", 0);
1260 strtok(pQuestsTXT_Raw, "\r");
1261 memset(pQuestTable.data(),0, sizeof(pQuestTable));
1262 for (i=0; i<512; ++i)
1263 {
1264 test_string = strtok(NULL, "\r") + 1;
1265 break_loop = false;
1266 decode_step=0;
1267 do
1268 {
1269 c = *(unsigned char*)test_string;
1270 temp_str_len = 0;
1271 while((c!='\t')&&(c>0))
1272 {
1273 ++temp_str_len;
1274 c=test_string[temp_str_len];
1275 }
1276 tmp_pos=test_string+temp_str_len;
1277 if (*tmp_pos == 0)
1278 break_loop = true;
1279 *tmp_pos = 0;
1280 if (temp_str_len)
1281 {
1282 if ( decode_step == 1)
1283 pQuestTable[i+1] =RemoveQuotes(test_string);
1284 }
1285 else
1286 {
1287 break_loop = true;
1288 }
1289 ++decode_step;
1290 test_string=tmp_pos+1;
1291 } while ((decode_step<2)&&!break_loop);
1292 }
1293 }
1294
1295 //----- (004B29F2) --------------------------------------------------------
1296 const char * ContractSelectText( int pEventCode )
1297 {
1298 static const int dialogue_base=110;
1299 contract_approved = 0;
1300 dword_F8B1AC_award_bit_number = pEventCode + 50;
1301 gold_transaction_amount = price_for_membership[pEventCode];
1302 if ( pPlayers[uActiveCharacter]->CanAct() )
1303 {
1304 if ( (unsigned __int16)_449B57_test_bit((unsigned __int8 *)pPlayers[uActiveCharacter]->_achieved_awards_bits, dword_F8B1AC_award_bit_number) )
1305 return pNPCTopics[dialogue_base+13].pText;
1306 else
1307 {
1308 if ( (unsigned int)gold_transaction_amount <= pParty->uNumGold )
1309 {
1310 contract_approved = 1;
1311 return pNPCTopics[pEventCode + dialogue_base].pText;
1312 }
1313 else
1314 return pNPCTopics[dialogue_base+14].pText;
1315 }
1316 }
1317 else
1318 return pNPCTopics[dialogue_base+12].pText;
1319 }
1320 //----- (004B40E6) --------------------------------------------------------
1321 void NPCHireableDialogPrepare()
1322 {
1323 signed int v0; // ebx@1
1324 NPCData *v1; // edi@1
1325
1326 v0 = 0;
1327 v1 = HouseNPCData[(unsigned int)((char *)pDialogueNPCCount + -(dword_591080 != 0) )];//- 1
1328 pDialogueWindow->Release();
1329 pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 350, WINDOW_MainMenu, 0, 0);
1330 pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 0x1BDu, 0xA9u, 0x23u, 1, 0, UIMSG_Escape, 0, 0,
1331 pGlobalTXT_LocalizationStrings[34], //"Cancel"
1332 pIcons_LOD->GetTexture(uExitCancelTextureId),
1333 0);
1334 pDialogueWindow->CreateButton(0, 0, 0, 0, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0);
1335 if ( pNPCStats->pProfessions[v1->uProfession].pBenefits)//*(&pNPCStats->field_13A5C + 5 * v1->uProfession) )
1336 {
1337 pDialogueWindow->CreateButton( 480, 0xA0u, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Du, 0,
1338 pGlobalTXT_LocalizationStrings[407], 0);//"More Information"
1339 v0 = 1;
1340 }
1341 pDialogueWindow->CreateButton( 0x1E0u, 30 * v0 + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Cu, 0,
1342 pGlobalTXT_LocalizationStrings[406], 0); //"Hire"
1343 pDialogueWindow->_41D08F_set_keyboard_control_group(v0 + 1, 1, 0, 2);
1344 dialog_menu_id = HOUSE_DIALOGUE_OTHER;
1345 }
1346
1347 //----- (004B4224) --------------------------------------------------------
1348 void _4B4224_UpdateNPCTopics( int _this )
1349 {
1350 int num_menu_buttons; // ebx@1
1351 int i; // ebp@5
1352 // signed int v4; // ebp@9
1353 int v6; // eax@16
1354 int v8; // eax@21
1355 int v10; // eax@26
1356 int v12; // eax@31
1357 int v14; // eax@36
1358 int v16; // eax@41
1359 NPCData *v17; // [sp+10h] [bp-4h]@4
1360
1361 num_menu_buttons = 0;
1362 pDialogueNPCCount = (_this + 1);
1363 if ( _this + 1 == uNumDialogueNPCPortraits && uHouse_ExitPic )
1364 {
1365 pDialogueWindow->Release();
1366 pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_MainMenu, 0, 0);
1367 sprintfex(sHouseName.data(), pGlobalTXT_LocalizationStrings[LOCSTR_ENTER_S], pMapStats->pInfos[uHouse_ExitPic].pName);
1368 pBtn_ExitCancel = pDialogueWindow->CreateButton(566, 445, 75, 33, 1, 0, UIMSG_Escape, 0, 'N', pGlobalTXT_LocalizationStrings[34], pIcons_LOD->GetTexture(uTextureID_BUTTDESC2), 0);// "Cancel"
1369 pBtn_YES = pDialogueWindow->CreateButton(486, 445, 75, 33, 1, 0, UIMSG_BF, 1, 'Y', sHouseName.data(), pIcons_LOD->GetTexture(uTextureID_BUTTYES2), 0);
1370 pDialogueWindow->CreateButton( pNPCPortraits_x[0][0], pNPCPortraits_y[0][0], 63u, 73u, 1, 0, UIMSG_BF, 1u, 0x20u, sHouseName.data(), 0);
1371 pDialogueWindow->CreateButton(8, 8, 460, 344, 1, 0, UIMSG_BF, 1, 0x59u, sHouseName.data(), 0);
1372 }
1373 else
1374 {
1375 v17 = HouseNPCData[_this + 1 - ((dword_591080 != 0)?1:0 )];//+ 1
1376 if ( dialog_menu_id == HOUSE_DIALOGUE_OTHER )
1377 {
1378 pDialogueWindow->Release();
1379 }
1380 else
1381 {
1382 for ( i = 0; i < uNumDialogueNPCPortraits; ++i )
1383 HouseNPCPortraitsButtonsList[i]->Release();
1384 }
1385 pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 345, WINDOW_MainMenu, 0, 0);
1386 pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 445, 169, 35, 1, 0, UIMSG_Escape, 0, 0,
1387 pGlobalTXT_LocalizationStrings[74],// "End Conversation"
1388 pIcons_LOD->GetTexture(uExitCancelTextureId), 0);
1389 pDialogueWindow->CreateButton(8, 8, 450, 320, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0);
1390 if ( pDialogueNPCCount == 1 && dword_591080 )
1391 {
1392 InitializaDialogueOptions(in_current_building_type);
1393 }
1394 else
1395 {
1396 if ( v17->joins )
1397 {
1398 num_menu_buttons = 1;
1399 pDialogueWindow->CreateButton(480u, 160u, 140u, 30, 1, 0, UIMSG_ClickNPCTopic, 0xDu, 0, "", 0);
1400 }
1401 if ( v17->evt_A)
1402 {
1403 if ( num_menu_buttons < 4 )
1404 {
1405 v6 = NPC_EventProcessor(v17->evt_A);
1406 if ( v6 == 1 || v6 == 2 )
1407 pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x13u, 0, "", 0);
1408 }
1409 }
1410 if ( v17->evt_B )
1411 {
1412 if ( num_menu_buttons < 4 )
1413 {
1414 v8 = NPC_EventProcessor(v17->evt_B);
1415 if ( v8 == 1 || v8 == 2 )
1416 pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x14u, 0, "", 0);
1417 }
1418 }
1419 if ( v17->evt_C )
1420 {
1421 if ( num_menu_buttons < 4 )
1422 {
1423 v10 = NPC_EventProcessor(v17->evt_C);
1424 if ( v10 == 1 || v10 == 2 )
1425 pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x15u, 0, "", 0);
1426 }
1427 }
1428
1429 if ( v17->evt_D )
1430 {
1431 if ( num_menu_buttons < 4 )
1432 {
1433 v12 = NPC_EventProcessor(v17->evt_D);
1434 if ( v12 == 1 || v12 == 2 )
1435 pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x16u, 0, "", 0);
1436 }
1437 }
1438 if ( v17->evt_E )
1439 {
1440 if ( num_menu_buttons < 4 )
1441 {
1442 v14 = NPC_EventProcessor(v17->evt_E);
1443 if ( v14 == 1 || v14 == 2 )
1444 pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x17u, 0, "", 0);
1445 }
1446 }
1447 if ( v17->evt_F )
1448 {
1449 if ( num_menu_buttons < 4 )
1450 {
1451 v16 = NPC_EventProcessor(v17->evt_F);
1452 if ( v16 == 1 || v16 == 2 )
1453 pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x18u, 0, "", 0);
1454 }
1455 }
1456 pDialogueWindow->_41D08F_set_keyboard_control_group(num_menu_buttons, 1, 0, 2);
1457 dword_F8B1E0 = pDialogueWindow->pNumPresenceButton;
1458 }
1459 dialog_menu_id = HOUSE_DIALOGUE_MAIN;
1460 }
1461
1462 }
1463 //----- (004466C4) --------------------------------------------------------
1464 int NPC_EventProcessor(int npc_event_id, int entry_line)
1465 {
1466 signed int event_index; // ebp@1
1467 int evt_seq_num; // esi@3
1468 bool ready_to_exit; // [sp+Ch] [bp-Ch]@3
1469 signed int npc_activity; // [sp+10h] [bp-8h]@3
1470 int result;
1471
1472 event_index = 0;
1473 if ( !npc_event_id )
1474 return 0;
1475 evt_seq_num = entry_line;
1476 pSomeOtherEVT = pGlobalEVT.data();
1477 uSomeOtherEVT_NumEvents = uGlobalEVT_NumEvents;
1478 memcpy(pSomeOtherEVT_Events.data(), pGlobalEVT_Index.data(), sizeof(EventIndex)*4400);
1479 npc_activity = 1;
1480 ready_to_exit = false;
1481 if ( uSomeOtherEVT_NumEvents <= 0 )
1482 return 2;
1483 do
1484 {
1485 if ( (pSomeOtherEVT_Events[event_index].uEventID == npc_event_id) && (pSomeOtherEVT_Events[event_index].event_sequence_num == evt_seq_num) )
1486 {
1487 _evt_raw *_evt = (_evt_raw *)&pSomeOtherEVT[pSomeOtherEVT_Events[event_index].uEventOffsetInEVT];
1488 switch(_evt->_e_type)
1489 {
1490 case EVENT_Exit:
1491 //exit
1492 if ( ready_to_exit )
1493 result = npc_activity != 0;
1494 else
1495 result = 2;
1496 return result;
1497 break;
1498 case EVENT_OnCanShowDialogItemCmp:
1499 ready_to_exit = true;
1500 //v8 = (unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + (((unsigned __int8)v7[9] + ((unsigned __int8)v7[10] << 8)) << 8)) << 8);
1501 for(int i=0; i<4; ++i)
1502 {
1503 // if (pParty->pPlayers[i].CompareVariable((enum VariableType)((unsigned __int8)pSomeOtherEVT[v6 + 5] + ((unsigned __int8)pSomeOtherEVT[v6 + 6] << 8)),
1504 // v8))
1505 if (pParty->pPlayers[i].CompareVariable((enum VariableType)EVT_WORD(_evt->v5), EVT_DWORD(_evt->v7)))
1506 {
1507 event_index = -1;
1508 evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1;
1509 break;
1510 }
1511 }
1512 break;
1513 case EVENT_EndCanShowDialogItem :
1514 if ( ready_to_exit )
1515 result = npc_activity != 0;
1516 else
1517 result = 2;
1518 return result;
1519 break;
1520 case EVENT_SetCanShowDialogItem :
1521 ready_to_exit = true;
1522 npc_activity = EVT_BYTE(_evt->v5); //(unsigned __int8)v7[5];
1523 break;
1524 case EVENT_IsActorAssasinated :
1525 // if (IsActorAlive( (unsigned __int8)v7[5],
1526 // (unsigned __int8)v7[6] + (((unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + ((unsigned __int8)v7[9] << 8)) << 8)) << 8),
1527 // (unsigned __int8)v7[10]) )
1528 if (IsActorAlive( EVT_BYTE(_evt->v5), EVT_DWORD(_evt->v6), EVT_BYTE(_evt->v10)))
1529 { // drop linear sequense, going to new seq
1530 event_index = -1;
1531 evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1;
1532 }
1533 break;
1534 }
1535 ++evt_seq_num;
1536 }
1537 ++event_index;
1538 }
1539 while ( event_index < uSomeOtherEVT_NumEvents );
1540 if ( ready_to_exit )
1541 result = npc_activity != 0;
1542 else
1543 result = 2;
1544 return result;
1545 }
1546 //----- (00445C8B) --------------------------------------------------------
1547 int __fastcall GetGreetType(signed int SpeakingNPC_ID)
1548 {
1549 signed int v1; // ebx@1
1550 int v3; // edi@6
1551 int v4; // ecx@6
1552 int v5; // edx@6
1553 NPCData *v6; // eax@6
1554 char *v7; // ebp@11
1555 NPCData *v8; // esi@11
1556
1557 v1 = 0;
1558 if ( SpeakingNPC_ID >= 0 )
1559 {
1560 if ( SpeakingNPC_ID < 5000 )
1561 return 1;//QuestNPC_greet
1562 return 2;//HiredNPC_greet
1563 }
1564 if ( SpeakingNPC_ID >= 5000 )
1565 return 2;
1566 v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1;
1567 v4 = 0;
1568 v5 = 0;
1569 v6 = pParty->pHirelings.data();
1570 do
1571 {
1572 if ( v6->pName )
1573 pTmpBuf[v4++] = v5;
1574 ++v6;
1575 ++v5;
1576 }
1577 while ( (signed int)v6 < (signed int)&pParty->pPickedItem );
1578 if ( (signed int)pNPCStats->uNumNewNPCs > 0 )
1579 {
1580 v7 = &pTmpBuf[v4];
1581 v8 = pNPCStats->pNewNPCData;
1582 do
1583 {
1584 if (v8->Hired() && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) )
1585 {
1586 if ( !pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName) )
1587 *v7++ = v1 + 2;
1588 }
1589 ++v1;
1590 ++v8;
1591 }
1592 while ( v1 < (signed int)pNPCStats->uNumNewNPCs );
1593 }
1594 return ((unsigned __int8)pTmpBuf[v3] < 2) + 1;
1595 }
1596 //----- (00445308) --------------------------------------------------------
1597 const char *GetProfessionActionText(int a1)
1598 {
1599 if ( a1 == 10
1600 || a1 == 11
1601 || a1 == 12
1602 || a1 == 33
1603 || a1 == 34
1604 || a1 == 39
1605 || a1 == 40
1606 || a1 == 41
1607 || a1 == 42
1608 || a1 == 43
1609 || a1 == 52 )
1610 return pNPCStats->pProfessions[a1 - 1].pActionText;
1611 else
1612 return pNPCTopics[407].pTopic;
1613 }
1614
1615 //----- (004BB756) --------------------------------------------------------
1616 int UseNPCSkill(NPCProf profession)
1617 {
1618 switch (profession)
1619 {
1620 case Healer:
1621 {
1622 for (int i = 0; i < 4; ++i)
1623 pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
1624 }
1625 break;
1626
1627 case ExpertHealer:
1628 {
1629 for (int i = 0; i < 4; ++i)
1630 {
1631 __debugbreak();
1632 pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
1633
1634 for (int j = 0; j < 14; ++j)
1635 pParty->pPlayers[i].pConditions[j] = 0;
1636 pParty->pPlayers[i].pConditions[Condition_Good] = 0;
1637 }
1638 }
1639 break;
1640
1641 case MasterHealer:
1642 {
1643 for (int i = 0; i < 4; ++i)
1644 {
1645 __debugbreak(); //Ritor1:needed cleaned(Необходимо почистить)
1646 Player* player = &pParty->pPlayers[i];
1647 pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth();
1648
1649 int v5 = LODWORD(player->pConditions[19]);//*((int *)v4 - 32);
1650 int v6 = HIDWORD(player->pConditions[19]);//*((int *)v4 - 31);
1651 memset(&pParty->pPlayers[i].pConditions, 0, sizeof(pParty->pPlayers[i].pConditions));
1652
1653 *(int *)&player->pActiveSkills[PLAYER_SKILL_SHIELD] = v5;
1654 *(int *)&player->pActiveSkills[PLAYER_SKILL_CHAIN] = v6;
1655 }
1656 }
1657 break;
1658
1659 case Cook://Повар
1660 {
1661 if (pParty->uNumFoodRations >= 13)
1662 return 1;
1663
1664 Party::GiveFood(1);
1665 }
1666 break;
1667
1668 case Chef:
1669 {
1670 if (pParty->uNumFoodRations >= 13)
1671 return 1;
1672
1673 if (pParty->uNumFoodRations == 13)
1674 Party::GiveFood(1);
1675 else
1676 Party::GiveFood(2);
1677 }
1678 break;
1679
1680 case WindMaster:
1681 {
1682 if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
1683 {
1684 ShowStatusBarString(pGlobalTXT_LocalizationStrings[494], 2);//Нельзя применить знание Полет в помещении!
1685 pAudioPlayer->PlaySound(SOUND_203, 0, 0, -1, 0, 0, 0, 0);
1686 }
1687 else
1688 {
1689 int v19 = pOtherOverlayList->_4418B1(10008, 203, 0, 65536);
1690 pParty->pPartyBuffs[PARTY_BUFF_FLY].Apply(pParty->uTimePlayed + 60 * (256 * 2), 3, 1, v19, 0);
1691 pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags |= 1;
1692 pAudioPlayer->PlaySound(SOUND_11090, 0, 0, -1, 0, 0, 0, 0);
1693 }
1694 }
1695 break;
1696
1697 case WaterMaster:
1698 {
1699 int v20 = pOtherOverlayList->_4418B1(10005, 201, 0, 65536);
1700 pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].Apply(pParty->uTimePlayed + 60 * (256 * (2 + 1)), 3, 0, v20, 0);
1701 pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags |= 1;
1702 pAudioPlayer->PlaySound(SOUND_12040, 0, 0, -1, 0, 0, 0, 0);
1703 }
1704 break;
1705
1706 case GateMaster:
1707 {
1708 pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0);
1709 dword_50C9DC = 195;
1710 ptr_50C9E0 = GetNPCData(sDialogue_SpeakingActorNPC_ID);
1711 }
1712 break;
1713
1714 case Acolyte: _42777D_CastSpell_UseWand_ShootArrow(46, 0, 133, 0, 0); break;
1715 case Piper: _42777D_CastSpell_UseWand_ShootArrow(51, 0, 133, 0, 0); break;
1716 case FallenWizard: _42777D_CastSpell_UseWand_ShootArrow(86, 0, 133, 0, 0); break;
1717
1718 case Teacher:
1719 case Instructor:
1720 case Armsmaster:
1721 case Weaponsmaster:
1722 case Apprentice:
1723 case Mystic:
1724 case Spellmaster:
1725 case Trader:
1726 case Merchant:
1727 case Scout:
1728 case Herbalist:
1729 case Apothecary:
1730 case Tinker:
1731 case Locksmith:
1732 case Fool:
1733 case ChimneySweep:
1734 case Porter:
1735 case QuarterMaster:
1736 case Factor:
1737 case Banker:
1738 case Horseman:
1739 case Bard:
1740 case Enchanter:
1741 case Cartographer:
1742 case Explorer:
1743 case Pirate:
1744 case Squire:
1745 case Psychic:
1746 case Gypsy:
1747 case Diplomat:
1748 case Duper:
1749 case Burglar:
1750 case Acolyte2:
1751 case Initiate:
1752 case Prelate:
1753 case Monk:
1754 case Sage:
1755 case Hunter:
1756 break;
1757
1758 default:
1759 assert(false && "Invalid enum value");
1760 }
1761 return 0;
1762 }