added simple 'condition scripts'
[k8-i-v-a-n.git] / src / game / script.cpp
blob861278ed106cc29544020cff7d47abdfb8b4d4ef
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;
36 template <class type> void scriptmember<type>::ReadFrom (inputfile &SaveFile) {
37 if (!Member) Member = new type;
38 ReadData(*Member, SaveFile);
42 template <class type> void scriptmember<type>::Replace (scriptmemberbase &Base) {
43 scriptmember<type> &Data = static_cast<scriptmember<type> &>(Base);
44 if (Data.Member) {
45 delete Member;
46 Member = Data.Member;
47 Data.Member = 0;
52 template <class type> void scriptmember<type>::Save(outputfile &SaveFile) const {
53 if (Member) {
54 SaveFile.Put(1);
55 SaveFile << *Member;
56 } else {
57 SaveFile.Put(0);
61 template <class type> void scriptmember<type>::Load(inputfile &SaveFile) {
62 if (SaveFile.Get()) {
63 Member = new type;
64 SaveFile >> *Member;
69 #define INST_SCRIPT_MEMBER(type)\
70 template void scriptmember< type >::ReadFrom(inputfile&);\
71 template void scriptmember< type >::Replace(scriptmemberbase&);\
72 template void scriptmember< type >::Save(outputfile&) const;\
73 template void scriptmember< type >::Load(inputfile&)
75 INST_SCRIPT_MEMBER(uChar);
76 INST_SCRIPT_MEMBER(short);
77 INST_SCRIPT_MEMBER(int);
78 //INST_SCRIPT_MEMBER(sLong); //k8:64
79 INST_SCRIPT_MEMBER(v2);
80 INST_SCRIPT_MEMBER(festring);
81 INST_SCRIPT_MEMBER(fearray<v2>);
82 INST_SCRIPT_MEMBER(rect);
83 INST_SCRIPT_MEMBER(interval);
84 INST_SCRIPT_MEMBER(region);
85 INST_SCRIPT_MEMBER(posscript);
86 INST_SCRIPT_MEMBER(materialscript);
87 INST_SCRIPT_MEMBER(squarescript);
88 INST_SCRIPT_MEMBER(roomscript);
89 INST_SCRIPT_MEMBER(levelscript);
90 INST_SCRIPT_MEMBER(contentscript<character>);
91 INST_SCRIPT_MEMBER(fearray<contentscript<item> >);
92 INST_SCRIPT_MEMBER(contentscript<glterrain>);
93 INST_SCRIPT_MEMBER(contentscript<olterrain>);
94 INST_SCRIPT_MEMBER(charactercontentmap);
95 INST_SCRIPT_MEMBER(itemcontentmap);
96 INST_SCRIPT_MEMBER(glterraincontentmap);
97 INST_SCRIPT_MEMBER(olterraincontentmap);
98 INST_SCRIPT_MEMBER(fearray<packv2>);
101 template <class type> void fastscriptmember<type>::ReadFrom(inputfile &SaveFile) {
102 ReadData(*&Member, SaveFile); // gcc 3.4.1 sucks
106 template <class type> void fastscriptmember<type>::Replace(scriptmemberbase &Base) {
107 fastscriptmember<type>& Data = static_cast<fastscriptmember<type> &>(Base);
108 Member = Data.Member;
112 template <class type> void fastscriptmember<type>::Save(outputfile &SaveFile) const {
113 SaveFile << Member;
117 template <class type> void fastscriptmember<type>::Load(inputfile &SaveFile) {
118 SaveFile >> *&Member; // gcc 3.4.1 sucks
122 #define INST_FAST_SCRIPT_MEMBER(type)\
123 template void fastscriptmember< type >::ReadFrom(inputfile&);\
124 template void fastscriptmember< type >::Replace(scriptmemberbase&);\
125 template void fastscriptmember< type >::Save(outputfile&) const;\
126 template void fastscriptmember< type >::Load(inputfile&)
128 INST_FAST_SCRIPT_MEMBER(char);
129 INST_FAST_SCRIPT_MEMBER(uChar);
130 INST_FAST_SCRIPT_MEMBER(int);
131 //INST_FAST_SCRIPT_MEMBER(sLong); //k8:64
132 INST_FAST_SCRIPT_MEMBER(uLong);
133 INST_FAST_SCRIPT_MEMBER(packv2);
136 truth script::ReadMember (inputfile &SaveFile, cfestring &Word) {
137 scriptmemberbase *Data = GetData(Word.CStr());
138 if (Data) {
139 Data->ReadFrom(SaveFile);
140 return true;
142 return false;
146 scriptmemberbase *script::GetDataFromMap (const datamap &DataMap, cchar *Identifier) {
147 datamap::const_iterator i = DataMap.find(Identifier);
148 return i != DataMap.end() ? &(this->*i->second) : 0;
152 void script::SaveDataMap (const datamap &DataMap, outputfile &SaveFile) const {
153 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Save(SaveFile);
157 void script::LoadDataMap (const datamap &DataMap, inputfile &SaveFile) {
158 for (datamap::const_iterator i = DataMap.begin(); i != DataMap.end(); ++i) (this->*i->second).Load(SaveFile);
162 template <class scriptmemberptr> void InitMember (script::datamap &DataMap, cchar *Identifier, scriptmemberptr DataMember) {
163 DataMap[Identifier] = reinterpret_cast<scriptmemberbase script::*>(DataMember);
166 #define INIT_ENTRY(name) InitMember(DataMap, #name, &scripttype::name##Holder)
168 #define INIT(name, value) name##Holder(value)
171 void posscript::InitDataMap () {
172 INIT_ENTRY(Vector);
173 INIT_ENTRY(Flags);
174 INIT_ENTRY(Borders);
178 void posscript::ReadFrom (inputfile &SaveFile) {
179 static festring Word;
180 SaveFile.ReadWord(Word);
182 if (Word == "Pos") {
183 Random = false;
184 VectorHolder.ReadFrom(SaveFile);
187 if (Word == "Random") {
188 Random = true;
189 FlagsHolder.ReadFrom(SaveFile);
192 if (Word == "BoundedRandom") {
193 Random = true;
194 BordersHolder.ReadFrom(SaveFile);
195 FlagsHolder.ReadFrom(SaveFile);
200 void posscript::Save (outputfile &SaveFile) const {
201 script::Save(SaveFile);
202 SaveFile << Random;
206 void posscript::Load (inputfile &SaveFile) {
207 script::Load(SaveFile);
208 SaveFile >> Random;
212 void materialscript::InitDataMap () {
213 INIT_ENTRY(Volume);
217 void materialscript::ReadFrom (inputfile &SaveFile) {
218 static festring Word;
220 SaveFile.ReadWord(Word);
221 if (Word == "=") SaveFile.ReadWord(Word);
222 if (Word == "0") {
223 Config = 0;
224 } else {
225 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
227 if (i != game::GetGlobalValueMap().end()) Config = i->second;
228 else ABORT("Unconfigured material script detected at line %d!", SaveFile.TellLine());
230 if (SaveFile.ReadWord() != "{") return;
231 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
232 if (!ReadMember(SaveFile, Word)) {
233 ABORT("Odd script term %s encountered in material script line %d!", Word.CStr(), SaveFile.TellLine());
239 material *materialscript::Instantiate () const {
240 return MAKE_MATERIAL(Config, GetVolume() ? GetVolume()->Randomize() : 0);
244 void materialscript::Save (outputfile &SaveFile) const {
245 script::Save(SaveFile);
246 SaveFile << (uShort)Config;
250 void materialscript::Load (inputfile &SaveFile) {
251 script::Load(SaveFile);
252 Config = 0;
253 uShort s2;
254 SaveFile >> s2;
255 Config = s2;
259 void basecontentscript::InitDataMap () {
260 INIT_ENTRY(MainMaterial);
261 INIT_ENTRY(SecondaryMaterial);
262 INIT_ENTRY(Parameters);
266 basecontentscript::basecontentscript () : ContentType(0), Random(false), Config(0), INIT(Parameters, NO_PARAMETERS) {
270 void basecontentscript::ReadFrom (inputfile &SaveFile) {
271 static festring Word;
273 SaveFile.ReadWord(Word);
274 if (Word == "[") {
275 mCode = SaveFile.ReadCode();
276 SaveFile.ReadWord(Word);
278 if (Word == "=" || Word == ",") SaveFile.ReadWord(Word);
279 valuemap::const_iterator i = game::GetGlobalValueMap().find(Word);
280 if (i != game::GetGlobalValueMap().end()) {
281 if (!GetMainMaterial()) MainMaterialHolder.Member = new materialscript;
282 MainMaterialHolder.Member->SetConfig(i->second);
283 SaveFile.ReadWord(Word);
284 i = game::GetGlobalValueMap().find(Word);
285 if (i != game::GetGlobalValueMap().end()) {
286 if (!GetSecondaryMaterial()) SecondaryMaterialHolder.Member = new materialscript;
287 SecondaryMaterialHolder.Member->SetConfig(i->second);
288 SaveFile.ReadWord(Word);
291 if (Word == "NaturalMaterialForm") {
292 Random = false;
293 ContentType = NATURAL_MATERIAL_FORM;
294 SaveFile.ReadWord(Word);
295 } else if (Word == "Random") {
296 Random = true;
297 SaveFile.ReadWord(Word);
298 } else {
299 Random = false;
300 ContentType = SearchCodeName(Word);
301 if (ContentType || Word == "0") SaveFile.ReadWord(Word);
302 else ABORT("Odd script term %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
304 if (Word == "(") {
305 Config = SaveFile.ReadNumber();
306 SaveFile.ReadWord(Word);
307 } else {
308 Config = 0;
310 if (Word == "{") {
311 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
312 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.TellLine());
314 } else {
315 if (Word == "[") {
316 mCode = SaveFile.ReadCode();
317 SaveFile.ReadWord(Word);
319 if (Word != ";" && Word != ",") ABORT("Odd terminator %s encountered in %s content script, file %s line %d!", Word.CStr(), GetClassID(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
324 scriptmemberbase *basecontentscript::GetData (cchar *String) {
325 scriptmemberbase *Return = GetDataFromMap(GetDataMap(), String);
326 return Return ? Return : GetDataFromMap(DataMap, String);
330 void basecontentscript::Save (outputfile &SaveFile) const {
331 SaveDataMap(GetDataMap(), SaveFile);
332 SaveDataMap(DataMap, SaveFile);
333 SaveFile << ContentType;
334 SaveFile.Put(!!Random);
335 SaveFile << Config;
339 void basecontentscript::Load (inputfile &SaveFile) {
340 LoadDataMap(GetDataMap(), SaveFile);
341 LoadDataMap(DataMap, SaveFile);
342 ContentType = ReadType<uShort>(SaveFile);
343 Random = SaveFile.Get();
344 SaveFile >> Config;
348 template <class type> type *contentscripttemplate<type>::BasicInstantiate (int SpecialFlags) const {
349 type *Instance = 0;
350 const typename type::prototype *Proto = protocontainer<type>::GetProto(ContentType);
351 const typename type::database *const *ConfigData = Proto->GetConfigData();
352 const materialscript *MainMaterial = GetMainMaterial();
353 const materialscript *SecondaryMaterial = GetSecondaryMaterial();
354 const typename type::database *DataBase = *ConfigData;
355 truth UseOverriddenMaterials = false;
357 if (!Config && DataBase->IsAbstract) {
358 while (!Instance) {
359 DataBase = ConfigData[1+RAND()%(Proto->GetConfigSize()-1)];
360 if (DataBase->AllowRandomInstantiation()) {
361 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
362 SpecialFlags |= NO_MATERIALS;
363 UseOverriddenMaterials = true;
365 Instance = Proto->Spawn(DataBase->Config, SpecialFlags|NO_PIC_UPDATE);
368 } else {
369 if (!(SpecialFlags & NO_MATERIALS) && MainMaterial && (!DataBase->HasSecondaryMaterial || SecondaryMaterial)) {
370 SpecialFlags |= NO_MATERIALS;
371 UseOverriddenMaterials = true;
373 Instance = Proto->Spawn(Config, SpecialFlags|NO_PIC_UPDATE);
375 if (GetParameters() != NO_PARAMETERS) Instance->SetParameters(GetParameters());
376 if (UseOverriddenMaterials) {
377 Instance->InitMaterials(MainMaterial, SecondaryMaterial, false);
378 } else {
379 if (MainMaterial) Instance->ChangeMainMaterial(MainMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
380 if (SecondaryMaterial) Instance->ChangeSecondaryMaterial(SecondaryMaterial->Instantiate(), SpecialFlags|NO_PIC_UPDATE);
382 if (!(SpecialFlags & NO_PIC_UPDATE)) Instance->UpdatePictures();
383 return Instance;
387 /* Called by an inline function in script.h... */
389 template glterrain *contentscripttemplate<glterrain>::BasicInstantiate (int) const;
391 template <class type> int contentscripttemplate<type>::SearchCodeName (cfestring &String) const {
392 return protocontainer<type>::SearchCodeName(String);
395 /* GCC 2.952 SUCKS!!! IT MUST BURN!!! */
397 template int contentscripttemplate<character>::SearchCodeName(cfestring &) const;
398 template int contentscripttemplate<item>::SearchCodeName(cfestring &) const;
399 template int contentscripttemplate<glterrain>::SearchCodeName(cfestring &) const;
400 template int contentscripttemplate<olterrain>::SearchCodeName(cfestring &) const;
402 cchar *contentscript<character>::GetClassID () const { return "character"; }
403 cchar *contentscript<item>::GetClassID () const { return "item"; }
404 cchar *contentscript<glterrain>::GetClassID () const { return "glterrain"; }
405 cchar *contentscript<olterrain>::GetClassID () const { return "olterrain"; }
408 void contentscript<character>::InitDataMap () {
409 INIT_ENTRY(Inventory);
410 INIT_ENTRY(WayPoint);
411 INIT_ENTRY(Team);
412 INIT_ENTRY(Flags);
416 contentscript<character>::contentscript () : INIT(Team, DEFAULT_TEAM), INIT(Flags, 0) {
420 character *contentscript<character>::Instantiate (int SpecialFlags) const {
421 character *Instance = contentscripttemplate<character>::BasicInstantiate(SpecialFlags);
423 //fprintf(stderr, "instantiating character '%s'\n", Instance->GetNameSingular().CStr());
426 if (Instance->GetNameSingular() == "vampire") {
427 delete Instance;
428 return 0;
432 if (!mCode.IsEmpty()) {
433 game::ClearEventData();
434 if (!game::RunAllowScriptStr(mCode)) {
435 //fprintf(stderr, "dropping character '%s'\n", Instance->GetNameSingular().CStr());
436 delete Instance;
437 return 0;
441 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(game::GetTeam(GetTeam()));
442 const fearray<contentscript<item> > *Inventory = GetInventory();
443 if (Inventory) Instance->AddToInventory(*Inventory, SpecialFlags);
444 const fearray<packv2> *WayPoint = GetWayPoint();
445 if (WayPoint) Instance->SetWayPoints(*WayPoint);
446 Instance->RestoreHP();
447 Instance->RestoreStamina();
448 return Instance;
452 contentscript<item>::contentscript () :
453 INIT(Category, ANY_CATEGORY),
454 INIT(MinPrice, 0),
455 INIT(MaxPrice, MAX_PRICE),
456 INIT(Team, DEFAULT_TEAM),
457 INIT(SquarePosition, CENTER),
458 INIT(Chance, 100),
459 INIT(ConfigFlags, 0),
460 INIT(SpoilPercentage, 0),
461 INIT(Enchantment, 0),
462 INIT(IsActive, false)
467 void contentscript<item>::InitDataMap () {
468 INIT_ENTRY(ItemsInside);
469 INIT_ENTRY(Times);
470 INIT_ENTRY(MinPrice);
471 INIT_ENTRY(MaxPrice);
472 INIT_ENTRY(LifeExpectancy);
473 INIT_ENTRY(Team);
474 INIT_ENTRY(Category);
475 INIT_ENTRY(SquarePosition);
476 INIT_ENTRY(Chance);
477 INIT_ENTRY(ConfigFlags);
478 INIT_ENTRY(SpoilPercentage);
479 INIT_ENTRY(Enchantment);
480 INIT_ENTRY(IsActive);
484 item *contentscript<item>::InstantiateBasedOnMaterial (int MaterialConfig, int SpecialFlags) const {
485 if (ContentType == NATURAL_MATERIAL_FORM) {
486 const materialscript *MainMaterial = GetMainMaterial();
487 sLong Volume = MainMaterial && MainMaterial->GetVolume() ? MainMaterial->GetVolume()->Randomize() : 0;
488 return material::CreateNaturalForm(MaterialConfig, Volume);
490 return Instantiate(SpecialFlags);
494 item *contentscript<item>::Instantiate (int SpecialFlags) const {
495 int Chance = GetChance();
496 item *Instance;
498 if (!mCode.IsEmpty()) {
499 game::ClearEventData();
500 if (!game::RunAllowScriptStr(mCode)) return 0;
503 if (Chance != 100 && Chance <= RAND_N(100)) return 0;
504 if (Random) {
505 Instance = protosystem::BalancedCreateItem(GetMinPrice(), GetMaxPrice(), GetCategory(), SpecialFlags, GetConfigFlags());
506 } else {
507 Instance = contentscripttemplate<item>::BasicInstantiate(SpecialFlags);
509 if (GetLifeExpectancy()) Instance->SetLifeExpectancy(GetLifeExpectancy()->Min, (GetLifeExpectancy()->Max - GetLifeExpectancy()->Min) + 1);
510 if (GetTeam() != DEFAULT_TEAM) Instance->SetTeam(GetTeam());
511 if (IsActive()) Instance->SetIsActive(true);
512 if (GetEnchantment() != 0) Instance->SetEnchantment(GetEnchantment());
513 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
514 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
515 if (GetSpoilPercentage() != 0) Instance->SetSpoilPercentage(GetSpoilPercentage());
516 return Instance;
520 truth IsValidScript (const fearray<contentscript<item> > *Array) {
521 for (uInt c = 0; c < Array->Size; ++c) if (IsValidScript(&Array->Data[c])) return true;
522 return false;
526 void contentscript<glterrain>::InitDataMap () {
527 INIT_ENTRY(IsInside);
531 contentscript<olterrain>::contentscript () :
532 INIT(VisualEffects, 0),
533 INIT(AttachedArea, DEFAULT_ATTACHED_AREA),
534 INIT(AttachedEntry, DEFAULT_ATTACHED_ENTRY)
539 void contentscript<olterrain>::InitDataMap () {
540 INIT_ENTRY(ItemsInside);
541 INIT_ENTRY(Text);
542 INIT_ENTRY(VisualEffects);
543 INIT_ENTRY(AttachedArea);
544 INIT_ENTRY(AttachedEntry);
548 olterrain *contentscript<olterrain>::Instantiate (int SpecialFlags) const {
549 if (!ContentType) return 0;
550 olterrain *Instance = contentscripttemplate<olterrain>::BasicInstantiate(SpecialFlags);
551 if (GetVisualEffects()) {
552 Instance->SetVisualEffects(GetVisualEffects());
553 Instance->UpdatePictures();
555 if (GetAttachedArea() != DEFAULT_ATTACHED_AREA) Instance->SetAttachedArea(GetAttachedArea());
556 if (GetAttachedEntry() != DEFAULT_ATTACHED_ENTRY) Instance->SetAttachedEntry(GetAttachedEntry());
557 cfestring *Text = GetText();
558 if (Text) Instance->SetText(*Text);
559 const fearray<contentscript<item> > *ItemsInside = GetItemsInside();
560 if (ItemsInside) Instance->SetItemsInside(*ItemsInside, SpecialFlags);
561 return Instance;
565 squarescript::squarescript () : INIT(EntryIndex, NO_ENTRY), INIT(AttachRequired, false) {
569 void squarescript::InitDataMap () {
570 INIT_ENTRY(Position);
571 INIT_ENTRY(Character);
572 INIT_ENTRY(Items);
573 INIT_ENTRY(GTerrain);
574 INIT_ENTRY(OTerrain);
575 INIT_ENTRY(Times);
576 INIT_ENTRY(EntryIndex);
577 INIT_ENTRY(AttachRequired);
581 void squarescript::ReadFrom (inputfile &SaveFile) {
582 static festring Word;
584 SaveFile.ReadWord(Word);
585 if (Word != "=") {
586 PositionHolder.ReadFrom(SaveFile);
587 if (SaveFile.ReadWord() != "{") ABORT("Bracket missing in square script line %d!", SaveFile.TellLine());
588 for (SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word)) {
589 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in square script line %d!", Word.CStr(), SaveFile.TellLine());
591 } else {
592 GTerrainHolder.ReadFrom(SaveFile);
593 OTerrainHolder.ReadFrom(SaveFile);
597 template <class type, class contenttype> contentmap<type, contenttype>::contentmap() : ContentMap(0) { }
599 template <class type, class contenttype> contentmap<type, contenttype>::~contentmap<type, contenttype>()
601 delete [] ContentMap;
604 template <class type, class contenttype> void contentmap<type, contenttype>::InitDataMap()
606 INIT_ENTRY(Size);
607 INIT_ENTRY(Pos);
610 template <class type, class contenttype> void contentmap<type, contenttype>::ReadFrom(inputfile& SaveFile)
612 typedef std::map<int, contenttype> maptype;
613 typedef typename maptype::iterator mapiterator;
615 if(ContentMap)
616 ABORT("Illegal %s content map redefinition on line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
618 if(SaveFile.ReadWord() != "{")
619 ABORT("Bracket missing in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
621 SymbolMap.insert(std::pair<int, contenttype>('.', contenttype()));
622 static festring Word1, Word2;
624 for(SaveFile.ReadWord(Word1); Word1 != "}"; Word1 = SaveFile.ReadWord())
626 if(Word1 == "Types")
628 if(SaveFile.ReadWord() != "{")
629 ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
631 for(SaveFile.ReadWord(Word2); Word2 != "}"; Word2 = SaveFile.ReadWord())
633 std::pair<mapiterator, bool> Return = SymbolMap.insert(std::pair<int, contenttype>(Word2[0], contenttype()));
635 if(Return.second)
636 ReadData(Return.first->second, SaveFile);
637 else
638 ABORT("Symbol %c defined again in %s content map script line %d!", Word2[0], protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
641 continue;
644 if(!ReadMember(SaveFile, Word1))
645 ABORT("Odd script term %s encountered in %s content script line %d!", Word1.CStr(), protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
648 v2 Size = *GetSize();
649 Alloc2D(ContentMap, Size.X, Size.Y);
651 if(SaveFile.ReadWord() != "{")
652 ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
654 for(int y = 0; y < Size.Y; ++y)
655 for(int x = 0; x < Size.X; ++x)
657 int Char = SaveFile.ReadLetter();
658 typename std::map<int, contenttype>::iterator i = SymbolMap.find(Char);
660 if(i != SymbolMap.end())
661 ContentMap[x][y] = std::make_pair(Char, &i->second);
662 else
663 ABORT("Illegal content %c in %s content map line %d!", Char, protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
666 if(SaveFile.ReadWord() != "}")
667 ABORT("Missing bracket in %s content map script line %d!", protocontainer<type>::GetMainClassID(), SaveFile.TellLine());
670 template <class type, class contenttype> void contentmap<type, contenttype>::Save(outputfile& SaveFile) const
672 script::Save(SaveFile);
673 SaveFile << SymbolMap;
674 v2 Size = *GetSize();
676 for(int y = 0; y < Size.Y; ++y)
677 for(int x = 0; x < Size.X; ++x)
678 SaveFile << char(ContentMap[x][y].first);
681 template <class type, class contenttype> void contentmap<type, contenttype>::Load(inputfile& SaveFile)
683 script::Load(SaveFile);
684 SaveFile >> SymbolMap;
685 v2 Size = *GetSize();
686 Alloc2D(ContentMap, Size.X, Size.Y);
688 for(int y = 0; y < Size.Y; ++y)
689 for(int x = 0; x < Size.X; ++x)
691 int Char = ReadType<char>(SaveFile);
692 ContentMap[x][y] = std::make_pair(Char, &SymbolMap.find(Char)->second);
696 const std::list<squarescript>& roomscript::GetSquare() const { return Square; }
698 void roomscript::InitDataMap()
700 INIT_ENTRY(CharacterMap);
701 INIT_ENTRY(ItemMap);
702 INIT_ENTRY(GTerrainMap);
703 INIT_ENTRY(OTerrainMap);
704 INIT_ENTRY(WallSquare);
705 INIT_ENTRY(FloorSquare);
706 INIT_ENTRY(DoorSquare);
707 INIT_ENTRY(Size);
708 INIT_ENTRY(Pos);
709 INIT_ENTRY(AltarPossible);
710 INIT_ENTRY(GenerateDoor);
711 INIT_ENTRY(GenerateTunnel);
712 INIT_ENTRY(DivineMaster);
713 INIT_ENTRY(GenerateLanterns);
714 INIT_ENTRY(Type);
715 INIT_ENTRY(GenerateFountains);
716 INIT_ENTRY(AllowLockedDoors);
717 INIT_ENTRY(AllowBoobyTrappedDoors);
718 INIT_ENTRY(Shape);
719 INIT_ENTRY(IsInside);
720 INIT_ENTRY(GenerateWindows);
721 INIT_ENTRY(UseFillSquareWalls);
722 INIT_ENTRY(Flags);
723 INIT_ENTRY(GenerateWards);
726 void roomscript::ReadFrom(inputfile& SaveFile)
728 if(SaveFile.ReadWord() != "{")
729 ABORT("Bracket missing in room script line %d!", SaveFile.TellLine());
731 static festring Word;
733 for(SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word))
735 if(Word == "Square")
737 Square.push_back(squarescript());
738 Square.back().ReadFrom(SaveFile);
739 continue;
742 if(!ReadMember(SaveFile, Word))
743 ABORT("Odd script term %s encountered in room script line %d!", Word.CStr(), SaveFile.TellLine());
747 void roomscript::Save(outputfile& SaveFile) const
749 script::Save(SaveFile);
750 SaveFile << Square;
753 void roomscript::Load(inputfile& SaveFile)
755 script::Load(SaveFile);
756 SaveFile >> Square;
759 const std::list<squarescript>& levelscript::GetSquare() const { return Square; }
760 const std::list<roomscript>& levelscript::GetRoom() const { return Room; }
762 void levelscript::InitDataMap()
764 INIT_ENTRY(RoomDefault);
765 INIT_ENTRY(FillSquare);
766 INIT_ENTRY(TunnelSquare);
767 INIT_ENTRY(LevelMessage);
768 INIT_ENTRY(Size);
769 INIT_ENTRY(Items);
770 INIT_ENTRY(Rooms);
771 INIT_ENTRY(GenerateMonsters);
772 INIT_ENTRY(IsOnGround);
773 INIT_ENTRY(TeamDefault);
774 INIT_ENTRY(Description);
775 INIT_ENTRY(LOSModifier);
776 INIT_ENTRY(IgnoreDefaultSpecialSquares);
777 INIT_ENTRY(DifficultyBase);
778 INIT_ENTRY(DifficultyDelta);
779 INIT_ENTRY(MonsterAmountBase);
780 INIT_ENTRY(MonsterAmountDelta);
781 INIT_ENTRY(MonsterGenerationIntervalBase);
782 INIT_ENTRY(MonsterGenerationIntervalDelta);
783 INIT_ENTRY(AutoReveal);
784 INIT_ENTRY(ShortDescription);
785 INIT_ENTRY(CanGenerateBone);
786 INIT_ENTRY(ItemMinPriceBase);
787 INIT_ENTRY(ItemMinPriceDelta);
788 INIT_ENTRY(Type);
789 INIT_ENTRY(EnchantmentMinusChanceBase);
790 INIT_ENTRY(EnchantmentMinusChanceDelta);
791 INIT_ENTRY(EnchantmentPlusChanceBase);
792 INIT_ENTRY(EnchantmentPlusChanceDelta);
793 INIT_ENTRY(BackGroundType);
794 INIT_ENTRY(IsCatacomb);
795 INIT_ENTRY(EnterImage);
796 INIT_ENTRY(EnterTextDisplacement);
799 void levelscript::ReadFrom(inputfile& SaveFile)
801 if(SaveFile.ReadWord() != "{")
802 ABORT("Bracket missing in level script line %d!", SaveFile.TellLine());
804 if(Base)
806 cv2* Size = static_cast<const levelscript*>(Base)->GetSize();
808 if(Size)
810 game::GetGlobalValueMap()["XSize"] = Size->X;
811 game::GetGlobalValueMap()["YSize"] = Size->Y;
815 static festring Word;
817 for(SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word))
819 if(Word == "Square")
821 Square.push_back(squarescript());
822 Square.back().ReadFrom(SaveFile);
823 continue;
826 if(Word == "Room")
828 Room.push_back(roomscript());
829 const roomscript* RoomDefault = GetRoomDefault();
831 if(RoomDefault)
832 Room.back().SetBase(RoomDefault);
834 Room.back().ReadFrom(SaveFile);
835 continue;
838 if(!ReadMember(SaveFile, Word))
839 ABORT("Odd script term %s encountered in level script line %d!", Word.CStr(), SaveFile.TellLine());
841 if(Word == "Size")
843 game::GetGlobalValueMap()["XSize"] = GetSize()->X;
844 game::GetGlobalValueMap()["YSize"] = GetSize()->Y;
848 const levelscript* LevelBase = static_cast<const levelscript*>(Base);
850 if(LevelBase && RoomDefaultHolder.Member)
851 RoomDefaultHolder.Member->SetBase(LevelBase->RoomDefaultHolder.Member);
853 valuemap::iterator i = game::GetGlobalValueMap().find("XSize");
855 if(i != game::GetGlobalValueMap().end())
856 game::GetGlobalValueMap().erase(i);
858 i = game::GetGlobalValueMap().find("YSize");
860 if(i != game::GetGlobalValueMap().end())
861 game::GetGlobalValueMap().erase(i);
864 void levelscript::Combine(levelscript& Script)
866 if(!Base)
867 Base = Script.Base;
869 Square.splice(Square.end(), Script.Square);
870 Room.splice(Room.end(), Script.Room);
872 for(std::list<roomscript>::iterator i1 = Room.begin(); i1 != Room.end(); ++i1)
873 i1->SetBase(GetRoomDefault());
875 for(datamap::const_iterator i2 = DataMap.begin(); i2 != DataMap.end(); ++i2)
876 (this->*i2->second).Replace(Script.*i2->second);
879 void levelscript::SetBase(const scriptwithbase* What)
881 const levelscript* LevelBase = static_cast<const levelscript*>(Base = What);
882 roomscript* BaseRoomDefault = LevelBase->RoomDefaultHolder.Member;
884 if(BaseRoomDefault)
886 roomscript* ThisRoomDefault = RoomDefaultHolder.Member;
888 if(!ThisRoomDefault)
889 for(std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i)
890 i->SetBase(BaseRoomDefault);
891 else
892 ThisRoomDefault->SetBase(BaseRoomDefault);
896 void levelscript::Save(outputfile& SaveFile) const
898 script::Save(SaveFile);
899 SaveFile << Square << Room;
902 void levelscript::Load(inputfile& SaveFile)
904 script::Load(SaveFile);
905 SaveFile >> Square >> Room;
906 const roomscript* RoomDefault = GetRoomDefault();
908 if(RoomDefault)
909 for(std::list<roomscript>::iterator i = Room.begin(); i != Room.end(); ++i)
910 i->SetBase(RoomDefault);
913 dungeonscript::dungeonscript() { }
914 dungeonscript::~dungeonscript() { }
915 const std::map<int, levelscript>& dungeonscript::GetLevel() const { return Level; }
917 void dungeonscript::InitDataMap()
919 INIT_ENTRY(LevelDefault);
920 INIT_ENTRY(Levels);
921 INIT_ENTRY(Description);
922 INIT_ENTRY(ShortDescription);
925 void dungeonscript::ReadFrom(inputfile& SaveFile)
927 if(SaveFile.ReadWord() != "{")
928 ABORT("Bracket missing in dungeon script line %d!", SaveFile.TellLine());
930 static festring Word;
932 for(SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word))
934 if(Word == "Level")
936 int Index = SaveFile.ReadNumber();
937 std::pair<std::map<int, levelscript>::iterator, bool> Return = Level.insert(std::make_pair(Index, levelscript()));
939 if(Return.second)
941 levelscript& LS = Return.first->second;
942 const levelscript* LevelDefault = GetLevelDefault();
944 if(LevelDefault)
945 LS.SetBase(LevelDefault);
947 LS.ReadFrom(SaveFile);
949 else
950 ABORT("Level #%d defined again in dungeon script line %d!", Index, SaveFile.TellLine());
952 continue;
955 if(Word == "RandomLevel")
957 interval Interval;
958 ReadData(Interval, SaveFile);
959 RandomLevel.push_back(std::make_pair(Interval, levelscript()));
960 const levelscript* LevelDefault = GetLevelDefault();
962 if(LevelDefault)
963 RandomLevel.back().second.SetBase(LevelDefault);
965 RandomLevel.back().second.ReadFrom(SaveFile);
966 continue;
969 if(!ReadMember(SaveFile, Word))
970 ABORT("Odd script term %s encountered in dungeon script line %d!", Word.CStr(), SaveFile.TellLine());
974 void dungeonscript::RandomizeLevels()
976 for(std::list<std::pair<interval, levelscript> >::iterator i = RandomLevel.begin(); i != RandomLevel.end(); ++i)
978 int Index = i->first.Randomize();
979 Level[Index].Combine(i->second);
982 RandomLevel.clear();
985 void dungeonscript::Save(outputfile& SaveFile) const
987 script::Save(SaveFile);
988 SaveFile << Level << RandomLevel;
991 void dungeonscript::Load(inputfile& SaveFile)
993 script::Load(SaveFile);
994 SaveFile >> Level >> RandomLevel;
995 const levelscript* LevelDefault = GetLevelDefault();
997 if(LevelDefault)
999 for(std::map<int, levelscript>::iterator i1 = Level.begin(); i1 != Level.end(); ++i1)
1000 i1->second.SetBase(LevelDefault);
1002 for(std::list<std::pair<interval, levelscript> >::iterator i2 = RandomLevel.begin(); i2 != RandomLevel.end(); ++i2)
1003 i2->second.SetBase(LevelDefault);
1007 const std::vector<std::pair<int, int> >& teamscript::GetRelation() const { return Relation; }
1009 void teamscript::InitDataMap()
1011 INIT_ENTRY(KillEvilness);
1014 void teamscript::ReadFrom(inputfile& SaveFile)
1016 if(SaveFile.ReadWord() != "{")
1017 ABORT("Bracket missing in team script line %d!", SaveFile.TellLine());
1019 static festring Word;
1021 for(SaveFile.ReadWord(Word); Word != "}"; SaveFile.ReadWord(Word))
1023 if(Word == "Relation")
1025 std::pair<int, int> Rel;
1026 Rel.first = SaveFile.ReadNumber();
1027 Rel.second = SaveFile.ReadNumber();
1028 Relation.push_back(Rel);
1029 continue;
1032 if(!ReadMember(SaveFile, Word))
1033 ABORT("Odd script term %s encountered in team script line %d!", Word.CStr(), SaveFile.TellLine());
1037 void teamscript::Save(outputfile& SaveFile) const
1039 script::Save(SaveFile);
1040 SaveFile << Relation;
1043 void teamscript::Load(inputfile& SaveFile)
1045 script::Load(SaveFile);
1046 SaveFile >> Relation;
1049 const std::list<std::pair<int, teamscript> >& gamescript::GetTeam() const { return Team; }
1050 const std::map<int, dungeonscript>& gamescript::GetDungeon() const { return Dungeon; }
1053 void gamescript::InitDataMap () {
1054 INIT_ENTRY(Dungeons);
1055 INIT_ENTRY(Teams);
1059 void gamescript::ReadFrom (inputfile &SaveFile) {
1060 festring Word;
1061 SaveFile.setGetVarCB(game::ldrGetVar);
1062 for (SaveFile.ReadWord(Word, false); !SaveFile.Eof(); SaveFile.ReadWord(Word, false)) {
1063 if (Word == "Dungeon") {
1064 int Index = SaveFile.ReadNumber();
1065 std::pair<std::map<int, dungeonscript>::iterator, bool> Return = Dungeon.insert(std::make_pair(Index, dungeonscript()));
1066 if (Return.second) Return.first->second.ReadFrom(SaveFile);
1067 else ABORT("Dungeon #%d defined again in game script file %s line %d!", Index, SaveFile.GetFileName().CStr(), SaveFile.TellLine());
1068 continue;
1070 if (Word == "Team") {
1071 int Index = SaveFile.ReadNumber();
1072 Team.push_back(std::pair<int, teamscript>(Index, teamscript()));
1073 Team.back().second.ReadFrom(SaveFile);
1074 continue;
1076 if (Word == "Include") {
1077 Word = SaveFile.ReadWord();
1078 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TellLine());
1079 //fprintf(stderr, "loading: %s\n", Word.CStr());
1080 inputfile incf(game::GetGameDir()+"Script/"+Word, &game::GetGlobalValueMap());
1081 ReadFrom(incf);
1082 continue;
1084 if (Word == "Message") {
1085 Word = SaveFile.ReadWord();
1086 if (SaveFile.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile.GetFileName().CStr(), SaveFile.TellLine());
1087 fprintf(stderr, "MESSAGE: %s\n", Word.CStr());
1088 continue;
1090 if (!ReadMember(SaveFile, Word)) ABORT("Odd script term %s encountered in game script file %s line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
1095 void gamescript::RandomizeLevels()
1097 for(std::map<int, dungeonscript>::iterator i = Dungeon.begin(); i != Dungeon.end(); ++i)
1098 i->second.RandomizeLevels();
1101 void gamescript::Save(outputfile& SaveFile) const
1103 script::Save(SaveFile);
1104 SaveFile << Team << Dungeon;
1107 void gamescript::Load(inputfile& SaveFile)
1109 script::Load(SaveFile);
1110 SaveFile >> Team >> Dungeon;
1113 outputfile& operator<<(outputfile& SaveFile, const gamescript* Script)
1115 Script->Save(SaveFile);
1116 return SaveFile;
1119 inputfile& operator>>(inputfile& SaveFile, gamescript*& Script)
1121 Script = new gamescript;
1122 Script->Load(SaveFile);
1123 return SaveFile;
1126 void scriptsystem::Initialize()
1128 posscript::InitDataMap();
1129 materialscript::InitDataMap();
1130 basecontentscript::InitDataMap();
1131 contentscript<character>::InitDataMap();
1132 contentscript<item>::InitDataMap();
1133 contentscript<glterrain>::InitDataMap();
1134 contentscript<olterrain>::InitDataMap();
1135 squarescript::InitDataMap();
1136 itemcontentmap::InitDataMap();
1137 charactercontentmap::InitDataMap();
1138 glterraincontentmap::InitDataMap();
1139 olterraincontentmap::InitDataMap();
1140 roomscript::InitDataMap();
1141 levelscript::InitDataMap();
1142 dungeonscript::InitDataMap();
1143 teamscript::InitDataMap();
1144 gamescript::InitDataMap();