unnecessary messing with code
[k8-i-v-a-n.git] / src / game / script.cpp
blob3bef7eb6fc934b19a6f0a4c769cad1e7fb149591
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 "game.h"
15 #include "materia.h"
16 #include "char.h"
17 #include "proto.h"
18 #include "allocate.h"
20 script::datamap posscript::DataMap;
21 script::datamap materialscript::DataMap;
22 script::datamap basecontentscript::DataMap;
23 script::datamap contentscript<character>::DataMap;
24 script::datamap contentscript<item>::DataMap;
25 script::datamap contentscript<glterrain>::DataMap;
26 script::datamap contentscript<olterrain>::DataMap;
27 script::datamap squarescript::DataMap;
28 script::datamap roomscript::DataMap;
29 script::datamap levelscript::DataMap;
30 script::datamap dungeonscript::DataMap;
31 script::datamap teamscript::DataMap;
32 script::datamap gamescript::DataMap;
34 template <class type, class contenttype> script::datamap contentmap<type, contenttype>::DataMap;
37 template <class type> void scriptmember<type>::ReadFrom (inputfile &SaveFile) {
38 SrcFile = SaveFile.GetFileName();
39 SrcLine = SaveFile.CurrentLine();
40 if (!Member) Member = new type;
41 ReadData(*Member, SaveFile);
45 template <class type> void scriptmember<type>::Replace (scriptmemberbase &Base) {
46 scriptmember<type> &Data = static_cast<scriptmember<type> &>(Base);
48 if (Data.Member) {
49 delete Member;
50 Member = Data.Member;
51 Data.Member = 0;
53 SrcFile = Base.SrcFile;
54 SrcLine = Base.SrcLine;
58 template <class type> void scriptmember<type>::Save (outputfile &SaveFile) const {
59 if (Member) {
60 SaveFile.Put(1);
61 SaveFile << SrcFile << SrcLine;
62 SaveFile << *Member;
63 } else {
64 SaveFile.Put(0);
68 template <class type> void scriptmember<type>::Load (inputfile &SaveFile) {
69 if (SaveFile.Get()) {
70 Member = new type;
71 SaveFile >> SrcFile >> SrcLine;
72 SaveFile >> *Member;
77 #define INST_SCRIPT_MEMBER(type)\
78 template void scriptmember< type >::ReadFrom(inputfile &);\
79 template void scriptmember< type >::Replace(scriptmemberbase &);\
80 template void scriptmember< type >::Save(outputfile &) const;\
81 template void scriptmember< type >::Load(inputfile &)
83 INST_SCRIPT_MEMBER(uChar);
84 INST_SCRIPT_MEMBER(short);
85 INST_SCRIPT_MEMBER(int);
86 //INST_SCRIPT_MEMBER(sLong); //k8:64
87 INST_SCRIPT_MEMBER(v2);
88 INST_SCRIPT_MEMBER(festring);
89 INST_SCRIPT_MEMBER(fearray<v2>);
90 INST_SCRIPT_MEMBER(rect);
91 INST_SCRIPT_MEMBER(interval);
92 INST_SCRIPT_MEMBER(region);
93 INST_SCRIPT_MEMBER(posscript);
94 INST_SCRIPT_MEMBER(materialscript);
95 INST_SCRIPT_MEMBER(squarescript);
96 INST_SCRIPT_MEMBER(roomscript);
97 INST_SCRIPT_MEMBER(levelscript);
98 INST_SCRIPT_MEMBER(contentscript<character>);
99 INST_SCRIPT_MEMBER(fearray<contentscript<item> >);
100 INST_SCRIPT_MEMBER(contentscript<glterrain>);
101 INST_SCRIPT_MEMBER(contentscript<olterrain>);
102 INST_SCRIPT_MEMBER(charactercontentmap);
103 INST_SCRIPT_MEMBER(itemcontentmap);
104 INST_SCRIPT_MEMBER(glterraincontentmap);
105 INST_SCRIPT_MEMBER(olterraincontentmap);
106 INST_SCRIPT_MEMBER(fearray<packv2>);
109 template <class type> void fastscriptmember<type>::ReadFrom (inputfile &SaveFile) {
110 SrcFile = SaveFile.GetFileName();
111 SrcLine = SaveFile.CurrentLine();
112 ReadData(*&Member, SaveFile); // gcc 3.4.1 sucks
116 template <class type> void fastscriptmember<type>::Replace (scriptmemberbase &Base) {
117 fastscriptmember<type> &Data = static_cast<fastscriptmember<type> &>(Base);
119 Member = Data.Member;
120 SrcFile = Base.SrcFile;
121 SrcLine = Base.SrcLine;
125 template <class type> void fastscriptmember<type>::Save(outputfile &SaveFile) const {
126 SaveFile << SrcFile << SrcLine;
127 SaveFile << Member;
131 template <class type> void fastscriptmember<type>::Load (inputfile &SaveFile) {
132 SaveFile >> SrcFile >> SrcLine;
133 SaveFile >> *&Member; // gcc 3.4.1 sucks
137 #define INST_FAST_SCRIPT_MEMBER(type)\
138 template void fastscriptmember< type >::ReadFrom(inputfile&);\
139 template void fastscriptmember< type >::Replace(scriptmemberbase&);\
140 template void fastscriptmember< type >::Save(outputfile&) const;\
141 template void fastscriptmember< type >::Load(inputfile&)
143 INST_FAST_SCRIPT_MEMBER(char);
144 INST_FAST_SCRIPT_MEMBER(uChar);
145 INST_FAST_SCRIPT_MEMBER(int);
146 //INST_FAST_SCRIPT_MEMBER(sLong); //k8:64
147 INST_FAST_SCRIPT_MEMBER(feuLong);
148 INST_FAST_SCRIPT_MEMBER(packv2);
151 void script::Save (outputfile &SaveFile) const {
152 SaveFile << SrcFile << SrcLine;
153 SaveDataMap(GetDataMap(), SaveFile);
157 void script::Load (inputfile &SaveFile) {
158 SaveFile >> SrcFile >> SrcLine;
159 LoadDataMap(GetDataMap(), SaveFile);
163 truth script::ReadMember (inputfile &SaveFile, cfestring &Word) {
164 scriptmemberbase *Data = GetData(Word.CStr());
166 if (Data) {
167 Data->ReadFrom(SaveFile);
168 return true;
170 return false;
174 scriptmemberbase *script::GetDataFromMap (const datamap &DataMap, cchar *Identifier) {
175 datamap::const_iterator i = DataMap.find(Identifier);
177 return i != DataMap.end() ? &(this->*i->second) : 0;
181 void script::SaveDataMap (const datamap &DataMap, outputfile &SaveFile) const {
182 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Save(SaveFile);
186 void script::LoadDataMap (const datamap &DataMap, inputfile &SaveFile) {
187 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Load(SaveFile);
191 template <class scriptmemberptr> void InitMember (script::datamap &DataMap, cchar *Identifier, scriptmemberptr DataMember) {
192 DataMap[Identifier] = reinterpret_cast<scriptmemberbase script::*>(DataMember);
196 #define INIT_ENTRY(name) InitMember(DataMap, #name, &scripttype::name##Holder)
197 #define INIT(name, value) name##Holder(value)
200 void posscript::InitDataMap () {
201 INIT_ENTRY(Vector);
202 INIT_ENTRY(Flags);
203 INIT_ENTRY(Borders);
207 void posscript::ReadFrom (inputfile &SaveFile) {
208 static festring Word;
210 SrcFile = SaveFile.GetFileName();
211 SrcLine = SaveFile.CurrentLine();
212 SaveFile.ReadWord(Word);
213 if (Word == "Pos") {
214 Random = false;
215 VectorHolder.ReadFrom(SaveFile);
216 } else if (Word == "Random") {
217 Random = true;
218 FlagsHolder.ReadFrom(SaveFile);
219 } else if (Word == "BoundedRandom") {
220 Random = true;
221 BordersHolder.ReadFrom(SaveFile);
222 FlagsHolder.ReadFrom(SaveFile);
227 void posscript::Save (outputfile &SaveFile) const {
228 script::Save(SaveFile);
229 SaveFile << Random;
233 void posscript::Load (inputfile &SaveFile) {
234 script::Load(SaveFile);
235 SaveFile >> Random;
239 void materialscript::InitDataMap () {
240 INIT_ENTRY(Volume);
244 void materialscript::ReadFrom (inputfile &SaveFile) {
245 static festring Word;
247 SrcFile = SaveFile.GetFileName();
248 SrcLine = SaveFile.CurrentLine();
249 SaveFile.ReadWord(Word);
250 if (Word == "=") SaveFile.ReadWord(Word);
251 if (Word == "0") {
252 Config = 0;
253 } else {
254 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
256 if (i != game::GetGlobalValueMap().end()) Config = i->second;
257 else ABORT("Unconfigured material script detected at line %d!", SaveFile.TokenLine());
259 if (SaveFile.ReadWord() != "{") return;
260 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
261 if (!ReadMember(SaveFile, Word)) {
262 ABORT("Odd script term %s encountered in material script line %d!", Word.CStr(), SaveFile.TokenLine());
268 material *materialscript::Instantiate () const {
269 return MAKE_MATERIAL(Config, GetVolume() ? GetVolume()->Randomize() : 0);
273 void materialscript::Save (outputfile &SaveFile) const {
274 script::Save(SaveFile);
275 SaveFile << (uShort)Config;
279 void materialscript::Load (inputfile &SaveFile) {
280 script::Load(SaveFile);
281 Config = 0;
282 uShort s2;
283 SaveFile >> s2;
284 Config = s2;
288 void basecontentscript::InitDataMap () {
289 INIT_ENTRY(MainMaterial);
290 INIT_ENTRY(SecondaryMaterial);
291 INIT_ENTRY(Parameters);
295 basecontentscript::basecontentscript () : script(), ContentType(0), Random(false), Config(0), INIT(Parameters, NO_PARAMETERS) {
299 void basecontentscript::ReadFrom (inputfile &SaveFile) {
300 static festring Word;
302 SrcFile = SaveFile.GetFileName();
303 SrcLine = SaveFile.CurrentLine();
304 SaveFile.ReadWord(Word);
305 if (Word == "[") {
306 mCode = SaveFile.ReadCode();
307 SaveFile.ReadWord(Word);
309 if (Word == "=" || Word == ",") SaveFile.ReadWord(Word);
310 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
311 if (i != game::GetGlobalValueMap().end()) {
312 if (!GetMainMaterial()) MainMaterialHolder.Member = new materialscript;
313 MainMaterialHolder.Member->SetConfig(i->second);
314 SaveFile.ReadWord(Word);
315 i = game::GetGlobalValueMap().find(Word);
316 if (i != game::GetGlobalValueMap().end()) {
317 if (!GetSecondaryMaterial()) SecondaryMaterialHolder.Member = new materialscript;
318 SecondaryMaterialHolder.Member->SetConfig(i->second);
319 SaveFile.ReadWord(Word);
322 if (Word == "NaturalMaterialForm") {
323 Random = false;
324 ContentType = NATURAL_MATERIAL_FORM;
325 SaveFile.ReadWord(Word);
326 } else if (Word == "Random") {
327 Random = true;
328 SaveFile.ReadWord(Word);
329 } else {
330 Random = false;
331 ContentType = SearchCodeName(Word);
332 if (ContentType || Word == "0") SaveFile.ReadWord(Word);
333 else ABORT("Odd script term %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
335 if (Word == "(") {
336 Config = SaveFile.ReadNumber();
337 SaveFile.ReadWord(Word);
338 } else {
339 Config = 0;
341 if (Word == "{") {
342 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
343 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());
345 } else {
346 if (Word == "[") {
347 mCode = SaveFile.ReadCode();
348 SaveFile.ReadWord(Word);
350 if (Word != ";" && Word != ",") ABORT("Odd terminator %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
355 scriptmemberbase *basecontentscript::GetData (cchar *String) {
356 scriptmemberbase *Return = GetDataFromMap(GetDataMap(), String);
357 return Return ? Return : GetDataFromMap(DataMap, String);
361 void basecontentscript::Save (outputfile &SaveFile) const {
362 SaveFile << SrcFile << SrcLine;
363 SaveDataMap(GetDataMap(), SaveFile);
364 SaveDataMap(DataMap, SaveFile);
365 SaveFile << ContentType;
366 SaveFile.Put(!!Random);
367 SaveFile << Config;
371 void basecontentscript::Load (inputfile &SaveFile) {
372 SaveFile >> SrcFile >> SrcLine;
373 LoadDataMap(GetDataMap(), SaveFile);
374 LoadDataMap(DataMap, SaveFile);
375 ContentType = ReadType(uShort, SaveFile);
376 Random = SaveFile.Get();
377 SaveFile >> Config;
381 template <class type> type *contentscripttemplate<type>::BasicInstantiate (int SpecialFlags) const {
382 type *Instance = 0;
383 const typename type::prototype *Proto = protocontainer<type>::GetProto(ContentType);
384 const typename type::database *const *ConfigData = Proto->GetConfigData();
385 const materialscript *MainMaterial = GetMainMaterial();
386 const materialscript *SecondaryMaterial = GetSecondaryMaterial();
387 const typename type::database *DataBase = *ConfigData;
388 truth UseOverriddenMaterials = false;
390 if (!Config && DataBase->IsAbstract) {
391 while (!Instance) {
392 DataBase = ConfigData[1+RAND()%(Proto->GetConfigSize()-1)];
393 if (DataBase->AllowRandomInstantiation()) {
394 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
395 SpecialFlags |= NO_MATERIALS;
396 UseOverriddenMaterials = true;
398 Instance = Proto->Spawn(DataBase->Config, SpecialFlags|NO_PIC_UPDATE);
401 } else {
402 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
403 SpecialFlags |= NO_MATERIALS;
404 UseOverriddenMaterials = true;
406 Instance = Proto->Spawn(Config, SpecialFlags|NO_PIC_UPDATE);
408 if (GetParameters() != NO_PARAMETERS) Instance->SetParameters(GetParameters());
409 if (UseOverriddenMaterials) {
410 Instance->InitMaterials(MainMaterial, SecondaryMaterial, false);
411 } else {
412 if (MainMaterial) Instance->ChangeMainMaterial(MainMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
413 if (SecondaryMaterial) Instance->ChangeSecondaryMaterial(SecondaryMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
415 if (!(SpecialFlags & NO_PIC_UPDATE)) Instance->UpdatePictures();
416 return Instance;
420 /* Called by an inline function in script.h... */
422 template glterrain *contentscripttemplate<glterrain>::BasicInstantiate (int) const;
424 template <class type> int contentscripttemplate<type>::SearchCodeName (cfestring &String) const {
425 return protocontainer<type>::SearchCodeName(String);
428 /* GCC 2.952 SUCKS!!! IT MUST BURN!!! */
430 template int contentscripttemplate<character>::SearchCodeName(cfestring &) const;
431 template int contentscripttemplate<item>::SearchCodeName(cfestring &) const;
432 template int contentscripttemplate<glterrain>::SearchCodeName(cfestring &) const;
433 template int contentscripttemplate<olterrain>::SearchCodeName(cfestring &) const;
435 cchar *contentscript<character>::GetClassID () const { return "character"; }
436 cchar *contentscript<item>::GetClassID () const { return "item"; }
437 cchar *contentscript<glterrain>::GetClassID () const { return "glterrain"; }
438 cchar *contentscript<olterrain>::GetClassID () const { return "olterrain"; }
441 void contentscript<character>::InitDataMap () {
442 INIT_ENTRY(Inventory);
443 INIT_ENTRY(WayPoint);
444 INIT_ENTRY(Team);
445 INIT_ENTRY(Flags);
449 contentscript<character>::contentscript () : INIT(Team, DEFAULT_TEAM), INIT(Flags, 0) {
453 character *contentscript<character>::Instantiate (int SpecialFlags) const {
454 character *Instance = contentscripttemplate<character>::BasicInstantiate(SpecialFlags);
456 //fprintf(stderr, "instantiating character '%s'\n", Instance->GetNameSingular().CStr());
458 if (!mCode.IsEmpty()) {
459 game::ClearEventData();
460 if (!game::RunAllowScriptStr(mCode)) {
461 //fprintf(stderr, "dropping character '%s'\n", Instance->GetNameSingular().CStr());
462 delete Instance;
463 return 0;
467 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(game::GetTeam(GetTeam()));
468 const fearray<contentscript<item> > *Inventory = GetInventory();
469 if (Inventory) Instance->AddToInventory(*Inventory, SpecialFlags);
470 const fearray<packv2> *WayPoint = GetWayPoint();
471 if (WayPoint) Instance->SetWayPoints(*WayPoint);
472 Instance->RestoreHP();
473 Instance->RestoreStamina();
474 return Instance;
478 contentscript<item>::contentscript () :
479 INIT(Category, ANY_CATEGORY),
480 INIT(MinPrice, 0),
481 INIT(MaxPrice, MAX_PRICE),
482 INIT(Team, DEFAULT_TEAM),
483 INIT(SquarePosition, CENTER),
484 INIT(Chance, 100),
485 INIT(ConfigFlags, 0),
486 INIT(SpoilPercentage, 0),
487 INIT(Enchantment, 0),
488 INIT(IsActive, false)
493 void contentscript<item>::InitDataMap () {
494 INIT_ENTRY(ItemsInside);
495 INIT_ENTRY(Times);
496 INIT_ENTRY(MinPrice);
497 INIT_ENTRY(MaxPrice);
498 INIT_ENTRY(LifeExpectancy);
499 INIT_ENTRY(Team);
500 INIT_ENTRY(Category);
501 INIT_ENTRY(SquarePosition);
502 INIT_ENTRY(Chance);
503 INIT_ENTRY(ConfigFlags);
504 INIT_ENTRY(SpoilPercentage);
505 INIT_ENTRY(Enchantment);
506 INIT_ENTRY(IsActive);
510 item *contentscript<item>::InstantiateBasedOnMaterial (int MaterialConfig, int SpecialFlags) const {
511 if (ContentType == NATURAL_MATERIAL_FORM) {
512 const materialscript *MainMaterial = GetMainMaterial();
513 sLong Volume = MainMaterial && MainMaterial->GetVolume() ? MainMaterial->GetVolume()->Randomize() : 0;
514 return material::CreateNaturalForm(MaterialConfig, Volume);
516 return Instantiate(SpecialFlags);
520 item *contentscript<item>::Instantiate (int SpecialFlags) const {
521 int Chance = GetChance();
522 item *Instance;
524 if (!mCode.IsEmpty()) {
525 game::ClearEventData();
526 if (!game::RunAllowScriptStr(mCode)) return 0;
529 if (Chance != 100 && Chance <= RAND_N(100)) return 0;
530 if (Random) {
531 Instance = protosystem::BalancedCreateItem(0, GetMinPrice(), GetMaxPrice(), GetCategory(), SpecialFlags, GetConfigFlags());
532 } else {
533 Instance = contentscripttemplate<item>::BasicInstantiate(SpecialFlags);
535 if (GetLifeExpectancy()) Instance->SetLifeExpectancy(GetLifeExpectancy()->Min, (GetLifeExpectancy()->Max - GetLifeExpectancy()->Min) + 1);
536 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(GetTeam());
537 if (IsActive()) Instance->SetIsActive(true);
538 if (GetEnchantment() != 0) Instance->SetEnchantment(GetEnchantment());
539 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
540 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
541 if (GetSpoilPercentage() != 0) Instance->SetSpoilPercentage(GetSpoilPercentage());
542 return Instance;
546 truth IsValidScript (const fearray<contentscript<item> > *Array) {
547 for (uInt c = 0; c < Array->Size; ++c) if (IsValidScript(&Array->Data[c])) return true;
548 return false;
552 void contentscript<glterrain>::InitDataMap () {
553 INIT_ENTRY(IsInside);
557 contentscript<olterrain>::contentscript () :
558 INIT(VisualEffects, 0),
559 INIT(AttachedArea, DEFAULT_ATTACHED_AREA),
560 INIT(AttachedEntry, DEFAULT_ATTACHED_ENTRY)
565 void contentscript<olterrain>::InitDataMap () {
566 INIT_ENTRY(ItemsInside);
567 INIT_ENTRY(Text);
568 INIT_ENTRY(VisualEffects);
569 INIT_ENTRY(AttachedArea);
570 INIT_ENTRY(AttachedEntry);
574 olterrain *contentscript<olterrain>::Instantiate (int SpecialFlags) const {
575 if (!ContentType) return 0;
576 olterrain *Instance = contentscripttemplate<olterrain>::BasicInstantiate(SpecialFlags);
577 if (GetVisualEffects()) {
578 Instance->SetVisualEffects(GetVisualEffects());
579 Instance->UpdatePictures();
581 if (GetAttachedArea() != DEFAULT_ATTACHED_AREA) Instance->SetAttachedArea(GetAttachedArea());
582 if (GetAttachedEntry() != DEFAULT_ATTACHED_ENTRY) Instance->SetAttachedEntry(GetAttachedEntry());
583 cfestring *Text = GetText();
584 if (Text) Instance->SetText(*Text);
585 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
586 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
587 return Instance;
591 squarescript::squarescript () : INIT(EntryIndex, NO_ENTRY), INIT(AttachRequired, false) {
595 void squarescript::InitDataMap () {
596 INIT_ENTRY(Position);
597 INIT_ENTRY(Character);
598 INIT_ENTRY(Items);
599 INIT_ENTRY(GTerrain);
600 INIT_ENTRY(OTerrain);
601 INIT_ENTRY(Times);
602 INIT_ENTRY(EntryIndex);
603 INIT_ENTRY(AttachRequired);
607 void squarescript::ReadFrom (inputfile &SaveFile) {
608 static festring Word;
610 SrcFile = SaveFile.GetFileName();
611 SrcLine = SaveFile.CurrentLine();
612 SaveFile.ReadWord(Word);
613 if (Word != "=") {
614 PositionHolder.ReadFrom(SaveFile);
615 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in square script line %d!", SaveFile.TokenLine());
616 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
617 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in square script line %d!", Word.CStr(), SaveFile.TokenLine());
619 } else {
620 GTerrainHolder.ReadFrom(SaveFile);
621 OTerrainHolder.ReadFrom(SaveFile);
626 template <class type, class contenttype> contentmap<type, contenttype>::contentmap() : ContentMap(0) {
630 template <class type, class contenttype> contentmap<type, contenttype>::~contentmap<type, contenttype> () {
631 delete [] ContentMap;
635 template <class type, class contenttype> void contentmap<type, contenttype>::InitDataMap () {
636 INIT_ENTRY(Size);
637 INIT_ENTRY(Pos);
641 template <class type, class contenttype> void contentmap<type, contenttype>::ReadFrom (inputfile &SaveFile) {
642 typedef std::map<int, contenttype> maptype;
643 typedef typename maptype::iterator mapiterator;
644 festring Word1, Word2;
646 SrcFile = SaveFile.GetFileName();
647 SrcLine = SaveFile.CurrentLine();
648 if (ContentMap) ABORT("Illegal %s content map redefinition on line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
649 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
650 SymbolMap.insert(std::pair<int, contenttype>('.', contenttype()));
651 for (SaveFile.ReadWord(Word1); Word1 != "}"; Word1 = SaveFile.ReadWord()) {
652 if (Word1 == "Types") {
653 if (SaveFile.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
654 for (SaveFile.ReadWord(Word2); Word2 != "}"; Word2 = SaveFile.ReadWord()) {
655 std::pair<mapiterator, bool> Return = SymbolMap.insert(std::pair<int, contenttype>(Word2[0], contenttype()));
657 if (Return.second) {
658 ReadData(Return.first->second, SaveFile);
659 } else {
660 ABORT("Symbol %c defined again in %s content map script line %d!", Word2[0], protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
663 continue;
665 if (!ReadMember(SaveFile, Word1)) ABORT("Odd script term %s encountered in %s content script line %d!", Word1.CStr(), protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
668 v2 Size = *GetSize();
670 Alloc2D(ContentMap, Size.X, Size.Y);
671 if (SaveFile.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
672 for (int y = 0; y < Size.Y; ++y) {
673 for (int x = 0; x < Size.X; ++x) {
674 int Char = SaveFile.ReadLetter();
675 typename std::map<int, contenttype>::iterator i = SymbolMap.find(Char);
677 if (i != SymbolMap.end()) {
678 ContentMap[x][y] = std::make_pair(Char, &i->second);
679 } else {
680 ABORT("Illegal content %c in %s content map line %d!", Char, protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
684 if (SaveFile.ReadWord() != "}") ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TokenLine());
688 template <class type, class contenttype> void contentmap<type, contenttype>::Save (outputfile &SaveFile) const {
689 script::Save(SaveFile);
690 SaveFile << SymbolMap;
692 v2 Size = *GetSize();
693 for (int y = 0; y < Size.Y; ++y)
694 for (int x = 0; x < Size.X; ++x)
695 SaveFile << char(ContentMap[x][y].first);
699 template <class type, class contenttype> void contentmap<type, contenttype>::Load (inputfile &SaveFile) {
700 script::Load(SaveFile);
701 SaveFile >> SymbolMap;
703 v2 Size = *GetSize();
705 Alloc2D(ContentMap, Size.X, Size.Y);
706 for (int y = 0; y < Size.Y; ++y) {
707 for (int x = 0; x < Size.X; ++x) {
708 int Char = ReadType(char, SaveFile);
710 ContentMap[x][y] = std::make_pair(Char, &SymbolMap.find(Char)->second);
716 const std::list<squarescript> &roomscript::GetSquare () const { return Square; }
719 void roomscript::InitDataMap () {
720 INIT_ENTRY(CharacterMap);
721 INIT_ENTRY(ItemMap);
722 INIT_ENTRY(GTerrainMap);
723 INIT_ENTRY(OTerrainMap);
724 INIT_ENTRY(WallSquare);
725 INIT_ENTRY(FloorSquare);
726 INIT_ENTRY(DoorSquare);
727 INIT_ENTRY(Size);
728 INIT_ENTRY(Pos);
729 INIT_ENTRY(AltarPossible);
730 INIT_ENTRY(GenerateDoor);
731 INIT_ENTRY(GenerateTunnel);
732 INIT_ENTRY(DivineMaster);
733 INIT_ENTRY(GenerateLanterns);
734 INIT_ENTRY(Type);
735 INIT_ENTRY(GenerateFountains);
736 INIT_ENTRY(AllowLockedDoors);
737 INIT_ENTRY(AllowBoobyTrappedDoors);
738 INIT_ENTRY(Shape);
739 INIT_ENTRY(IsInside);
740 INIT_ENTRY(GenerateWindows);
741 INIT_ENTRY(UseFillSquareWalls);
742 INIT_ENTRY(Flags);
743 INIT_ENTRY(GenerateWards);
744 INIT_ENTRY(AllowedDivineMasters);
748 void roomscript::ReadFrom (inputfile &SaveFile) {
749 festring Word;
751 SrcFile = SaveFile.GetFileName();
752 SrcLine = SaveFile.CurrentLine();
753 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in room script line %d!", SaveFile.TokenLine());
754 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
755 if (Word == "Square") {
756 Square.push_back(squarescript());
757 Square.back().ReadFrom(SaveFile);
758 continue;
760 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in room script line %d!", Word.CStr(), SaveFile.TokenLine());
765 void roomscript::Save (outputfile &SaveFile) const {
766 script::Save(SaveFile);
767 SaveFile << Square;
771 void roomscript::Load (inputfile &SaveFile) {
772 script::Load(SaveFile);
773 SaveFile >> Square;
777 const std::list<squarescript> &levelscript::GetSquare () const { return Square; }
778 const std::list<roomscript> &levelscript::GetRoom () const { return Room; }
781 void levelscript::InitDataMap () {
782 INIT_ENTRY(RoomDefault);
783 INIT_ENTRY(FillSquare);
784 INIT_ENTRY(TunnelSquare);
785 INIT_ENTRY(LevelMessage);
786 INIT_ENTRY(Size);
787 INIT_ENTRY(Items);
788 INIT_ENTRY(Rooms);
789 INIT_ENTRY(GenerateMonsters);
790 INIT_ENTRY(IsOnGround);
791 INIT_ENTRY(TeamDefault);
792 INIT_ENTRY(Description);
793 INIT_ENTRY(LOSModifier);
794 INIT_ENTRY(IgnoreDefaultSpecialSquares);
795 INIT_ENTRY(DifficultyBase);
796 INIT_ENTRY(DifficultyDelta);
797 INIT_ENTRY(MonsterAmountBase);
798 INIT_ENTRY(MonsterAmountDelta);
799 INIT_ENTRY(MonsterGenerationIntervalBase);
800 INIT_ENTRY(MonsterGenerationIntervalDelta);
801 INIT_ENTRY(AutoReveal);
802 INIT_ENTRY(ShortDescription);
803 INIT_ENTRY(CanGenerateBone);
804 INIT_ENTRY(ItemMinPriceBase);
805 INIT_ENTRY(ItemMinPriceDelta);
806 INIT_ENTRY(Type);
807 INIT_ENTRY(EnchantmentMinusChanceBase);
808 INIT_ENTRY(EnchantmentMinusChanceDelta);
809 INIT_ENTRY(EnchantmentPlusChanceBase);
810 INIT_ENTRY(EnchantmentPlusChanceDelta);
811 INIT_ENTRY(BackGroundType);
812 INIT_ENTRY(IsCatacomb);
813 INIT_ENTRY(EnterImage);
814 INIT_ENTRY(EnterTextDisplacement);
815 INIT_ENTRY(Tag);
819 void levelscript::ReadFrom (inputfile &SaveFile) {
820 festring Word;
822 SrcFile = SaveFile.GetFileName();
823 SrcLine = SaveFile.CurrentLine();
824 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in level script line %d!", SaveFile.TokenLine());
825 if (Base) {
826 cv2 *Size = static_cast<const levelscript *>(Base)->GetSize();
828 if (Size) {
829 game::GetGlobalValueMap()["XSize"] = Size->X;
830 game::GetGlobalValueMap()["YSize"] = Size->Y;
833 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
834 if (Word == "Square") {
835 Square.push_back(squarescript());
836 Square.back().ReadFrom(SaveFile);
837 continue;
839 if (Word == "Room") {
840 Room.push_back(roomscript());
841 const roomscript *RoomDefault = GetRoomDefault();
842 if (RoomDefault) Room.back().SetBase(RoomDefault);
843 Room.back().ReadFrom(SaveFile);
844 continue;
846 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in level script line %d!", Word.CStr(), SaveFile.TokenLine());
847 if (Word == "Size") {
848 game::GetGlobalValueMap()["XSize"] = GetSize()->X;
849 game::GetGlobalValueMap()["YSize"] = GetSize()->Y;
853 const levelscript *LevelBase = static_cast<const levelscript *>(Base);
855 if (LevelBase && RoomDefaultHolder.Member) RoomDefaultHolder.Member->SetBase(LevelBase->RoomDefaultHolder.Member);
856 valuemap::iterator i = game::GetGlobalValueMap().find("XSize");
857 if (i != game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i);
858 i = game::GetGlobalValueMap().find("YSize");
859 if (i != game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i);
863 void levelscript::Combine (levelscript &Script) {
864 if (!Base) Base = Script.Base;
865 Square.splice(Square.end(), Script.Square);
866 Room.splice(Room.end(), Script.Room);
867 for (std::list<roomscript>::iterator i1 = Room.begin(); i1 != Room.end(); ++i1) i1->SetBase(GetRoomDefault());
868 for (datamap::const_iterator i2 = DataMap.begin(); i2 != DataMap.end(); ++i2) (this->*i2->second).Replace(Script.*i2->second);
872 void levelscript::SetBase (const scriptwithbase *What) {
873 const levelscript *LevelBase = static_cast<const levelscript *>(Base = What);
874 roomscript *BaseRoomDefault = LevelBase->RoomDefaultHolder.Member;
876 if (BaseRoomDefault) {
877 roomscript *ThisRoomDefault = RoomDefaultHolder.Member;
878 if (!ThisRoomDefault) {
879 for (std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i) i->SetBase(BaseRoomDefault);
880 } else {
881 ThisRoomDefault->SetBase(BaseRoomDefault);
887 void levelscript::Save (outputfile &SaveFile) const {
888 script::Save(SaveFile);
889 //if (Tag) SaveFile << Tag; else SaveFile << "";
890 SaveFile << Square << Room;
894 void levelscript::Load (inputfile &SaveFile) {
895 script::Load(SaveFile);
896 SaveFile >> Square >> Room;
898 const roomscript *RoomDefault = GetRoomDefault();
899 if (RoomDefault) for (std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i) i->SetBase(RoomDefault);
903 dungeonscript::dungeonscript () {
907 dungeonscript::~dungeonscript () {
911 const std::map<int, levelscript> &dungeonscript::GetLevel () const { return Level; }
914 void dungeonscript::InitDataMap () {
915 INIT_ENTRY(LevelDefault);
916 INIT_ENTRY(Levels);
917 INIT_ENTRY(Description);
918 INIT_ENTRY(ShortDescription);
922 void dungeonscript::ReadFrom (inputfile &SaveFile) {
923 festring Word;
925 SrcFile = SaveFile.GetFileName();
926 SrcLine = SaveFile.CurrentLine();
927 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in dungeon script line %d!", SaveFile.TokenLine());
928 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
929 if (Word == "Level") {
930 int Index = SaveFile.ReadNumber();
931 std::pair<std::map<int, levelscript>::iterator, bool> Return = Level.insert(std::make_pair(Index, levelscript()));
933 if (Return.second) {
934 levelscript &LS = Return.first->second;
935 const levelscript *LevelDefault = GetLevelDefault();
937 if (LevelDefault) LS.SetBase(LevelDefault);
938 LS.ReadFrom(SaveFile);
939 } else {
940 ABORT("Level #%d defined again in dungeon script line %d!", Index, SaveFile.TokenLine());
942 continue;
944 if (Word == "RandomLevel") {
945 interval Interval;
946 ReadData(Interval, SaveFile);
947 RandomLevel.push_back(std::make_pair(Interval, levelscript()));
948 const levelscript *LevelDefault = GetLevelDefault();
950 if (LevelDefault) RandomLevel.back().second.SetBase(LevelDefault);
951 RandomLevel.back().second.ReadFrom(SaveFile);
952 continue;
954 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in dungeon script line %d!", Word.CStr(), SaveFile.TokenLine());
959 void dungeonscript::RandomizeLevels () {
960 for (std::list<std::pair<interval, levelscript> >::iterator i = RandomLevel.begin(); i != RandomLevel.end(); ++i) {
961 int Index = i->first.Randomize();
962 Level[Index].Combine(i->second);
964 RandomLevel.clear();
968 void dungeonscript::Save (outputfile &SaveFile) const {
969 script::Save(SaveFile);
970 SaveFile << Level << RandomLevel;
974 void dungeonscript::Load (inputfile &SaveFile) {
975 script::Load(SaveFile);
976 SaveFile >> Level >> RandomLevel;
977 const levelscript *LevelDefault = GetLevelDefault();
978 if (LevelDefault) {
979 for (std::map<int, levelscript>::iterator i1 = Level.begin(); i1 != Level.end(); ++i1) i1->second.SetBase(LevelDefault);
980 for (std::list<std::pair<interval, levelscript> >::iterator i2 = RandomLevel.begin(); i2 != RandomLevel.end(); ++i2) i2->second.SetBase(LevelDefault);
985 const std::vector<std::pair<int, int> > &teamscript::GetRelation () const { return Relation; }
988 void teamscript::InitDataMap () {
989 INIT_ENTRY(KillEvilness);
990 INIT_ENTRY(Name);
994 void teamscript::ReadFrom (inputfile &SaveFile) {
995 festring Word;
997 SrcFile = SaveFile.GetFileName();
998 SrcLine = SaveFile.CurrentLine();
999 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in team script line %d!", SaveFile.TokenLine());
1000 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
1001 if (Word == "Relation") {
1002 std::pair<int, int> Rel;
1004 Rel.first = SaveFile.ReadNumber();
1005 Rel.second = SaveFile.ReadNumber();
1006 Relation.push_back(Rel);
1007 continue;
1009 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in team script line %d!", Word.CStr(), SaveFile.TokenLine());
1014 void teamscript::Save (outputfile &SaveFile) const {
1015 script::Save(SaveFile);
1016 SaveFile << Relation;
1020 void teamscript::Load (inputfile &SaveFile) {
1021 script::Load(SaveFile);
1022 SaveFile >> Relation;
1026 const std::list<std::pair<int, teamscript> > &gamescript::GetTeam () const { return Team; }
1027 const std::map<int, dungeonscript> &gamescript::GetDungeon () const { return Dungeon; }
1030 void gamescript::InitDataMap () {
1031 //INIT_ENTRY(Dungeons);
1032 //INIT_ENTRY(Teams);
1036 void gamescript::ReadFrom (inputfile &SaveFile) {
1037 festring Word;
1039 SrcFile = SaveFile.GetFileName();
1040 SrcLine = SaveFile.CurrentLine();
1041 SaveFile.setGetVarCB(game::ldrGetVar);
1042 for (SaveFile.ReadWord(Word, false); !SaveFile.Eof(); SaveFile.ReadWord(Word, false)) {
1043 if (Word == "Dungeon") {
1044 int Index = SaveFile.ReadNumber();
1046 if (Index < 0 || Index > 16383) ABORT("Invalid dungeon number (%d) in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1047 if (mDungeons < Index) mDungeons = Index;
1048 //fprintf(stderr, "dungeon: %d; mDungeons: %d\n", Index, mDungeons);
1049 std::pair<dungeonlist::iterator, bool> Return = Dungeon.insert(std::make_pair(Index, dungeonscript()));
1051 if (Return.second) Return.first->second.ReadFrom(SaveFile);
1052 else ABORT("Dungeon #%d defined again in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1053 continue;
1055 if (Word == "Team") {
1056 int Index = SaveFile.ReadNumber();
1058 if (Index < 0 || Index > 16383) ABORT("Invalid team number (%d) in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1059 for (teamlist::const_iterator it = Team.begin(); it != Team.end(); ++it) {
1060 if (it->first == Index) ABORT("Team #%d redefinition in file %s at line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1062 if (mTeams < Index+1) mTeams = Index+1;
1065 fprintf(stderr, "new team #%d\n", Index);
1066 fprintf(stderr, "defined teams:\n");
1067 for (teamlist::const_iterator it = Team.begin(); it != Team.end(); ++it) fprintf(stderr, " %d\n", it->first);
1071 Team.push_back(teamlistitem(Index, teamscript()));
1072 Team.back().second.ReadFrom(SaveFile);
1073 continue;
1075 if (Word == "Include") {
1076 Word = SaveFile.ReadWord();
1077 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1078 //fprintf(stderr, "loading: %s\n", Word.CStr());
1079 inputfile incf(game::GetGameDir()+"Script/"+Word, &game::GetGlobalValueMap());
1080 ReadFrom(incf);
1081 continue;
1083 if (Word == "Message") {
1084 Word = SaveFile.ReadWord();
1085 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1086 fprintf(stderr, "MESSAGE: %s\n", Word.CStr());
1087 continue;
1089 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in game script file %s line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine());
1094 void gamescript::RandomizeLevels () {
1095 for (std::map<int, dungeonscript>::iterator i = Dungeon.begin(); i != Dungeon.end(); ++i) i->second.RandomizeLevels();
1099 void gamescript::Save (outputfile &SaveFile) const {
1100 script::Save(SaveFile);
1101 SaveFile << Team << Dungeon;
1105 void gamescript::Load (inputfile &SaveFile) {
1106 script::Load(SaveFile);
1107 SaveFile >> Team >> Dungeon;
1111 outputfile &operator << (outputfile &SaveFile, const gamescript *Script) {
1112 Script->Save(SaveFile);
1113 return SaveFile;
1117 inputfile &operator >> (inputfile &SaveFile, gamescript *&Script) {
1118 Script = new gamescript;
1119 Script->Load(SaveFile);
1120 return SaveFile;
1124 void scriptsystem::Initialize () {
1125 posscript::InitDataMap();
1126 materialscript::InitDataMap();
1127 basecontentscript::InitDataMap();
1128 contentscript<character>::InitDataMap();
1129 contentscript<item>::InitDataMap();
1130 contentscript<glterrain>::InitDataMap();
1131 contentscript<olterrain>::InitDataMap();
1132 squarescript::InitDataMap();
1133 itemcontentmap::InitDataMap();
1134 charactercontentmap::InitDataMap();
1135 glterraincontentmap::InitDataMap();
1136 olterraincontentmap::InitDataMap();
1137 roomscript::InitDataMap();
1138 levelscript::InitDataMap();
1139 dungeonscript::InitDataMap();
1140 teamscript::InitDataMap();
1141 gamescript::InitDataMap();