1 /***************************************************************************
2 * Copyright (C) 2009 by Andrey Afletdinov <fheroes2@gmail.com> *
3 * *
4 * Part of the Free Heroes2 Engine: *
5 * http://sourceforge.net/projects/fheroes2 *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22
23 #include "spell.h"
24 #include "artifact.h"
25 #include "heroes_base.h"
26 #include "race.h"
27 #include "rand.h"
28 #include "resource.h"
29 #include "serialize.h"
30 #include "translations.h"
31
32 struct spellstats_t
33 {
34 const char * name;
35 uint8_t spellPoints;
36 uint16_t movePoints;
37 uint32_t imageId;
38 uint8_t extraValue;
39 const char * description;
40 };
41
42 // The original resources don't have most of sprites for Mass Spells
43 // so we made some tricks in AGG source file. All modified sprite IDs start from 60
44
45 spellstats_t spells[] = {
46 // name | sp | mp | spr | value| bits | description
47 { "Unknown", 0, 0, 0, 0, "Unknown spell." },
48 { gettext_noop( "Fireball" ), 9, 0, 8, 10, gettext_noop( "Causes a giant fireball to strike the selected area, damaging all nearby creatures." ) },
49 { gettext_noop( "Fireblast" ), 15, 0, 9, 10,
50 gettext_noop( "An improved version of fireball, fireblast affects two hexes around the center point of the spell, rather than one." ) },
51 { gettext_noop( "Lightning Bolt" ), 7, 0, 4, 25, gettext_noop( "Causes a bolt of electrical energy to strike the selected creature." ) },
52 { gettext_noop( "Chain Lightning" ), 15, 0, 5, 40,
53 gettext_noop(
54 "Causes a bolt of electrical energy to strike a selected creature, then strike the nearest creature with half damage, then strike the NEXT nearest creature with half again damage, and so on, until it becomes too weak to be harmful. Warning: This spell can hit your own creatures!" ) },
55 { gettext_noop( "Teleport" ), 9, 0, 10, 0, gettext_noop( "Teleports the creature you select to any open position on the battlefield." ) },
56 { gettext_noop( "Cure" ), 6, 0, 6, 5,
57 gettext_noop( "Removes all negative spells cast upon one of your units, and restores up to %{count} HP per level of spell power." ) },
58 { gettext_noop( "Mass Cure" ), 15, 0, 60, 5,
59 gettext_noop( "Removes all negative spells cast upon your forces, and restores up to %{count} HP per level of spell power, per creature." ) },
60 { gettext_noop( "Resurrect" ), 12, 0, 13, 50, gettext_noop( "Resurrects creatures from a damaged or dead unit until end of combat." ) },
61 { gettext_noop( "Resurrect True" ), 15, 0, 12, 50, gettext_noop( "Resurrects creatures from a damaged or dead unit permanently." ) },
62 { gettext_noop( "Haste" ), 3, 0, 14, 0, gettext_noop( "Increases the speed of any creature by %{count}." ) },
63 { gettext_noop( "Mass Haste" ), 10, 0, 61, 0, gettext_noop( "Increases the speed of all of your creatures by %{count}." ) },
64 { gettext_noop( "spell|Slow" ), 3, 0, 1, 0, gettext_noop( "Slows target to half movement rate." ) },
65 { gettext_noop( "Mass Slow" ), 15, 0, 62, 0, gettext_noop( "Slows all enemies to half movement rate." ) },
66 { gettext_noop( "spell|Blind" ), 6, 0, 21, 0, gettext_noop( "Clouds the affected creatures' eyes, preventing them from moving." ) },
67 { gettext_noop( "Bless" ), 3, 0, 7, 0, gettext_noop( "Causes the selected creatures to inflict maximum damage." ) },
68 { gettext_noop( "Mass Bless" ), 12, 0, 63, 0, gettext_noop( "Causes all of your units to inflict maximum damage." ) },
69 { gettext_noop( "Stoneskin" ), 3, 0, 31, 3, gettext_noop( "Magically increases the defense skill of the selected creatures." ) },
70 { gettext_noop( "Steelskin" ), 6, 0, 30, 5, gettext_noop( "Increases the defense skill of the targeted creatures. This is an improved version of Stoneskin." ) },
71 { gettext_noop( "Curse" ), 3, 0, 3, 0, gettext_noop( "Causes the selected creatures to inflict minimum damage." ) },
72 { gettext_noop( "Mass Curse" ), 12, 0, 64, 0, gettext_noop( "Causes all enemy troops to inflict minimum damage." ) },
73 { gettext_noop( "Holy Word" ), 9, 0, 22, 10, gettext_noop( "Damages all undead in the battle." ) },
74 { gettext_noop( "Holy Shout" ), 12, 0, 23, 20, gettext_noop( "Damages all undead in the battle. This is an improved version of Holy Word." ) },
75 { gettext_noop( "Anti-Magic" ), 7, 0, 17, 0, gettext_noop( "Prevents harmful magic against the selected creatures." ) },
76 { gettext_noop( "Dispel Magic" ), 5, 0, 18, 0, gettext_noop( "Removes all magic spells from a single target." ) },
77 { gettext_noop( "Mass Dispel" ), 12, 0, 18, 0, gettext_noop( "Removes all magic spells from all creatures." ) },
78 { gettext_noop( "Magic Arrow" ), 3, 0, 38, 10, gettext_noop( "Causes a magic arrow to strike the selected target." ) },
79 { gettext_noop( "Berserker" ), 12, 0, 19, 0, gettext_noop( "Causes a creature to attack its nearest neighbor." ) },
80 { gettext_noop( "Armageddon" ), 20, 0, 16, 50, gettext_noop( "Holy terror strikes the battlefield, causing severe damage to all creatures." ) },
81 { gettext_noop( "Elemental Storm" ), 15, 0, 11, 25, gettext_noop( "Magical elements pour down on the battlefield, damaging all creatures." ) },
82 { gettext_noop( "Meteor Shower" ), 15, 0, 24, 25, gettext_noop( "A rain of rocks strikes an area of the battlefield, damaging all nearby creatures." ) },
83 { gettext_noop( "Paralyze" ), 9, 0, 20, 0, gettext_noop( "The targeted creatures are paralyzed, unable to move or retaliate." ) },
84 { gettext_noop( "Hypnotize" ), 15, 0, 37, 25,
85 gettext_noop( "Brings a single enemy unit under your control if its hits are less than %{count} times the caster's spell power." ) },
86 { gettext_noop( "Cold Ray" ), 6, 0, 36, 20, gettext_noop( "Drains body heat from a single enemy unit." ) },
87 { gettext_noop( "Cold Ring" ), 9, 0, 35, 10, gettext_noop( "Drains body heat from all units surrounding the center point, but not including the center point." ) },
88 { gettext_noop( "Disrupting Ray" ), 7, 0, 34, 3, gettext_noop( "Reduces the defense rating of an enemy unit by three." ) },
89 { gettext_noop( "Death Ripple" ), 6, 0, 28, 5, gettext_noop( "Damages all living (non-undead) units in the battle." ) },
90 { gettext_noop( "Death Wave" ), 10, 0, 29, 10,
91 gettext_noop( "Damages all living (non-undead) units in the battle. This spell is an improved version of Death Ripple." ) },
92 { gettext_noop( "Dragon Slayer" ), 6, 0, 32, 5, gettext_noop( "Greatly increases a unit's attack skill vs. Dragons." ) },
93 { gettext_noop( "Blood Lust" ), 3, 0, 27, 3, gettext_noop( "Increases a unit's attack skill." ) },
94 { gettext_noop( "Animate Dead" ), 10, 0, 25, 50, gettext_noop( "Resurrects creatures from a damaged or dead undead unit permanently." ) },
95 { gettext_noop( "Mirror Image" ), 25, 0, 26, 0,
96 gettext_noop(
97 "Creates an illusionary unit that duplicates one of your existing units. This illusionary unit does the same damages as the original, but will vanish if it takes any damage." ) },
98 { gettext_noop( "Shield" ), 3, 0, 15, 2, gettext_noop( "Halves damage received from ranged attacks for a single unit." ) },
99 { gettext_noop( "Mass Shield" ), 7, 0, 65, 0, gettext_noop( "Halves damage received from ranged attacks for all of your units." ) },
100 { gettext_noop( "Summon Earth Elemental" ), 30, 0, 56, 3, gettext_noop( "Summons Earth Elementals to fight for your army." ) },
101 { gettext_noop( "Summon Air Elemental" ), 30, 0, 57, 3, gettext_noop( "Summons Air Elementals to fight for your army." ) },
102 { gettext_noop( "Summon Fire Elemental" ), 30, 0, 58, 3, gettext_noop( "Summons Fire Elementals to fight for your army." ) },
103 { gettext_noop( "Summon Water Elemental" ), 30, 0, 59, 3, gettext_noop( "Summons Water Elementals to fight for your army." ) },
104 { gettext_noop( "Earthquake" ), 15, 0, 33, 0, gettext_noop( "Damages castle walls." ) },
105 { gettext_noop( "View Mines" ), 1, 0, 39, 0, gettext_noop( "Causes all mines across the land to become visible." ) },
106 { gettext_noop( "View Resources" ), 1, 0, 40, 0, gettext_noop( "Causes all resources across the land to become visible." ) },
107 { gettext_noop( "View Artifacts" ), 2, 0, 41, 0, gettext_noop( "Causes all artifacts across the land to become visible." ) },
108 { gettext_noop( "View Towns" ), 2, 0, 42, 0, gettext_noop( "Causes all towns and castles across the land to become visible." ) },
109 { gettext_noop( "View Heroes" ), 2, 0, 43, 0, gettext_noop( "Causes all Heroes across the land to become visible." ) },
110 { gettext_noop( "View All" ), 3, 0, 44, 0, gettext_noop( "Causes the entire land to become visible." ) },
111 { gettext_noop( "Identify Hero" ), 3, 0, 45, 0, gettext_noop( "Allows the caster to view detailed information on enemy Heroes." ) },
112 { gettext_noop( "Summon Boat" ), 5, 0, 46, 0,
113 gettext_noop(
114 "Summons the nearest unoccupied, friendly boat to an adjacent shore location. A friendly boat is one which you just built or were the most recent player to occupy." ) },
115 { gettext_noop( "Dimension Door" ), 10, 0, 47, 0, gettext_noop( "Allows the caster to magically transport to a nearby location." ) },
116 { gettext_noop( "Town Gate" ), 10, 0, 48, 0, gettext_noop( "Returns the caster to any town or castle currently owned." ) },
117 { gettext_noop( "Town Portal" ), 20, 0, 49, 0, gettext_noop( "Returns the hero to the town or castle of choice, provided it is controlled by you." ) },
118 { gettext_noop( "Visions" ), 6, 0, 50, 3, gettext_noop( "Visions predicts the likely outcome of an encounter with a neutral army camp." ) },
119 { gettext_noop( "Haunt" ), 8, 0, 51, 4,
120 gettext_noop( "Haunts a mine you control with Ghosts. This mine stops producing resources. (If I can't keep it, nobody will!)" ) },
121 { gettext_noop( "Set Earth Guardian" ), 15, 0, 52, 4, gettext_noop( "Sets Earth Elementals to guard a mine against enemy armies." ) },
122 { gettext_noop( "Set Air Guardian" ), 15, 0, 53, 4, gettext_noop( "Sets Air Elementals to guard a mine against enemy armies." ) },
123 { gettext_noop( "Set Fire Guardian" ), 15, 0, 54, 4, gettext_noop( "Sets Fire Elementals to guard a mine against enemy armies." ) },
124 { gettext_noop( "Set Water Guardian" ), 15, 0, 55, 4, gettext_noop( "Sets Water Elementals to guard a mine against enemy armies." ) },
125 { "Random", 1, 0, 0, 0, "Random" },
126 { "Random 1", 1, 0, 0, 0, "Random 1" },
127 { "Random 2", 1, 0, 0, 0, "Random 2" },
128 { "Random 3", 1, 0, 0, 0, "Random 3" },
129 { "Random 4", 1, 0, 0, 0, "Random 4" },
130 { "Random 5", 1, 0, 0, 0, "Random 5" },
131 { gettext_noop( "Petrification" ), 1, 0, 0, 0,
132 gettext_noop( "Turns the affected creature into stone. A petrified creature receives half damage from a direct attack." ) },
133 };
134
Spell(int s)135 Spell::Spell( int s )
136 : id( s > STONE ? NONE : s )
137 {}
138
operator <(const Spell & s) const139 bool Spell::operator<( const Spell & s ) const
140 {
141 return id < s.id;
142 }
143
operator ==(const Spell & s) const144 bool Spell::operator==( const Spell & s ) const
145 {
146 return s.id == id;
147 }
148
operator !=(const Spell & s) const149 bool Spell::operator!=( const Spell & s ) const
150 {
151 return s.id != id;
152 }
153
isValid(void) const154 bool Spell::isValid( void ) const
155 {
156 return id != Spell::NONE;
157 }
158
GetID(void) const159 int Spell::GetID( void ) const
160 {
161 return id;
162 }
163
GetName(void) const164 const char * Spell::GetName( void ) const
165 {
166 return _( spells[id].name );
167 }
168
GetDescription(void) const169 const char * Spell::GetDescription( void ) const
170 {
171 return _( spells[id].description );
172 }
173
MovePoint(void) const174 u32 Spell::MovePoint( void ) const
175 {
176 return spells[id].movePoints;
177 }
178
SpellPoint(const HeroBase * hero) const179 u32 Spell::SpellPoint( const HeroBase * hero ) const
180 {
181 u32 res = spells[id].spellPoints;
182 u32 acount = 0;
183
184 if ( hero ) {
185 switch ( id ) {
186 case BLESS:
187 case MASSBLESS:
188 acount = hero->artifactCount( Artifact::SNAKE_RING );
189 if ( acount )
190 res = spells[id].spellPoints / ( acount * 2 );
191 break;
192
193 case SUMMONEELEMENT:
194 case SUMMONAELEMENT:
195 case SUMMONFELEMENT:
196 case SUMMONWELEMENT:
197 acount = hero->artifactCount( Artifact::ELEMENTAL_RING );
198 if ( acount )
199 res = spells[id].spellPoints / ( acount * 2 );
200 break;
201
202 case CURSE:
203 case MASSCURSE:
204 acount = hero->artifactCount( Artifact::EVIL_EYE );
205 if ( acount )
206 res = spells[id].spellPoints / ( acount * 2 );
207 break;
208
209 default:
210 break;
211 }
212
213 if ( isMindInfluence() ) {
214 acount = hero->artifactCount( Artifact::SKULLCAP );
215 if ( acount )
216 res = spells[id].spellPoints / ( acount * 2 );
217 }
218 }
219
220 return res ? res : 1;
221 }
222
isLevel(int lvl) const223 bool Spell::isLevel( int lvl ) const
224 {
225 return Level() == lvl;
226 }
227
Level(void) const228 int Spell::Level( void ) const
229 {
230 switch ( id ) {
231 case BLESS:
232 case BLOODLUST:
233 case CURE:
234 case CURSE:
235 case DISPEL:
236 case HASTE:
237 case ARROW:
238 case SHIELD:
239 case SLOW:
240 case STONESKIN:
241
242 case VIEWMINES:
243 case VIEWRESOURCES:
244 return 1;
245
246 case BLIND:
247 case COLDRAY:
248 case DEATHRIPPLE:
249 case DISRUPTINGRAY:
250 case DRAGONSLAYER:
251 case LIGHTNINGBOLT:
252 case STEELSKIN:
253
254 case HAUNT:
255 case SUMMONBOAT:
256 case VIEWARTIFACTS:
257 case VISIONS:
258 return 2;
259
260 case ANIMATEDEAD:
261 case ANTIMAGIC:
262 case COLDRING:
263 case DEATHWAVE:
264 case EARTHQUAKE:
265 case FIREBALL:
266 case HOLYWORD:
267 case MASSBLESS:
268 case MASSCURSE:
269 case MASSDISPEL:
270 case MASSHASTE:
271 case PARALYZE:
272 case TELEPORT:
273
274 case IDENTIFYHERO:
275 case VIEWHEROES:
276 case VIEWTOWNS:
277 return 3;
278
279 case BERSERKER:
280 case CHAINLIGHTNING:
281 case ELEMENTALSTORM:
282 case FIREBLAST:
283 case HOLYSHOUT:
284 case MASSCURE:
285 case MASSSHIELD:
286 case MASSSLOW:
287 case METEORSHOWER:
288 case RESURRECT:
289
290 case SETEGUARDIAN:
291 case SETAGUARDIAN:
292 case SETFGUARDIAN:
293 case SETWGUARDIAN:
294 case TOWNGATE:
295 case VIEWALL:
296 return 4;
297
298 case ARMAGEDDON:
299 case HYPNOTIZE:
300 case MIRRORIMAGE:
301 case RESURRECTTRUE:
302 case SUMMONEELEMENT:
303 case SUMMONAELEMENT:
304 case SUMMONFELEMENT:
305 case SUMMONWELEMENT:
306
307 case DIMENSIONDOOR:
308 case TOWNPORTAL:
309 return 5;
310
311 default:
312 break;
313 }
314
315 return 0;
316 }
317
isCombat(void) const318 bool Spell::isCombat( void ) const
319 {
320 switch ( id ) {
321 case NONE:
322 case VIEWMINES:
323 case VIEWRESOURCES:
324 case VIEWARTIFACTS:
325 case VIEWTOWNS:
326 case VIEWHEROES:
327 case VIEWALL:
328 case IDENTIFYHERO:
329 case SUMMONBOAT:
330 case DIMENSIONDOOR:
331 case TOWNGATE:
332 case TOWNPORTAL:
333 case VISIONS:
334 case HAUNT:
335 case SETEGUARDIAN:
336 case SETAGUARDIAN:
337 case SETFGUARDIAN:
338 case SETWGUARDIAN:
339 return false;
340 default:
341 break;
342 }
343 return true;
344 }
345
isFire() const346 bool Spell::isFire() const
347 {
348 return id == FIREBALL || id == FIREBLAST;
349 }
350
isCold() const351 bool Spell::isCold() const
352 {
353 return id == COLDRAY || id == COLDRING;
354 }
355
isGuardianType() const356 bool Spell::isGuardianType() const
357 {
358 switch ( id ) {
359 case HAUNT:
360 case SETEGUARDIAN:
361 case SETAGUARDIAN:
362 case SETFGUARDIAN:
363 case SETWGUARDIAN:
364 return true;
365 default:
366 break;
367 }
368
369 return false;
370 }
371
isAdventure(void) const372 bool Spell::isAdventure( void ) const
373 {
374 return !isCombat();
375 }
376
isDamage(void) const377 bool Spell::isDamage( void ) const
378 {
379 return Damage() != 0;
380 }
381
Damage(void) const382 u32 Spell::Damage( void ) const
383 {
384 switch ( id ) {
385 case ARROW:
386 case FIREBALL:
387 case FIREBLAST:
388 case LIGHTNINGBOLT:
389 case COLDRING:
390 case DEATHWAVE:
391 case HOLYWORD:
392 case CHAINLIGHTNING:
393 case ARMAGEDDON:
394 case ELEMENTALSTORM:
395 case METEORSHOWER:
396 case COLDRAY:
397 case HOLYSHOUT:
398 case DEATHRIPPLE:
399 return spells[id].extraValue;
400
401 default:
402 break;
403 }
404
405 return 0;
406 }
407
isMindInfluence(void) const408 bool Spell::isMindInfluence( void ) const
409 {
410 switch ( id ) {
411 case BLIND:
412 case PARALYZE:
413 case BERSERKER:
414 case HYPNOTIZE:
415 return true;
416
417 default:
418 break;
419 }
420
421 return false;
422 }
423
IndexSprite(void) const424 u32 Spell::IndexSprite( void ) const
425 {
426 return spells[id].imageId;
427 }
428
Restore(void) const429 u32 Spell::Restore( void ) const
430 {
431 switch ( id ) {
432 case Spell::CURE:
433 case Spell::MASSCURE:
434 return spells[id].extraValue;
435
436 default:
437 break;
438 }
439
440 return Resurrect();
441 }
442
Resurrect(void) const443 u32 Spell::Resurrect( void ) const
444 {
445 switch ( id ) {
446 case Spell::ANIMATEDEAD:
447 case Spell::RESURRECT:
448 case Spell::RESURRECTTRUE:
449 return spells[id].extraValue;
450
451 default:
452 break;
453 }
454
455 return 0;
456 }
457
isRestore(void) const458 bool Spell::isRestore( void ) const
459 {
460 return Restore() != 0;
461 }
462
isResurrect(void) const463 bool Spell::isResurrect( void ) const
464 {
465 return Resurrect() != 0;
466 }
467
ExtraValue(void) const468 u32 Spell::ExtraValue( void ) const
469 {
470 return spells[id].extraValue;
471 }
472
Rand(int lvl,bool adv)473 Spell Spell::Rand( int lvl, bool adv )
474 {
475 std::vector<Spell> v;
476 v.reserve( 15 );
477
478 for ( u32 sp = NONE; sp < STONE; ++sp ) {
479 const Spell spell( sp );
480 if ( ( ( adv && !spell.isCombat() ) || ( !adv && spell.isCombat() ) ) && lvl == spell.Level() )
481 v.push_back( spell );
482 }
483 return !v.empty() ? Rand::Get( v ) : Spell( Spell::NONE );
484 }
485
RandCombat(int lvl)486 Spell Spell::RandCombat( int lvl )
487 {
488 return Rand( lvl, false );
489 }
490
RandAdventure(int lvl)491 Spell Spell::RandAdventure( int lvl )
492 {
493 Spell res = Rand( lvl, true );
494 return res.isValid() ? res : RandCombat( lvl );
495 }
496
isUndeadOnly(void) const497 bool Spell::isUndeadOnly( void ) const
498 {
499 switch ( id ) {
500 case ANIMATEDEAD:
501 case HOLYWORD:
502 case HOLYSHOUT:
503 return true;
504
505 default:
506 break;
507 }
508
509 return false;
510 }
511
isALiveOnly(void) const512 bool Spell::isALiveOnly( void ) const
513 {
514 switch ( id ) {
515 case BLESS:
516 case MASSBLESS:
517 case CURSE:
518 case MASSCURSE:
519 case DEATHRIPPLE:
520 case DEATHWAVE:
521 case RESURRECT:
522 case RESURRECTTRUE:
523 return true;
524
525 default:
526 break;
527 }
528
529 return false;
530 }
531
isSingleTarget() const532 bool Spell::isSingleTarget() const
533 {
534 switch ( id ) {
535 case LIGHTNINGBOLT:
536 case TELEPORT:
537 case CURE:
538 case RESURRECT:
539 case RESURRECTTRUE:
540 case HASTE:
541 case SLOW:
542 case BLIND:
543 case BLESS:
544 case STONESKIN:
545 case STEELSKIN:
546 case CURSE:
547 case ANTIMAGIC:
548 case DISPEL:
549 case ARROW:
550 case BERSERKER:
551 case PARALYZE:
552 case HYPNOTIZE:
553 case COLDRAY:
554 case DISRUPTINGRAY:
555 case DRAGONSLAYER:
556 case BLOODLUST:
557 case ANIMATEDEAD:
558 case MIRRORIMAGE:
559 case SHIELD:
560 return true;
561 }
562
563 return false;
564 }
565
isApplyWithoutFocusObject(void) const566 bool Spell::isApplyWithoutFocusObject( void ) const
567 {
568 if ( isMassActions() || isSummon() )
569 return true;
570 else
571 switch ( id ) {
572 case DEATHRIPPLE:
573 case DEATHWAVE:
574 case EARTHQUAKE:
575 case HOLYWORD:
576 case HOLYSHOUT:
577 case ARMAGEDDON:
578 case ELEMENTALSTORM:
579 return true;
580
581 default:
582 break;
583 }
584
585 return false;
586 }
587
isSummon(void) const588 bool Spell::isSummon( void ) const
589 {
590 switch ( id ) {
591 case SUMMONEELEMENT:
592 case SUMMONAELEMENT:
593 case SUMMONFELEMENT:
594 case SUMMONWELEMENT:
595 return true;
596
597 default:
598 break;
599 }
600
601 return false;
602 }
603
isEffectDispel() const604 bool Spell::isEffectDispel() const
605 {
606 switch ( id ) {
607 case CURE:
608 case MASSCURE:
609 case DISPEL:
610 case MASSDISPEL:
611 return true;
612
613 default:
614 break;
615 }
616
617 return false;
618 }
619
isApplyToAnyTroops(void) const620 bool Spell::isApplyToAnyTroops( void ) const
621 {
622 switch ( id ) {
623 case DISPEL:
624 case MASSDISPEL:
625 return true;
626
627 default:
628 break;
629 }
630
631 return false;
632 }
633
isApplyToFriends(void) const634 bool Spell::isApplyToFriends( void ) const
635 {
636 switch ( id ) {
637 case BLESS:
638 case BLOODLUST:
639 case CURE:
640 case HASTE:
641 case SHIELD:
642 case STONESKIN:
643 case DRAGONSLAYER:
644 case STEELSKIN:
645 case ANIMATEDEAD:
646 case ANTIMAGIC:
647 case TELEPORT:
648 case RESURRECT:
649 case MIRRORIMAGE:
650 case RESURRECTTRUE:
651
652 case MASSBLESS:
653 case MASSCURE:
654 case MASSHASTE:
655 case MASSSHIELD:
656 return true;
657
658 default:
659 break;
660 }
661
662 return false;
663 }
664
isMassActions(void) const665 bool Spell::isMassActions( void ) const
666 {
667 switch ( id ) {
668 case MASSCURE:
669 case MASSHASTE:
670 case MASSSLOW:
671 case MASSBLESS:
672 case MASSCURSE:
673 case MASSDISPEL:
674 case MASSSHIELD:
675 return true;
676
677 default:
678 break;
679 }
680
681 return false;
682 }
683
isApplyToEnemies(void) const684 bool Spell::isApplyToEnemies( void ) const
685 {
686 switch ( id ) {
687 case MASSSLOW:
688 case MASSCURSE:
689
690 case CURSE:
691 case ARROW:
692 case SLOW:
693 case BLIND:
694 case COLDRAY:
695 case DISRUPTINGRAY:
696 case LIGHTNINGBOLT:
697 case CHAINLIGHTNING:
698 case PARALYZE:
699 case BERSERKER:
700 case HYPNOTIZE:
701 return true;
702
703 default:
704 break;
705 }
706
707 return false;
708 }
709
isRaceCompatible(int race) const710 bool Spell::isRaceCompatible( int race ) const
711 {
712 switch ( id ) {
713 case MASSCURE:
714 case MASSBLESS:
715 case HOLYSHOUT:
716 case HOLYWORD:
717 case BLESS:
718 case CURE:
719 if ( Race::NECR == race )
720 return false;
721 break;
722
723 case DEATHWAVE:
724 case DEATHRIPPLE:
725 case ANIMATEDEAD:
726 if ( Race::NECR != race )
727 return false;
728 break;
729
730 default:
731 break;
732 }
733
734 return true;
735 }
736
CalculateDimensionDoorDistance()737 int32_t Spell::CalculateDimensionDoorDistance()
738 {
739 // original h2 variant
740 return 14;
741 }
742
operator <<(StreamBase & msg,const Spell & spell)743 StreamBase & operator<<( StreamBase & msg, const Spell & spell )
744 {
745 return msg << spell.id;
746 }
747
operator >>(StreamBase & msg,Spell & spell)748 StreamBase & operator>>( StreamBase & msg, Spell & spell )
749 {
750 return msg >> spell.id;
751 }
752