Move EventMgr to GUI.
[gemrb.git] / gemrb / core / Spellbook.cpp
blobfe8201e36911bcc6129950ccdb0c3172cac75a2a
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"
23 #include "GameData.h"
24 #include "Interface.h"
25 #include "Projectile.h"
26 #include "Spell.h"
27 #include "TableMgr.h"
28 #include "Scriptable/Actor.h"
30 #include <cstdio>
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()
44 if (!SBInitialized) {
45 InitializeSpellbook();
47 spells = new std::vector<CRESpellMemorization*> [NUM_BOOK_TYPES];
50 void Spellbook::InitializeSpellbook()
52 if (!SBInitialized) {
53 SBInitialized=true;
54 if (core->HasFeature(GF_HAS_SPELLLIST)) {
55 NUM_BOOK_TYPES=NUM_IWD2_SPELLTYPES; //iwd2 spell types
56 } else {
57 NUM_BOOK_TYPES=NUM_SPELLTYPES; //bg/pst/iwd1 spell types
60 return;
63 void Spellbook::ReleaseMemory()
65 SBInitialized=false;
68 Spellbook::~Spellbook()
70 for (int i = 0; i < NUM_BOOK_TYPES; i++) {
71 for (unsigned int j = 0; j < spells[i].size(); j++) {
72 if (spells[i][j]) {
73 FreeSpellPage( spells[i][j] );
74 spells[i][j] = NULL;
78 ClearSpellInfo();
79 delete [] spells;
82 void Spellbook::FreeSpellPage(CRESpellMemorization *sm)
84 size_t i = sm->known_spells.size();
85 while(i--) {
86 delete sm->known_spells[i];
88 i = sm->memorized_spells.size();
89 while(i--) {
90 delete sm->memorized_spells[i];
92 delete sm;
95 //ITEM, SPPR, SPWI, SPIN, SPCL
96 int sections[]={3,0,1,2,2};
98 //flags bits
99 // 1 - unmemorize it
100 bool Spellbook::HaveSpell(int spellid, ieDword flags)
102 int type = spellid/1000;
103 if (type>4) {
104 return false;
106 type = sections[type];
107 if (type >= NUM_BOOK_TYPES) {
108 return false;
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];
116 if (ms->Flags) {
117 if (atoi(ms->SpellResRef+4)==spellid) {
118 if (flags&HS_DEPLETE) {
119 if (DepleteSpell(ms) && (sorcerer & (1<<type) ) ) {
120 DepleteLevel (sm);
123 return true;
128 return false;
131 bool Spellbook::KnowSpell(int spellid)
133 int type = spellid/1000;
134 if (type>4) {
135 return false;
137 type = sections[type];
138 if (type >= NUM_BOOK_TYPES) {
139 return false;
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) {
148 return true;
152 return false;
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) ) {
164 continue;
166 return true;
170 return false;
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];
181 if (ms->Flags) {
182 if (resref[0] && stricmp(ms->SpellResRef, resref) ) {
183 continue;
185 if (flags&HS_DEPLETE) {
186 if (DepleteSpell(ms) && (sorcerer & (1<<i) ) ) {
187 DepleteLevel (sm);
190 return true;
195 return false;
198 int Spellbook::GetTypes() const
200 return NUM_BOOK_TYPES;
203 bool Spellbook::IsIWDSpellBook() const
205 return IWD2Style;
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);
219 return total;
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);
227 while(level--) {
228 total += GetKnownSpellsCount(type, level);
231 return total;
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);
239 while(level--) {
240 total += GetMemorizedSpellsCount(type, level);
243 return total;
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))
250 return 0;
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) ) ) {
262 continue;
264 delete *ms;
265 sm->memorized_spells.erase(ms);
266 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++) {
278 if (*ks == spell) {
279 ieResRef ResRef;
281 memcpy(ResRef, (*ks)->SpellResRef, sizeof(ieResRef) );
282 delete *ks;
283 (*sm)->known_spells.erase(ks);
284 RemoveMemorization(*sm, ResRef);
285 ClearSpellInfo();
286 return true;
291 return false;
295 //removes all instances of spellid (probably not needed)
296 void Spellbook::RemoveSpell(int spellid)
298 int type = spellid/1000;
299 if (type>4) {
300 return;
302 type = sections[type];
303 if (type >= NUM_BOOK_TYPES) {
304 return;
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) {
313 ieResRef ResRef;
315 memcpy(ResRef, (*ks)->SpellResRef, sizeof(ieResRef) );
316 delete *ks;
317 (*sm)->known_spells.erase(ks);
318 RemoveMemorization(*sm, ResRef);
319 ks--;
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) ) ) {
335 continue;
337 delete *ks;
338 (*sm)->known_spells.erase(ks);
339 RemoveMemorization(*sm, ResRef);
340 ks--;
346 void Spellbook::SetBookType(int bt)
348 sorcerer = 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
356 //in the right group
357 //the rest are stored as innate
358 int Spellbook::GetSpellType(int spelltype)
360 if (IWD2Style) return spelltype;
362 if (spelltype<6) {
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) {
374 spl->Level = 0;
376 else {
377 spl->Level = (ieWord) (spell->SpellLevel-1);
379 bool ret=AddKnownSpell(spl, memo);
380 if (!ret) {
381 delete spl;
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) {
391 return false;
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) ) {
400 delete sm;
401 return false;
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++;
410 if (flg) {
411 MemorizeSpell(spl, true);
413 return 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())
419 return NULL;
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);
427 while(i--) {
428 count += (unsigned int) spells[type][i]->memorized_spells.size();
430 return count;
433 unsigned int Spellbook::GetMemorizedSpellsCount(int type, unsigned int level) const
435 if (type >= NUM_BOOK_TYPES)
436 return 0;
437 if (level >= GetSpellLevelCount(type))
438 return 0;
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())
445 return NULL;
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) {
453 return false;
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 ) {
459 return false;
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) {
474 s->push_back(sm);
475 return true;
477 return false;
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()
496 int type;
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) ) {
516 delete sm;
517 return NULL;
520 return 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)
528 int diff;
530 if (type >= NUM_BOOK_TYPES) {
531 return;
534 CRESpellMemorization* sm = GetSpellMemorization(type, level);
535 if (bonus) {
536 if (!Value) {
537 Value=sm->Number;
539 sm->Number2=(ieWord) (sm->Number2+Value);
541 else {
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))
551 return 0;
552 CRESpellMemorization* sm = spells[type][level];
553 if (bonus)
554 return sm->Number2;
555 return sm->Number;
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) ) )
564 return false;
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 );
572 ClearSpellInfo();
573 return true;
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++) {
583 if (*s == spell) {
584 delete *s;
585 (*sm)->memorized_spells.erase( s );
586 ClearSpellInfo();
587 return true;
593 return false;
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)
600 int mask=1;
602 for (int i = 0; i < NUM_BOOK_TYPES; i++) {
603 if (type&mask) {
604 mask<<=1;
605 continue;
607 mask<<=1;
608 for (unsigned int j = 0; j<spells[i].size(); j++) {
609 CRESpellMemorization* sm = spells[i][j];
610 if (level && (sm->Level!=level-1)) {
611 continue;
614 for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
615 CREMemorizedSpell *ret = sm->memorized_spells[k];
616 if (ret->Flags == 0) {
617 return ret;
622 return NULL;
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();
632 while(cnt--) {
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];
638 cnt = sm->Number2;
639 while(cnt--) {
640 MemorizeSpell(ck, true);
646 void Spellbook::ChargeAllSpells()
648 int j = 1;
649 for (int i = 0; i < NUM_BOOK_TYPES; j+=j,i++) {
650 //this spellbook page type is sorcerer-like
651 if (sorcerer&j ) {
652 CreateSorcererMemory(i);
653 continue;
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) {
670 return false;
672 size_t j = GetSpellLevelCount(type);
673 while(j--) {
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) ) {
679 DepleteLevel (sm);
681 return true;
685 return false;
688 void Spellbook::DepleteLevel(CRESpellMemorization* sm)
690 size_t cnt = sm->memorized_spells.size();
691 ieResRef last={""};
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) );
697 delete cms;
698 sm->memorized_spells.erase(sm->memorized_spells.begin()+i);
699 i--;
700 cnt--;
705 bool Spellbook::DepleteSpell(int type, unsigned int page, unsigned int slot)
707 bool ret;
709 if (NUM_BOOK_TYPES<=type) {
710 return false;
712 if (spells[type].size()<=page) {
713 return false;
715 CRESpellMemorization* sm = spells[page][type];
716 if (sm->memorized_spells.size()<=slot) {
717 return false;
720 CREMemorizedSpell* cms = sm->memorized_spells[slot];
721 ret = DepleteSpell(cms);
722 if (ret && (sorcerer & (1<<type) ) ) {
723 DepleteLevel (sm);
726 return ret;
729 bool Spellbook::ChargeSpell(CREMemorizedSpell* spl)
731 spl->Flags = 1;
732 ClearSpellInfo();
733 return true;
736 bool Spellbook::DepleteSpell(CREMemorizedSpell* spl)
738 if (spl->Flags) {
739 spl->Flags = 0;
740 ClearSpellInfo();
741 return true;
743 return false;
746 void Spellbook::ClearSpellInfo()
748 size_t i = spellinfo.size();
749 while(i--) {
750 delete spellinfo[i];
752 spellinfo.clear();
755 bool Spellbook::GetSpellInfo(SpellExtHeader *array, int type, int startindex, int count)
757 memset(array, 0, count * sizeof(SpellExtHeader) );
758 if (spellinfo.size() == 0) {
759 GenerateSpellInfo();
761 int actual = 0;
762 bool ret = false;
763 for (unsigned int i = 0; i<spellinfo.size(); i++) {
764 if ( !(type & (1<<spellinfo[i]->type)) ) {
765 continue;
767 if (startindex>0) {
768 startindex--;
769 continue;
771 if (actual>=count) {
772 ret = true;
773 break;
775 memcpy(array+actual, spellinfo[i], sizeof(SpellExtHeader));
776 actual++;
778 return ret;
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();
786 if (!i) {
787 GenerateSpellInfo();
788 i = spellinfo.size();
790 if (!type) {
791 return (unsigned int) i;
793 unsigned int count = 0;
794 while(i--) {
795 if (1<<(spellinfo[i]->type)&type) {
796 count++;
799 return count;
802 SpellExtHeader *Spellbook::FindSpellInfo(unsigned int level, unsigned int type, const ieResRef spellname)
804 size_t i = spellinfo.size();
805 while(i--) {
806 if ( (spellinfo[i]->level==level) &&
807 (spellinfo[i]->type==type) &&
808 !strnicmp(spellinfo[i]->spellname, spellname, 8)) {
809 return spellinfo[i];
812 return NULL;
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];
825 if (!slot)
826 continue;
827 if (!slot->Flags)
828 continue;
829 Spell *spl = gamedata->GetSpell(slot->SpellResRef);
830 if (!spl)
831 continue;
832 ieDword level = 0;
833 SpellExtHeader *seh = FindSpellInfo(sm->Level, sm->Type, slot->SpellResRef);
834 if (seh) {
835 seh->count++;
836 continue;
838 seh = new SpellExtHeader;
839 spellinfo.push_back( seh );
841 memcpy(seh->spellname, slot->SpellResRef, sizeof(ieResRef) );
842 int ehc;
844 for (ehc = 0; ehc < spl->ExtHeaderCount-1; ehc++) {
845 if (level<spl->ext_headers[ehc+1].RequiredLevel) {
846 break;
849 SPLExtHeader *ext_header = spl->ext_headers+ehc;
850 seh->headerindex = ehc;
851 seh->level = sm->Level;
852 seh->type = sm->Type;
853 seh->slot = k;
854 seh->count = 1;
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()
871 unsigned int k;
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;
878 if (!sm) 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];
888 if (!spl) continue;
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];
897 if (!spl) continue;
899 printf ( " %2u: %8s %x\n", k, spl->SpellResRef, spl->Flags );