3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
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
);
54 SrcFile
= Base
.SrcFile
;
55 SrcLine
= Base
.SrcLine
;
59 template <class type
> void scriptmember
<type
>::Save (outputfile
&SaveFile
) const {
62 SaveFile
<< SrcFile
<< SrcLine
;
69 template <class type
> void scriptmember
<type
>::Load (inputfile
&SaveFile
) {
72 SaveFile
>> SrcFile
>> SrcLine
;
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
;
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());
168 Data
->ReadFrom(SaveFile
);
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 () {
208 void posscript::ReadFrom (TextInput
&SaveFile
) {
209 static festring Word
;
211 SrcFile
= SaveFile
.GetFileName();
212 SrcLine
= SaveFile
.CurrentLine();
213 SaveFile
.ReadWord(Word
);
216 VectorHolder
.ReadFrom(SaveFile
);
217 } else if (Word
== "Random") {
219 FlagsHolder
.ReadFrom(SaveFile
);
220 } else if (Word
== "BoundedRandom") {
222 BordersHolder
.ReadFrom(SaveFile
);
223 FlagsHolder
.ReadFrom(SaveFile
);
228 void posscript::Save (outputfile
&SaveFile
) const {
229 script::Save(SaveFile
);
234 void posscript::Load (inputfile
&SaveFile
) {
235 script::Load(SaveFile
);
240 void materialscript::InitDataMap () {
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
);
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
);
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
;
302 SrcFile
= SaveFile
.GetFileName();
303 SrcLine
= SaveFile
.CurrentLine();
305 SaveFile
.ReadWord(Word
);
307 //mCode = SaveFile.ReadCode();
308 mCode
.collectSource(SaveFile
);
309 SaveFile
.skipBlanks();
310 int ch
= SaveFile
.GetChar();
311 if (ch
!= ';') SaveFile
.UngetChar(ch
);
316 if (Word
== "=" || Word
== ",") SaveFile
.ReadWord(Word
);
317 valuemap::const_iterator i
= game::GetGlobalValueMap().find(Word
);
318 if (i
!= game::GetGlobalValueMap().end()) {
319 if (!GetMainMaterial()) MainMaterialHolder
.Member
= new materialscript
;
320 MainMaterialHolder
.Member
->SetConfig(i
->second
);
321 SaveFile
.ReadWord(Word
);
322 i
= game::GetGlobalValueMap().find(Word
);
323 if (i
!= game::GetGlobalValueMap().end()) {
324 if (!GetSecondaryMaterial()) SecondaryMaterialHolder
.Member
= new materialscript
;
325 SecondaryMaterialHolder
.Member
->SetConfig(i
->second
);
326 SaveFile
.ReadWord(Word
);
329 if (Word
== "NaturalMaterialForm") {
331 ContentType
= NATURAL_MATERIAL_FORM
;
332 SaveFile
.ReadWord(Word
);
333 } else if (Word
== "Random") {
335 SaveFile
.ReadWord(Word
);
338 ContentType
= SearchCodeName(Word
);
339 if (ContentType
|| Word
== "0") SaveFile
.ReadWord(Word
);
340 else ABORT("Odd script term %s encountered in %s content script, file %s line %d!", Word
.CStr(), GetClassID(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
343 Config
= SaveFile
.ReadNumber();
344 SaveFile
.ReadWord(Word
);
349 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
350 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());
355 mCode = SaveFile.ReadCode();
356 SaveFile.ReadWord(Word);
359 if (Word
!= ";" && Word
!= ",") ABORT("Odd terminator %s encountered in %s content script, file %s line %d!", Word
.CStr(), GetClassID(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
364 scriptmemberbase
*basecontentscript::GetData (cchar
*String
) {
365 scriptmemberbase
*Return
= GetDataFromMap(GetDataMap(), String
);
366 return Return
? Return
: GetDataFromMap(DataMap
, String
);
370 void basecontentscript::Save (outputfile
&SaveFile
) const {
371 SaveFile
<< SrcFile
<< SrcLine
;
372 SaveDataMap(GetDataMap(), SaveFile
);
373 SaveDataMap(DataMap
, SaveFile
);
374 SaveFile
<< ContentType
;
375 SaveFile
.Put(!!Random
);
380 void basecontentscript::Load (inputfile
&SaveFile
) {
381 SaveFile
>> SrcFile
>> SrcLine
;
382 LoadDataMap(GetDataMap(), SaveFile
);
383 LoadDataMap(DataMap
, SaveFile
);
384 ContentType
= ReadType(uShort
, SaveFile
);
385 Random
= SaveFile
.Get();
390 template <class type
> type
*contentscripttemplate
<type
>::BasicInstantiate (int SpecialFlags
) const {
392 const typename
type::prototype
*Proto
= protocontainer
<type
>::GetProto(ContentType
);
393 if (!Proto
) ABORT("BasicInstantiate error for type '%s'!", getTypeName
<type
>().c_str());
394 const typename
type::database
*const *ConfigData
= Proto
->GetConfigData();
395 const materialscript
*MainMaterial
= GetMainMaterial();
396 const materialscript
*SecondaryMaterial
= GetSecondaryMaterial();
397 const typename
type::database
*DataBase
= *ConfigData
;
398 truth UseOverriddenMaterials
= false;
400 if (!Config
&& DataBase
->IsAbstract
) {
402 DataBase
= ConfigData
[1+RAND()%(Proto
->GetConfigSize()-1)];
403 if (DataBase
->AllowRandomInstantiation()) {
404 if (!(SpecialFlags
& NO_MATERIALS
) && MainMaterial
&& (!DataBase
->HasSecondaryMaterial
|| SecondaryMaterial
)) {
405 SpecialFlags
|= NO_MATERIALS
;
406 UseOverriddenMaterials
= true;
408 Instance
= Proto
->Spawn(DataBase
->Config
, SpecialFlags
|NO_PIC_UPDATE
);
412 if (!(SpecialFlags
& NO_MATERIALS
) && MainMaterial
&& (!DataBase
->HasSecondaryMaterial
|| SecondaryMaterial
)) {
413 SpecialFlags
|= NO_MATERIALS
;
414 UseOverriddenMaterials
= true;
416 Instance
= Proto
->Spawn(Config
, SpecialFlags
|NO_PIC_UPDATE
);
418 if (GetParameters() != NO_PARAMETERS
) Instance
->SetParameters(GetParameters());
419 if (UseOverriddenMaterials
) {
420 Instance
->InitMaterials(MainMaterial
, SecondaryMaterial
, false);
422 if (MainMaterial
) Instance
->ChangeMainMaterial(MainMaterial
->Instantiate(), SpecialFlags
|NO_PIC_UPDATE
);
423 if (SecondaryMaterial
) Instance
->ChangeSecondaryMaterial(SecondaryMaterial
->Instantiate(), SpecialFlags
|NO_PIC_UPDATE
);
425 if (!(SpecialFlags
& NO_PIC_UPDATE
)) Instance
->UpdatePictures();
430 /* Called by an inline function in script.h... */
432 template glterrain
*contentscripttemplate
<glterrain
>::BasicInstantiate (int) const;
434 template <class type
> int contentscripttemplate
<type
>::SearchCodeName (cfestring
&String
) const {
435 return protocontainer
<type
>::SearchCodeName(String
);
438 /* GCC 2.952 SUCKS!!! IT MUST BURN!!! */
440 template int contentscripttemplate
<character
>::SearchCodeName(cfestring
&) const;
441 template int contentscripttemplate
<item
>::SearchCodeName(cfestring
&) const;
442 template int contentscripttemplate
<glterrain
>::SearchCodeName(cfestring
&) const;
443 template int contentscripttemplate
<olterrain
>::SearchCodeName(cfestring
&) const;
445 cchar
*contentscript
<character
>::GetClassID () const { return "character"; }
446 cchar
*contentscript
<item
>::GetClassID () const { return "item"; }
447 cchar
*contentscript
<glterrain
>::GetClassID () const { return "glterrain"; }
448 cchar
*contentscript
<olterrain
>::GetClassID () const { return "olterrain"; }
451 void contentscript
<character
>::InitDataMap () {
452 INIT_ENTRY(Inventory
);
453 INIT_ENTRY(WayPoint
);
459 contentscript
<character
>::contentscript () : INIT(Team
, DEFAULT_TEAM
), INIT(Flags
, 0) {
463 character
*contentscript
<character
>::Instantiate (int SpecialFlags
) const {
464 character
*Instance
= contentscripttemplate
<character
>::BasicInstantiate(SpecialFlags
);
465 //fprintf(stderr, "instantiating character '%s'\n", Instance->GetNameSingular().CStr());
467 game::ClearEventData();
468 if (!game::RunCharAllowScript(Instance
, mCode
, "spawn")) {
469 //fprintf(stderr, "dropping character '%s'\n", Instance->GetNameSingular().CStr());
474 if (GetTeam() != DEFAULT_TEAM
) Instance
->SetTeam(game::GetTeam(GetTeam()));
475 const fearray
<contentscript
<item
> > *Inventory
= GetInventory();
476 if (Inventory
) Instance
->AddToInventory(*Inventory
, SpecialFlags
);
477 const fearray
<packv2
> *WayPoint
= GetWayPoint();
478 if (WayPoint
) Instance
->SetWayPoints(*WayPoint
);
479 Instance
->RestoreHP();
480 Instance
->RestoreStamina();
485 contentscript
<item
>::contentscript () :
486 INIT(Category
, ANY_CATEGORY
),
488 INIT(MaxPrice
, MAX_PRICE
),
489 INIT(Team
, DEFAULT_TEAM
),
490 INIT(SquarePosition
, CENTER
),
492 INIT(ConfigFlags
, 0),
493 INIT(SpoilPercentage
, 0),
494 INIT(Enchantment
, 0),
495 INIT(IsActive
, false)
500 void contentscript
<item
>::InitDataMap () {
501 INIT_ENTRY(ItemsInside
);
503 INIT_ENTRY(MinPrice
);
504 INIT_ENTRY(MaxPrice
);
505 INIT_ENTRY(LifeExpectancy
);
507 INIT_ENTRY(Category
);
508 INIT_ENTRY(SquarePosition
);
510 INIT_ENTRY(ConfigFlags
);
511 INIT_ENTRY(SpoilPercentage
);
512 INIT_ENTRY(Enchantment
);
513 INIT_ENTRY(IsActive
);
517 item
*contentscript
<item
>::InstantiateBasedOnMaterial (int MaterialConfig
, int SpecialFlags
) const {
518 if (ContentType
== NATURAL_MATERIAL_FORM
) {
519 const materialscript
*MainMaterial
= GetMainMaterial();
520 sLong Volume
= MainMaterial
&& MainMaterial
->GetVolume() ? MainMaterial
->GetVolume()->Randomize() : 0;
521 return material::CreateNaturalForm(MaterialConfig
, Volume
);
523 return Instantiate(SpecialFlags
);
527 item
*contentscript
<item
>::Instantiate (int SpecialFlags
) const {
528 int Chance
= GetChance();
531 if (Chance
!= 100 && Chance
<= RAND_N(100)) return 0;
534 Instance
= protosystem::BalancedCreateItem(0, GetMinPrice(), GetMaxPrice(), GetCategory(), SpecialFlags
, GetConfigFlags());
536 Instance
= contentscripttemplate
<item
>::BasicInstantiate(SpecialFlags
);
539 game::ClearEventData();
540 if (!game::RunItemAllowScript(Instance
, mCode
, "spawn")) {
541 //fprintf(stderr, "dropping character '%s'\n", Instance->GetNameSingular().CStr());
546 if (GetLifeExpectancy()) Instance
->SetLifeExpectancy(GetLifeExpectancy()->Min
, (GetLifeExpectancy()->Max
- GetLifeExpectancy()->Min
) + 1);
547 if (GetTeam() != DEFAULT_TEAM
) Instance
->SetTeam(GetTeam());
548 if (IsActive()) Instance
->SetIsActive(true);
549 if (GetEnchantment() != 0) Instance
->SetEnchantment(GetEnchantment());
550 const fearray
<contentscript
<item
> > *ItemsInside
= GetItemsInside();
551 if (ItemsInside
) Instance
->SetItemsInside(*ItemsInside
, SpecialFlags
);
552 if (GetSpoilPercentage() != 0) Instance
->SetSpoilPercentage(GetSpoilPercentage());
557 truth
IsValidScript (const fearray
<contentscript
<item
> > *Array
) {
558 for (uInt c
= 0; c
< Array
->Size
; ++c
) if (IsValidScript(&Array
->Data
[c
])) return true;
563 void contentscript
<glterrain
>::InitDataMap () {
564 INIT_ENTRY(IsInside
);
568 contentscript
<olterrain
>::contentscript () :
569 INIT(VisualEffects
, 0),
570 INIT(AttachedArea
, DEFAULT_ATTACHED_AREA
),
571 INIT(AttachedEntry
, DEFAULT_ATTACHED_ENTRY
)
576 void contentscript
<olterrain
>::InitDataMap () {
577 INIT_ENTRY(ItemsInside
);
579 INIT_ENTRY(VisualEffects
);
580 INIT_ENTRY(AttachedArea
);
581 INIT_ENTRY(AttachedEntry
);
585 olterrain
*contentscript
<olterrain
>::Instantiate (int SpecialFlags
) const {
586 if (!ContentType
) return 0;
587 olterrain
*Instance
= contentscripttemplate
<olterrain
>::BasicInstantiate(SpecialFlags
);
588 if (GetVisualEffects()) {
589 Instance
->SetVisualEffects(GetVisualEffects());
590 Instance
->UpdatePictures();
592 if (GetAttachedArea() != DEFAULT_ATTACHED_AREA
) Instance
->SetAttachedArea(GetAttachedArea());
593 if (GetAttachedEntry() != DEFAULT_ATTACHED_ENTRY
) Instance
->SetAttachedEntry(GetAttachedEntry());
594 cfestring
*Text
= GetText();
595 if (Text
) Instance
->SetText(*Text
);
596 const fearray
<contentscript
<item
> > *ItemsInside
= GetItemsInside();
597 if (ItemsInside
) Instance
->SetItemsInside(*ItemsInside
, SpecialFlags
);
602 squarescript::squarescript () : INIT(EntryIndex
, NO_ENTRY
), INIT(AttachRequired
, false) {
606 void squarescript::InitDataMap () {
607 INIT_ENTRY(Position
);
608 INIT_ENTRY(Character
);
610 INIT_ENTRY(GTerrain
);
611 INIT_ENTRY(OTerrain
);
613 INIT_ENTRY(EntryIndex
);
614 INIT_ENTRY(AttachRequired
);
618 void squarescript::ReadFrom (TextInput
&SaveFile
) {
619 static festring Word
;
621 SrcFile
= SaveFile
.GetFileName();
622 SrcLine
= SaveFile
.CurrentLine();
623 SaveFile
.ReadWord(Word
);
625 PositionHolder
.ReadFrom(SaveFile
);
626 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in square script line %d!", SaveFile
.TokenLine());
627 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
628 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in square script line %d!", Word
.CStr(), SaveFile
.TokenLine());
631 GTerrainHolder
.ReadFrom(SaveFile
);
632 OTerrainHolder
.ReadFrom(SaveFile
);
637 template <class type
, class contenttype
> contentmap
<type
, contenttype
>::contentmap() : ContentMap(0) {
641 template <class type
, class contenttype
> contentmap
<type
, contenttype
>::~contentmap
<type
, contenttype
> () {
642 delete [] ContentMap
;
646 template <class type
, class contenttype
> void contentmap
<type
, contenttype
>::InitDataMap () {
652 template <class type
, class contenttype
> void contentmap
<type
, contenttype
>::ReadFrom (TextInput
&SaveFile
) {
653 typedef std::map
<int, contenttype
> maptype
;
654 typedef typename
maptype::iterator mapiterator
;
655 festring Word1
, Word2
;
657 SrcFile
= SaveFile
.GetFileName();
658 SrcLine
= SaveFile
.CurrentLine();
659 if (ContentMap
) ABORT("Illegal %s content map redefinition on line %d!", protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
660 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in %s content map script line %d!", protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
661 SymbolMap
.insert(std::pair
<int, contenttype
>('.', contenttype()));
662 for (SaveFile
.ReadWord(Word1
); Word1
!= "}"; Word1
= SaveFile
.ReadWord()) {
663 if (Word1
== "Types") {
664 if (SaveFile
.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
665 for (SaveFile
.ReadWord(Word2
); Word2
!= "}"; Word2
= SaveFile
.ReadWord()) {
666 std::pair
<mapiterator
, bool> Return
= SymbolMap
.insert(std::pair
<int, contenttype
>(Word2
[0], contenttype()));
669 ReadData(Return
.first
->second
, SaveFile
);
671 ABORT("Symbol %c defined again in %s content map script line %d!", Word2
[0], protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
676 if (!ReadMember(SaveFile
, Word1
)) ABORT("Odd script term %s encountered in %s content script line %d!", Word1
.CStr(), protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
679 v2 Size
= *GetSize();
681 Alloc2D(ContentMap
, Size
.X
, Size
.Y
);
682 if (SaveFile
.ReadWord() != "{") ABORT("Missing bracket in %s content map script line %d!", protocontainer
<type
>::GetMainClassID(), SaveFile
.TokenLine());
683 for (int y
= 0; y
< Size
.Y
; ++y
) {
684 for (int x
= 0; x
< Size
.X
; ++x
) {
685 int Char
= SaveFile
.ReadLetter();
686 //typename std::map<int, contenttype>::iterator i = SymbolMap.find(Char);
687 auto i
= SymbolMap
.find(Char
);
688 if (i
!= SymbolMap
.end()) {
689 ContentMap
[x
][y
] = std::make_pair(Char
, &i
->second
);
692 ABORT("Illegal content '\\x%02x' in %s content map in file '%s' line %d!", (unsigned)Char
, protocontainer
<type
>::GetMainClassID(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
694 ABORT("Illegal content '%c' in %s content map in file '%s' line %d!", Char
, protocontainer
<type
>::GetMainClassID(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
699 if (SaveFile
.ReadWord() != "}") ABORT("Missing bracket in %s content map script in file '%s' line %d!", protocontainer
<type
>::GetMainClassID(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
703 template <class type
, class contenttype
> void contentmap
<type
, contenttype
>::Save (outputfile
&SaveFile
) const {
704 script::Save(SaveFile
);
705 SaveFile
<< SymbolMap
;
707 v2 Size
= *GetSize();
708 for (int y
= 0; y
< Size
.Y
; ++y
)
709 for (int x
= 0; x
< Size
.X
; ++x
)
710 SaveFile
<< char(ContentMap
[x
][y
].first
);
714 template <class type
, class contenttype
> void contentmap
<type
, contenttype
>::Load (inputfile
&SaveFile
) {
715 script::Load(SaveFile
);
716 SaveFile
>> SymbolMap
;
718 v2 Size
= *GetSize();
720 Alloc2D(ContentMap
, Size
.X
, Size
.Y
);
721 for (int y
= 0; y
< Size
.Y
; ++y
) {
722 for (int x
= 0; x
< Size
.X
; ++x
) {
723 int Char
= ReadType(char, SaveFile
);
725 ContentMap
[x
][y
] = std::make_pair(Char
, &SymbolMap
.find(Char
)->second
);
731 const std::list
<squarescript
> &roomscript::GetSquare () const { return Square
; }
734 void roomscript::InitDataMap () {
735 INIT_ENTRY(CharacterMap
);
737 INIT_ENTRY(GTerrainMap
);
738 INIT_ENTRY(OTerrainMap
);
739 INIT_ENTRY(WallSquare
);
740 INIT_ENTRY(FloorSquare
);
741 INIT_ENTRY(DoorSquare
);
744 INIT_ENTRY(AltarPossible
);
745 INIT_ENTRY(GenerateDoor
);
746 INIT_ENTRY(GenerateTunnel
);
747 INIT_ENTRY(DivineMaster
);
748 INIT_ENTRY(GenerateLanterns
);
750 INIT_ENTRY(GenerateFountains
);
751 INIT_ENTRY(AllowLockedDoors
);
752 INIT_ENTRY(AllowBoobyTrappedDoors
);
754 INIT_ENTRY(IsInside
);
755 INIT_ENTRY(GenerateWindows
);
756 INIT_ENTRY(UseFillSquareWalls
);
758 INIT_ENTRY(GenerateWards
);
759 INIT_ENTRY(AllowedDivineMasters
);
763 void roomscript::ReadFrom (TextInput
&SaveFile
) {
766 SrcFile
= SaveFile
.GetFileName();
767 SrcLine
= SaveFile
.CurrentLine();
768 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in room script line %d!", SaveFile
.TokenLine());
769 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
770 if (Word
== "Square") {
771 Square
.push_back(squarescript());
772 Square
.back().ReadFrom(SaveFile
);
775 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in room script line %d!", Word
.CStr(), SaveFile
.TokenLine());
780 void roomscript::Save (outputfile
&SaveFile
) const {
781 script::Save(SaveFile
);
786 void roomscript::Load (inputfile
&SaveFile
) {
787 script::Load(SaveFile
);
792 const std::list
<squarescript
> &levelscript::GetSquare () const { return Square
; }
793 const std::list
<roomscript
> &levelscript::GetRoom () const { return Room
; }
796 void levelscript::InitDataMap () {
797 INIT_ENTRY(RoomDefault
);
798 INIT_ENTRY(FillSquare
);
799 INIT_ENTRY(TunnelSquare
);
800 INIT_ENTRY(LevelMessage
);
804 INIT_ENTRY(GenerateMonsters
);
805 INIT_ENTRY(IsOnGround
);
806 INIT_ENTRY(EarthquakesAffectTunnels
);
807 INIT_ENTRY(TeamDefault
);
808 INIT_ENTRY(Description
);
809 INIT_ENTRY(LOSModifier
);
810 INIT_ENTRY(IgnoreDefaultSpecialSquares
);
811 INIT_ENTRY(DifficultyBase
);
812 INIT_ENTRY(DifficultyDelta
);
813 INIT_ENTRY(MonsterAmountBase
);
814 INIT_ENTRY(MonsterAmountDelta
);
815 INIT_ENTRY(MonsterGenerationIntervalBase
);
816 INIT_ENTRY(MonsterGenerationIntervalDelta
);
817 INIT_ENTRY(AutoReveal
);
818 INIT_ENTRY(ShortDescription
);
819 INIT_ENTRY(CanGenerateBone
);
820 INIT_ENTRY(ItemMinPriceBase
);
821 INIT_ENTRY(ItemMinPriceDelta
);
823 INIT_ENTRY(EnchantmentMinusChanceBase
);
824 INIT_ENTRY(EnchantmentMinusChanceDelta
);
825 INIT_ENTRY(EnchantmentPlusChanceBase
);
826 INIT_ENTRY(EnchantmentPlusChanceDelta
);
827 INIT_ENTRY(BackGroundType
);
828 INIT_ENTRY(IsCatacomb
);
829 INIT_ENTRY(EnterImage
);
830 INIT_ENTRY(EnterTextDisplacement
);
835 void levelscript::ReadFrom (TextInput
&SaveFile
) {
838 SrcFile
= SaveFile
.GetFileName();
839 SrcLine
= SaveFile
.CurrentLine();
840 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in level script line %d!", SaveFile
.TokenLine());
842 cv2
*Size
= static_cast<const levelscript
*>(Base
)->GetSize();
845 game::GetGlobalValueMap()["XSize"] = Size
->X
;
846 game::GetGlobalValueMap()["YSize"] = Size
->Y
;
849 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
850 if (Word
== "Square") {
851 Square
.push_back(squarescript());
852 Square
.back().ReadFrom(SaveFile
);
855 if (Word
== "Room") {
856 Room
.push_back(roomscript());
857 const roomscript
*RoomDefault
= GetRoomDefault();
858 if (RoomDefault
) Room
.back().SetBase(RoomDefault
);
859 Room
.back().ReadFrom(SaveFile
);
862 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in level script line %d!", Word
.CStr(), SaveFile
.TokenLine());
863 if (Word
== "Size") {
864 game::GetGlobalValueMap()["XSize"] = GetSize()->X
;
865 game::GetGlobalValueMap()["YSize"] = GetSize()->Y
;
869 const levelscript
*LevelBase
= static_cast<const levelscript
*>(Base
);
871 if (LevelBase
&& RoomDefaultHolder
.Member
) RoomDefaultHolder
.Member
->SetBase(LevelBase
->RoomDefaultHolder
.Member
);
872 valuemap::iterator i
= game::GetGlobalValueMap().find("XSize");
873 if (i
!= game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i
);
874 i
= game::GetGlobalValueMap().find("YSize");
875 if (i
!= game::GetGlobalValueMap().end()) game::GetGlobalValueMap().erase(i
);
879 void levelscript::Combine (levelscript
&Script
) {
880 if (!Base
) Base
= Script
.Base
;
881 Square
.splice(Square
.end(), Script
.Square
);
882 Room
.splice(Room
.end(), Script
.Room
);
883 for (std::list
<roomscript
>::iterator i1
= Room
.begin(); i1
!= Room
.end(); ++i1
) i1
->SetBase(GetRoomDefault());
884 for (datamap::const_iterator i2
= DataMap
.begin(); i2
!= DataMap
.end(); ++i2
) (this->*i2
->second
).Replace(Script
.*i2
->second
);
888 void levelscript::SetBase (const scriptwithbase
*What
) {
889 const levelscript
*LevelBase
= static_cast<const levelscript
*>(Base
= What
);
890 roomscript
*BaseRoomDefault
= LevelBase
->RoomDefaultHolder
.Member
;
892 if (BaseRoomDefault
) {
893 roomscript
*ThisRoomDefault
= RoomDefaultHolder
.Member
;
894 if (!ThisRoomDefault
) {
895 for (std::list
<roomscript
>::iterator i
= Room
.begin(); i
!= Room
.end(); ++i
) i
->SetBase(BaseRoomDefault
);
897 ThisRoomDefault
->SetBase(BaseRoomDefault
);
903 void levelscript::Save (outputfile
&SaveFile
) const {
904 script::Save(SaveFile
);
905 //if (Tag) SaveFile << Tag; else SaveFile << "";
906 SaveFile
<< Square
<< Room
;
910 void levelscript::Load (inputfile
&SaveFile
) {
911 script::Load(SaveFile
);
912 SaveFile
>> Square
>> Room
;
914 const roomscript
*RoomDefault
= GetRoomDefault();
915 if (RoomDefault
) for (std::list
<roomscript
>::iterator i
= Room
.begin(); i
!= Room
.end(); ++i
) i
->SetBase(RoomDefault
);
919 dungeonscript::dungeonscript () {
923 dungeonscript::~dungeonscript () {
927 const std::map
<int, levelscript
> &dungeonscript::GetLevel () const { return Level
; }
930 void dungeonscript::InitDataMap () {
931 INIT_ENTRY(LevelDefault
);
933 INIT_ENTRY(Description
);
934 INIT_ENTRY(ShortDescription
);
938 void dungeonscript::ReadFrom (TextInput
&SaveFile
) {
941 SrcFile
= SaveFile
.GetFileName();
942 SrcLine
= SaveFile
.CurrentLine();
943 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in dungeon script line %d!", SaveFile
.TokenLine());
944 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
945 if (Word
== "Level") {
946 int Index
= SaveFile
.ReadNumber();
947 std::pair
<std::map
<int, levelscript
>::iterator
, bool> Return
= Level
.insert(std::make_pair(Index
, levelscript()));
950 levelscript
&LS
= Return
.first
->second
;
951 const levelscript
*LevelDefault
= GetLevelDefault();
953 if (LevelDefault
) LS
.SetBase(LevelDefault
);
954 LS
.ReadFrom(SaveFile
);
956 ABORT("Level #%d defined again in dungeon script line %d!", Index
, SaveFile
.TokenLine());
960 if (Word
== "RandomLevel") {
962 ReadData(Interval
, SaveFile
);
963 RandomLevel
.push_back(std::make_pair(Interval
, levelscript()));
964 const levelscript
*LevelDefault
= GetLevelDefault();
966 if (LevelDefault
) RandomLevel
.back().second
.SetBase(LevelDefault
);
967 RandomLevel
.back().second
.ReadFrom(SaveFile
);
970 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in dungeon script line %d!", Word
.CStr(), SaveFile
.TokenLine());
975 void dungeonscript::RandomizeLevels () {
976 for (std::list
<std::pair
<interval
, levelscript
> >::iterator i
= RandomLevel
.begin(); i
!= RandomLevel
.end(); ++i
) {
977 int Index
= i
->first
.Randomize();
978 Level
[Index
].Combine(i
->second
);
984 void dungeonscript::Save (outputfile
&SaveFile
) const {
985 script::Save(SaveFile
);
986 SaveFile
<< Level
<< RandomLevel
;
990 void dungeonscript::Load (inputfile
&SaveFile
) {
991 script::Load(SaveFile
);
992 SaveFile
>> Level
>> RandomLevel
;
993 const levelscript
*LevelDefault
= GetLevelDefault();
995 for (std::map
<int, levelscript
>::iterator i1
= Level
.begin(); i1
!= Level
.end(); ++i1
) i1
->second
.SetBase(LevelDefault
);
996 for (std::list
<std::pair
<interval
, levelscript
> >::iterator i2
= RandomLevel
.begin(); i2
!= RandomLevel
.end(); ++i2
) i2
->second
.SetBase(LevelDefault
);
1001 const std::vector
<std::pair
<int, int> > &teamscript::GetRelation () const { return Relation
; }
1004 void teamscript::InitDataMap () {
1005 INIT_ENTRY(KillEvilness
);
1010 void teamscript::ReadFrom (TextInput
&SaveFile
) {
1013 SrcFile
= SaveFile
.GetFileName();
1014 SrcLine
= SaveFile
.CurrentLine();
1015 if (SaveFile
.ReadWord() != "{") ABORT("Bracket missing in team script line %d!", SaveFile
.TokenLine());
1016 for (SaveFile
.ReadWord(Word
); Word
!= "}"; SaveFile
.ReadWord(Word
)) {
1017 if (Word
== "Relation") {
1018 std::pair
<int, int> Rel
;
1020 Rel
.first
= SaveFile
.ReadNumber();
1021 Rel
.second
= SaveFile
.ReadNumber();
1022 Relation
.push_back(Rel
);
1025 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in team script line %d!", Word
.CStr(), SaveFile
.TokenLine());
1030 void teamscript::Save (outputfile
&SaveFile
) const {
1031 script::Save(SaveFile
);
1032 SaveFile
<< Relation
;
1036 void teamscript::Load (inputfile
&SaveFile
) {
1037 script::Load(SaveFile
);
1038 SaveFile
>> Relation
;
1042 const std::list
<std::pair
<int, teamscript
> > &gamescript::GetTeam () const { return Team
; }
1043 const std::map
<int, dungeonscript
> &gamescript::GetDungeon () const { return Dungeon
; }
1046 void gamescript::InitDataMap () {
1047 //INIT_ENTRY(Dungeons);
1048 //INIT_ENTRY(Teams);
1052 void gamescript::ReadFrom (TextInput
&SaveFile
) {
1055 SrcFile
= SaveFile
.GetFileName();
1056 SrcLine
= SaveFile
.CurrentLine();
1057 SaveFile
.setGetVarCB(game::ldrGetVar
);
1058 for (SaveFile
.ReadWord(Word
, false); !SaveFile
.Eof(); SaveFile
.ReadWord(Word
, false)) {
1059 if (Word
== "Dungeon") {
1060 int Index
= SaveFile
.ReadNumber();
1062 if (Index
< 0 || Index
> 16383) ABORT("Invalid dungeon number (%d) in game script file %s line %d!", Index
, SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1063 if (mDungeons
< Index
) mDungeons
= Index
;
1064 //fprintf(stderr, "dungeon: %d; mDungeons: %d\n", Index, mDungeons);
1065 std::pair
<dungeonlist::iterator
, bool> Return
= Dungeon
.insert(std::make_pair(Index
, dungeonscript()));
1067 if (Return
.second
) Return
.first
->second
.ReadFrom(SaveFile
);
1068 else ABORT("Dungeon #%d defined again in game script file %s line %d!", Index
, SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1071 if (Word
== "Team") {
1072 int Index
= SaveFile
.ReadNumber();
1074 if (Index
< 0 || Index
> 16383) ABORT("Invalid team number (%d) in game script file %s line %d!", Index
, SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1075 for (teamlist::const_iterator it
= Team
.begin(); it
!= Team
.end(); ++it
) {
1076 if (it
->first
== Index
) ABORT("Team #%d redefinition in file %s at line %d!", Index
, SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1078 if (mTeams
< Index
+1) mTeams
= Index
+1;
1081 fprintf(stderr, "new team #%d\n", Index);
1082 fprintf(stderr, "defined teams:\n");
1083 for (teamlist::const_iterator it = Team.begin(); it != Team.end(); ++it) fprintf(stderr, " %d\n", it->first);
1087 Team
.push_back(teamlistitem(Index
, teamscript()));
1088 Team
.back().second
.ReadFrom(SaveFile
);
1091 if (Word
== "Include") {
1092 Word
= SaveFile
.ReadWord();
1093 if (SaveFile
.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1094 //fprintf(stderr, "loading: %s\n", Word.CStr());
1095 TextInputFile
incf(inputfile::buildIncludeName(SaveFile
.GetFileName(), Word
), &game::GetGlobalValueMap());
1099 if (Word
== "Message") {
1100 Word
= SaveFile
.ReadWord();
1101 if (SaveFile
.ReadWord() != ";") ABORT("Invalid terminator in file %s at line %d!", SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1102 fprintf(stderr
, "MESSAGE: %s\n", Word
.CStr());
1105 if (!ReadMember(SaveFile
, Word
)) ABORT("Odd script term %s encountered in game script file %s line %d!", Word
.CStr(), SaveFile
.GetFileName().CStr(), SaveFile
.TokenLine());
1110 void gamescript::RandomizeLevels () {
1111 for (std::map
<int, dungeonscript
>::iterator i
= Dungeon
.begin(); i
!= Dungeon
.end(); ++i
) i
->second
.RandomizeLevels();
1115 void gamescript::Save (outputfile
&SaveFile
) const {
1116 script::Save(SaveFile
);
1117 SaveFile
<< Team
<< Dungeon
;
1121 void gamescript::Load (inputfile
&SaveFile
) {
1122 script::Load(SaveFile
);
1123 SaveFile
>> Team
>> Dungeon
;
1127 outputfile
&operator << (outputfile
&SaveFile
, const gamescript
*Script
) {
1128 Script
->Save(SaveFile
);
1133 inputfile
&operator >> (inputfile
&SaveFile
, gamescript
*&Script
) {
1134 Script
= new gamescript
;
1135 Script
->Load(SaveFile
);
1140 void scriptsystem::Initialize () {
1141 posscript::InitDataMap();
1142 materialscript::InitDataMap();
1143 basecontentscript::InitDataMap();
1144 contentscript
<character
>::InitDataMap();
1145 contentscript
<item
>::InitDataMap();
1146 contentscript
<glterrain
>::InitDataMap();
1147 contentscript
<olterrain
>::InitDataMap();
1148 squarescript::InitDataMap();
1149 itemcontentmap::InitDataMap();
1150 charactercontentmap::InitDataMap();
1151 glterraincontentmap::InitDataMap();
1152 olterraincontentmap::InitDataMap();
1153 roomscript::InitDataMap();
1154 levelscript::InitDataMap();
1155 dungeonscript::InitDataMap();
1156 teamscript::InitDataMap();
1157 gamescript::InitDataMap();