1 /*
2 *
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
7 *
8 * See LICENSING which should be included
9 * along with this file for more details
10 *
11 */
12
13 /* Compiled through dataset.cpp */
14
15 #include "confdef.h"
16 #include "miscitem.h"
17 #include "stack.h"
18
19 #include "dbgmsgproj.h"
20
21 itemdatabase** protosystem::ItemConfigData;
22 int protosystem::ItemConfigDataSize;
23 itemdatabase** protosystem::ItemCategoryData[ITEM_CATEGORIES];
24 int protosystem::ItemCategorySize[ITEM_CATEGORIES];
25 long protosystem::ItemCategoryPossibility[ITEM_CATEGORIES];
26 long protosystem::TotalItemPossibility;
27
BalancedCreateMonster()28 character* protosystem::BalancedCreateMonster()
29 {
30 for(int c = 0;; ++c)
31 {
32 double MinDifficulty = game::GetMinDifficulty(), MaxDifficulty = MinDifficulty * 25;
33 std::vector<configid> Possible;
34
35 for(int Type = 1; Type < protocontainer<character>::GetSize(); ++Type)
36 {
37 const character::prototype* Proto = protocontainer<character>::GetProto(Type);
38 const character::database*const* ConfigData = Proto->GetConfigData();
39 int ConfigSize = Proto->GetConfigSize();
40
41 for(int c = 0; c < ConfigSize; ++c)
42 {
43 const character::database* DataBase = ConfigData[c];
44
45 if(!DataBase->IsAbstract && DataBase->CanBeGenerated)
46 {
47 truth Allowed = false;
48 const fearray<int> &DungeonList = DataBase->AllowedDungeons;
49 for (uint f = 0; f < DungeonList.Size; ++f)
50 {
51 if ((DungeonList[f] == ALL_DUNGEONS) || (DungeonList[f] == game::GetCurrentDungeonIndex()))
52 {
53 Allowed = true;
54 break;
55 }
56 }
57 if (!Allowed)
58 continue;
59
60 if(DataBase->IsUnique
61 && DataBase->Flags & HAS_BEEN_GENERATED)
62 continue;
63
64 truth IsCatacomb = *game::GetCurrentLevel()->GetLevelScript()->IsCatacomb();
65
66 if((IsCatacomb && !DataBase->IsCatacombCreature)
67 || (!IsCatacomb && DataBase->CanBeGeneratedOnlyInTheCatacombs))
68 continue;
69
70 configid ConfigID(Type, ConfigData[c]->Config);
71
72 if(c >= 100)
73 {
74 Possible.push_back(ConfigID);
75 continue;
76 }
77
78 const dangerid& DangerID = game::GetDangerMap().find(ConfigID)->second;
79
80 if(!DataBase->IgnoreDanger)
81 {
82 double Danger = DangerID.EquippedDanger;
83
84 if(Danger > 99.0
85 || Danger < 0.0011
86 || (DataBase->IsUnique && Danger < 3.5))
87 continue;
88
89 double DangerModifier
90 = DataBase->DangerModifier == 100
91 ? Danger
92 : Danger * 100 / DataBase->DangerModifier;
93
94 if(DangerModifier < MinDifficulty
95 || DangerModifier > MaxDifficulty)
96 continue;
97 }
98
99 ivantime Time;
100 game::GetTime(Time);
101
102 if(PLAYER->GetMaxHP() < DataBase->HPRequirementForGeneration
103 && Time.Day < DataBase->DayRequirementForGeneration)
104 continue;
105
106 Possible.push_back(ConfigID);
107 }
108 }
109 }
110
111 if(Possible.empty())
112 continue;
113
114 for(int i = 0; i < 25; ++i)
115 {
116 configid Chosen = Possible[RAND_GOOD(Possible.size())];
117 const character::prototype* Proto = protocontainer<character>::GetProto(Chosen.Type);
118 character* Monster = Proto->Spawn(Chosen.Config);
119
120 if(c >= 100
121 || ((Monster->GetFrequency() == 10000
122 || Monster->GetFrequency() > RAND_GOOD(10000))
123 && (Monster->IsUnique()
124 || (Monster->GetTimeToKill(PLAYER, true) > 5000
125 && PLAYER->GetTimeToKill(Monster, true) < 200000))))
126 {
127 Monster->SetTeam(game::GetTeam(MONSTER_TEAM));
128 return Monster;
129 }
130 else
131 delete Monster;
132 }
133 }
134
135 ABORT("BalancedCreateMonster failed!");
136 /* This line is never reached, but it prevents warnings given by some (stupid) compilers. */
137 return NULL;
138 }
139
BalancedCreateItem(long MinPrice,long MaxPrice,long RequiredCategory,int SpecialFlags,int ConfigFlags,int RequiredGod,truth Polymorph)140 item* protosystem::BalancedCreateItem(long MinPrice, long MaxPrice, long RequiredCategory,
141 int SpecialFlags, int ConfigFlags, int RequiredGod, truth Polymorph)
142 {
143 typedef item::database database;
144 database** PossibleCategory[ITEM_CATEGORIES];
145 int PossibleCategorySize[ITEM_CATEGORIES];
146 long PartialCategoryPossibilitySum[ITEM_CATEGORIES];
147 int PossibleCategories = 0;
148 long TotalPossibility = 0;
149 long database::*PartialPossibilitySumPtr;
150
151 if(RequiredCategory == ANY_CATEGORY)
152 {
153 PartialPossibilitySumPtr = &database::PartialPossibilitySum;
154 PossibleCategory[0] = ItemConfigData;
155 PossibleCategorySize[0] = ItemConfigDataSize;
156 TotalPossibility = TotalItemPossibility;
157 PartialCategoryPossibilitySum[0] = TotalPossibility;
158 PossibleCategories = 1;
159 }
160 else
161 {
162 PartialPossibilitySumPtr = &database::PartialCategoryPossibilitySum;
163
164 for(long CategoryIndex = 0, Category = 1; CategoryIndex < ITEM_CATEGORIES; ++CategoryIndex, Category <<= 1)
165 if(Category & RequiredCategory)
166 {
167 PossibleCategory[PossibleCategories] = ItemCategoryData[CategoryIndex];
168 PossibleCategorySize[PossibleCategories] = ItemCategorySize[CategoryIndex];
169 TotalPossibility += ItemCategoryPossibility[CategoryIndex];
170 PartialCategoryPossibilitySum[PossibleCategories] = TotalPossibility;
171 ++PossibleCategories;
172 }
173 }
174
175 for(int c0 = 0;; ++c0)
176 {
177 for(int c1 = 0; c1 < BALANCED_CREATE_ITEM_ITERATIONS; ++c1)
178 {
179 long Rand = RAND_GOOD(TotalPossibility);
180 int Category;
181
182 if(RequiredCategory == ANY_CATEGORY)
183 Category = 0;
184 else
185 {
186 for(int c2 = 0;; ++c2)
187 if(PartialCategoryPossibilitySum[c2] > Rand)
188 {
189 Category = c2;
190 break;
191 }
192
193 if(Category)
194 Rand -= PartialCategoryPossibilitySum[Category - 1];
195 }
196
197 const database*const* ChosenCategory = PossibleCategory[Category];
198 const database* ChosenDataBase;
199
200 if(ChosenCategory[0]->PartialCategoryPossibilitySum > Rand)
201 ChosenDataBase = ChosenCategory[0];
202 else
203 {
204 long A = 0;
205 long B = PossibleCategorySize[Category] - 1;
206
207 for(;;)
208 {
209 long C = (A + B) >> 1;
210
211 if(A != C)
212 {
213 if(ChosenCategory[C]->*PartialPossibilitySumPtr > Rand)
214 B = C;
215 else
216 A = C;
217 }
218 else
219 {
220 ChosenDataBase = ChosenCategory[B];
221 break;
222 }
223 }
224 }
225
226 int Config = ChosenDataBase->Config;
227
228 if((!(ConfigFlags & NO_BROKEN)
229 || !(Config & BROKEN))
230 && (!Polymorph
231 || ChosenDataBase->IsPolymorphSpawnable))
232 {
233 // Check allowed dungeons
234 truth Allowed = false;
235 const fearray<int> &DungeonList = ChosenDataBase->AllowedDungeons;
236 for (uint f = 0; f < DungeonList.Size; ++f)
237 {
238 if (DungeonList[f] == ALL_DUNGEONS || DungeonList[f] == game::GetCurrentDungeonIndex())
239 {
240 Allowed = true;
241 break;
242 }
243 }
244 if (!Allowed)
245 continue;
246
247 item* Item = ChosenDataBase->ProtoType->Spawn(Config, SpecialFlags);
248 truth GodOK = !RequiredGod || Item->GetAttachedGod() == RequiredGod;
249
250 /* Optimization, GetTruePrice() may be rather slow */
251
252 if(((MinPrice == 0 && MaxPrice == MAX_PRICE)
253 || (Config & BROKEN && ConfigFlags & IGNORE_BROKEN_PRICE)) && GodOK)
254 return Item;
255
256 long Price = Item->GetTruePrice();
257
258 if(Item->HandleInPairs())
259 Price <<= 1;
260
261 if(Price >= MinPrice && Price <= MaxPrice && GodOK)
262 return Item;
263
264 delete Item;
265 }
266 }
267
268 if(c0 == 25 && RequiredGod)
269 return 0;
270
271 MinPrice = MinPrice * 7 >> 3;
272 MaxPrice = MaxPrice * 9 >> 3;
273 }
274 }
275
CreateMonster(int MinDanger,int MaxDanger,int SpecialFlags)276 character* protosystem::CreateMonster(int MinDanger, int MaxDanger, int SpecialFlags)
277 {
278 std::vector<configid> Possible;
279 character* Monster = NULL;
280
281 for(int i = 0; !Monster; ++i)
282 {
283 if(i == -1)
284 break; // this means the algorithm is bad
285
286 for(int Type = 1; Type < protocontainer<character>::GetSize(); ++Type)
287 {
288 const character::prototype* Proto = protocontainer<character>::GetProto(Type);
289 const character::database*const* ConfigData = Proto->GetConfigData();
290 int ConfigSize = Proto->GetConfigSize();
291
292 for(int c = 0; c < ConfigSize; ++c)
293 {
294 const character::database* DataBase = ConfigData[c];
295
296 if(!DataBase->IsAbstract
297 && DataBase->CanBeGenerated
298 && DataBase->CanBeWished
299 && !DataBase->IsUnique
300 && (DataBase->Frequency == 10000
301 || DataBase->Frequency > RAND_GOOD(10000)))
302 {
303 configid ConfigID(Type, DataBase->Config);
304
305 if((MinDanger > 0 || MaxDanger < 1000000) && c < 25)
306 {
307 const dangerid& DangerID = game::GetDangerMap().find(ConfigID)->second;
308 double RawDanger = SpecialFlags & NO_EQUIPMENT ? DangerID.NakedDanger : DangerID.EquippedDanger;
309 int Danger = int(DataBase->DangerModifier == 100 ?
310 RawDanger * 1000 : RawDanger * 100000 / DataBase->DangerModifier);
311
312 if(Danger < MinDanger || Danger > MaxDanger)
313 continue;
314 }
315
316 Possible.push_back(ConfigID);
317 }
318 }
319 }
320
321 if(Possible.empty())
322 {
323 MinDanger = MinDanger > 0 ? Max(MinDanger * 3 >> 2, 1) : 0;
324 MaxDanger = MaxDanger < 1000000 ? Min(MaxDanger * 5 >> 2, 999999) : 1000000;
325 continue;
326 }
327
328 configid Chosen = Possible[RAND_GOOD(Possible.size())];
329 Monster = protocontainer<character>::GetProto(Chosen.Type)->Spawn(Chosen.Config, SpecialFlags);
330 Monster->SignalGeneration();
331 Monster->SetTeam(game::GetTeam(MONSTER_TEAM));
332 }
333
334 if(Monster == NULL)
335 ABORT("Failed to create monster!");
336 return Monster;
337 }
338
339 template <class type>
ScoreFlexibleName(const typename type::database * DataBase,cfestring & Identifier,festring & Name,festring::sizetype & NamePos,int & NameScore)340 static void ScoreFlexibleName(
341 const typename type::database* DataBase,
342 cfestring& Identifier,
343 festring& Name,
344 festring::sizetype& NamePos,
345 int& NameScore)
346 {
347 // noop
348 }
349
350 template <>
ScoreFlexibleName(const item::database * DataBase,cfestring & Identifier,festring & Name,festring::sizetype & NamePos,int & NameScore)351 void ScoreFlexibleName<item>(
352 const item::database* DataBase,
353 cfestring& Identifier,
354 festring& Name,
355 festring::sizetype& NamePos,
356 int& NameScore)
357 {
358 if(!DataBase->FlexibleNameSingular.IsEmpty() && DataBase->NameSingular != DataBase->FlexibleNameSingular)
359 {
360 if((NamePos = festring::IgnoreCaseFind(Identifier, " " + DataBase->FlexibleNameSingular + ' ')) != festring::NPos)
361 {
362 Name = DataBase->FlexibleNameSingular;
363 NameScore = DataBase->FlexibleNameSingular.GetSize();
364 }
365 }
366 }
367
368 template <class type>
ScoreName(const typename type::database * DataBase,cfestring & Identifier)369 static std::pair<int, int> ScoreName(const typename type::database* DataBase, cfestring& Identifier)
370 {
371 std::pair<int, int> Result(0, 0); // (score, misses)
372 festring Name;
373 festring::sizetype NamePos, AdjectivePos, PostfixPos, AliasPos;
374 int NameScore, AdjectiveScore, PostfixScore, AliasScore;
375
376 NameScore = AdjectiveScore = PostfixScore = AliasScore = 0;
377 NamePos = AdjectivePos = PostfixPos = AliasPos = festring::NPos;
378
379 if(!DataBase->NameSingular.IsEmpty())
380 {
381 if((NamePos = festring::IgnoreCaseFind(Identifier, " " + DataBase->NameSingular + ' ')) != festring::NPos)
382 {
383 Name = DataBase->NameSingular;
384 NameScore = DataBase->NameSingular.GetSize();
385 }
386 }
387
388 if(NamePos == festring::NPos)
389 ScoreFlexibleName<type>(DataBase, Identifier, Name, NamePos, NameScore);
390
391 for(uint c = 0; c < DataBase->Alias.Size; ++c)
392 {
393 cfestring& Alias = DataBase->Alias[c];
394
395 if((AliasPos = festring::IgnoreCaseFind(Identifier, " " + Alias + ' ')) != festring::NPos)
396 {
397 AliasScore = Alias.GetSize();
398
399 // XXX: alias may contain adjective and postfix
400 if(AliasScore > NameScore)
401 {
402 Name = Alias;
403 NamePos = AliasPos;
404 NameScore = AliasScore;
405 }
406 }
407 }
408
409 if(NamePos == festring::NPos)
410 ++Result.second;
411
412 if(!DataBase->Adjective.IsEmpty())
413 {
414 if((AdjectivePos = festring::IgnoreCaseFind(Identifier, " " + DataBase->Adjective + ' ')) != festring::NPos)
415 {
416 if(NamePos != festring::NPos && AdjectivePos + DataBase->Adjective.GetSize() < NamePos)
417 AdjectiveScore = DataBase->Adjective.GetSize();
418 else
419 AdjectiveScore = DataBase->Adjective.GetSize() / 2;
420 }
421 else
422 ++Result.second;
423 }
424
425 if(!DataBase->PostFix.IsEmpty())
426 {
427 if((PostfixPos = festring::IgnoreCaseFind(Identifier, " " + DataBase->PostFix + ' ')) != festring::NPos)
428 {
429 if(NamePos != festring::NPos && PostfixPos > NamePos + Name.GetSize())
430 PostfixScore = DataBase->PostFix.GetSize();
431 else
432 PostfixScore = DataBase->PostFix.GetSize() / 2;
433 }
434 else
435 ++Result.second;
436 }
437
438 Result.first = NameScore + AdjectiveScore + PostfixScore;
439 return Result;
440 }
441
SearchForProto(cfestring & What,truth Output)442 template <class type> std::pair<const typename type::prototype*, int> SearchForProto(cfestring& What, truth Output)
443 {
444 typedef typename type::prototype prototype;
445 typedef typename type::database database;
446
447 festring Identifier = " " + What + ' ';
448 Identifier.ShrinkWhitespace();
449
450 truth BrokenRequested = festring::IgnoreCaseFind(Identifier, " broken ") != festring::NPos;
451 truth Illegal = false, Conflict = false;
452 std::pair<const prototype*, int> ID(0, 0);
453 std::pair<int, int> Best(0, 0);
454
455 for(int c = 1; c < protocontainer<type>::GetSize(); ++c)
456 {
457 const prototype* Proto = protocontainer<type>::GetProto(c);
458 const database*const* ConfigData = Proto->GetConfigData();
459 int ConfigSize = Proto->GetConfigSize();
460
461 for(int c = 0; c < ConfigSize; ++c)
462 if(!ConfigData[c]->IsAbstract)
463 {
464 truth IsBroken = ConfigData[c]->Config & BROKEN
465 || festring::IgnoreCaseFind(" " + ConfigData[c]->Adjective + ' ', " broken ") != festring::NPos;
466
467 if(BrokenRequested == !IsBroken)
468 continue;
469
470 std::pair<int, int> Score = ScoreName<type>(ConfigData[c], Identifier);
471
472 if(Score == Best)
473 Conflict = true;
474 else if(Score.first > Best.first || (Score.first == Best.first && Score.second < Best.second))
475 {
476 if(ConfigData[c]->CanBeWished || game::WizardModeIsActive())
477 {
478 ID.first = Proto;
479 ID.second = ConfigData[c]->Config;
480 Best = Score;
481 Conflict = false;
482 }
483 else
484 Illegal = true;
485 }
486 }
487 }
488
489 if(Output)
490 {
491 if(!Best.first)
492 {
493 if(Illegal)
494 ADD_MESSAGE("You hear a booming voice: \"No, mortal! This will not be done!\"");
495 else
496 ADD_MESSAGE("What a strange wish!");
497 }
498 else if(Conflict)
499 {
500 ADD_MESSAGE("Be more precise!");
501 return std::pair<const prototype*, int>(0, 0);
502 }
503 }
504
505 return ID;
506 }
507
CreateMonster(cfestring & What,int SpecialFlags,truth Output)508 character* protosystem::CreateMonster(cfestring& What, int SpecialFlags, truth Output)
509 {
510 std::pair<const character::prototype*, int> ID = SearchForProto<character>(What, Output);
511
512 if(ID.first)
513 {
514 character* Char = ID.first->Spawn(ID.second, SpecialFlags);
515
516 if(!Char->HasBeenSeen() && !game::WizardModeIsActive())
517 {
518 ADD_MESSAGE("You have no idea what this creature is like.");
519 delete Char;
520 return 0;
521 }
522 else
523 return Char;
524 }
525 else
526 return 0;
527 }
528
EmptyContainer(item * Item)529 static void EmptyContainer(item* Item)
530 {
531 if (materialcontainer* Container = dynamic_cast<materialcontainer*>(Item))
532 {
533 delete Container->RemoveSecondaryMaterial();
534 }
535 else if (itemcontainer* Container = dynamic_cast<itemcontainer*>(Item))
536 Container->GetContained()->Clean();
537 }
538
CreateItemToCraft(cfestring & What)539 item* protosystem::CreateItemToCraft(cfestring& What)
540 {
541 std::pair<const item::prototype*, int> ID = SearchForProto<item>(What, false);
542 if(ID.first)
543 {
544 item* Item = ID.first->Spawn(ID.second);
545 EmptyContainer(Item);
546 return Item;
547 }
548 return NULL;
549 }
550
CreateItem(cfestring & What,truth Output)551 item* protosystem::CreateItem(cfestring& What, truth Output)
552 {
553 std::pair<const item::prototype*, int> ID = SearchForProto<item>(What, Output);
554
555 if(ID.first)
556 {
557 item* Item = ID.first->Spawn(ID.second);
558
559 if(festring::IgnoreCaseFind(" " + What + ' ', " empty ") != festring::NPos)
560 EmptyContainer(Item);
561
562 if(game::WizardModeIsActive())
563 // If WizMode prompt player to confirm wish
564 {
565 festring Q = "Do you want to wish for ";
566 Item->AddName(Q, INDEFINITE|STRIPPED);
567 Q << "? [y/N]";
568
569 if(!game::TruthQuestion(Q))
570 {
571 delete Item;
572 return 0;
573 }
574 }
575
576 return Item;
577 }
578 else
579 return 0;
580 }
581
CreateMaterialForDetection(cfestring & What)582 material* protosystem::CreateMaterialForDetection(cfestring& What)
583 {
584 return CreateMaterial(What,0,true,true);
585 }
586
CreateMaterial(cfestring & What,long Volume,truth Output,truth DetectMode)587 material* protosystem::CreateMaterial(cfestring& What, long Volume, truth Output, truth DetectMode)
588 {
589 for(int c1 = 1; c1 < protocontainer<material>::GetSize(); ++c1)
590 {
591 const material::prototype* Proto = protocontainer<material>::GetProto(c1);
592 const material::database*const* ConfigData = Proto->GetConfigData();
593 int ConfigSize = Proto->GetConfigSize();
594
595 for(int c2 = 1; c2 < ConfigSize; ++c2)
596 if(ConfigData[c2]->NameStem == What)
597 {
598 if(
599 (ConfigData[c2]->CommonFlags & CAN_BE_WISHED) ||
600 (DetectMode && (ConfigData[c2]->CommonFlags & CAN_BE_DETECTED)) ||
601 game::WizardModeIsActive()
602 ){
603 return ConfigData[c2]->ProtoType->Spawn(ConfigData[c2]->Config, Volume);
604 }else if(Output){
605 ADD_MESSAGE("You hear a booming voice: \"No, mortal! This will not be done!\"");
606 return 0;
607 }
608 }
609 }
610
611 if(Output)
612 ADD_MESSAGE("There is no such material.");
613
614 return 0;
615 }
616
617 #ifdef WIZARD
618
CreateEveryCharacter(charactervector & Character)619 void protosystem::CreateEveryCharacter(charactervector& Character)
620 {
621 for(int c1 = 1; c1 < protocontainer<character>::GetSize(); ++c1)
622 {
623 const character::prototype* Proto = protocontainer<character>::GetProto(c1);
624 const character::database*const* ConfigData = Proto->GetConfigData();
625 int ConfigSize = Proto->GetConfigSize();
626
627 for(int c2 = 0; c2 < ConfigSize; ++c2)
628 if(!ConfigData[c2]->IsAbstract)
629 Character.push_back(Proto->Spawn(ConfigData[c2]->Config));
630 }
631 }
632
CreateEveryItem(itemvectorvector & Item)633 void protosystem::CreateEveryItem(itemvectorvector& Item)
634 {
635 for(int c = 1; c < protocontainer<item>::GetSize(); ++c)
636 {
637 const item::prototype* Proto = protocontainer<item>::GetProto(c);
638 const item::database*const* ConfigData = Proto->GetConfigData();
639 int ConfigSize = Proto->GetConfigSize();
640
641 for(int c2 = 0; c2 < ConfigSize; ++c2)
642 if(!ConfigData[c2]->IsAbstract && ConfigData[c2]->IsAutoInitializable)
643 Item.push_back(itemvector(1, Proto->Spawn(ConfigData[c2]->Config)));
644 }
645 }
646
647 #endif
648
CreateEveryNormalEnemy(charactervector & EnemyVector)649 void protosystem::CreateEveryNormalEnemy(charactervector& EnemyVector)
650 {
651 for(int c = 1; c < protocontainer<character>::GetSize(); ++c)
652 {
653 const character::prototype* Proto = protocontainer<character>::GetProto(c);
654 const character::database*const* ConfigData = Proto->GetConfigData();
655 int ConfigSize = Proto->GetConfigSize();
656
657 for(int c2 = 0; c2 < ConfigSize; ++c2)
658 if(!ConfigData[c2]->IsAbstract
659 && !ConfigData[c2]->IsUnique
660 && ConfigData[c2]->CanBeGenerated)
661 EnemyVector.push_back(Proto->Spawn(ConfigData[c2]->Config, NO_PIC_UPDATE|NO_EQUIPMENT_PIC_UPDATE));
662 }
663 }
664
Initialize()665 void protosystem::Initialize()
666 {
667 typedef item::prototype prototype;
668 typedef item::database database;
669 int c;
670
671 for(c = 1; c < protocontainer<item>::GetSize(); ++c)
672 {
673 const prototype* Proto = protocontainer<item>::GetProtoData()[c]; DBG1(Proto->GetClassID());
674 ItemConfigDataSize += Proto->GetConfigSize(); DBG1(Proto->GetConfigData());
675
676 if(Proto->GetConfigData()==NULL)
677 ABORT("missing prototype for '%s' ex. at item.dat add: %s { }",Proto->GetClassID(),Proto->GetClassID());
678
679 if(Proto->GetConfigData()[0]->IsAbstract)
680 --ItemConfigDataSize;
681 }
682
683 ItemConfigData = new database*[ItemConfigDataSize];
684 int Index = 0;
685
686 for(c = 1; c < protocontainer<item>::GetSize(); ++c)
687 {
688 const prototype* Proto = protocontainer<item>::GetProtoData()[c];
689 const database*const* ProtoConfigData = Proto->GetConfigData();
690 const database* MainDataBase = *ProtoConfigData;
691
692 if(!MainDataBase->IsAbstract)
693 ItemConfigData[Index++] = const_cast<database*>(MainDataBase);
694
695 int ConfigSize = Proto->GetConfigSize();
696
697 for(int c2 = 1; c2 < ConfigSize; ++c2)
698 ItemConfigData[Index++] = const_cast<database*>(ProtoConfigData[c2]);
699 }
700
701 database** DataBaseBuffer = new database*[ItemConfigDataSize];
702
703 for(int CategoryIndex = 0, Category = 1; CategoryIndex < ITEM_CATEGORIES; ++CategoryIndex, Category <<= 1)
704 {
705 long TotalPossibility = 0;
706 int CSize = 0;
707
708 for(int c = 0; c < ItemConfigDataSize; ++c)
709 {
710 database* DataBase = ItemConfigData[c];
711
712 if(DataBase->Category == Category)
713 {
714 DataBaseBuffer[CSize++] = DataBase;
715 TotalPossibility += DataBase->Possibility;
716 DataBase->PartialCategoryPossibilitySum = TotalPossibility;
717 }
718 }
719
720 ItemCategoryData[CategoryIndex] = new database*[CSize];
721 ItemCategorySize[CategoryIndex] = CSize;
722 ItemCategoryPossibility[CategoryIndex] = TotalPossibility;
723 memcpy(ItemCategoryData[CategoryIndex], DataBaseBuffer, CSize * sizeof(database*));
724 }
725
726 delete [] DataBaseBuffer;
727
728 for(c = 0; c < ItemConfigDataSize; ++c)
729 {
730 database* DataBase = ItemConfigData[c];
731 TotalItemPossibility += DataBase->Possibility;
732 DataBase->PartialPossibilitySum = TotalItemPossibility;
733 }
734 }
735
InitCharacterDataBaseFlags()736 void protosystem::InitCharacterDataBaseFlags()
737 {
738 for(int c1 = 1; c1 < protocontainer<character>::GetSize(); ++c1)
739 {
740 const character::prototype* Proto = protocontainer<character>::GetProto(c1);
741 character::database** ConfigData = Proto->ConfigData;
742 int ConfigSize = Proto->GetConfigSize();
743
744 for(int c2 = 0; c2 < ConfigSize; ++c2)
745 if(!ConfigData[c2]->AutomaticallySeen)
746 ConfigData[c2]->Flags = 0;
747 else
748 ConfigData[c2]->Flags = HAS_BEEN_SEEN;
749 }
750 }
751
SaveCharacterDataBaseFlags(outputfile & SaveFile)752 void protosystem::SaveCharacterDataBaseFlags(outputfile& SaveFile)
753 {
754 for(int c1 = 1; c1 < protocontainer<character>::GetSize(); ++c1)
755 {
756 const character::prototype* Proto = protocontainer<character>::GetProto(c1);
757 const character::database*const* ConfigData = Proto->ConfigData;
758 int ConfigSize = Proto->GetConfigSize();
759
760 for(int c2 = 0; c2 < ConfigSize; ++c2)
761 SaveFile << ConfigData[c2]->Flags;
762 }
763 }
764
LoadCharacterDataBaseFlags(inputfile & SaveFile)765 void protosystem::LoadCharacterDataBaseFlags(inputfile& SaveFile)
766 {
767 for(int c1 = 1; c1 < protocontainer<character>::GetSize(); ++c1)
768 {
769 const character::prototype* Proto = protocontainer<character>::GetProto(c1);
770 character::database** ConfigData = Proto->ConfigData;
771 int ConfigSize = Proto->GetConfigSize();
772
773 for(int c2 = 0; c2 < ConfigSize; ++c2)
774 SaveFile >> ConfigData[c2]->Flags;
775 }
776 }
777
CreateEverySeenCharacter(charactervector & Character)778 void protosystem::CreateEverySeenCharacter(charactervector& Character)
779 {
780 for(int c1 = 1; c1 < protocontainer<character>::GetSize(); ++c1)
781 {
782 const character::prototype* Proto = protocontainer<character>::GetProto(c1);
783 const character::database*const* ConfigData = Proto->GetConfigData();
784 int ConfigSize = Proto->GetConfigSize();
785
786 for(int c2 = 0; c2 < ConfigSize; ++c2)
787 if(!ConfigData[c2]->IsAbstract && ConfigData[c2]->Flags & HAS_BEEN_SEEN)
788 {
789 character* Char = Proto->Spawn(ConfigData[c2]->Config);
790 Char->SetAssignedName("");
791 Character.push_back(Char);
792 }
793 }
794 }
795
796 // For gods
CreateEveryGodlyMaterial(std::vector<material * > & Material,const god * God,ccharacter * Char)797 void protosystem::CreateEveryGodlyMaterial(std::vector<material*>& Material, const god* God, ccharacter* Char)
798 {
799 for(int c1 = 1; c1 < protocontainer<material>::GetSize(); ++c1)
800 {
801 const material::prototype* Proto = protocontainer<material>::GetProto(c1);
802 const material::database*const* ConfigData = Proto->GetConfigData();
803 int ConfigSize = Proto->GetConfigSize();
804
805 for(int c2 = 1; c2 < ConfigSize; ++c2)
806 if(God->LikesMaterial(ConfigData[c2], Char))
807 Material.push_back(Proto->Spawn(ConfigData[c2]->Config));
808 }
809 }
810
811 // For wizards and alchemists
CreateEveryMaterial(std::vector<material * > & Material)812 void protosystem::CreateEveryMaterial(std::vector<material*>& Material)
813 {
814 for(int c1 = 1; c1 < protocontainer<material>::GetSize(); ++c1)
815 {
816 const material::prototype* Proto = protocontainer<material>::GetProto(c1);
817 const material::database*const* ConfigData = Proto->GetConfigData();
818 int ConfigSize = Proto->GetConfigSize();
819
820 for(int c2 = 1; c2 < ConfigSize; ++c2)
821 Material.push_back(Proto->Spawn(ConfigData[c2]->Config));
822 }
823 }
824