1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2003 The GemRB Project
3  *
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.
8 
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.
13 
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.
17  *
18  *
19  */
20 
21 #include "Spellbook.h"
22 
23 #include "ActorMgr.h"
24 #include "GameData.h"
25 #include "Interface.h"
26 #include "PluginMgr.h"
27 #include "Projectile.h"
28 #include "Spell.h"
29 #include "TableMgr.h"
30 #include "Scriptable/Actor.h"
31 #include "System/StringBuffer.h"
32 
33 #include <cstdio>
34 
35 namespace GemRB {
36 
37 static bool SBInitialized = false;
38 static int NUM_BOOK_TYPES = 3;
39 static bool IWD2Style = false;
40 
41 //spell header-->spell book type conversion (iwd2 is different)
42 static const int spelltypes[NUM_SPELL_TYPES]={
43 	IE_SPELL_TYPE_INNATE, IE_SPELL_TYPE_WIZARD, IE_SPELL_TYPE_PRIEST,
44 	IE_SPELL_TYPE_WIZARD, IE_SPELL_TYPE_INNATE, IE_SPELL_TYPE_SONG
45 };
46 
Spellbook()47 Spellbook::Spellbook()
48 {
49 	if (!SBInitialized) {
50 		InitializeSpellbook();
51 	}
52 	spells = new std::vector<CRESpellMemorization*> [NUM_BOOK_TYPES];
53 	sorcerer = 0;
54 	if (IWD2Style) {
55 		innate = 1<<IE_IWD2_SPELL_INNATE;
56 	} else {
57 		innate = 1<<IE_SPELL_TYPE_INNATE;
58 	}
59 }
60 
InitializeSpellbook()61 void Spellbook::InitializeSpellbook()
62 {
63 	if (!SBInitialized) {
64 		SBInitialized=true;
65 		if (core->HasFeature(GF_HAS_SPELLLIST)) {
66 			NUM_BOOK_TYPES=NUM_IWD2_SPELLTYPES; //iwd2 spell types
67 			IWD2Style = true;
68 		} else {
69 			NUM_BOOK_TYPES=NUM_SPELLTYPES; //bg/pst/iwd1 spell types
70 			IWD2Style = false;
71 		}
72 	}
73 	return;
74 }
75 
ReleaseMemory()76 void Spellbook::ReleaseMemory()
77 {
78 	SBInitialized=false;
79 }
80 
~Spellbook()81 Spellbook::~Spellbook()
82 {
83 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
84 		for (unsigned int j = 0; j < spells[i].size(); j++) {
85 			if (spells[i][j]) {
86 				FreeSpellPage( spells[i][j] );
87 				spells[i][j] = NULL;
88 			}
89 		}
90 	}
91 	ClearSpellInfo();
92 	delete [] spells;
93 }
94 
FreeSpellPage(CRESpellMemorization * sm)95 void Spellbook::FreeSpellPage(CRESpellMemorization *sm)
96 {
97 	size_t i = sm->known_spells.size();
98 	while(i--) {
99 		delete sm->known_spells[i];
100 	}
101 	i = sm->memorized_spells.size();
102 	while(i--) {
103 		delete sm->memorized_spells[i];
104 	}
105 	delete sm;
106 }
107 
108 // FIXME: exclude slayer, all bhaal innates?
CopyFrom(const Actor * source)109 void Spellbook::CopyFrom(const Actor *source)
110 {
111 	if (!source) {
112 		return;
113 	}
114 
115 	// clear it first
116 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
117 		for (unsigned int j = 0; j < spells[i].size(); j++) {
118 			if (spells[i][j]) {
119 				FreeSpellPage( spells[i][j] );
120 				spells[i][j] = NULL;
121 			}
122 		}
123 		spells[i].clear();
124 	}
125 	ClearSpellInfo();
126 
127 	const Spellbook &wikipedia = source->spellbook;
128 
129 	for (int t = 0; t < NUM_BOOK_TYPES; t++) {
130 		for (size_t i = 0; i < wikipedia.spells[t].size(); i++) {
131 			unsigned int k;
132 			CRESpellMemorization *wm = wikipedia.spells[t][i];
133 			CRESpellMemorization *sm = new CRESpellMemorization();
134 			spells[t].push_back(sm);
135 			sm->Level = wm->Level;
136 			sm->SlotCount = wm->SlotCount;
137 			sm->SlotCountWithBonus = wm->SlotCountWithBonus;
138 			sm->Type = wm->Type;
139 			for (k = 0; k < wm->known_spells.size(); k++) {
140 				CREKnownSpell *tmp_known = new CREKnownSpell();
141 				sm->known_spells.push_back(tmp_known);
142 				memcpy(tmp_known, wm->known_spells[k], sizeof(CREKnownSpell));
143 			}
144 			for (k = 0; k < wm->memorized_spells.size(); k++) {
145 				CREMemorizedSpell *tmp_mem = new CREMemorizedSpell();
146 				sm->memorized_spells.push_back(tmp_mem);
147 				memcpy(tmp_mem, wm->memorized_spells[k], sizeof(CREMemorizedSpell));
148 			}
149 		}
150 	}
151 
152 	sorcerer = wikipedia.sorcerer;
153 }
154 
155 //ITEM, SPPR, SPWI, SPIN, SPCL
156 int sections[]={3,0,1,2,2};
157 // domain spells are of all types, so look them up in all cases
158 // ignore songs and shapes altogether
159 int arcanetypes[] = {IE_IWD2_SPELL_BARD, IE_IWD2_SPELL_SORCERER, IE_IWD2_SPELL_WIZARD, IE_IWD2_SPELL_DOMAIN};
160 int divinetypes[] = {IE_IWD2_SPELL_CLERIC, IE_IWD2_SPELL_DRUID, IE_IWD2_SPELL_PALADIN, IE_IWD2_SPELL_RANGER, IE_IWD2_SPELL_DOMAIN};
161 int *alltypes[2] = {divinetypes, arcanetypes};
162 
GetType(int spellid,unsigned int & bookcount,int & idx)163 int inline GetType(int spellid, unsigned int &bookcount, int &idx)
164 {
165 	int type = spellid/1000;
166 	if (type>4) {
167 		return -1;
168 	}
169 	if (IWD2Style) {
170 		if (type == 1) {
171 			// check divine
172 			idx = 0;
173 			bookcount = sizeof(divinetypes)/sizeof(int);
174 		} else if (type == 2) {
175 			// check arcane
176 			idx = 1;
177 			bookcount = sizeof(arcanetypes)/sizeof(int);
178 		} else if (type == 3) {
179 			type = IE_IWD2_SPELL_INNATE;
180 		}
181 	} else {
182 		type = sections[type];
183 		if (type >= NUM_BOOK_TYPES) {
184 			return -1;
185 		}
186 	}
187 	return type;
188 }
189 
190 //flags bits
191 // 1 - unmemorize it
HaveSpell(int spellid,ieDword flags)192 bool Spellbook::HaveSpell(int spellid, ieDword flags)
193 {
194 	int idx = -1;
195 	unsigned int bookcount;
196 	int type = GetType(spellid, bookcount, idx);
197 	if (type == -1) {
198 		return false;
199 	}
200 
201 	spellid = spellid % 1000;
202 
203 	if (idx == -1) {
204 		return HaveSpell(spellid, type, flags);
205 	} else {
206 		for (unsigned int book = 0; book < bookcount; book++) {
207 			if (HaveSpell(spellid, alltypes[idx][book], flags)) {
208 				return true;
209 			}
210 		}
211 	}
212 	return false;
213 }
HaveSpell(int spellid,int type,ieDword flags)214 bool Spellbook::HaveSpell(int spellid, int type, ieDword flags)
215 {
216 	for (unsigned int j = 0; j < GetSpellLevelCount(type); j++) {
217 		CRESpellMemorization* sm = spells[type][j];
218 		for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
219 			CREMemorizedSpell* ms = sm->memorized_spells[k];
220 			if (ms->Flags) {
221 				if (atoi(ms->SpellResRef+4)==spellid) {
222 					if (flags&HS_DEPLETE) {
223 						if (DepleteSpell(ms) && (sorcerer & (1<<type) ) ) {
224 							DepleteLevel (sm, ms->SpellResRef);
225 						}
226 					}
227 					return true;
228 				}
229 			}
230 		}
231 	}
232 	return false;
233 }
234 
235 //returns count of memorized spells of a given name/type
CountSpells(const char * resref,unsigned int type,int flag) const236 int Spellbook::CountSpells(const char *resref, unsigned int type, int flag) const
237 {
238 	int i, max;
239 	int count = 0;
240 
241 	if (type==0xffffffff) {
242 		i=0;
243 		max = NUM_BOOK_TYPES;
244 	} else {
245 		i = type;
246 		max = i+1;
247 	}
248 
249 	while(i < max) {
250 		for (unsigned int j = 0; j < spells[i].size(); j++) {
251 			CRESpellMemorization* sm = spells[i][j];
252 			for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
253 				CREMemorizedSpell* ms = sm->memorized_spells[k];
254 				if (resref[0] && !stricmp(ms->SpellResRef, resref) ) {
255 					if (flag || ms->Flags) {
256 						count++;
257 					}
258 				}
259 			}
260 		}
261 		i++;
262 	}
263 	return count;
264 }
265 
KnowSpell(int spellid) const266 bool Spellbook::KnowSpell(int spellid) const
267 {
268 	int idx = -1;
269 	unsigned int bookcount;
270 	int type = GetType(spellid, bookcount, idx);
271 	if (type == -1) {
272 		return false;
273 	}
274 	spellid = spellid % 1000;
275 
276 	if (idx == -1) {
277 		return KnowSpell(spellid, type);
278 	} else {
279 		for (unsigned int book = 0; book < bookcount; book++) {
280 			if (KnowSpell(spellid, alltypes[idx][book])) {
281 				return true;
282 			}
283 		}
284 	}
285 	return false;
286 }
287 
KnowSpell(int spellid,int type) const288 bool Spellbook::KnowSpell(int spellid, int type) const
289 {
290 	for (unsigned int j = 0; j < GetSpellLevelCount(type); j++) {
291 		CRESpellMemorization* sm = spells[type][j];
292 		for (unsigned int k = 0; k < sm->known_spells.size(); k++) {
293 			CREKnownSpell* ks = sm->known_spells[k];
294 			if (atoi(ks->SpellResRef+4)==spellid) {
295 				return true;
296 			}
297 		}
298 	}
299 	return false;
300 }
301 
302 //if resref=="" then it is a knownanyspell
KnowSpell(const char * resref) const303 bool Spellbook::KnowSpell(const char *resref) const
304 {
305 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
306 		for (unsigned int j = 0; j < spells[i].size(); j++) {
307 			CRESpellMemorization* sm = spells[i][j];
308 			for (unsigned int k = 0; k < sm->known_spells.size(); k++) {
309 				CREKnownSpell* ks = sm->known_spells[k];
310 				if (resref[0] && stricmp(ks->SpellResRef, resref) ) {
311 					continue;
312 				}
313 				return true;
314 			}
315 		}
316 	}
317 	return false;
318 }
319 
320 //if resref=="" then it is a haveanyspell
HaveSpell(const char * resref,ieDword flags)321 bool Spellbook::HaveSpell(const char *resref, ieDword flags)
322 {
323 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
324 		for (unsigned int j = 0; j < spells[i].size(); j++) {
325 			CRESpellMemorization* sm = spells[i][j];
326 			for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
327 				CREMemorizedSpell* ms = sm->memorized_spells[k];
328 
329 				if (!ms->Flags) continue;
330 				if (resref[0] && stricmp(ms->SpellResRef, resref)) {
331 					continue;
332 				}
333 
334 				if (flags&HS_DEPLETE) {
335 					if (DepleteSpell(ms) && (sorcerer & (1<<i))) {
336 						DepleteLevel(sm, ms->SpellResRef);
337 					}
338 				}
339 				return true;
340 			}
341 		}
342 	}
343 	return false;
344 }
345 
GetTypes() const346 int Spellbook::GetTypes() const
347 {
348 	return NUM_BOOK_TYPES;
349 }
350 
IsIWDSpellBook() const351 bool Spellbook::IsIWDSpellBook() const
352 {
353 	return IWD2Style;
354 }
355 
GetSpellLevelCount(int type) const356 unsigned int Spellbook::GetSpellLevelCount(int type) const
357 {
358 	assert(type < NUM_BOOK_TYPES);
359 	return (unsigned int) spells[type].size();
360 }
361 
GetTotalPageCount() const362 unsigned int Spellbook::GetTotalPageCount() const
363 {
364 	unsigned int total = 0;
365 	for (int type = 0; type < NUM_BOOK_TYPES; type++) {
366 		total += GetSpellLevelCount(type);
367 	}
368 	return total;
369 }
370 
GetTotalKnownSpellsCount() const371 unsigned int Spellbook::GetTotalKnownSpellsCount() const
372 {
373 	unsigned int total = 0;
374 	for (int type = 0; type < NUM_BOOK_TYPES; type++) {
375 		unsigned int level = GetSpellLevelCount(type);
376 		while(level--) {
377 			total += GetKnownSpellsCount(type, level);
378 		}
379 	}
380 	return total;
381 }
382 
GetTotalMemorizedSpellsCount() const383 unsigned int Spellbook::GetTotalMemorizedSpellsCount() const
384 {
385 	unsigned int total = 0;
386 	for (int type = 0; type < NUM_BOOK_TYPES; type++) {
387 		unsigned int level = GetSpellLevelCount(type);
388 		while(level--) {
389 			total += GetMemorizedSpellsCount(type, level, false);
390 		}
391 	}
392 	return total;
393 }
394 
395 // returns the number of known spells of level (level+1)
GetKnownSpellsCount(int type,unsigned int level) const396 unsigned int Spellbook::GetKnownSpellsCount(int type, unsigned int level) const
397 {
398 	if (type >= NUM_BOOK_TYPES || level >= GetSpellLevelCount(type))
399 		return 0;
400 	return (unsigned int) spells[type][level]->known_spells.size();
401 }
402 
403 //called when a spell was removed from spellbook
404 //this one purges all instances of known spells of the same name from memory
RemoveMemorization(CRESpellMemorization * sm,const ieResRef ResRef)405 void Spellbook::RemoveMemorization(CRESpellMemorization* sm, const ieResRef ResRef)
406 {
407 	std::vector< CREMemorizedSpell* >::iterator ms;
408 
409 	for (ms = sm->memorized_spells.begin(); ms != sm->memorized_spells.end(); ++ms) {
410 		if (strnicmp(ResRef, (*ms)->SpellResRef, sizeof(ieResRef) ) ) {
411 			continue;
412 		}
413 		delete *ms;
414 		ms = sm->memorized_spells.erase(ms);
415 		--ms;
416 	}
417 }
418 
419 //removes one instance of spell (from creknownspell)
RemoveSpell(const CREKnownSpell * spell)420 bool Spellbook::RemoveSpell(const CREKnownSpell* spell)
421 {
422 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
423 		std::vector< CRESpellMemorization* >::iterator sm;
424 		for (sm = spells[i].begin(); sm != spells[i].end(); ++sm) {
425 			std::vector< CREKnownSpell* >::iterator ks;
426 			for (ks = (*sm)->known_spells.begin(); ks != (*sm)->known_spells.end(); ++ks) {
427 				if (*ks == spell) {
428 					ieResRef ResRef;
429 
430 					memcpy(ResRef, (*ks)->SpellResRef, sizeof(ieResRef) );
431 					delete *ks;
432 					(*sm)->known_spells.erase(ks);
433 					RemoveMemorization(*sm, ResRef);
434 					ClearSpellInfo();
435 					return true;
436 				}
437 			}
438 		}
439 	}
440 	return false;
441 }
442 
443 //removes all instances of spellid (probably not needed)
444 //IWD2 clab files use it
RemoveSpell(int spellid)445 void Spellbook::RemoveSpell(int spellid)
446 {
447 	int idx = -1;
448 	unsigned int bookcount;
449 	int type = GetType(spellid, bookcount, idx);
450 	if (type == -1) {
451 		return;
452 	}
453 	spellid = spellid % 1000;
454 
455 	if (idx == -1) {
456 		RemoveSpell(spellid, type);
457 	} else {
458 		for (unsigned int book = 0; book < bookcount; book++) {
459 			RemoveSpell(spellid, alltypes[idx][book]);
460 		}
461 	}
462 
463 }
464 
RemoveSpell(int spellid,int type)465 void Spellbook::RemoveSpell(int spellid, int type)
466 {
467 	std::vector< CRESpellMemorization* >::iterator sm;
468 	for (sm = spells[type].begin(); sm != spells[type].end(); ++sm) {
469 		std::vector< CREKnownSpell* >::iterator ks;
470 
471 		for (ks = (*sm)->known_spells.begin(); ks != (*sm)->known_spells.end(); ++ks) {
472 			if (atoi((*ks)->SpellResRef+4)==spellid) {
473 				ieResRef ResRef;
474 
475 				memcpy(ResRef, (*ks)->SpellResRef, sizeof(ieResRef) );
476 				delete *ks;
477 				ks = (*sm)->known_spells.erase(ks);
478 				RemoveMemorization(*sm, ResRef);
479 				--ks;
480 				ClearSpellInfo();
481 			}
482 		}
483 	}
484 }
485 
486 //removes spell from both memorized/book
RemoveSpell(const ieResRef ResRef,bool onlyknown)487 void Spellbook::RemoveSpell(const ieResRef ResRef, bool onlyknown)
488 {
489 	for (int type = 0; type<NUM_BOOK_TYPES; type++) {
490 		std::vector< CRESpellMemorization* >::iterator sm;
491 		for (sm = spells[type].begin(); sm != spells[type].end(); ++sm) {
492 			std::vector< CREKnownSpell* >::iterator ks;
493 
494 			for (ks = (*sm)->known_spells.begin(); ks != (*sm)->known_spells.end(); ++ks) {
495 				if (strnicmp(ResRef, (*ks)->SpellResRef, sizeof(ieResRef) ) ) {
496 					continue;
497 				}
498 				delete *ks;
499 				ks = (*sm)->known_spells.erase(ks);
500 				if (!onlyknown) RemoveMemorization(*sm, ResRef);
501 				--ks;
502 				ClearSpellInfo();
503 			}
504 		}
505 	}
506 }
507 
SetBookType(int bt)508 void Spellbook::SetBookType(int bt)
509 {
510 	sorcerer |= bt;
511 }
512 
513 //returns the page group of the spellbook this spelltype belongs to
514 //psionics are stored in the mage spell list
515 //wizard/priest are trivial
516 //songs are stored elsewhere
517 //wildshapes are marked as innate, they need some hack to get stored
518 //in the right group
519 //the rest are stored as innate
520 
LearnSpell(Spell * spell,int memo,unsigned int clsmsk,unsigned int kit,int level)521 int Spellbook::LearnSpell(Spell *spell, int memo, unsigned int clsmsk, unsigned int kit, int level)
522 {
523 	CREKnownSpell *spl = new CREKnownSpell();
524 	CopyResRef(spl->SpellResRef, spell->Name);
525 	spl->Level = 0;
526 	if (IWD2Style) {
527 		PluginHolder<ActorMgr> gm(IE_CRE_CLASS_ID);
528 		// is there an override (domain spells)?
529 		if (level == -1) {
530 			level = spell->SpellLevel-1;
531 		}
532 		spl->Level = level;
533 		spl->Type = gm->FindSpellType(spell->Name, spl->Level, clsmsk, kit);
534 	} else {
535 		//not IWD2
536 		if (spell->SpellType<6) {
537 			spl->Type = spelltypes[spell->SpellType];
538 			if (spell->SpellLevel == 0) { // totemic druid has some broken innates (fixed by fixpack)
539 				spell->SpellLevel = 1;
540 			}
541 			spl->Level = spell->SpellLevel-1;
542 		} else {
543 			spl->Type = IE_SPELL_TYPE_INNATE;
544 		}
545 	}
546 
547 	bool ret=AddKnownSpell(spl, memo);
548 	if (!ret) {
549 		delete spl;
550 		return 0;
551 	}
552 	return spell->SpellLevel; // return only the spell level (xp is based on xpbonus)
553 }
554 
555 //if flg is set, it will be also memorized
AddKnownSpell(CREKnownSpell * spl,int flg)556 bool Spellbook::AddKnownSpell(CREKnownSpell *spl, int flg)
557 {
558 	int type = spl->Type;
559 	if (type >= NUM_BOOK_TYPES) {
560 		return false;
561 	}
562 	unsigned int level = spl->Level;
563 	if ( level >= GetSpellLevelCount(type) ) {
564 		CRESpellMemorization *sm = new CRESpellMemorization();
565 		sm->Type = (ieWord) type;
566 		sm->Level = (ieWord) level;
567 		sm->SlotCount = sm->SlotCountWithBonus = 0;
568 		if ( !AddSpellMemorization(sm) ) {
569 			delete sm;
570 			return false;
571 		}
572 	}
573 
574 	spells[type][level]->known_spells.push_back(spl);
575 	if (1<<type == innate || 1<<type == 1<<IE_IWD2_SPELL_SONG) {
576 		spells[type][level]->SlotCount++;
577 		spells[type][level]->SlotCountWithBonus++;
578 	}
579 	if (flg) {
580 		MemorizeSpell(spl, true);
581 	}
582 	return true;
583 }
584 
GetKnownSpell(int type,unsigned int level,unsigned int index) const585 CREKnownSpell* Spellbook::GetKnownSpell(int type, unsigned int level, unsigned int index) const
586 {
587 	if (type >= NUM_BOOK_TYPES || level >= GetSpellLevelCount(type) || index >= spells[type][level]->known_spells.size())
588 		return NULL;
589 	return spells[type][level]->known_spells[index];
590 }
591 
GetMemorizedSpellsCount(int type,bool real) const592 unsigned int Spellbook::GetMemorizedSpellsCount(int type, bool real) const
593 {
594 	unsigned int count = 0;
595 	size_t i=GetSpellLevelCount(type);
596 	while(i--) {
597 		if (real) {
598 			int j = spells[type][i]->memorized_spells.size();
599 			while(j--) {
600 				if (spells[type][i]->memorized_spells[j]->Flags) count++;
601 			}
602 		} else {
603 			count += (unsigned int) spells[type][i]->memorized_spells.size();
604 		}
605 	}
606 	return count;
607 }
608 
GetMemorizedSpellsCount(int type,unsigned int level,bool real) const609 unsigned int Spellbook::GetMemorizedSpellsCount(int type, unsigned int level, bool real) const
610 {
611 	if (type >= NUM_BOOK_TYPES)
612 		return 0;
613 	if (level >= GetSpellLevelCount(type))
614 		return 0;
615 	if (real) {
616 		unsigned int count = 0;
617 		int j = spells[type][level]->memorized_spells.size();
618 		while(j--) {
619 			if (spells[type][level]->memorized_spells[j]->Flags) count++;
620 		}
621 		return count;
622 	}
623 	return (unsigned int) spells[type][level]->memorized_spells.size();
624 }
625 
GetMemorizedSpellsCount(const ieResRef name,int type,bool real) const626 unsigned int Spellbook::GetMemorizedSpellsCount(const ieResRef name, int type, bool real) const
627 {
628 	if (type >= NUM_BOOK_TYPES)
629 		return 0;
630 	int t;
631 	if (type<0) {
632 		t = NUM_BOOK_TYPES-1;
633 	} else {
634 		t = type;
635 	}
636 
637 	int j = 0;
638 	while(t>=0) {
639 		unsigned int level = GetSpellLevelCount(t);
640 		while(level--) {
641 			int i = spells[t][level]->memorized_spells.size();
642 			while(i--) {
643 				CREMemorizedSpell *cms = spells[t][level]->memorized_spells[i];
644 
645 				if (strnicmp(cms->SpellResRef, name, sizeof(ieResRef) ) ) continue;
646 				if (!real || cms->Flags) j++;
647 			}
648 		}
649 		if (type>=0) break;
650 		t--;
651 	}
652 	return j;
653 }
654 
GetMemorizedSpell(int type,unsigned int level,unsigned int index) const655 CREMemorizedSpell* Spellbook::GetMemorizedSpell(int type, unsigned int level, unsigned int index) const
656 {
657 	if (type >= NUM_BOOK_TYPES || level >= GetSpellLevelCount(type) || index >= spells[type][level]->memorized_spells.size())
658 		return NULL;
659 	return spells[type][level]->memorized_spells[index];
660 }
661 
662 //creates a spellbook level
AddSpellMemorization(CRESpellMemorization * sm)663 bool Spellbook::AddSpellMemorization(CRESpellMemorization* sm)
664 {
665 	if (sm->Type>=NUM_BOOK_TYPES) {
666 		return false;
667 	}
668 	std::vector<CRESpellMemorization*>* s = &spells[sm->Type];
669 	//when loading, level starts on 0
670 	unsigned int level = sm->Level;
671 	if (level > MAX_SPELL_LEVEL ) {
672 		return false;
673 	}
674 
675 	while (s->size() < level ) {
676 		// this code previously added NULLs, leading to crashes,
677 		// so this is an attempt to make it not broken
678 		CRESpellMemorization *newsm = new CRESpellMemorization();
679 		newsm->Type = sm->Type;
680 		newsm->Level = (ieWord) s->size();
681 		newsm->SlotCount = newsm->SlotCountWithBonus = 0;
682 		s->push_back( newsm );
683 	}
684 
685 	// only add this one if necessary
686 	assert (s->size() == level);
687 	s->push_back(sm);
688 	return true;
689 }
690 
691 //apply the wisdom bonus on all spell levels for type
692 //count is optimally the count of spell levels
BonusSpells(int type,int count,const int * bonuses)693 void Spellbook::BonusSpells(int type, int count, const int *bonuses)
694 {
695 	int level = GetSpellLevelCount(type);
696 	if (level>count) level=count;
697 	for (int i = 0; i < level; i++) {
698 		CRESpellMemorization* sm = GetSpellMemorization(type, i);
699 		// don't give access to new spell levels through these boni
700 		if (sm->SlotCountWithBonus) {
701 			sm->SlotCountWithBonus+=bonuses[i];
702 		}
703 	}
704 }
705 
706 //call this in every ai cycle when recalculating spell bonus
707 //TODO:add in wisdom bonus here
ClearBonus()708 void Spellbook::ClearBonus()
709 {
710 	int type;
711 
712 	for (type = 0; type < NUM_BOOK_TYPES; type++) {
713 		int level = GetSpellLevelCount(type);
714 		for (int i = 0; i < level; i++) {
715 			CRESpellMemorization* sm = GetSpellMemorization(type, i);
716 			sm->SlotCountWithBonus=sm->SlotCount;
717 		}
718 	}
719 }
720 
GetSpellMemorization(unsigned int type,unsigned int level)721 CRESpellMemorization *Spellbook::GetSpellMemorization(unsigned int type, unsigned int level)
722 {
723 	if (type >= (unsigned int)NUM_BOOK_TYPES)
724 		return NULL;
725 
726 	CRESpellMemorization *sm;
727 	if (level >= GetSpellLevelCount(type)) {
728 		sm = new CRESpellMemorization();
729 		sm->Type = (ieWord) type;
730 		sm->Level = (ieWord) level;
731 		sm->SlotCount = sm->SlotCountWithBonus = 0;
732 		if ( !AddSpellMemorization(sm) ) {
733 			delete sm;
734 			return NULL;
735 		}
736 		assert(sm == spells[type][level]);
737 	} else {
738 		sm = spells[type][level];
739 	}
740 	return sm;
741 }
742 //if bonus is not set, then sets the base value (adjusts bonus too)
743 //if bonus is set, then sets only the bonus
744 //if the bonus value is 0, then the bonus is double base value
745 //bonus is cummulative, but not saved
SetMemorizableSpellsCount(int Value,int type,unsigned int level,bool bonus)746 void Spellbook::SetMemorizableSpellsCount(int Value, int type, unsigned int level, bool bonus)
747 {
748 	int diff;
749 
750 	if (type >= NUM_BOOK_TYPES) {
751 		return;
752 	}
753 
754 	CRESpellMemorization* sm = GetSpellMemorization(type, level);
755 	if (bonus) {
756 		if (!Value) {
757 			Value=sm->SlotCountWithBonus;
758 		}
759                 //if can't cast w/o bonus then can't cast at all!
760                 if (sm->SlotCount)
761                     sm->SlotCountWithBonus=(ieWord) (sm->SlotCountWithBonus+Value);
762 	}
763 	else {
764 		diff=sm->SlotCountWithBonus-sm->SlotCount;
765 		sm->SlotCount=(ieWord) Value;
766 		sm->SlotCountWithBonus=(ieWord) (Value+diff);
767 	}
768 }
769 
GetMemorizableSpellsCount(int type,unsigned int level,bool bonus) const770 int Spellbook::GetMemorizableSpellsCount(int type, unsigned int level, bool bonus) const
771 {
772 	if (type >= NUM_BOOK_TYPES || level >= GetSpellLevelCount(type))
773 		return 0;
774 	CRESpellMemorization* sm = spells[type][level];
775 	if (bonus)
776 		return sm->SlotCountWithBonus;
777 	return sm->SlotCount;
778 }
779 
MemorizeSpell(const CREKnownSpell * spell,bool usable)780 bool Spellbook::MemorizeSpell(const CREKnownSpell* spell, bool usable)
781 {
782 	ieWord spellType = spell->Type;
783 	CRESpellMemorization* sm = spells[spellType][spell->Level];
784 	if (sm->SlotCountWithBonus <= sm->memorized_spells.size() && !(innate & (1<<spellType))) {
785 		//it is possible to have sorcerer type spellbooks for any spellbook type
786 		if (! (sorcerer & (1<<spellType) ) )
787 			return false;
788 	}
789 
790 	CREMemorizedSpell* mem_spl = new CREMemorizedSpell();
791 	CopyResRef( mem_spl->SpellResRef, spell->SpellResRef );
792 	mem_spl->Flags = usable ? 1 : 0; // FIXME: is it all it's used for?
793 
794 	sm->memorized_spells.push_back( mem_spl );
795 	ClearSpellInfo();
796 	return true;
797 }
798 
UnmemorizeSpell(const CREMemorizedSpell * spell)799 bool Spellbook::UnmemorizeSpell(const CREMemorizedSpell* spell)
800 {
801 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
802 		std::vector< CRESpellMemorization* >::iterator sm;
803 		for (sm = spells[i].begin(); sm != spells[i].end(); ++sm) {
804 			std::vector< CREMemorizedSpell* >::iterator s;
805 			for (s = (*sm)->memorized_spells.begin(); s != (*sm)->memorized_spells.end(); ++s) {
806 				if (*s == spell) {
807 					delete *s;
808 					(*sm)->memorized_spells.erase( s );
809 					ClearSpellInfo();
810 					return true;
811 				}
812 			}
813 		}
814 	}
815 
816 	return false;
817 }
818 
UnmemorizeSpell(const ieResRef ResRef,bool deplete,bool onlydepleted)819 bool Spellbook::UnmemorizeSpell(const ieResRef ResRef, bool deplete, bool onlydepleted)
820 {
821 	for (int type = 0; type<NUM_BOOK_TYPES; type++) {
822 		std::vector< CRESpellMemorization* >::iterator sm;
823 		for (sm = spells[type].begin(); sm != spells[type].end(); ++sm) {
824 			std::vector< CREMemorizedSpell* >::iterator s;
825 			for (s = (*sm)->memorized_spells.begin(); s != (*sm)->memorized_spells.end(); ++s) {
826 				if (strnicmp(ResRef, (*s)->SpellResRef, sizeof(ieResRef) ) ) {
827 					continue;
828 				}
829 				if (onlydepleted && (*s)->Flags != 0) {
830 					continue;
831 				}
832 				if (deplete) {
833 					(*s)->Flags = 0;
834 				} else {
835 					delete *s;
836 					(*sm)->memorized_spells.erase( s );
837 				}
838 				ClearSpellInfo();
839 				return true;
840 			}
841 		}
842 	}
843 
844 	return false;
845 }
846 
847 //bitfield disabling type: 1 - mage, 2 - cleric etc
848 //level: if set, then finds that level only
FindUnchargedSpell(int type,int level) const849 CREMemorizedSpell* Spellbook::FindUnchargedSpell(int type, int level) const
850 {
851 	int mask=1;
852 
853 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
854 		if (type&mask) {
855 			mask<<=1;
856 			continue;
857 		}
858 		mask<<=1;
859 		for (unsigned int j = 0; j<spells[i].size(); j++) {
860 			CRESpellMemorization* sm = spells[i][j];
861 			if (level && (sm->Level!=level-1)) {
862 				continue;
863 			}
864 
865 			for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
866 				CREMemorizedSpell *ret = sm->memorized_spells[k];
867 				if (ret->Flags == 0) {
868 					return ret;
869 				}
870 			}
871 		}
872 	}
873 	return NULL;
874 }
875 
876 //creates sorcerer style memory for the given spell type
CreateSorcererMemory(int type)877 void Spellbook::CreateSorcererMemory(int type)
878 {
879 	for (size_t j = 0; j < spells[type].size(); j++) {
880 		CRESpellMemorization* sm = spells[type][j];
881 
882 		size_t cnt = sm->memorized_spells.size();
883 		while(cnt--) {
884 			delete sm->memorized_spells[cnt];
885 		}
886 		sm->memorized_spells.clear();
887 		for (unsigned int k = 0; k < sm->known_spells.size(); k++) {
888 			CREKnownSpell *ck = sm->known_spells[k];
889 			cnt = sm->SlotCountWithBonus;
890 			while(cnt--) {
891 				MemorizeSpell(ck, true);
892 			}
893 		}
894 	}
895 }
896 
ChargeAllSpells()897 void Spellbook::ChargeAllSpells()
898 {
899 	int j = 1;
900 	for (int i = 0; i < NUM_BOOK_TYPES; j+=j,i++) {
901 		//this spellbook page type is sorcerer-like
902 		if (sorcerer&j ) {
903 			CreateSorcererMemory(i);
904 			continue;
905 		}
906 
907 		for (unsigned int j = 0; j < spells[i].size(); j++) {
908 			CRESpellMemorization* sm = spells[i][j];
909 
910 			for (unsigned int k = 0; k < sm->memorized_spells.size(); k++)
911 				ChargeSpell( sm->memorized_spells[k] );
912 		}
913 	}
914 }
915 
916 //unmemorizes the highest level spell possible
917 //returns true if successful
DepleteSpell(int type)918 bool Spellbook::DepleteSpell(int type)
919 {
920 	if (type>=NUM_BOOK_TYPES) {
921 		return false;
922 	}
923 	size_t j = GetSpellLevelCount(type);
924 	while(j--) {
925 		CRESpellMemorization* sm = spells[type][j];
926 
927 		for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
928 			if (DepleteSpell( sm->memorized_spells[k] )) {
929 				if (sorcerer & (1<<type) ) {
930 					DepleteLevel (sm, sm->memorized_spells[k]->SpellResRef);
931 				}
932 				return true;
933 			}
934 		}
935 	}
936 	return false;
937 }
938 
DepleteLevel(CRESpellMemorization * sm,const ieResRef except)939 void Spellbook::DepleteLevel(CRESpellMemorization* sm, const ieResRef except)
940 {
941 	size_t cnt = sm->memorized_spells.size();
942 	ieResRef last={""};
943 
944 	for (size_t i = 0; i < cnt && cnt>0; i++) {
945 		CREMemorizedSpell *cms = sm->memorized_spells[i];
946 		//sorcerer spells are created in orderly manner
947 		if (cms->Flags && strncmp(last,cms->SpellResRef,8) && strncmp(except,cms->SpellResRef,8)) {
948 			memcpy(last, cms->SpellResRef, sizeof(ieResRef) );
949 			cms->Flags=0;
950 /*
951 			delete cms;
952 			sm->memorized_spells.erase(sm->memorized_spells.begin()+i);
953 			i--;
954 			cnt--;
955 */
956 		}
957 	}
958 }
959 
DepleteSpell(int type,unsigned int page,unsigned int slot)960 bool Spellbook::DepleteSpell(int type, unsigned int page, unsigned int slot)
961 {
962 	bool ret;
963 
964 	if (NUM_BOOK_TYPES<=type) {
965 		return false;
966 	}
967 	if (spells[type].size()<=page) {
968 		return false;
969 	}
970 	CRESpellMemorization* sm = spells[page][type];
971 	if (sm->memorized_spells.size()<=slot) {
972 		return false;
973 	}
974 
975 	CREMemorizedSpell* cms = sm->memorized_spells[slot];
976 	ret = DepleteSpell(cms);
977 	if (ret && (sorcerer & (1<<type) ) ) {
978 		DepleteLevel (sm, cms->SpellResRef);
979 	}
980 
981 	return ret;
982 }
983 
ChargeSpell(CREMemorizedSpell * spl)984 bool Spellbook::ChargeSpell(CREMemorizedSpell* spl)
985 {
986 	spl->Flags = 1;
987 	ClearSpellInfo();
988 	return true;
989 }
990 
DepleteSpell(CREMemorizedSpell * spl)991 bool Spellbook::DepleteSpell(CREMemorizedSpell* spl)
992 {
993 	if (spl->Flags) {
994 		spl->Flags = 0;
995 		ClearSpellInfo();
996 		return true;
997 	}
998 	return false;
999 }
1000 
ClearSpellInfo()1001 void Spellbook::ClearSpellInfo()
1002 {
1003 	size_t i = spellinfo.size();
1004 	while(i--) {
1005 		delete spellinfo[i];
1006 	}
1007 	spellinfo.clear();
1008 }
1009 
GetSpellInfo(SpellExtHeader * array,int type,int startindex,int count)1010 bool Spellbook::GetSpellInfo(SpellExtHeader *array, int type, int startindex, int count)
1011 {
1012 	memset(array, 0, count * sizeof(SpellExtHeader) );
1013 	if (spellinfo.empty()) {
1014 		GenerateSpellInfo();
1015 	}
1016 	int actual = 0;
1017 	bool ret = false;
1018 	for (unsigned int i = 0; i<spellinfo.size(); i++) {
1019 		if ( !(type & (1<<spellinfo[i]->type)) ) {
1020 			continue;
1021 		}
1022 		if (startindex>0) {
1023 			startindex--;
1024 			continue;
1025 		}
1026 		if (actual>=count) {
1027 			ret = true;
1028 			break;
1029 		}
1030 		memcpy(array+actual, spellinfo[i], sizeof(SpellExtHeader));
1031 		actual++;
1032 	}
1033 	return ret;
1034 }
1035 
1036 // returns the size of spellinfo vector, if type is nonzero it is used as filter
1037 // for example type==1 lists the number of different mage spells
GetSpellInfoSize(int type)1038 unsigned int Spellbook::GetSpellInfoSize(int type)
1039 {
1040 	size_t i = spellinfo.size();
1041 	if (!i) {
1042 		GenerateSpellInfo();
1043 		i = spellinfo.size();
1044 	}
1045 	if (!type) {
1046 		return (unsigned int) i;
1047 	}
1048 	unsigned int count = 0;
1049 	while(i--) {
1050 		if (1<<(spellinfo[i]->type)&type) {
1051 			count++;
1052 		}
1053 	}
1054 	return count;
1055 }
1056 
1057 //type = 0 means any type
FindSpellInfo(SpellExtHeader * array,const ieResRef spellname,unsigned int type)1058 int Spellbook::FindSpellInfo(SpellExtHeader *array, const ieResRef spellname, unsigned int type)
1059 {
1060 	memset(array, 0, sizeof(SpellExtHeader) );
1061 	if (spellinfo.empty()) {
1062 		GenerateSpellInfo();
1063 	}
1064 	int offset = 0;
1065 	for (unsigned int i = 0; i<spellinfo.size(); i++) {
1066 		// take the offset into account, since we need per-type indices
1067 		if (type && !(1<<(spellinfo[i]->type) & type)) {
1068 			offset++;
1069 			continue;
1070 		}
1071 		if (strnicmp(spellinfo[i]->spellname, spellname, sizeof(ieResRef) ) ) continue;
1072 		memcpy(array, spellinfo[i], sizeof(SpellExtHeader));
1073 		return i-offset+1;
1074 	}
1075 	return 0;
1076 }
1077 
FindSpellInfo(unsigned int level,unsigned int type,const ieResRef spellname) const1078 SpellExtHeader *Spellbook::FindSpellInfo(unsigned int level, unsigned int type, const ieResRef spellname) const
1079 {
1080 	size_t i = spellinfo.size();
1081 	while(i--) {
1082 		if ( (spellinfo[i]->level==level) &&
1083 			(spellinfo[i]->type==type) &&
1084 			!strnicmp(spellinfo[i]->spellname, spellname, 8)) {
1085 				return spellinfo[i];
1086 		}
1087 	}
1088 	return NULL;
1089 }
1090 
AddSpellInfo(unsigned int sm_level,unsigned int sm_type,const ieResRef spellname,unsigned int idx)1091 void Spellbook::AddSpellInfo(unsigned int sm_level, unsigned int sm_type, const ieResRef spellname, unsigned int idx)
1092 {
1093 	Spell *spl = gamedata->GetSpell(spellname, true);
1094 	if (!spl)
1095 		return;
1096 	if (spl->ExtHeaderCount<1)
1097 		return;
1098 
1099 	ieDword level = 0;
1100 	SpellExtHeader *seh = FindSpellInfo(sm_level, sm_type, spellname);
1101 	if (seh) {
1102 		seh->count++;
1103 		return;
1104 	}
1105 
1106 	seh = new SpellExtHeader;
1107 	spellinfo.push_back( seh );
1108 
1109 	memcpy(seh->spellname, spellname, sizeof(ieResRef) );
1110 	int ehc;
1111 
1112 	for (ehc = 0; ehc < spl->ExtHeaderCount-1; ehc++) {
1113 		if (level<spl->ext_headers[ehc+1].RequiredLevel) {
1114 			break;
1115 		}
1116 	}
1117 
1118 	SPLExtHeader *ext_header = spl->ext_headers+ehc;
1119 	seh->headerindex = ehc;
1120 	seh->level = sm_level;
1121 	seh->type = sm_type;
1122 	seh->slot = idx;
1123 	seh->count = 1;
1124 	seh->SpellForm = ext_header->SpellForm;
1125 	memcpy(seh->MemorisedIcon, ext_header->MemorisedIcon,sizeof(ieResRef) );
1126 	seh->Target = ext_header->Target;
1127 	seh->TargetNumber = ext_header->TargetNumber;
1128 	seh->Range = ext_header->Range;
1129 	seh->Projectile = ext_header->ProjectileAnimation;
1130 	seh->CastingTime = (ieWord) ext_header->CastingTime;
1131 	seh->strref = spl->SpellName;
1132 	gamedata->FreeSpell(spl, spellname, false);
1133 }
1134 
SetCustomSpellInfo(const ieResRef * data,ieResRef spell,int type)1135 void Spellbook::SetCustomSpellInfo(const ieResRef *data, ieResRef spell, int type)
1136 {
1137 	ClearSpellInfo();
1138 	if (data) {
1139 		for(int i = 0; i<type;i++) {
1140 			AddSpellInfo(0,0,data[i],-1);
1141 		}
1142 		return;
1143 	}
1144 
1145 	//if data is not set, use the known spells list to set up the spellinfo list
1146 	for(int i = 0; i<NUM_BOOK_TYPES; i++) {
1147 		if ((1<<i)&type) {
1148 			for(unsigned int j = 0; j<spells[i].size(); j++) {
1149 				CRESpellMemorization* sm = spells[i][j];
1150 
1151 				for(unsigned int k=0;k<sm->known_spells.size(); k++) {
1152 					CREKnownSpell* slot = sm->known_spells[k];
1153 					if (!slot)
1154 						continue;
1155 					//skip the spell itself
1156 					if (spell && !strnicmp(slot->SpellResRef, spell, sizeof(ieResRef)))
1157 						continue;
1158 					AddSpellInfo(sm->Level, sm->Type, slot->SpellResRef, -1);
1159 				}
1160 			}
1161 		}
1162 	}
1163 }
1164 
1165 // grouping the castable spells
GenerateSpellInfo()1166 void Spellbook::GenerateSpellInfo()
1167 {
1168 	ClearSpellInfo(); //just in case
1169 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
1170 		for (unsigned int j = 0; j < spells[i].size(); j++) {
1171 			CRESpellMemorization* sm = spells[i][j];
1172 
1173 			for (unsigned int k = 0; k < sm->memorized_spells.size(); k++) {
1174 				CREMemorizedSpell* slot = sm->memorized_spells[k];
1175 				if (!slot)
1176 					continue;
1177 				if (!slot->Flags)
1178 					continue;
1179 				AddSpellInfo(sm->Level, sm->Type, slot->SpellResRef, k);
1180 			}
1181 		}
1182 	}
1183 }
1184 
dump() const1185 void Spellbook::dump() const
1186 {
1187 	StringBuffer buffer;
1188 	dump(buffer);
1189 	Log(DEBUG, "Spellbook", buffer);
1190 }
1191 
dump(StringBuffer & buffer) const1192 void Spellbook::dump(StringBuffer& buffer) const
1193 {
1194 	unsigned int k;
1195 
1196 	buffer.append( "SPELLBOOK:\n" );
1197 	for (int i = 0; i < NUM_BOOK_TYPES; i++) {
1198 		for (unsigned int j = 0; j < spells[i].size(); j++) {
1199 			CRESpellMemorization* sm = spells[i][j];
1200 
1201 			if (sm->known_spells.size())
1202 				buffer.append( " Known spells:\n" );
1203 			for (k = 0; k < sm->known_spells.size(); k++) {
1204 				CREKnownSpell* spl = sm->known_spells[k];
1205 				if (!spl) continue;
1206 
1207 				buffer.appendFormatted ( " %2d: %8s L: %d T: %d\n", k, spl->SpellResRef, spl->Level, spl->Type );
1208 			}
1209 
1210 			if (sm->memorized_spells.size())
1211 				buffer.append( " Memorized spells:\n" );
1212 			for (k = 0; k < sm->memorized_spells.size (); k++) {
1213 				CREMemorizedSpell* spl = sm->memorized_spells[k];
1214 				if (!spl) continue;
1215 
1216 				buffer.appendFormatted ( " %2u: %8s %x\n", k, spl->SpellResRef, spl->Flags );
1217 			}
1218 		}
1219 	}
1220 }
1221 
1222 }
1223