1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "Spellbook.h"
24 #include "Interface.h"
25 #include "Projectile.h"
28 #include "Scriptable/Actor.h"
32 static bool SBInitialized
= false;
33 static int NUM_BOOK_TYPES
= 3;
34 static bool IWD2Style
= false;
36 //spell header-->spell book type conversion (iwd2 is different)
37 static const int spelltypes
[NUM_SPELL_TYPES
]={
38 IE_SPELL_TYPE_INNATE
, IE_SPELL_TYPE_WIZARD
, IE_SPELL_TYPE_PRIEST
,
39 IE_SPELL_TYPE_WIZARD
, IE_SPELL_TYPE_INNATE
, IE_SPELL_TYPE_SONG
42 Spellbook::Spellbook()
45 InitializeSpellbook();
47 spells
= new std::vector
<CRESpellMemorization
*> [NUM_BOOK_TYPES
];
50 void Spellbook::InitializeSpellbook()
54 if (core
->HasFeature(GF_HAS_SPELLLIST
)) {
55 NUM_BOOK_TYPES
=NUM_IWD2_SPELLTYPES
; //iwd2 spell types
57 NUM_BOOK_TYPES
=NUM_SPELLTYPES
; //bg/pst/iwd1 spell types
63 void Spellbook::ReleaseMemory()
68 Spellbook::~Spellbook()
70 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
71 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
73 FreeSpellPage( spells
[i
][j
] );
82 void Spellbook::FreeSpellPage(CRESpellMemorization
*sm
)
84 size_t i
= sm
->known_spells
.size();
86 delete sm
->known_spells
[i
];
88 i
= sm
->memorized_spells
.size();
90 delete sm
->memorized_spells
[i
];
95 //ITEM, SPPR, SPWI, SPIN, SPCL
96 int sections
[]={3,0,1,2,2};
100 bool Spellbook::HaveSpell(int spellid
, ieDword flags
)
102 int type
= spellid
/1000;
106 type
= sections
[type
];
107 if (type
>= NUM_BOOK_TYPES
) {
110 spellid
= spellid
% 1000;
112 for (unsigned int j
= 0; j
< GetSpellLevelCount(type
); j
++) {
113 CRESpellMemorization
* sm
= spells
[type
][j
];
114 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
115 CREMemorizedSpell
* ms
= sm
->memorized_spells
[k
];
117 if (atoi(ms
->SpellResRef
+4)==spellid
) {
118 if (flags
&HS_DEPLETE
) {
119 if (DepleteSpell(ms
) && (sorcerer
& (1<<type
) ) ) {
131 bool Spellbook::KnowSpell(int spellid
)
133 int type
= spellid
/1000;
137 type
= sections
[type
];
138 if (type
>= NUM_BOOK_TYPES
) {
141 spellid
= spellid
% 1000;
143 for (unsigned int j
= 0; j
< GetSpellLevelCount(type
); j
++) {
144 CRESpellMemorization
* sm
= spells
[type
][j
];
145 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
146 CREKnownSpell
* ks
= sm
->known_spells
[k
];
147 if (atoi(ks
->SpellResRef
+4)==spellid
) {
155 //if resref=="" then it is a knownanyspell
156 bool Spellbook::KnowSpell(const char *resref
)
158 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
159 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
160 CRESpellMemorization
* sm
= spells
[i
][j
];
161 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
162 CREKnownSpell
* ks
= sm
->known_spells
[k
];
163 if (resref
[0] && stricmp(ks
->SpellResRef
, resref
) ) {
173 //if resref=="" then it is a haveanyspell
174 bool Spellbook::HaveSpell(const char *resref
, ieDword flags
)
176 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
177 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
178 CRESpellMemorization
* sm
= spells
[i
][j
];
179 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
180 CREMemorizedSpell
* ms
= sm
->memorized_spells
[k
];
182 if (resref
[0] && stricmp(ms
->SpellResRef
, resref
) ) {
185 if (flags
&HS_DEPLETE
) {
186 if (DepleteSpell(ms
) && (sorcerer
& (1<<i
) ) ) {
198 int Spellbook::GetTypes() const
200 return NUM_BOOK_TYPES
;
203 bool Spellbook::IsIWDSpellBook() const
208 unsigned int Spellbook::GetSpellLevelCount(int type
) const
210 return (unsigned int) spells
[type
].size();
213 unsigned int Spellbook::GetTotalPageCount() const
215 unsigned int total
= 0;
216 for (int type
= 0; type
< NUM_BOOK_TYPES
; type
++) {
217 total
+= GetSpellLevelCount(type
);
222 unsigned int Spellbook::GetTotalKnownSpellsCount() const
224 unsigned int total
= 0;
225 for (int type
= 0; type
< NUM_BOOK_TYPES
; type
++) {
226 unsigned int level
= GetSpellLevelCount(type
);
228 total
+= GetKnownSpellsCount(type
, level
);
234 unsigned int Spellbook::GetTotalMemorizedSpellsCount() const
236 unsigned int total
= 0;
237 for (int type
= 0; type
< NUM_BOOK_TYPES
; type
++) {
238 unsigned int level
= GetSpellLevelCount(type
);
240 total
+= GetMemorizedSpellsCount(type
, level
);
246 // returns the number of known spells of level (level+1)
247 unsigned int Spellbook::GetKnownSpellsCount(int type
, unsigned int level
) const
249 if (type
>= NUM_BOOK_TYPES
|| level
>= GetSpellLevelCount(type
))
251 return (unsigned int) spells
[type
][level
]->known_spells
.size();
254 //called when a spell was removed from spellbook
255 //this one purges all instances of known spells of the same name from memory
256 void Spellbook::RemoveMemorization(CRESpellMemorization
* sm
, const ieResRef ResRef
)
258 std::vector
< CREMemorizedSpell
* >::iterator ms
;
260 for (ms
= sm
->memorized_spells
.begin(); ms
!= sm
->memorized_spells
.end(); ms
++) {
261 if (strnicmp(ResRef
, (*ms
)->SpellResRef
, sizeof(ieResRef
) ) ) {
265 sm
->memorized_spells
.erase(ms
);
270 //removes one instance of spell (from creknownspell)
271 bool Spellbook::RemoveSpell(CREKnownSpell
* spell
)
273 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
274 std::vector
< CRESpellMemorization
* >::iterator sm
;
275 for (sm
= spells
[i
].begin(); sm
!= spells
[i
].end(); sm
++) {
276 std::vector
< CREKnownSpell
* >::iterator ks
;
277 for (ks
= (*sm
)->known_spells
.begin(); ks
!= (*sm
)->known_spells
.end(); ks
++) {
281 memcpy(ResRef
, (*ks
)->SpellResRef
, sizeof(ieResRef
) );
283 (*sm
)->known_spells
.erase(ks
);
284 RemoveMemorization(*sm
, ResRef
);
295 //removes all instances of spellid (probably not needed)
296 void Spellbook::RemoveSpell(int spellid
)
298 int type
= spellid
/1000;
302 type
= sections
[type
];
303 if (type
>= NUM_BOOK_TYPES
) {
306 spellid
= spellid
% 1000;
307 std::vector
< CRESpellMemorization
* >::iterator sm
;
308 for (sm
= spells
[type
].begin(); sm
!= spells
[type
].end(); sm
++) {
309 std::vector
< CREKnownSpell
* >::iterator ks
;
311 for (ks
= (*sm
)->known_spells
.begin(); ks
!= (*sm
)->known_spells
.end(); ks
++) {
312 if (atoi((*ks
)->SpellResRef
+4)==spellid
) {
315 memcpy(ResRef
, (*ks
)->SpellResRef
, sizeof(ieResRef
) );
317 (*sm
)->known_spells
.erase(ks
);
318 RemoveMemorization(*sm
, ResRef
);
325 //removes spell from both memorized/book
326 void Spellbook::RemoveSpell(const ieResRef ResRef
)
328 for (int type
= 0; type
<NUM_BOOK_TYPES
; type
++) {
329 std::vector
< CRESpellMemorization
* >::iterator sm
;
330 for (sm
= spells
[type
].begin(); sm
!= spells
[type
].end(); sm
++) {
331 std::vector
< CREKnownSpell
* >::iterator ks
;
333 for (ks
= (*sm
)->known_spells
.begin(); ks
!= (*sm
)->known_spells
.end(); ks
++) {
334 if (strnicmp(ResRef
, (*ks
)->SpellResRef
, sizeof(ResRef
) ) ) {
338 (*sm
)->known_spells
.erase(ks
);
339 RemoveMemorization(*sm
, ResRef
);
346 void Spellbook::SetBookType(int bt
)
351 //returns the page group of the spellbook this spelltype belongs to
352 //psionics are stored in the mage spell list
353 //wizard/priest are trivial
354 //songs are stored elsewhere
355 //wildshapes are marked as innate, they need some hack to get stored
357 //the rest are stored as innate
358 int Spellbook::GetSpellType(int spelltype
)
360 if (IWD2Style
) return spelltype
;
363 return spelltypes
[spelltype
];
365 return IE_SPELL_TYPE_INNATE
;
368 int Spellbook::LearnSpell(Spell
*spell
, int memo
)
370 CREKnownSpell
*spl
= new CREKnownSpell();
371 strncpy(spl
->SpellResRef
, spell
->Name
, 8);
372 spl
->Type
= (ieWord
) GetSpellType(spell
->SpellType
);
373 if ( spl
->Type
== IE_SPELL_TYPE_INNATE
) {
377 spl
->Level
= (ieWord
) (spell
->SpellLevel
-1);
379 bool ret
=AddKnownSpell(spl
, memo
);
383 return spell
->SpellLevel
; // return only the spell level (xp is based on xpbonus)
386 //if flg is set, it will be also memorized
387 bool Spellbook::AddKnownSpell(CREKnownSpell
*spl
, int flg
)
389 int type
= spl
->Type
;
390 if (type
>= NUM_BOOK_TYPES
) {
393 unsigned int level
= spl
->Level
;
394 if ( level
>= GetSpellLevelCount(type
) ) {
395 CRESpellMemorization
*sm
= new CRESpellMemorization();
396 sm
->Type
= (ieWord
) type
;
397 sm
->Level
= (ieWord
) level
;
398 sm
->Number
= sm
->Number2
= 0;
399 if ( !AddSpellMemorization(sm
) ) {
405 spells
[type
][level
]->known_spells
.push_back(spl
);
406 if (type
==IE_SPELL_TYPE_INNATE
) {
407 spells
[type
][level
]->Number
++;
408 spells
[type
][level
]->Number2
++;
411 MemorizeSpell(spl
, true);
416 CREKnownSpell
* Spellbook::GetKnownSpell(int type
, unsigned int level
, unsigned int index
) const
418 if (type
>= NUM_BOOK_TYPES
|| level
>= GetSpellLevelCount(type
) || index
>= spells
[type
][level
]->known_spells
.size())
420 return spells
[type
][level
]->known_spells
[index
];
423 unsigned int Spellbook::GetMemorizedSpellsCount(int type
) const
425 unsigned int count
= 0;
426 size_t i
=GetSpellLevelCount(type
);
428 count
+= (unsigned int) spells
[type
][i
]->memorized_spells
.size();
433 unsigned int Spellbook::GetMemorizedSpellsCount(int type
, unsigned int level
) const
435 if (type
>= NUM_BOOK_TYPES
)
437 if (level
>= GetSpellLevelCount(type
))
439 return (unsigned int) spells
[type
][level
]->memorized_spells
.size();
442 CREMemorizedSpell
* Spellbook::GetMemorizedSpell(int type
, unsigned int level
, unsigned int index
) const
444 if (type
>= NUM_BOOK_TYPES
|| level
>= GetSpellLevelCount(type
) || index
>= spells
[type
][level
]->memorized_spells
.size())
446 return spells
[type
][level
]->memorized_spells
[index
];
449 //creates a spellbook level
450 bool Spellbook::AddSpellMemorization(CRESpellMemorization
* sm
)
452 if (sm
->Type
>=NUM_BOOK_TYPES
) {
455 std::vector
<CRESpellMemorization
*>* s
= &spells
[sm
->Type
];
456 //when loading, level starts on 0
457 unsigned int level
= sm
->Level
;
458 if (level
> MAX_SPELL_LEVEL
) {
462 while (s
->size() < level
) {
463 // this code previously added NULLs, leading to crashes,
464 // so this is an attempt to make it not broken
465 CRESpellMemorization
*newsm
= new CRESpellMemorization();
466 newsm
->Type
= sm
->Type
;
467 newsm
->Level
= (ieWord
) s
->size();
468 newsm
->Number
= newsm
->Number2
= 0;
469 s
->push_back( newsm
);
472 // only add this one if necessary
473 if (s
->size() == level
) {
480 //apply the wisdom bonus on all spell levels for type
481 //count is optimally the count of spell levels
482 void Spellbook::BonusSpells(int type
, int count
, int *bonuses
)
484 int level
= GetSpellLevelCount(type
);
485 if (level
>count
) level
=count
;
486 for (int i
= 0; i
< level
; i
++) {
487 CRESpellMemorization
* sm
= GetSpellMemorization(type
, i
);
488 sm
->Number2
+=bonuses
[i
];
492 //call this in every ai cycle when recalculating spell bonus
493 //TODO:add in wisdom bonus here
494 void Spellbook::ClearBonus()
498 for (type
= 0; type
< NUM_BOOK_TYPES
; type
++) {
499 int level
= GetSpellLevelCount(type
);
500 for (int i
= 0; i
< level
; i
++) {
501 CRESpellMemorization
* sm
= GetSpellMemorization(type
, i
);
502 sm
->Number2
=sm
->Number
;
507 CRESpellMemorization
*Spellbook::GetSpellMemorization(unsigned int type
, unsigned int level
)
509 CRESpellMemorization
*sm
;
510 if (level
>= GetSpellLevelCount(type
) || !(sm
= spells
[type
][level
]) ) {
511 sm
= new CRESpellMemorization();
512 sm
->Type
= (ieWord
) type
;
513 sm
->Level
= (ieWord
) level
;
514 sm
->Number
= sm
->Number2
= 0;
515 if ( !AddSpellMemorization(sm
) ) {
522 //if bonus is not set, then sets the base value (adjusts bonus too)
523 //if bonus is set, then sets only the bonus
524 //if the bonus value is 0, then the bonus is double base value
525 //bonus is cummulative, but not saved
526 void Spellbook::SetMemorizableSpellsCount(int Value
, int type
, unsigned int level
, bool bonus
)
530 if (type
>= NUM_BOOK_TYPES
) {
534 CRESpellMemorization
* sm
= GetSpellMemorization(type
, level
);
539 sm
->Number2
=(ieWord
) (sm
->Number2
+Value
);
542 diff
=sm
->Number2
-sm
->Number
;
543 sm
->Number
=(ieWord
) Value
;
544 sm
->Number2
=(ieWord
) (Value
+diff
);
548 int Spellbook::GetMemorizableSpellsCount(int type
, unsigned int level
, bool bonus
) const
550 if (type
>= NUM_BOOK_TYPES
|| level
>= GetSpellLevelCount(type
))
552 CRESpellMemorization
* sm
= spells
[type
][level
];
558 bool Spellbook::MemorizeSpell(CREKnownSpell
* spell
, bool usable
)
560 CRESpellMemorization
* sm
= spells
[spell
->Type
][spell
->Level
];
561 if (sm
->Number2
<= sm
->memorized_spells
.size()) {
562 //it is possible to have sorcerer type spellbooks for any spellbook type
563 if (! (sorcerer
& (1<<spell
->Type
) ) )
567 CREMemorizedSpell
* mem_spl
= new CREMemorizedSpell();
568 strncpy( mem_spl
->SpellResRef
, spell
->SpellResRef
, 8 );
569 mem_spl
->Flags
= usable
? 1 : 0; // FIXME: is it all it's used for?
571 sm
->memorized_spells
.push_back( mem_spl
);
576 bool Spellbook::UnmemorizeSpell(CREMemorizedSpell
* spell
)
578 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
579 std::vector
< CRESpellMemorization
* >::iterator sm
;
580 for (sm
= spells
[i
].begin(); sm
!= spells
[i
].end(); sm
++) {
581 std::vector
< CREMemorizedSpell
* >::iterator s
;
582 for (s
= (*sm
)->memorized_spells
.begin(); s
!= (*sm
)->memorized_spells
.end(); s
++) {
585 (*sm
)->memorized_spells
.erase( s
);
596 //bitfield disabling type: 1 - mage, 2 - cleric etc
597 //level: if set, then finds that level only
598 CREMemorizedSpell
* Spellbook::FindUnchargedSpell(int type
, int level
)
602 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
608 for (unsigned int j
= 0; j
<spells
[i
].size(); j
++) {
609 CRESpellMemorization
* sm
= spells
[i
][j
];
610 if (level
&& (sm
->Level
!=level
-1)) {
614 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
615 CREMemorizedSpell
*ret
= sm
->memorized_spells
[k
];
616 if (ret
->Flags
== 0) {
625 //creates sorcerer style memory for the given spell type
626 void Spellbook::CreateSorcererMemory(int type
)
628 for (size_t j
= 0; j
< spells
[type
].size(); j
++) {
629 CRESpellMemorization
* sm
= spells
[type
][j
];
631 size_t cnt
= sm
->memorized_spells
.size();
633 delete sm
->memorized_spells
[cnt
];
635 sm
->memorized_spells
.clear();
636 for (unsigned int k
= 0; k
< sm
->known_spells
.size(); k
++) {
637 CREKnownSpell
*ck
= sm
->known_spells
[k
];
640 MemorizeSpell(ck
, true);
646 void Spellbook::ChargeAllSpells()
649 for (int i
= 0; i
< NUM_BOOK_TYPES
; j
+=j
,i
++) {
650 //this spellbook page type is sorcerer-like
652 CreateSorcererMemory(i
);
656 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
657 CRESpellMemorization
* sm
= spells
[i
][j
];
659 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++)
660 ChargeSpell( sm
->memorized_spells
[k
] );
665 //unmemorizes the highest level spell possible
666 //returns true if successful
667 bool Spellbook::DepleteSpell(int type
)
669 if (type
>=NUM_BOOK_TYPES
) {
672 size_t j
= GetSpellLevelCount(type
);
674 CRESpellMemorization
* sm
= spells
[type
][j
];
676 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
677 if (DepleteSpell( sm
->memorized_spells
[k
] )) {
678 if (sorcerer
& (1<<type
) ) {
688 void Spellbook::DepleteLevel(CRESpellMemorization
* sm
)
690 size_t cnt
= sm
->memorized_spells
.size();
692 for (size_t i
= 0; i
< cnt
&& cnt
>0; i
++) {
693 CREMemorizedSpell
*cms
= sm
->memorized_spells
[i
];
694 //sorcerer spells are created in orderly manner
695 if (strncmp(last
,cms
->SpellResRef
,8) ) {
696 memcpy(last
, cms
->SpellResRef
, sizeof(ieResRef
) );
698 sm
->memorized_spells
.erase(sm
->memorized_spells
.begin()+i
);
705 bool Spellbook::DepleteSpell(int type
, unsigned int page
, unsigned int slot
)
709 if (NUM_BOOK_TYPES
<=type
) {
712 if (spells
[type
].size()<=page
) {
715 CRESpellMemorization
* sm
= spells
[page
][type
];
716 if (sm
->memorized_spells
.size()<=slot
) {
720 CREMemorizedSpell
* cms
= sm
->memorized_spells
[slot
];
721 ret
= DepleteSpell(cms
);
722 if (ret
&& (sorcerer
& (1<<type
) ) ) {
729 bool Spellbook::ChargeSpell(CREMemorizedSpell
* spl
)
736 bool Spellbook::DepleteSpell(CREMemorizedSpell
* spl
)
746 void Spellbook::ClearSpellInfo()
748 size_t i
= spellinfo
.size();
755 bool Spellbook::GetSpellInfo(SpellExtHeader
*array
, int type
, int startindex
, int count
)
757 memset(array
, 0, count
* sizeof(SpellExtHeader
) );
758 if (spellinfo
.size() == 0) {
763 for (unsigned int i
= 0; i
<spellinfo
.size(); i
++) {
764 if ( !(type
& (1<<spellinfo
[i
]->type
)) ) {
775 memcpy(array
+actual
, spellinfo
[i
], sizeof(SpellExtHeader
));
781 // returns the size of spellinfo vector, if type is nonzero it is used as filter
782 // for example type==1 lists the number of different mage spells
783 unsigned int Spellbook::GetSpellInfoSize(int type
)
785 size_t i
= spellinfo
.size();
788 i
= spellinfo
.size();
791 return (unsigned int) i
;
793 unsigned int count
= 0;
795 if (1<<(spellinfo
[i
]->type
)&type
) {
802 SpellExtHeader
*Spellbook::FindSpellInfo(unsigned int level
, unsigned int type
, const ieResRef spellname
)
804 size_t i
= spellinfo
.size();
806 if ( (spellinfo
[i
]->level
==level
) &&
807 (spellinfo
[i
]->type
==type
) &&
808 !strnicmp(spellinfo
[i
]->spellname
, spellname
, 8)) {
815 // grouping the castable spells
816 void Spellbook::GenerateSpellInfo()
818 ClearSpellInfo(); //just in case
819 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
820 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
821 CRESpellMemorization
* sm
= spells
[i
][j
];
823 for (unsigned int k
= 0; k
< sm
->memorized_spells
.size(); k
++) {
824 CREMemorizedSpell
* slot
= sm
->memorized_spells
[k
];
829 Spell
*spl
= gamedata
->GetSpell(slot
->SpellResRef
);
833 SpellExtHeader
*seh
= FindSpellInfo(sm
->Level
, sm
->Type
, slot
->SpellResRef
);
838 seh
= new SpellExtHeader
;
839 spellinfo
.push_back( seh
);
841 memcpy(seh
->spellname
, slot
->SpellResRef
, sizeof(ieResRef
) );
844 for (ehc
= 0; ehc
< spl
->ExtHeaderCount
-1; ehc
++) {
845 if (level
<spl
->ext_headers
[ehc
+1].RequiredLevel
) {
849 SPLExtHeader
*ext_header
= spl
->ext_headers
+ehc
;
850 seh
->headerindex
= ehc
;
851 seh
->level
= sm
->Level
;
852 seh
->type
= sm
->Type
;
855 seh
->SpellForm
= ext_header
->SpellForm
;
856 memcpy(seh
->MemorisedIcon
, ext_header
->MemorisedIcon
,sizeof(ieResRef
) );
857 seh
->Target
= ext_header
->Target
;
858 seh
->TargetNumber
= ext_header
->TargetNumber
;
859 seh
->Range
= ext_header
->Range
;
860 seh
->Projectile
= ext_header
->ProjectileAnimation
;
861 seh
->CastingTime
= (ieWord
) ext_header
->CastingTime
;
862 seh
->strref
= spl
->SpellName
;
863 gamedata
->FreeSpell(spl
, slot
->SpellResRef
, false);
869 void Spellbook::dump()
873 printf( "SPELLBOOK:\n" );
874 for (int i
= 0; i
< NUM_BOOK_TYPES
; i
++) {
875 for (unsigned int j
= 0; j
< spells
[i
].size(); j
++) {
876 CRESpellMemorization
* sm
= spells
[i
][j
];
877 //if (!sm || !sm->Number) continue;
880 //Never ever use field length qualifiers it is not portable, if you need to convert, convert to compatible values, anyway we don't need this!
881 //printf ( "type: %d: L: %d; N1: %d; N2: %d; T: %d; KC: %d; MC: %d\n", i,
882 // sm->Level, sm->Number, sm->Number2, sm->Type, (int) sm->known_spells.size(), (int) sm->memorized_spells.size() );
884 if (sm
->known_spells
.size())
885 printf( " Known spells:\n" );
886 for (k
= 0; k
< sm
->known_spells
.size(); k
++) {
887 CREKnownSpell
* spl
= sm
->known_spells
[k
];
890 printf ( " %2d: %8s L: %d T: %d\n", k
, spl
->SpellResRef
, spl
->Level
, spl
->Type
);
893 if (sm
->memorized_spells
.size())
894 printf( " Memorized spells:\n" );
895 for (k
= 0; k
< sm
->memorized_spells
.size (); k
++) {
896 CREMemorizedSpell
* spl
= sm
->memorized_spells
[k
];
899 printf ( " %2u: %8s %x\n", k
, spl
->SpellResRef
, spl
->Flags
);