CodingStyle: Document header include order.
[gemrb.git] / gemrb / core / Spell.cpp
blobc3eaf5ff9f59f518cf86a645e516d7233463aab6
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 //This class represents the .spl (spell) files of the game.
23 #include "Spell.h"
25 #include "win32def.h"
27 #include "Actor.h"
28 #include "Game.h"
29 #include "Interface.h"
30 #include "Projectile.h"
31 #include "ProjectileServer.h"
33 SPLExtHeader::SPLExtHeader(void)
35 features = NULL;
38 SPLExtHeader::~SPLExtHeader(void)
40 delete [] features;
43 Spell::Spell(void)
45 ext_headers = NULL;
46 casting_features = NULL;
49 Spell::~Spell(void)
51 //Spell is in the core, so this is not needed, i guess (Avenger)
52 //core->FreeSPLExt(ext_headers, casting_features);
53 delete [] ext_headers;
54 delete [] casting_features;
57 int Spell::GetHeaderIndexFromLevel(int level) const
59 if (level<0) return -1;
60 if (Flags & SF_SIMPLIFIED_DURATION) {
61 return level;
63 int block_index;
64 for(block_index=0;block_index<ExtHeaderCount-1;block_index++) {
65 if (ext_headers[block_index+1].RequiredLevel>level) {
66 return block_index;
69 return ExtHeaderCount-1;
72 //-1 will return cfb
73 //0 will always return first spell block
74 //otherwise set to caster level
75 static EffectRef fx_casting_glow_ref={"CastingGlow",NULL,-1};
77 void Spell::AddCastingGlow(EffectQueue *fxqueue, ieDword duration)
79 Effect *fx = EffectQueue::CreateEffect(fx_casting_glow_ref, 0, CastingGraphics, FX_DURATION_ABSOLUTE);
80 fx->Duration = core->GetGame()->GameTime + duration;
81 fx->InventorySlot = 0xffff;
82 fx->Projectile = 0;
83 fxqueue->AddEffect(fx);
84 //AddEffect creates a copy, we need to destroy the original
85 delete fx;
88 EffectQueue *Spell::GetEffectBlock(Scriptable *self, const Point &pos, int block_index, ieDword pro) const
90 Effect *features;
91 int count;
93 //iwd2 has this hack
94 if (block_index>=0) {
95 if (Flags & SF_SIMPLIFIED_DURATION) {
96 features = ext_headers[0].features;
97 count = ext_headers[0].FeatureCount;
98 } else {
99 features = ext_headers[block_index].features;
100 count = ext_headers[block_index].FeatureCount;
102 } else {
103 features = casting_features;
104 count = CastingFeatureCount;
106 EffectQueue *fxqueue = new EffectQueue();
108 for (int i=0;i<count;i++) {
109 if (Flags & SF_SIMPLIFIED_DURATION) {
110 //hack the effect according to Level
111 //fxqueue->AddEffect will copy the effect,
112 //so we don't risk any overwriting
113 if (EffectQueue::HasDuration(features+i)) {
114 features[i].Duration = (TimePerLevel*block_index+TimeConstant)*7;
117 //fill these for completeness, inventoryslot is a good way
118 //to discern a spell from an item effect
119 features[i].InventorySlot = 0xffff;
120 if (features[i].Target != FX_TARGET_SELF) {
121 features[i].Projectile = pro;
122 fxqueue->AddEffect( features+i );
123 } else {
124 Actor *target = (self->Type==ST_ACTOR)?(Actor *) self:NULL;
125 features[i].Projectile = 0;
126 features[i].PosX=pos.x;
127 features[i].PosY=pos.y;
128 //FIXME (r7193):
129 //This is bad, effects should be able to affect non living targets
130 //This is done by NULL target, the position should be enough
131 //to tell which non-actor object is affected
132 if (target) {
133 core->ApplyEffect(features+i, target, self);
137 return fxqueue;
140 Projectile *Spell::GetProjectile(Scriptable *self, int header, const Point &target) const
142 SPLExtHeader *seh = GetExtHeader(header);
143 if (!seh) {
144 printMessage("Spell", "Cannot retrieve spell header!!! ",RED);
145 printf("required header: %d, maximum: %d\n", header, (int) ExtHeaderCount);
146 return NULL;
148 Projectile *pro = core->GetProjectileServer()->GetProjectileByIndex(seh->ProjectileAnimation);
149 if (seh->FeatureCount) {
150 pro->SetEffects(GetEffectBlock(self, target, header, seh->ProjectileAnimation));
152 return pro;
155 //get the casting distance of the spell
156 //it depends on the casting level of the actor
157 //if actor isn't given, then the first header is used
158 //TODO: fix casting level for all class combos
159 unsigned int Spell::GetCastingDistance(Actor *actor) const
161 int level = 1;
162 if(actor) {
163 level = actor->GetStat(IE_LEVEL);
164 if(SpellType==IE_SPL_WIZARD) {
165 level+=actor->GetStat(IE_CASTINGLEVELBONUSMAGE);
167 else if(SpellType==IE_SPL_PRIEST) {
168 level+=actor->GetStat(IE_CASTINGLEVELBONUSCLERIC);
172 if(level<1) level=1;
173 int idx = GetHeaderIndexFromLevel(level);
174 SPLExtHeader *seh = GetExtHeader(idx);
175 if (!seh) {
176 printMessage("Spell", "Cannot retrieve spell header!!! ",RED);
177 printf("required header: %d, maximum: %d\n", idx, (int) ExtHeaderCount);
178 return 0;
180 return (unsigned int) seh->Range;