replaced old numbered script file system with new "modules" system; "Include" is...
[k8-i-v-a-n.git] / src / game / script.cpp
blobf1e824245e6fa714a8a01c79b12bcc6744bc94ca
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #include "script.h"
13 #include "fesave.h"
14 #include "feparse.h"
15 #include "game.h"
16 #include "materia.h"
17 #include "char.h"
18 #include "proto.h"
19 #include "allocate.h"
21 script::datamap posscript::DataMap;
22 script::datamap materialscript::DataMap;
23 script::datamap basecontentscript::DataMap;
24 script::datamap contentscript<character>::DataMap;
25 script::datamap contentscript<item>::DataMap;
26 script::datamap contentscript<glterrain>::DataMap;
27 script::datamap contentscript<olterrain>::DataMap;
28 script::datamap squarescript::DataMap;
29 script::datamap roomscript::DataMap;
30 script::datamap levelscript::DataMap;
31 script::datamap dungeonscript::DataMap;
32 script::datamap teamscript::DataMap;
33 script::datamap gamescript::DataMap;
35 template <class type, class contenttype> script::datamap contentmap<type, contenttype>::DataMap;
38 template <class type> void scriptmember<type>::ReadFrom (TextInput &SaveFile) {
39 SrcFile = SaveFile.GetFileName();
40 SrcLine = SaveFile.CurrentLine();
41 if (!Member) Member = new type;
42 ReadData(*Member, SaveFile);
46 template <class type> void scriptmember<type>::Replace (scriptmemberbase &Base) {
47 scriptmember<type> &Data = static_cast<scriptmember<type> &>(Base);
49 if (Data.Member) {
50 delete Member;
51 Member = Data.Member;
52 Data.Member = 0;
54 SrcFile = Base.SrcFile;
55 SrcLine = Base.SrcLine;
59 template <class type> void scriptmember<type>::Save (outputfile &SaveFile) const {
60 if (Member) {
61 SaveFile.Put(1);
62 SaveFile << SrcFile << SrcLine;
63 SaveFile << *Member;
64 } else {
65 SaveFile.Put(0);
69 template <class type> void scriptmember<type>::Load (inputfile &SaveFile) {
70 if (SaveFile.Get()) {
71 Member = new type;
72 SaveFile >> SrcFile >> SrcLine;
73 SaveFile >> *Member;
78 #define INST_SCRIPT_MEMBER(type)\
79 template void scriptmember< type >::ReadFrom(TextInput &);\
80 template void scriptmember< type >::Replace(scriptmemberbase &);\
81 template void scriptmember< type >::Save(outputfile &) const;\
82 template void scriptmember< type >::Load(inputfile &)
84 INST_SCRIPT_MEMBER(uChar);
85 INST_SCRIPT_MEMBER(short);
86 INST_SCRIPT_MEMBER(int);
87 //INST_SCRIPT_MEMBER(sLong); //k8:64
88 INST_SCRIPT_MEMBER(v2);
89 INST_SCRIPT_MEMBER(festring);
90 INST_SCRIPT_MEMBER(fearray<v2>);
91 INST_SCRIPT_MEMBER(rect);
92 INST_SCRIPT_MEMBER(interval);
93 INST_SCRIPT_MEMBER(region);
94 INST_SCRIPT_MEMBER(posscript);
95 INST_SCRIPT_MEMBER(materialscript);
96 INST_SCRIPT_MEMBER(squarescript);
97 INST_SCRIPT_MEMBER(roomscript);
98 INST_SCRIPT_MEMBER(levelscript);
99 INST_SCRIPT_MEMBER(contentscript<character>);
100 INST_SCRIPT_MEMBER(fearray<contentscript<item> >);
101 INST_SCRIPT_MEMBER(contentscript<glterrain>);
102 INST_SCRIPT_MEMBER(contentscript<olterrain>);
103 INST_SCRIPT_MEMBER(charactercontentmap);
104 INST_SCRIPT_MEMBER(itemcontentmap);
105 INST_SCRIPT_MEMBER(glterraincontentmap);
106 INST_SCRIPT_MEMBER(olterraincontentmap);
107 INST_SCRIPT_MEMBER(fearray<packv2>);
110 template <class type> void fastscriptmember<type>::ReadFrom (TextInput &SaveFile) {
111 SrcFile = SaveFile.GetFileName();
112 SrcLine = SaveFile.CurrentLine();
113 ReadData(*&Member, SaveFile); // gcc 3.4.1 sucks
117 template <class type> void fastscriptmember<type>::Replace (scriptmemberbase &Base) {
118 fastscriptmember<type> &Data = static_cast<fastscriptmember<type> &>(Base);
120 Member = Data.Member;
121 SrcFile = Base.SrcFile;
122 SrcLine = Base.SrcLine;
126 template <class type> void fastscriptmember<type>::Save(outputfile &SaveFile) const {
127 SaveFile << SrcFile << SrcLine;
128 SaveFile << Member;
132 template <class type> void fastscriptmember<type>::Load (inputfile &SaveFile) {
133 SaveFile >> SrcFile >> SrcLine;
134 SaveFile >> *&Member; // gcc 3.4.1 sucks
138 #define INST_FAST_SCRIPT_MEMBER(type)\
139 template void fastscriptmember< type >::ReadFrom(TextInput&);\
140 template void fastscriptmember< type >::Replace(scriptmemberbase&);\
141 template void fastscriptmember< type >::Save(outputfile&) const;\
142 template void fastscriptmember< type >::Load(inputfile&)
144 INST_FAST_SCRIPT_MEMBER(char);
145 INST_FAST_SCRIPT_MEMBER(uChar);
146 INST_FAST_SCRIPT_MEMBER(int);
147 //INST_FAST_SCRIPT_MEMBER(sLong); //k8:64
148 INST_FAST_SCRIPT_MEMBER(feuLong);
149 INST_FAST_SCRIPT_MEMBER(packv2);
152 void script::Save (outputfile &SaveFile) const {
153 SaveFile << SrcFile << SrcLine;
154 SaveDataMap(GetDataMap(), SaveFile);
158 void script::Load (inputfile &SaveFile) {
159 SaveFile >> SrcFile >> SrcLine;
160 LoadDataMap(GetDataMap(), SaveFile);
164 truth script::ReadMember (TextInput &SaveFile, cfestring &Word) {
165 scriptmemberbase *Data = GetData(Word.CStr());
167 if (Data) {
168 Data->ReadFrom(SaveFile);
169 return true;
171 return false;
175 scriptmemberbase *script::GetDataFromMap (const datamap &DataMap, cchar *Identifier) {
176 datamap::const_iterator i = DataMap.find(Identifier);
178 return i != DataMap.end() ? &(this->*i->second) : 0;
182 void script::SaveDataMap (const datamap &DataMap, outputfile &SaveFile) const {
183 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Save(SaveFile);
187 void script::LoadDataMap (const datamap &DataMap, inputfile &SaveFile) {
188 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Load(SaveFile);
192 template <class scriptmemberptr> void InitMember (script::datamap &DataMap, cchar *Identifier, scriptmemberptr DataMember) {
193 DataMap[Identifier] = reinterpret_cast<scriptmemberbase script::*>(DataMember);
197 #define INIT_ENTRY(name) InitMember(DataMap, #name, &scripttype::name##Holder)
198 #define INIT(name, value) name##Holder(value)
201 void posscript::InitDataMap () {
202 INIT_ENTRY(Vector);
203 INIT_ENTRY(Flags);
204 INIT_ENTRY(Borders);
208 void posscript::ReadFrom (TextInput &SaveFile) {
209 static festring Word;
211 SrcFile = SaveFile.GetFileName();
212 SrcLine = SaveFile.CurrentLine();
213 SaveFile.ReadWord(Word);
214 if (Word == "Pos") {
215 Random = false;
216 VectorHolder.ReadFrom(SaveFile);
217 } else if (Word == "Random") {
218 Random = true;
219 FlagsHolder.ReadFrom(SaveFile);
220 } else if (Word == "BoundedRandom") {
221 Random = true;
222 BordersHolder.ReadFrom(SaveFile);
223 FlagsHolder.ReadFrom(SaveFile);
228 void posscript::Save (outputfile &SaveFile) const {
229 script::Save(SaveFile);
230 SaveFile << Random;
234 void posscript::Load (inputfile &SaveFile) {
235 script::Load(SaveFile);
236 SaveFile >> Random;
240 void materialscript::InitDataMap () {
241 INIT_ENTRY(Volume);
245 void materialscript::ReadFrom (TextInput &SaveFile) {
246 static festring Word;
248 SrcFile = SaveFile.GetFileName();
249 SrcLine = SaveFile.CurrentLine();
250 SaveFile.ReadWord(Word);
251 if (Word == "=") SaveFile.ReadWord(Word);
252 if (Word == "0") {
253 Config = 0;
254 } else {
255 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
257 if (i != game::GetGlobalValueMap().end()) Config = i->second;
258 else ABORT("Unconfigured material script detected at line %d!", SaveFile.TokenLine());
260 if (SaveFile.ReadWord() != "{") return;
261 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
262 if (!ReadMember(SaveFile, Word)) {
263 ABORT("Odd script term %s encountered in material script line %d!", Word.CStr(), SaveFile.TokenLine());
269 material *materialscript::Instantiate () const {
270 return MAKE_MATERIAL(Config, GetVolume() ? GetVolume()->Randomize() : 0);
274 void materialscript::Save (outputfile &SaveFile) const {
275 script::Save(SaveFile);
276 SaveFile << (uShort)Config;
280 void materialscript::Load (inputfile &SaveFile) {
281 script::Load(SaveFile);
282 Config = 0;
283 uShort s2;
284 SaveFile >> s2;
285 Config = s2;
289 void basecontentscript::InitDataMap () {
290 INIT_ENTRY(MainMaterial);
291 INIT_ENTRY(SecondaryMaterial);
292 INIT_ENTRY(Parameters);
296 basecontentscript::basecontentscript () : script(), ContentType(0), Random(false), Config(0), INIT(Parameters, NO_PARAMETERS) {
300 void basecontentscript::ReadFrom (TextInput &SaveFile) {
301 static festring Word;
303 SrcFile = SaveFile.GetFileName();
304 SrcLine = SaveFile.CurrentLine();
305 SaveFile.ReadWord(Word);
306 if (Word == "[") {
307 mCode = SaveFile.ReadCode();
308 SaveFile.ReadWord(Word);
310 if (Word == "=" || Word == ",") SaveFile.ReadWord(Word);
311 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
312 if (i != game::GetGlobalValueMap().end()) {
313 if (!GetMainMaterial()) MainMaterialHolder.Member = new materialscript;
314 MainMaterialHolder.Member->SetConfig(i->second);
315 SaveFile.ReadWord(Word);
316 i = game::GetGlobalValueMap().find(Word);
317 if (i != game::GetGlobalValueMap().end()) {
318 if (!GetSecondaryMaterial()) SecondaryMaterialHolder.Member = new materialscript;
319 SecondaryMaterialHolder.Member->SetConfig(i->second);
320 SaveFile.ReadWord(Word);
323 if (Word == "NaturalMaterialForm") {
324 Random = false;
325 ContentType = NATURAL_MATERIAL_FORM;
326 SaveFile.ReadWord(Word);
327 } else if (Word == "Random") {
328 Random = true;
329 SaveFile.ReadWord(Word);
330 } else {
331 Random = false;
332 ContentType = SearchCodeName(Word);
333 if (ContentType || Word == "0") SaveFile.ReadWord(Word);
334 else ABORT("Odd script term %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
336 if (Word == "(") {
337 Config = SaveFile.ReadNumber();
338 SaveFile.ReadWord(Word);
339 } else {
340 Config = 0;
342 if (Word == "{") {
343 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
344 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
346 } else {
347 if (Word == "[") {
348 mCode = SaveFile.ReadCode();
349 SaveFile.ReadWord(Word);
351 if (Word != ";" && Word != ",") ABORT("Odd terminator %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
356 scriptmemberbase *basecontentscript::GetData (cchar *String) {
357 scriptmemberbase *Return = GetDataFromMap(GetDataMap(), String);
358 return Return ? Return : GetDataFromMap(DataMap, String);
362 void basecontentscript::Save (outputfile &SaveFile) const {
363 SaveFile << SrcFile << SrcLine;
364 SaveDataMap(GetDataMap(), SaveFile);
365 SaveDataMap(DataMap, SaveFile);
366 SaveFile << ContentType;
367 SaveFile.Put(!!Random);
368 SaveFile << Config;
372 void basecontentscript::Load (inputfile &SaveFile) {
373 SaveFile >> SrcFile >> SrcLine;
374 LoadDataMap(GetDataMap(), SaveFile);
375 LoadDataMap(DataMap, SaveFile);
376 ContentType = ReadType(uShort, SaveFile);
377 Random = SaveFile.Get();
378 SaveFile >> Config;
382 template <class type> type *contentscripttemplate<type>::BasicInstantiate (int SpecialFlags) const {
383 type *Instance = 0;
384 const typename type::prototype *Proto = protocontainer<type>::GetProto(ContentType);
385 const typename type::database *const *ConfigData = Proto->GetConfigData();
386 const materialscript *MainMaterial = GetMainMaterial();
387 const materialscript *SecondaryMaterial = GetSecondaryMaterial();
388 const typename type::database *DataBase = *ConfigData;
389 truth UseOverriddenMaterials = false;
391 if (!Config && DataBase->IsAbstract) {
392 while (!Instance) {
393 DataBase = ConfigData[1+RAND()%(Proto->GetConfigSize()-1)];
394 if (DataBase->AllowRandomInstantiation()) {
395 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
396 SpecialFlags |= NO_MATERIALS;
397 UseOverriddenMaterials = true;
399 Instance = Proto->Spawn(DataBase->Config, SpecialFlags|NO_PIC_UPDATE);
402 } else {
403 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
404 SpecialFlags |= NO_MATERIALS;
405 UseOverriddenMaterials = true;
407 Instance = Proto->Spawn(Config, SpecialFlags|NO_PIC_UPDATE);
409 if (GetParameters() != NO_PARAMETERS) Instance->SetParameters(GetParameters());
410 if (UseOverriddenMaterials) {
411 Instance->InitMaterials(MainMaterial, SecondaryMaterial, false);
412 } else {
413 if (MainMaterial) Instance->ChangeMainMaterial(MainMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
414 if (SecondaryMaterial) Instance->ChangeSecondaryMaterial(SecondaryMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
416 if (!(SpecialFlags & NO_PIC_UPDATE)) Instance->UpdatePictures();
417 return Instance;
421 /* Called by an inline function in script.h... */
423 template glterrain *contentscripttemplate<glterrain>::BasicInstantiate (int) const;
425 template <class type> int contentscripttemplate<type>::SearchCodeName (cfestring &String) const {
426 return protocontainer<type>::SearchCodeName(String);
429 /* GCC 2.952 SUCKS!!! IT MUST BURN!!! */
431 template int contentscripttemplate<character>::SearchCodeName(cfestring &) const;
432 template int contentscripttemplate<item>::SearchCodeName(cfestring &) const;
433 template int contentscripttemplate<glterrain>::SearchCodeName(cfestring &) const;
434 template int contentscripttemplate<olterrain>::SearchCodeName(cfestring &) const;
436 cchar *contentscript<character>::GetClassID () const { return "character"; }
437 cchar *contentscript<item>::GetClassID () const { return "item"; }
438 cchar *contentscript<glterrain>::GetClassID () const { return "glterrain"; }
439 cchar *contentscript<olterrain>::GetClassID () const { return "olterrain"; }
442 void contentscript<character>::InitDataMap () {
443 INIT_ENTRY(Inventory);
444 INIT_ENTRY(WayPoint);
445 INIT_ENTRY(Team);
446 INIT_ENTRY(Flags);
450 contentscript<character>::contentscript () : INIT(Team, DEFAULT_TEAM), INIT(Flags, 0) {
454 character *contentscript<character>::Instantiate (int SpecialFlags) const {
455 character *Instance = contentscripttemplate<character>::BasicInstantiate(SpecialFlags);
456 //fprintf(stderr, "instantiating character '%s'\n", Instance->GetNameSingular().CStr());
457 if (!mCode.IsEmpty()) {
458 game::ClearEventData();
459 if (!game::RunAllowScriptStr(mCode)) {
460 //fprintf(stderr, "dropping character '%s'\n", Instance->GetNameSingular().CStr());
461 delete Instance;
462 return 0;
465 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(game::GetTeam(GetTeam()));
466 const fearray<contentscript<item> > *Inventory = GetInventory();
467 if (Inventory) Instance->AddToInventory(*Inventory, SpecialFlags);
468 const fearray<packv2> *WayPoint = GetWayPoint();
469 if (WayPoint) Instance->SetWayPoints(*WayPoint);
470 Instance->RestoreHP();
471 Instance->RestoreStamina();
472 return Instance;
476 contentscript<item>::contentscript () :
477 INIT(Category, ANY_CATEGORY),
478 INIT(MinPrice, 0),
479 INIT(MaxPrice, MAX_PRICE),
480 INIT(Team, DEFAULT_TEAM),
481 INIT(SquarePosition, CENTER),
482 INIT(Chance, 100),
483 INIT(ConfigFlags, 0),
484 INIT(SpoilPercentage, 0),
485 INIT(Enchantment, 0),
486 INIT(IsActive, false)
491 void contentscript<item>::InitDataMap () {
492 INIT_ENTRY(ItemsInside);
493 INIT_ENTRY(Times);
494 INIT_ENTRY(MinPrice);
495 INIT_ENTRY(MaxPrice);
496 INIT_ENTRY(LifeExpectancy);
497 INIT_ENTRY(Team);
498 INIT_ENTRY(Category);
499 INIT_ENTRY(SquarePosition);
500 INIT_ENTRY(Chance);
501 INIT_ENTRY(ConfigFlags);
502 INIT_ENTRY(SpoilPercentage);
503 INIT_ENTRY(Enchantment);
504 INIT_ENTRY(IsActive);
508 item *contentscript<item>::InstantiateBasedOnMaterial (int MaterialConfig, int SpecialFlags) const {
509 if (ContentType == NATURAL_MATERIAL_FORM) {
510 const materialscript *MainMaterial = GetMainMaterial();
511 sLong Volume = MainMaterial && MainMaterial->GetVolume() ? MainMaterial->GetVolume()->Randomize() : 0;
512 return material::CreateNaturalForm(MaterialConfig, Volume);
514 return Instantiate(SpecialFlags);
518 item *contentscript<item>::Instantiate (int SpecialFlags) const {
519 int Chance = GetChance();
520 item *Instance;
522 if (!mCode.IsEmpty()) {
523 game::ClearEventData();
524 if (!game::RunAllowScriptStr(mCode)) return 0;
527 if (Chance != 100 && Chance <= RAND_N(100)) return 0;
528 if (Random) {
529 Instance = protosystem::BalancedCreateItem(0, GetMinPrice(), GetMaxPrice(), GetCategory(), SpecialFlags, GetConfigFlags());
530 } else {
531 Instance = contentscripttemplate<item>::BasicInstantiate(SpecialFlags);
533 if (GetLifeExpectancy()) Instance->SetLifeExpectancy(GetLifeExpectancy()->Min, (GetLifeExpectancy()->Max - GetLifeExpectancy()->Min) + 1);
534 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(GetTeam());
535 if (IsActive()) Instance->SetIsActive(true);
536 if (GetEnchantment() != 0) Instance->SetEnchantment(GetEnchantment());
537 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
538 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
539 if (GetSpoilPercentage() != 0) Instance->SetSpoilPercentage(GetSpoilPercentage());
540 return Instance;
544 truth IsValidScript (const fearray<contentscript<item> > *Array) {
545 for (uInt c = 0; c < Array->Size; ++c) if (IsValidScript(&Array->Data[c])) return true;
546 return false;
550 void contentscript<glterrain>::InitDataMap () {
551 INIT_ENTRY(IsInside);
555 contentscript<olterrain>::contentscript () :
556 INIT(VisualEffects, 0),
557 INIT(AttachedArea, DEFAULT_ATTACHED_AREA),
558 INIT(AttachedEntry, DEFAULT_ATTACHED_ENTRY)
563 void contentscript<olterrain>::InitDataMap () {
564 INIT_ENTRY(ItemsInside);
565 INIT_ENTRY(Text);
566 INIT_ENTRY(VisualEffects);
567 INIT_ENTRY(AttachedArea);
568 INIT_ENTRY(AttachedEntry);
572 olterrain *contentscript<olterrain>::Instantiate (int SpecialFlags) const {
573 if (!ContentType) return 0;
574 olterrain *Instance = contentscripttemplate<olterrain>::BasicInstantiate(SpecialFlags);
575 if (GetVisualEffects()) {
576 Instance->SetVisualEffects(GetVisualEffects());
577 Instance->UpdatePictures();
579 if (GetAttachedArea() != DEFAULT_ATTACHED_AREA) Instance->SetAttachedArea(GetAttachedArea());
580 if (GetAttachedEntry() != DEFAULT_ATTACHED_ENTRY) Instance->SetAttachedEntry(GetAttachedEntry());
581 cfestring *Text = GetText();
582 if (Text) Instance->SetText(*Text);
583 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
584 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
585 return Instance;
589 squarescript::squarescript () : INIT(EntryIndex, NO_ENTRY), INIT(AttachRequired, false) {
593 void squarescript::InitDataMap () {
594 INIT_ENTRY(Position);
595 INIT_ENTRY(Character);
596 INIT_ENTRY(Items);
597 INIT_ENTRY(GTerrain);
598 INIT_ENTRY(OTerrain);
599 INIT_ENTRY(Times);
600 INIT_ENTRY(EntryIndex);
601 INIT_ENTRY(AttachRequired);
605 void squarescript::ReadFrom (TextInput &SaveFile) {
606 static festring Word;
608 SrcFile = SaveFile.GetFileName();
609 SrcLine = SaveFile.CurrentLine();
610 SaveFile.ReadWord(Word);
611 if (Word != "=") {
612 PositionHolder.ReadFrom(SaveFile);
613 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in square script line %d!", SaveFile.TokenLine());
614 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
615 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in square script line %d!", Word.CStr(), SaveFile.TokenLine());
617 } else {
618 GTerrainHolder.ReadFrom(SaveFile);
619 OTerrainHolder.ReadFrom(SaveFile);
624 template <class type, class contenttype> contentmap<type, contenttype>::contentmap() : ContentMap(0) {
628 template <class type, class contenttype> contentmap<type, contenttype>::~contentmap<type, contenttype> () {
629 delete [] ContentMap;
633 template <class type, class contenttype> void contentmap<type, contenttype>::InitDataMap () {
634 INIT_ENTRY(Size);
635 INIT_ENTRY(Pos);
639 template <class type, class contenttype> void contentmap<type, contenttype>::ReadFrom (TextInput &SaveFile) {
640 typedef std::map<int, contenttype> maptype;
641 typedef typename maptype::iterator mapiterator;
642 festring Word1, Word2;
644 SrcFile = SaveFile.GetFileName();
645 SrcLine = SaveFile.CurrentLine();
646 if (ContentMap) ABORT("Illegal %s content map redefinition on line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
647 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
648 SymbolMap.insert(std::pair<int, contenttype>('.', contenttype()));
649 for (SaveFile.ReadWord(Word1); Word1 != "}"; Word1 = SaveFile.ReadWord()) {
650 if (Word1 == "Types") {
651 if (SaveFile.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
652 for (SaveFile.ReadWord(Word2); Word2 != "}"; Word2 = SaveFile.ReadWord()) {
653 std::pair<mapiterator, bool> Return = SymbolMap.insert(std::pair<int, contenttype>(Word2[0], contenttype()));
655 if (Return.second) {
656 ReadData(Return.first->second, SaveFile);
657 } else {
658 ABORT("Symbol %c defined again in %s content map script line %d!", Word2[0], protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
661 continue;
663 if (!ReadMember(SaveFile, Word1)) ABORT("Odd script term %s encountered in %s content script line %d!", Word1.CStr(), protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
666 v2 Size = *GetSize();
668 Alloc2D(ContentMap, Size.X, Size.Y);
669 if (SaveFile.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
670 for (int y = 0; y < Size.Y; ++y) {
671 for (int x = 0; x < Size.X; ++x) {
672 int Char = SaveFile.ReadLetter();
673 typename std::map<int, contenttype>::iterator i = SymbolMap.find(Char);
675 if (i != SymbolMap.end()) {
676 ContentMap[x][y] = std::make_pair(Char, &i->second);
677 } else {
678 ABORT("Illegal content %c in %s content map line %d!", Char, protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
682 if (SaveFile.ReadWord() != "}") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
686 template <class type, class contenttype> void contentmap<type, contenttype>::Save (outputfile &SaveFile) const {
687 script::Save(SaveFile);
688 SaveFile << SymbolMap;
690 v2 Size = *GetSize();
691 for (int y = 0; y < Size.Y; ++y)
692 for (int x = 0; x < Size.X; ++x)
693 SaveFile << char(ContentMap[x][y].first);
697 template <class type, class contenttype> void contentmap<type, contenttype>::Load (inputfile &SaveFile) {
698 script::Load(SaveFile);
699 SaveFile >> SymbolMap;
701 v2 Size = *GetSize();
703 Alloc2D(ContentMap, Size.X, Size.Y);
704 for (int y = 0; y < Size.Y; ++y) {
705 for (int x = 0; x < Size.X; ++x) {
706 int Char = ReadType(char, SaveFile);
708 ContentMap[x][y] = std::make_pair(Char, &SymbolMap.find(Char)->second);
714 const std::list<squarescript> &roomscript::GetSquare () const { return Square; }
717 void roomscript::InitDataMap () {
718 INIT_ENTRY(CharacterMap);
719 INIT_ENTRY(ItemMap);
720 INIT_ENTRY(GTerrainMap);
721 INIT_ENTRY(OTerrainMap);
722 INIT_ENTRY(WallSquare);
723 INIT_ENTRY(FloorSquare);
724 INIT_ENTRY(DoorSquare);
725 INIT_ENTRY(Size);
726 INIT_ENTRY(Pos);
727 INIT_ENTRY(AltarPossible);
728 INIT_ENTRY(GenerateDoor);
729 INIT_ENTRY(GenerateTunnel);
730 INIT_ENTRY(DivineMaster);
731 INIT_ENTRY(GenerateLanterns);
732 INIT_ENTRY(Type);
733 INIT_ENTRY(GenerateFountains);
734 INIT_ENTRY(AllowLockedDoors);
735 INIT_ENTRY(AllowBoobyTrappedDoors);
736 INIT_ENTRY(Shape);
737 INIT_ENTRY(IsInside);
738 INIT_ENTRY(GenerateWindows);
739 INIT_ENTRY(UseFillSquareWalls);
740 INIT_ENTRY(Flags);
741 INIT_ENTRY(GenerateWards);
742 INIT_ENTRY(AllowedDivineMasters);
746 void roomscript::ReadFrom (TextInput &SaveFile) {
747 festring Word;
749 SrcFile = SaveFile.GetFileName();
750 SrcLine = SaveFile.CurrentLine();
751 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in room script line %d!", SaveFile.TokenLine());
752 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
753 if (Word == "Square") {
754 Square.push_back(squarescript());
755 Square.back().ReadFrom(SaveFile);
756 continue;
758 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in room script line %d!", Word.CStr(), SaveFile.TokenLine());
763 void roomscript::Save (outputfile &SaveFile) const {
764 script::Save(SaveFile);
765 SaveFile << Square;
769 void roomscript::Load (inputfile &SaveFile) {
770 script::Load(SaveFile);
771 SaveFile >> Square;
775 const std::list<squarescript> &levelscript::GetSquare () const { return Square; }
776 const std::list<roomscript> &levelscript::GetRoom () const { return Room; }
779 void levelscript::InitDataMap () {
780 INIT_ENTRY(RoomDefault);
781 INIT_ENTRY(FillSquare);
782 INIT_ENTRY(TunnelSquare);
783 INIT_ENTRY(LevelMessage);
784 INIT_ENTRY(Size);
785 INIT_ENTRY(Items);
786 INIT_ENTRY(Rooms);
787 INIT_ENTRY(GenerateMonsters);
788 INIT_ENTRY(IsOnGround);
789 INIT_ENTRY(EarthquakesAffectTunnels);
790 INIT_ENTRY(TeamDefault);
791 INIT_ENTRY(Description);
792 INIT_ENTRY(LOSModifier);
793 INIT_ENTRY(IgnoreDefaultSpecialSquares);
794 INIT_ENTRY(DifficultyBase);
795 INIT_ENTRY(DifficultyDelta);
796 INIT_ENTRY(MonsterAmountBase);
797 INIT_ENTRY(MonsterAmountDelta);
798 INIT_ENTRY(MonsterGenerationIntervalBase);
799 INIT_ENTRY(MonsterGenerationIntervalDelta);
800 INIT_ENTRY(AutoReveal);
801 INIT_ENTRY(ShortDescription);
802 INIT_ENTRY(CanGenerateBone);
803 INIT_ENTRY(ItemMinPriceBase);
804 INIT_ENTRY(ItemMinPriceDelta);
805 INIT_ENTRY(Type);
806 INIT_ENTRY(EnchantmentMinusChanceBase);
807 INIT_ENTRY(EnchantmentMinusChanceDelta);
808 INIT_ENTRY(EnchantmentPlusChanceBase);
809 INIT_ENTRY(EnchantmentPlusChanceDelta);
810 INIT_ENTRY(BackGroundType);
811 INIT_ENTRY(IsCatacomb);
812 INIT_ENTRY(EnterImage);
813 INIT_ENTRY(EnterTextDisplacement);
814 INIT_ENTRY(Tag);
818 void levelscript::ReadFrom (TextInput &SaveFile) {
819 festring Word;
821 SrcFile = SaveFile.GetFileName();
822 SrcLine = SaveFile.CurrentLine();
823 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in level script line %d!", SaveFile.TokenLine());
824 if (Base) {
825 cv2 *Size = static_cast<const levelscript *>(Base)->GetSize();
827 if (Size) {
828 game::GetGlobalValueMap()["XSize"] = Size->X;
829 game::GetGlobalValueMap()["YSize"] = Size->Y;
832 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
833 if (Word == "Square") {
834 Square.push_back(squarescript());
835 Square.back().ReadFrom(SaveFile);
836 continue;
838 if (Word == "Room") {
839 Room.push_back(roomscript());
840 const roomscript *RoomDefault = GetRoomDefault();
841 if (RoomDefault) Room.back().SetBase(RoomDefault);
842 Room.back().ReadFrom(SaveFile);
843 continue;
845 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in level script line %d!", Word.CStr(), SaveFile.TokenLine());
846 if (Word == "Size") {
847 game::GetGlobalValueMap()["XSize"] = GetSize()->X;
848 game::GetGlobalValueMap()["YSize"] = GetSize()->Y;
852 const levelscript *LevelBase = static_cast<const levelscript *>(Base);
854 if (LevelBase && RoomDefaultHolder.Member) RoomDefaultHolder.Member->SetBase(LevelBase->RoomDefaultHolder.Member);
855 valuemap::iterator i = game::GetGlobalValueMap().find("XSize");
856 if (i != game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i);
857 i = game::GetGlobalValueMap().find("YSize");
858 if (i != game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i);
862 void levelscript::Combine (levelscript &Script) {
863 if (!Base) Base = Script.Base;
864 Square.splice(Square.end(), Script.Square);
865 Room.splice(Room.end(), Script.Room);
866 for (std::list<roomscript>::iterator i1 = Room.begin(); i1 != Room.end(); ++i1) i1->SetBase(GetRoomDefault());
867 for (datamap::const_iterator i2 = DataMap.begin(); i2 != DataMap.end(); ++i2) (this->*i2->second).Replace(Script.*i2->second);
871 void levelscript::SetBase (const scriptwithbase *What) {
872 const levelscript *LevelBase = static_cast<const levelscript *>(Base = What);
873 roomscript *BaseRoomDefault = LevelBase->RoomDefaultHolder.Member;
875 if (BaseRoomDefault) {
876 roomscript *ThisRoomDefault = RoomDefaultHolder.Member;
877 if (!ThisRoomDefault) {
878 for (std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i) i->SetBase(BaseRoomDefault);
879 } else {
880 ThisRoomDefault->SetBase(BaseRoomDefault);
886 void levelscript::Save (outputfile &SaveFile) const {
887 script::Save(SaveFile);
888 //if (Tag) SaveFile << Tag; else SaveFile << "";
889 SaveFile << Square << Room;
893 void levelscript::Load (inputfile &SaveFile) {
894 script::Load(SaveFile);
895 SaveFile >> Square >> Room;
897 const roomscript *RoomDefault = GetRoomDefault();
898 if (RoomDefault) for (std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i) i->SetBase(RoomDefault);
902 dungeonscript::dungeonscript () {
906 dungeonscript::~dungeonscript () {
910 const std::map<int, levelscript> &dungeonscript::GetLevel () const { return Level; }
913 void dungeonscript::InitDataMap () {
914 INIT_ENTRY(LevelDefault);
915 INIT_ENTRY(Levels);
916 INIT_ENTRY(Description);
917 INIT_ENTRY(ShortDescription);
921 void dungeonscript::ReadFrom (TextInput &SaveFile) {
922 festring Word;
924 SrcFile = SaveFile.GetFileName();
925 SrcLine = SaveFile.CurrentLine();
926 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in dungeon script line %d!", SaveFile.TokenLine());
927 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
928 if (Word == "Level") {
929 int Index = SaveFile.ReadNumber();
930 std::pair<std::map<int, levelscript>::iterator, bool> Return = Level.insert(std::make_pair(Index, levelscript()));
932 if (Return.second) {
933 levelscript &LS = Return.first->second;
934 const levelscript *LevelDefault = GetLevelDefault();
936 if (LevelDefault) LS.SetBase(LevelDefault);
937 LS.ReadFrom(SaveFile);
938 } else {
939 ABORT("Level #%d defined again in dungeon script line %d!", Index, SaveFile.TokenLine());
941 continue;
943 if (Word == "RandomLevel") {
944 interval Interval;
945 ReadData(Interval, SaveFile);
946 RandomLevel.push_back(std::make_pair(Interval, levelscript()));
947 const levelscript *LevelDefault = GetLevelDefault();
949 if (LevelDefault) RandomLevel.back().second.SetBase(LevelDefault);
950 RandomLevel.back().second.ReadFrom(SaveFile);
951 continue;
953 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in dungeon script line %d!", Word.CStr(), SaveFile.TokenLine());
958 void dungeonscript::RandomizeLevels () {
959 for (std::list<std::pair<interval, levelscript> >::iterator i = RandomLevel.begin(); i != RandomLevel.end(); ++i) {
960 int Index = i->first.Randomize();
961 Level[Index].Combine(i->second);
963 RandomLevel.clear();
967 void dungeonscript::Save (outputfile &SaveFile) const {
968 script::Save(SaveFile);
969 SaveFile << Level << RandomLevel;
973 void dungeonscript::Load (inputfile &SaveFile) {
974 script::Load(SaveFile);
975 SaveFile >> Level >> RandomLevel;
976 const levelscript *LevelDefault = GetLevelDefault();
977 if (LevelDefault) {
978 for (std::map<int, levelscript>::iterator i1 = Level.begin(); i1 != Level.end(); ++i1) i1->second.SetBase(LevelDefault);
979 for (std::list<std::pair<interval, levelscript> >::iterator i2 = RandomLevel.begin(); i2 != RandomLevel.end(); ++i2) i2->second.SetBase(LevelDefault);
984 const std::vector<std::pair<int, int> > &teamscript::GetRelation () const { return Relation; }
987 void teamscript::InitDataMap () {
988 INIT_ENTRY(KillEvilness);
989 INIT_ENTRY(Name);
993 void teamscript::ReadFrom (TextInput &SaveFile) {
994 festring Word;
996 SrcFile = SaveFile.GetFileName();
997 SrcLine = SaveFile.CurrentLine();
998 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in team script line %d!", SaveFile.TokenLine());
999 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
1000 if (Word == "Relation") {
1001 std::pair<int, int> Rel;
1003 Rel.first = SaveFile.ReadNumber();
1004 Rel.second = SaveFile.ReadNumber();
1005 Relation.push_back(Rel);
1006 continue;
1008 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in team script line %d!", Word.CStr(), SaveFile.TokenLine());
1013 void teamscript::Save (outputfile &SaveFile) const {
1014 script::Save(SaveFile);
1015 SaveFile << Relation;
1019 void teamscript::Load (inputfile &SaveFile) {
1020 script::Load(SaveFile);
1021 SaveFile >> Relation;
1025 const std::list<std::pair<int, teamscript> > &gamescript::GetTeam () const { return Team; }
1026 const std::map<int, dungeonscript> &gamescript::GetDungeon () const { return Dungeon; }
1029 void gamescript::InitDataMap () {
1030 //INIT_ENTRY(Dungeons);
1031 //INIT_ENTRY(Teams);
1035 void gamescript::ReadFrom (TextInput &SaveFile) {
1036 festring Word;
1038 SrcFile = SaveFile.GetFileName();
1039 SrcLine = SaveFile.CurrentLine();
1040 SaveFile.setGetVarCB(game::ldrGetVar);
1041 for (SaveFile.ReadWord(Word, false); !SaveFile.Eof(); SaveFile.ReadWord(Word, false)) {
1042 if (Word == "Dungeon") {
1043 int Index = SaveFile.ReadNumber();
1045 if (Index < 0 || Index > 16383) ABORT("Invalid dungeon number (%d) in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1046 if (mDungeons < Index) mDungeons = Index;
1047 //fprintf(stderr, "dungeon: %d; mDungeons: %d\n", Index, mDungeons);
1048 std::pair<dungeonlist::iterator, bool> Return = Dungeon.insert(std::make_pair(Index, dungeonscript()));
1050 if (Return.second) Return.first->second.ReadFrom(SaveFile);
1051 else ABORT("Dungeon #%d defined again in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1052 continue;
1054 if (Word == "Team") {
1055 int Index = SaveFile.ReadNumber();
1057 if (Index < 0 || Index > 16383) ABORT("Invalid team number (%d) in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1058 for (teamlist::const_iterator it = Team.begin(); it != Team.end(); ++it) {
1059 if (it->first == Index) ABORT("Team #%d redefinition in file %s at line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1061 if (mTeams < Index+1) mTeams = Index+1;
1064 fprintf(stderr, "new team #%d\n", Index);
1065 fprintf(stderr, "defined teams:\n");
1066 for (teamlist::const_iterator it = Team.begin(); it != Team.end(); ++it) fprintf(stderr, " %d\n", it->first);
1070 Team.push_back(teamlistitem(Index, teamscript()));
1071 Team.back().second.ReadFrom(SaveFile);
1072 continue;
1074 if (Word == "Include") {
1075 Word = SaveFile.ReadWord();
1076 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1077 //fprintf(stderr, "loading: %s\n", Word.CStr());
1078 TextInputFile incf(inputfile::buildIncludeName(SaveFile.GetFileName(), Word), &game::GetGlobalValueMap());
1079 ReadFrom(incf);
1080 continue;
1082 if (Word == "Message") {
1083 Word = SaveFile.ReadWord();
1084 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1085 fprintf(stderr, "MESSAGE: %s\n", Word.CStr());
1086 continue;
1088 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in game script file %s line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1093 void gamescript::RandomizeLevels () {
1094 for (std::map<int, dungeonscript>::iterator i = Dungeon.begin(); i != Dungeon.end(); ++i) i->second.RandomizeLevels();
1098 void gamescript::Save (outputfile &SaveFile) const {
1099 script::Save(SaveFile);
1100 SaveFile << Team << Dungeon;
1104 void gamescript::Load (inputfile &SaveFile) {
1105 script::Load(SaveFile);
1106 SaveFile >> Team >> Dungeon;
1110 outputfile &operator << (outputfile &SaveFile, const gamescript *Script) {
1111 Script->Save(SaveFile);
1112 return SaveFile;
1116 inputfile &operator >> (inputfile &SaveFile, gamescript *&Script) {
1117 Script = new gamescript;
1118 Script->Load(SaveFile);
1119 return SaveFile;
1123 void scriptsystem::Initialize () {
1124 posscript::InitDataMap();
1125 materialscript::InitDataMap();
1126 basecontentscript::InitDataMap();
1127 contentscript<character>::InitDataMap();
1128 contentscript<item>::InitDataMap();
1129 contentscript<glterrain>::InitDataMap();
1130 contentscript<olterrain>::InitDataMap();
1131 squarescript::InitDataMap();
1132 itemcontentmap::InitDataMap();
1133 charactercontentmap::InitDataMap();
1134 glterraincontentmap::InitDataMap();
1135 olterraincontentmap::InitDataMap();
1136 roomscript::InitDataMap();
1137 levelscript::InitDataMap();
1138 dungeonscript::InitDataMap();
1139 teamscript::InitDataMap();
1140 gamescript::InitDataMap();