1 /*
2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
44
45 #include "game/Spells.h"
46
47 #include <algorithm>
48 #include <cmath>
49 #include <cstdio>
50 #include <cstdlib>
51 #include <cstring>
52 #include <limits>
53 #include <map>
54 #include <set>
55 #include <sstream>
56 #include <utility>
57
58 #include <boost/foreach.hpp>
59 #include <boost/lexical_cast.hpp>
60
61 #include "core/Application.h"
62 #include "core/Config.h"
63 #include "core/Core.h"
64 #include "core/GameTime.h"
65 #include "core/Localisation.h"
66
67 #include "game/Damage.h"
68 #include "game/EntityManager.h"
69 #include "game/Equipment.h"
70 #include "game/NPC.h"
71 #include "game/Player.h"
72 #include "game/Inventory.h"
73
74 #include "gui/Speech.h"
75 #include "gui/Menu.h"
76 #include "gui/Interface.h"
77 #include "gui/MiniMap.h"
78
79 #include "graphics/BaseGraphicsTypes.h"
80 #include "graphics/Color.h"
81 #include "graphics/Draw.h"
82 #include "graphics/GraphicsTypes.h"
83 #include "graphics/Math.h"
84 #include "graphics/Renderer.h"
85 #include "graphics/Vertex.h"
86 #include "graphics/data/Mesh.h"
87 #include "graphics/data/TextureContainer.h"
88 #include "graphics/effects/SpellEffects.h"
89 #include "graphics/particle/ParticleEffects.h"
90 #include "graphics/particle/ParticleSystem.h"
91 #include "graphics/spells/Spells01.h"
92 #include "graphics/spells/Spells02.h"
93 #include "graphics/spells/Spells03.h"
94 #include "graphics/spells/Spells04.h"
95 #include "graphics/spells/Spells05.h"
96 #include "graphics/spells/Spells06.h"
97 #include "graphics/spells/Spells07.h"
98 #include "graphics/spells/Spells09.h"
99 #include "graphics/spells/Spells10.h"
100
101 #include "input/Input.h"
102
103 #include "io/resource/ResourcePath.h"
104 #include "io/log/Logger.h"
105
106 #include "math/Angle.h"
107 #include "math/Vector2.h"
108 #include "math/Vector3.h"
109
110 #include "physics/Collisions.h"
111
112 #include "platform/Platform.h"
113
114 #include "scene/Light.h"
115 #include "scene/Scene.h"
116 #include "scene/GameSound.h"
117 #include "scene/Interactive.h"
118
119 #include "script/Script.h"
120
121 using std::abs;
122 using std::string;
123
124 static const float DEC_FOCAL = 50.0f;
125 static const float IMPROVED_FOCAL = 320.0f;
126
127 void MakeSpCol();
128 extern bool TRUE_PLAYER_MOUSELOOK_ON;
129 long passwall=0;
130 long WILLRETURNTOFREELOOK = 0;
131 long GLOBAL_MAGIC_MODE=1;
132 bool bPrecastSpell = false;
133 extern std::string LAST_FAILED_SEQUENCE;
134 enum ARX_SPELLS_RuneDirection
135 {
136 AUP,
137 AUPRIGHT,
138 ARIGHT,
139 ADOWNRIGHT,
140 ADOWN,
141 ADOWNLEFT,
142 ALEFT,
143 AUPLEFT
144 };
145 long sp_arm=0;
146 long cur_arm=0;
147 long cur_sos=0;
148 static void ApplyPasswall();
149 static void ApplySPArm();
150 static void ApplySPuw();
151 static void ApplySPRf();
152 static void ApplySPMax();
153 static void ApplySPWep();
154 static void ApplySPBow();
155 static void ApplyCurPNux();
156 static void ApplyCurMr();
157 static void ApplyCurSOS();
158
159
160 extern long FistParticles;
161 extern long sp_max;
162 short uw_mode=0;
163 static short uw_mode_pos=0;
164 extern long MAGICMODE;
165 extern Entity * CURRENT_TORCH;
166 extern float GLOBAL_SLOWDOWN;
167 extern void ARX_SPSound();
168 extern float sp_max_y[64];
169 extern Color sp_max_col[64];
170 extern char sp_max_ch[64];
171 extern long sp_max_nb;
172 long cur_mega=0;
173 float sp_max_start = 0;
174 long sp_wep=0;
175
176 extern bool bRenderInCursorMode;
177
178 bool bOldLookToggle;
179 extern float SLID_START;
180
181 long BH_MODE = 0;
EERIE_OBJECT_SetBHMode()182 void EERIE_OBJECT_SetBHMode()
183 {
184 if (BH_MODE)
185 BH_MODE=0;
186 else
187 {
188 BH_MODE=1;
189 MakeCoolFx(&player.pos);
190 MakeSpCol();
191 strcpy(sp_max_ch,"!!!_Super-Deformed_!!!");
192 sp_max_nb=strlen(sp_max_ch);
193 sp_max_start=arxtime.get_updated();
194 }
195 }
196
197 struct SYMBOL_DRAW {
198 unsigned long starttime;
199 Vec3f lastpos;
200 short lasttim;
201 short duration;
202 char sequence[32];
203 char cPosStartX;
204 char cPosStartY;
205 };
206
207 extern bool FrustrumsClipSphere(EERIE_FRUSTRUM_DATA * frustrums,EERIE_SPHERE * sphere);
208 extern bool bGToggleCombatModeWithKey;
209 void ARX_INTERFACE_Combat_Mode(long i);
210
211 static float ARX_SPELLS_GetManaCost(Spell _lNumSpell,long _lNumSpellTab);
212
213 ///////////////Spell Interpretation
214 SPELL spells[MAX_SPELLS];
215 short ARX_FLARES_broken(1);
216 long CurrPoint(0);
217 long cur_mx=0;
218 long cur_pnux=0;
219 long cur_pom=0;
220 long cur_rf=0;
221 long cur_mr=0;
222 long cur_sm=0;
223 long cur_bh=0;
224
225 static float LASTTELEPORT(0.0F);
226 long snip=0;
227 static Vec2s Lm;
228
229 static const long MAX_POINTS(200);
230 static Vec2s plist[MAX_POINTS];
231 static std::string SpellMoves;
232 Rune SpellSymbol[MAX_SPELL_SYMBOLS];
233 size_t CurrSpellSymbol=0;
234
235 static long lMaxSymbolDrawSizeX;
236 static long lMaxSymbolDrawSizeY;
237
238 unsigned char ucFlick=0;
239
GetSpellPosition(Vec3f * pos,long i)240 bool GetSpellPosition(Vec3f * pos,long i)
241 {
242
243
244 switch (spells[i].type)
245 {
246 //*********************************************************************************************
247 // LEVEL 1 SPELLS -----------------------------------------------------------------------------
248 case SPELL_MAGIC_SIGHT: // Launching MAGIC_SIGHT
249 break;
250 //----------------------------------------------------------------------------------------------
251 case SPELL_MAGIC_MISSILE: // Launching MAGIC_MISSILE
252 break;
253 //----------------------------------------------------------------------------------------------
254 case SPELL_IGNIT:// Launching IGNIT
255 break;
256 //---------------------------------------------------------------------------------------------
257 case SPELL_DOUSE:// Launching DOUSE
258 break;
259 //---------------------------------------------------------------------------------------------
260 case SPELL_ACTIVATE_PORTAL:// Launching ACTIVATE_PORTAL
261 break;
262 //*************************************************************************************************
263 // LEVEL 2 SPELLS -----------------------------------------------------------------------------
264 case SPELL_HEAL:// Launching HEAL
265 break;
266 //---------------------------------------------------------------------------------------------
267 case SPELL_DETECT_TRAP:// Launching DETECT_TRAP
268 break;
269 //---------------------------------------------------------------------------------------------
270 case SPELL_ARMOR:// Launching ARMOR
271
272 if (ValidIONum(spells[i].target))
273 {
274 *pos = entities[spells[i].target]->pos;
275 return true;
276 }
277
278 break;
279 //------------------------------------------------------------------------------------------------
280 case SPELL_LOWER_ARMOR:// Launching LOWER_ARMOR
281
282 if (ValidIONum(spells[i].target))
283 {
284 *pos = entities[spells[i].target]->pos;
285 return true;
286 }
287
288 break;
289 //------------------------------------------------------------------------------------------------
290 case SPELL_HARM:// Launching HARM
291 break;
292 //**********************************************************************************************
293 // LEVEL 3 SPELLS -----------------------------------------------------------------------------
294 case SPELL_SPEED:// Launching SPEED
295
296 if (ValidIONum(spells[i].target))
297 {
298 *pos = entities[spells[i].target]->pos;
299 return true;
300 }
301
302 break;
303 //--------------------------------------------------------------------------------------------------
304 case SPELL_DISPELL_ILLUSION:// Launching DISPELL_ILLUSION (REVEAL)
305 break;
306 //----------------------------------------------------------------------------------------------
307 case SPELL_FIREBALL:// Launching FIREBALL
308 break;
309 //-------------------------------------------------------------------------------------------------
310 case SPELL_CREATE_FOOD:// Launching CREATE_FOOD
311 break;
312 //----------------------------------------------------------------------------------------------
313 case SPELL_ICE_PROJECTILE:// Launching ICE_PROJECTILE
314 break;
315 //***********************************************************************************************
316 // LEVEL 4 SPELLS -----------------------------------------------------------------------------
317 case SPELL_BLESS:// Launching BLESS
318
319 if (ValidIONum(spells[i].target))
320 {
321 *pos = entities[spells[i].target]->pos;
322 return true;
323 }
324
325 break;
326 //-----------------------------------------------------------------------------------------------
327 case SPELL_DISPELL_FIELD:// Launching DISPELL_FIELD
328 break;
329 //-----------------------------------------------------------------------------------------------
330 case SPELL_FIRE_PROTECTION:// Launching FIRE_PROTECTION
331
332 if (ValidIONum(spells[i].target))
333 {
334 *pos = entities[spells[i].target]->pos;
335 return true;
336 }
337
338 break;
339 //----------------------------------------------------------------------------------------------
340 case SPELL_COLD_PROTECTION:// Launching COLD_PROTECTION
341
342 if (ValidIONum(spells[i].target))
343 {
344 *pos = entities[spells[i].target]->pos;
345 return true;
346 }
347
348 break;
349 //----------------------------------------------------------------------------------------------
350 case SPELL_TELEKINESIS:// Launching TELEKINESIS
351 break;
352 //-----------------------------------------------------------------------------------------------
353 case SPELL_CURSE:// Launching CURSE
354
355 if (ValidIONum(spells[i].target))
356 {
357 *pos = entities[spells[i].target]->pos;
358 return true;
359 }
360
361 break;
362 //*********************************************************************
363 // LEVEL 5 SPELLS -----------------------------------------------------------------------------
364 case SPELL_RUNE_OF_GUARDING:
365 break;
366 //----------------------------------------------------------------------------
367 case SPELL_LEVITATE:
368 break;
369 //----------------------------------------------------------------------------
370 case SPELL_CURE_POISON:
371 break;
372 //----------------------------------------------------------------------------
373 case SPELL_REPEL_UNDEAD:
374 break;
375 //----------------------------------------------------------------------------
376 case SPELL_POISON_PROJECTILE:
377 break;
378 //***************************************************************************
379 // LEVEL 6 -----------------------------------------------------------------------------
380 case SPELL_RISE_DEAD:
381 break;
382 //----------------------------------------------------------------------------
383 case SPELL_PARALYSE:
384
385 if (ValidIONum(spells[i].target))
386 {
387 *pos = entities[spells[i].target]->pos;
388 return true;
389 }
390
391 break;
392 //----------------------------------------------------------------------------
393 case SPELL_CREATE_FIELD:
394 break;
395 //----------------------------------------------------------------------------
396 case SPELL_DISARM_TRAP:
397 break;
398 //----------------------------------------------------------------------------
399 case SPELL_SLOW_DOWN:
400
401 if (ValidIONum(spells[i].target))
402 {
403 *pos = entities[spells[i].target]->pos;
404 return true;
405 }
406
407 break;
408 //****************************************************************************************
409 // LEVEL 7 SPELLS -----------------------------------------------------------------------------
410 case SPELL_FLYING_EYE:
411 {
412 *pos = eyeball.pos;
413 return true;
414 }
415 break;
416 //----------------------------------------------------------------------------
417 case SPELL_FIRE_FIELD:
418 CSpellFx *pCSpellFX;
419 pCSpellFX = spells[i].pSpellFx;
420
421 if (pCSpellFX)
422 {
423 CFireField *pFireField = (CFireField *) pCSpellFX;
424
425 *pos = pFireField->pos;
426 return true;
427 }
428
429 break;
430 //----------------------------------------------------------------------------
431 case SPELL_ICE_FIELD:
432 break;
433 //----------------------------------------------------------------------------
434 case SPELL_LIGHTNING_STRIKE:
435 break;
436 //----------------------------------------------------------------------------
437 case SPELL_CONFUSE:
438
439 if (ValidIONum(spells[i].target))
440 {
441 *pos = entities[spells[i].target]->pos;
442 return true;
443 }
444
445 break;
446 //*********************************************************************************
447 // LEVEL 8 SPELLS -----------------------------------------------------------------------------
448 case SPELL_INVISIBILITY:
449
450 if (ValidIONum(spells[i].target))
451 {
452 *pos = entities[spells[i].target]->pos;
453 return true;
454 }
455
456 break;
457 //----------------------------------------------------------------------------
458 case SPELL_MANA_DRAIN:
459
460 if (ValidIONum(spells[i].target))
461 {
462 *pos = entities[spells[i].target]->pos;
463 return true;
464 }
465
466 break;
467 //----------------------------------------------------------------------------
468 case SPELL_EXPLOSION:
469 break;
470 //----------------------------------------------------------------------------
471 case SPELL_ENCHANT_WEAPON:
472 break;
473 //----------------------------------------------------------------------------
474 case SPELL_LIFE_DRAIN:
475
476 if (ValidIONum(spells[i].target))
477 {
478 *pos = entities[spells[i].target]->pos;
479 return true;
480 }
481
482 break;
483 //*****************************************************************************************
484 // LEVEL 9 SPELLS -----------------------------------------------------------------------------
485 case SPELL_SUMMON_CREATURE:
486 break;
487 //----------------------------------------------------------------------------
488 case SPELL_NEGATE_MAGIC:
489 break;
490 //----------------------------------------------------------------------------
491 case SPELL_INCINERATE:
492
493 if (ValidIONum(spells[i].target))
494 {
495 *pos = entities[spells[i].target]->pos;
496 return true;
497 }
498
499 break;
500 //----------------------------------------------------------------------------
501 case SPELL_MASS_PARALYSE:
502 break;
503 //----------------------------------------------------------------------------
504 //********************************************************************************************
505 // LEVEL 10 SPELLS -----------------------------------------------------------------------------
506 case SPELL_MASS_LIGHTNING_STRIKE:
507 break;
508 //----------------------------------------------------------------------------
509 case SPELL_CONTROL_TARGET:
510 break;
511 //----------------------------------------------------------------------------
512 case SPELL_FREEZE_TIME:
513 break;
514 //----------------------------------------------------------------------------
515 case SPELL_MASS_INCINERATE:
516 break;
517 //----------------------------------------------------------------------------
518 case SPELL_TELEPORT:
519 break;
520 //----------------------------------------------------------------------------
521 default: break;
522 }
523
524 if (ValidIONum(spells[i].caster))
525 {
526 *pos = entities[spells[i].caster]->pos;
527 return true;
528 }
529
530 return false;
531 }
532
LaunchAntiMagicField(size_t ident)533 void LaunchAntiMagicField(size_t ident) {
534
535 for(size_t n = 0 ; n < MAX_SPELLS; n++) {
536
537 if(!spells[n].exist || n == ident) {
538 continue;
539 }
540
541 if(spells[ident].caster_level < spells[n].caster_level) {
542 continue;
543 }
544
545 Vec3f pos;
546 GetSpellPosition(&pos,n);
547 if(closerThan(pos, entities[spells[ident].caster]->pos, 600.f)) {
548 if(spells[n].type != SPELL_CREATE_FIELD) {
549 spells[n].tolive = 0;
550 } else if(spells[ident].caster == 0 && spells[n].caster == 0) {
551 spells[n].tolive = 0;
552 }
553 }
554 }
555 }
556
557 //-----------------------------------------------------------------------------
ARX_SPELLS_AddSpellOn(const long & caster,const long & spell)558 void ARX_SPELLS_AddSpellOn(const long &caster, const long &spell)
559 {
560 if (caster < 0 || spell < 0 || !entities[caster]) return;
561
562 Entity *io = entities[caster];
563 void *ptr;
564
565 ptr = realloc(io->spells_on, sizeof(long) * (io->nb_spells_on + 1));
566
567 if (!ptr) return;
568
569 io->spells_on = (long *)ptr;
570 io->spells_on[io->nb_spells_on] = spell;
571 io->nb_spells_on++;
572 }
573
574 //-----------------------------------------------------------------------------
ARX_SPELLS_GetSpellOn(const Entity * io,Spell spellid)575 long ARX_SPELLS_GetSpellOn(const Entity * io, Spell spellid)
576 {
577 if (!io) return -1;
578
579 for (long i(0); i < io->nb_spells_on; i++)
580 {
581 if ( (spells[io->spells_on[i]].type == spellid)
582 && (spells[io->spells_on[i]].exist) )
583 return io->spells_on[i];
584 }
585
586 return -1;
587 }
588
589 //-----------------------------------------------------------------------------
ARX_SPELLS_RemoveSpellOn(const long & caster,const long & spell)590 void ARX_SPELLS_RemoveSpellOn(const long &caster, const long &spell)
591 {
592 if (caster < 0 || spell < 0) return;
593
594 Entity *io = entities[caster];
595
596 if (!io || !io->nb_spells_on) return;
597
598 if (io->nb_spells_on == 1)
599 {
600 free(io->spells_on);
601 io->spells_on = NULL;
602 io->nb_spells_on = 0;
603 return;
604 }
605
606 long i(0);
607
608 for (; i < io->nb_spells_on; i++)
609 if (io->spells_on[i] == spell) break;
610
611 if ( i >= io->nb_spells_on) return;
612
613 io->nb_spells_on--;
614 memcpy(&io->spells_on[i], &io->spells_on[i + 1], sizeof(long) * (io->nb_spells_on - i));
615
616 io->spells_on = (long *)realloc(io->spells_on, sizeof(long) * io->nb_spells_on);
617 }
618
ARX_SPELLS_RemoveMultiSpellOn(long spell_id)619 void ARX_SPELLS_RemoveMultiSpellOn(long spell_id) {
620 for(size_t i = 0; i < entities.size(); i++) {
621 ARX_SPELLS_RemoveSpellOn(i, spells[spell_id].type);
622 }
623 }
624
ARX_SPELLS_RemoveAllSpellsOn(Entity * io)625 void ARX_SPELLS_RemoveAllSpellsOn(Entity *io) {
626 free(io->spells_on), io->spells_on = NULL, io->nb_spells_on = 0;
627 }
628
ARX_SPELLS_RequestSymbolDraw(Entity * io,const string & name,float duration)629 void ARX_SPELLS_RequestSymbolDraw(Entity *io, const string & name, float duration) {
630
631 const char * sequence;
632 int iPosX = 0;
633 int iPosY = 0;
634
635 if(name == "aam") iPosX = 0, iPosY = 2, sequence = "6666";
636 else if(name == "cetrius") iPosX = 1, iPosY = 1, sequence = "33388886666";
637 else if(name == "comunicatum") iPosX = 0, iPosY = 0, sequence = "6666622244442226666";
638 else if(name == "cosum") iPosX = 0, iPosY = 2, sequence = "66666222244448888";
639 else if(name == "folgora") iPosX = 0, iPosY = 3, sequence = "99993333";
640 else if(name == "fridd") iPosX = 0, iPosY = 4, sequence = "888886662222";
641 else if(name == "kaom") iPosX = 3, iPosY = 0, sequence = "44122366";
642 else if(name == "mega") iPosX = 2, iPosY = 4, sequence = "88888";
643 else if(name == "morte") iPosX = 0, iPosY = 2, sequence = "66666222";
644 else if(name == "movis") iPosX = 0, iPosY = 0, sequence = "666611116666";
645 else if(name == "nhi") iPosX = 4, iPosY = 2, sequence = "4444";
646 else if(name == "rhaa") iPosX = 2, iPosY = 0, sequence = "22222";
647 else if(name == "spacium") iPosX = 4, iPosY = 0, sequence = "44444222266688";
648 else if(name == "stregum") iPosX = 0, iPosY = 4, sequence = "8888833338888";
649 else if(name == "taar") iPosX = 0, iPosY = 1, sequence = "666222666";
650 else if(name == "tempus") iPosX = 0, iPosY = 4, sequence = "88886662226668866";
651 else if(name == "tera") iPosX = 0, iPosY = 3, sequence = "99922266";
652 else if(name == "vista") iPosX = 1, iPosY = 0, sequence = "333111";
653 else if(name == "vitae") iPosX = 0, iPosY = 2, sequence = "66666888";
654 else if(name == "yok") iPosX = 0, iPosY = 0, sequence = "222226666888";
655 else if(name == "akbaa") iPosX = 0, iPosY = 0, sequence = "22666772222";
656 else return;
657
658 io->symboldraw = (SYMBOL_DRAW *)realloc(io->symboldraw, sizeof(SYMBOL_DRAW));
659
660 if (!io->symboldraw) return;
661
662 SYMBOL_DRAW *sd = io->symboldraw;
663
664 sd->duration = (short)std::max(1l, long(duration));
665 strcpy(sd->sequence, sequence);
666
667 sd->starttime = (unsigned long)(arxtime);
668 sd->lasttim = 0;
669 sd->lastpos.x = io->pos.x - EEsin(radians(MAKEANGLE(io->angle.b - 45.0F + iPosX*2))) * 60.0F;
670 sd->lastpos.y = io->pos.y - 120.0F - iPosY*5;
671 sd->lastpos.z = io->pos.z + EEcos(radians(MAKEANGLE(io->angle.b - 45.0F + iPosX*2))) * 60.0F;
672
673 sd->cPosStartX = checked_range_cast<char>(iPosX);
674 sd->cPosStartY = checked_range_cast<char>(iPosY);
675
676 io->gameFlags &= ~GFLAG_INVISIBILITY;
677 }
678
ARX_SPELLS_RequestSymbolDraw2(Entity * io,Rune symb,float duration)679 static void ARX_SPELLS_RequestSymbolDraw2(Entity *io, Rune symb, float duration)
680 {
681 const char * sequence;
682 int iPosX = 0;
683 int iPosY = 0;
684
685 switch (symb)
686 {
687 case RUNE_AAM :
688 iPosX = 0, iPosY = 2, sequence = "6666";
689 break;
690 case RUNE_CETRIUS:
691 iPosX = 0, iPosY = 1, sequence = "33388886666";
692 break;
693 case RUNE_COMUNICATUM:
694 iPosX = 0, iPosY = 0, sequence = "6666622244442226666";
695 break;
696 case RUNE_COSUM:
697 iPosX = 0, iPosY = 2, sequence = "66666222244448888";
698 break;
699 case RUNE_FOLGORA:
700 iPosX = 0, iPosY = 3, sequence = "99993333";
701 break;
702 case RUNE_FRIDD:
703 iPosX = 0, iPosY = 4, sequence = "888886662222";
704 break;
705 case RUNE_KAOM:
706 iPosX = 3, iPosY = 0, sequence = "44122366";
707 break;
708 case RUNE_MEGA:
709 iPosX = 2, iPosY = 4, sequence = "88888";
710 break;
711 case RUNE_MORTE:
712 iPosX = 0, iPosY = 2, sequence = "66666222";
713 break;
714 case RUNE_MOVIS:
715 iPosX = 0, iPosY = 0, sequence = "666611116666";
716 break;
717 case RUNE_NHI:
718 iPosX = 4, iPosY = 2, sequence = "4444";
719 break;
720 case RUNE_RHAA:
721 iPosX = 2, iPosY = 0, sequence = "22222";
722 break;
723 case RUNE_SPACIUM:
724 iPosX = 4, iPosY = 0, sequence = "44444222266688";
725 break;
726 case RUNE_STREGUM:
727 iPosX = 0, iPosY = 4, sequence = "8888833338888";
728 break;
729 case RUNE_TAAR:
730 iPosX = 0, iPosY = 1, sequence = "666222666";
731 break;
732 case RUNE_TEMPUS:
733 iPosX = 0, iPosY = 4, sequence = "88886662226668866";
734 break;
735 case RUNE_TERA:
736 iPosX = 0, iPosY = 3, sequence = "99922266";
737 break;
738 case RUNE_VISTA:
739 iPosX = 1, iPosY = 0, sequence = "333111";
740 break;
741 case RUNE_VITAE:
742 iPosX = 0, iPosY = 2, sequence = "66666888";
743 break;
744 case RUNE_YOK:
745 iPosX = 0, iPosY = 0, sequence = "222226666888";
746 break;
747 default:
748 return;
749 }
750
751 SYMBOL_DRAW * ptr;
752 ptr = (SYMBOL_DRAW *)realloc(io->symboldraw, sizeof(SYMBOL_DRAW));
753
754 if (!ptr) return;
755
756 io->symboldraw = ptr;
757
758 SYMBOL_DRAW *sd = io->symboldraw;
759 sd->duration = duration < 1.0F ? 1 : (short)(long)duration;
760 strcpy(sd->sequence, sequence);
761 sd->starttime = (unsigned long)(arxtime);
762 sd->lasttim = 0;
763
764 sd->lastpos.x = io->pos.x - EEsin(radians(MAKEANGLE(io->angle.b - 45.0F + iPosX*2))) * 60.0F;
765 sd->lastpos.y = io->pos.y - 120.0F - iPosY*5;
766 sd->lastpos.z = io->pos.z + EEcos(radians(MAKEANGLE(io->angle.b - 45.0F + iPosX*2))) * 60.0F;
767
768 sd->cPosStartX = checked_range_cast<char>(iPosX);
769 sd->cPosStartY = checked_range_cast<char>(iPosY);
770
771 io->gameFlags &= ~GFLAG_INVISIBILITY;
772
773 }
774
775 //-----------------------------------------------------------------------------
ARX_SPELLS_RequestSymbolDraw3(const char * _pcName,char * _pcRes)776 void ARX_SPELLS_RequestSymbolDraw3(const char *_pcName,char *_pcRes)
777 {
778 if (!strcmp(_pcName, "aam")) strcpy(_pcRes, "6666");
779 else if (!strcmp(_pcName, "cetrius")) strcpy(_pcRes, "33388886666");
780 else if (!strcmp(_pcName, "comunicatum")) strcpy(_pcRes, "6666622244442226666");
781 else if (!strcmp(_pcName, "cosum")) strcpy(_pcRes, "66666222244448888");
782 else if (!strcmp(_pcName, "folgora")) strcpy(_pcRes, "99993333");
783 else if (!strcmp(_pcName, "fridd")) strcpy(_pcRes, "888886662222");
784 else if (!strcmp(_pcName, "kaom")) strcpy(_pcRes, "44122366");
785 else if (!strcmp(_pcName, "mega")) strcpy(_pcRes, "88888");
786 else if (!strcmp(_pcName, "morte")) strcpy(_pcRes, "66666222");
787 else if (!strcmp(_pcName, "movis")) strcpy(_pcRes, "666611116666");
788 else if (!strcmp(_pcName, "nhi")) strcpy(_pcRes, "4444");
789 else if (!strcmp(_pcName, "rhaa")) strcpy(_pcRes, "22222");
790 else if (!strcmp(_pcName, "spacium")) strcpy(_pcRes, "44444222266688");
791 else if (!strcmp(_pcName, "stregum")) strcpy(_pcRes, "8888833338888");
792 else if (!strcmp(_pcName, "taar")) strcpy(_pcRes, "666222666");
793 else if (!strcmp(_pcName, "tempus")) strcpy(_pcRes, "88886662226668866");
794 else if (!strcmp(_pcName, "tera")) strcpy(_pcRes, "99922266");
795 else if (!strcmp(_pcName, "vista")) strcpy(_pcRes, "333111");
796 else if (!strcmp(_pcName, "vitae")) strcpy(_pcRes, "66666888");
797 else if (!strcmp(_pcName, "yok")) strcpy(_pcRes, "222226666888");
798 else if (!strcmp(_pcName, "akbaa")) strcpy(_pcRes, "22666772222");
799 }
800
801 #define OFFSET_X 8*2//0
802 #define OFFSET_Y 6*2//0
803
804 //-----------------------------------------------------------------------------
GetSymbVector(char c,Vec2s * vec)805 void GetSymbVector(char c,Vec2s * vec)
806 {
807 switch (c)
808 {
809 case '1' :
810 vec->x = -OFFSET_X, vec->y = OFFSET_Y;
811 break;
812 case '2' :
813 vec->x = 0, vec->y = OFFSET_Y;
814 break;
815 case '3' :
816 vec->x = OFFSET_X, vec->y = OFFSET_Y;
817 break;
818 case '4' :
819 vec->x = -OFFSET_X, vec->y = 0;
820 break;
821 case '6' :
822 vec->x = OFFSET_X, vec->y = 0;
823 break;
824 case '7' :
825 vec->x = -OFFSET_X, vec->y = -OFFSET_Y;
826 break;
827 case '8' :
828 vec->x = 0, vec->y = -OFFSET_Y;
829 break;
830 case '9' :
831 vec->x = OFFSET_X, vec->y = -OFFSET_Y;
832 break;
833 default :
834 vec->x = 0, vec->y = 0;
835 break;
836 }
837 }
838
MakeSpellName(char * spell,Spell num)839 static bool MakeSpellName(char * spell, Spell num) {
840
841 // TODO(spells) use map
842
843 switch (num)
844 {
845 // Level 1
846 case SPELL_MAGIC_SIGHT :
847 strcpy(spell, "magic_sight");
848 break;
849 case SPELL_MAGIC_MISSILE :
850 strcpy(spell, "magic_missile");
851 break;
852 case SPELL_IGNIT :
853 strcpy(spell, "ignit");
854 break;
855 case SPELL_DOUSE :
856 strcpy(spell, "douse");
857 break;
858 case SPELL_ACTIVATE_PORTAL :
859 strcpy(spell, "activate_portal");
860 break;
861
862 // Level 2
863 case SPELL_HEAL :
864 strcpy(spell, "heal");
865 break;
866 case SPELL_DETECT_TRAP :
867 strcpy(spell, "detect_trap");
868 break;
869 case SPELL_ARMOR :
870 strcpy(spell, "armor");
871 break;
872 case SPELL_LOWER_ARMOR :
873 strcpy(spell, "lower_armor");
874 break;
875 case SPELL_HARM :
876 strcpy(spell, "harm");
877 break;
878
879 // Level 3
880 case SPELL_SPEED :
881 strcpy(spell, "speed");
882 break;
883 case SPELL_DISPELL_ILLUSION :
884 strcpy(spell, "dispell_illusion");
885 break;
886 case SPELL_FIREBALL :
887 strcpy(spell, "fireball");
888 break;
889 case SPELL_CREATE_FOOD :
890 strcpy(spell, "create_food");
891 break;
892 case SPELL_ICE_PROJECTILE :
893 strcpy(spell, "ice_projectile");
894 break;
895
896 // Level 4
897 case SPELL_BLESS :
898 strcpy(spell, "bless");
899 break;
900 case SPELL_DISPELL_FIELD :
901 strcpy(spell, "dispell_field");
902 break;
903 case SPELL_FIRE_PROTECTION :
904 strcpy(spell, "fire_protection");
905 break;
906 case SPELL_TELEKINESIS :
907 strcpy(spell, "telekinesis");
908 break;
909 case SPELL_CURSE :
910 strcpy(spell, "curse");
911 break;
912 case SPELL_COLD_PROTECTION :
913 strcpy(spell, "cold_protection");
914 break;
915
916 // Level 5
917 case SPELL_RUNE_OF_GUARDING :
918 strcpy(spell, "rune_of_guarding");
919 break;
920 case SPELL_LEVITATE :
921 strcpy(spell, "levitate");
922 break;
923 case SPELL_CURE_POISON :
924 strcpy(spell, "cure_poison");
925 break;
926 case SPELL_REPEL_UNDEAD :
927 strcpy(spell, "repel_undead");
928 break;
929 case SPELL_POISON_PROJECTILE :
930 strcpy(spell, "poison_projectile");
931 break;
932
933 // Level 6
934 case SPELL_RISE_DEAD :
935 strcpy(spell, "raise_dead");
936 break;
937 case SPELL_PARALYSE :
938 strcpy(spell, "paralyse");
939 break;
940 case SPELL_CREATE_FIELD :
941 strcpy(spell, "create_field");
942 break;
943 case SPELL_DISARM_TRAP :
944 strcpy(spell, "disarm_trap");
945 break;
946 case SPELL_SLOW_DOWN :
947 strcpy(spell, "slowdown");
948 break;
949
950 // Level 7
951 case SPELL_FLYING_EYE :
952 strcpy(spell, "flying_eye");
953 break;
954 case SPELL_FIRE_FIELD :
955 strcpy(spell, "fire_field");
956 break;
957 case SPELL_ICE_FIELD :
958 strcpy(spell, "ice_field");
959 break;
960 case SPELL_LIGHTNING_STRIKE :
961 strcpy(spell, "lightning_strike");
962 break;
963 case SPELL_CONFUSE :
964 strcpy(spell, "confuse");
965 break;
966
967 // Level 8
968 case SPELL_INVISIBILITY :
969 strcpy(spell, "invisibility");
970 break;
971 case SPELL_MANA_DRAIN :
972 strcpy(spell, "mana_drain");
973 break;
974 case SPELL_EXPLOSION :
975 strcpy(spell, "explosion");
976 break;
977 case SPELL_ENCHANT_WEAPON :
978 strcpy(spell, "enchant_weapon");
979 break;
980 case SPELL_LIFE_DRAIN :
981 strcpy(spell, "life_drain");
982 break;
983
984 // Level 9
985 case SPELL_SUMMON_CREATURE :
986 strcpy(spell, "summon_creature");
987 break;
988 case SPELL_FAKE_SUMMON :
989 strcpy(spell, "fake_summon");
990 break;
991 case SPELL_NEGATE_MAGIC :
992 strcpy(spell, "negate_magic");
993 break;
994 case SPELL_INCINERATE :
995 strcpy(spell, "incinerate");
996 break;
997 case SPELL_MASS_PARALYSE :
998 strcpy(spell, "mass_paralyse");
999 break;
1000
1001 // Level 10
1002 case SPELL_MASS_LIGHTNING_STRIKE :
1003 strcpy(spell, "mass_lightning_strike");
1004 break;
1005 case SPELL_CONTROL_TARGET :
1006 strcpy(spell, "control");
1007 break;
1008 case SPELL_FREEZE_TIME :
1009 strcpy(spell, "freeze_time");
1010 break;
1011 case SPELL_MASS_INCINERATE :
1012 strcpy(spell, "mass_incinerate");
1013 break;
1014 default :
1015 return false;
1016 }
1017
1018 return true;
1019 }
1020
SPELLCAST_Notify(long num)1021 void SPELLCAST_Notify(long num) {
1022
1023 if(num < 0) {
1024 return;
1025 }
1026
1027 if(size_t(num) >= MAX_SPELLS) {
1028 return;
1029 }
1030
1031 char spell[128];
1032 long source = spells[num].caster;
1033 if(!MakeSpellName(spell, spells[num].type)) {
1034 return;
1035 }
1036
1037 for(size_t i = 0; i < entities.size(); i++) {
1038 if(entities[i] != NULL) {
1039 EVENT_SENDER = (source >= 0) ? entities[source] : NULL;
1040 char param[256];
1041 sprintf(param, "%s %ld", spell, (long)spells[num].caster_level);
1042 SendIOScriptEvent(entities[i], SM_SPELLCAST, param);
1043 }
1044 }
1045 }
1046
1047 //-----------------------------------------------------------------------------
SPELLCAST_NotifyOnlyTarget(long num)1048 void SPELLCAST_NotifyOnlyTarget(long num)
1049 {
1050 if (num < 0) return;
1051
1052 if ((size_t)num >= MAX_SPELLS) return;
1053
1054 if(spells[num].target<0) return;
1055
1056 char spell[128];
1057 long source = spells[num].caster;
1058
1059 if (MakeSpellName(spell,spells[num].type))
1060 {
1061 if (source >= 0) EVENT_SENDER = entities[source];
1062 else EVENT_SENDER = NULL;
1063
1064 char param[256];
1065 sprintf(param,"%s %ld",spell,(long)spells[num].caster_level);
1066 SendIOScriptEvent(entities[spells[num].target], SM_SPELLCAST, param);
1067 }
1068 }
1069
1070 //-----------------------------------------------------------------------------
SPELLEND_Notify(long num)1071 void SPELLEND_Notify(long num)
1072 {
1073 if(num < 0 || (size_t)num >= MAX_SPELLS) {
1074 return;
1075 }
1076
1077 char spell[128];
1078 long source=spells[num].caster;
1079
1080 if (spells[num].type==SPELL_CONFUSE)
1081 {
1082 if (ValidIONum(source))
1083 EVENT_SENDER = entities[source];
1084 else
1085 EVENT_SENDER = NULL;
1086
1087 if(ValidIONum(spells[num].target)) {
1088 if(MakeSpellName(spell,spells[num].type)) {
1089 Entity * targ = entities[spells[num].target];
1090 char param[128];
1091 sprintf(param,"%s %ld",spell,(long)spells[num].caster_level);
1092 SendIOScriptEvent(targ,SM_SPELLEND,param);
1093 }
1094 }
1095 return;
1096 }
1097
1098 // we only notify player spells end.
1099 if(!MakeSpellName(spell,spells[num].type)) {
1100 return;
1101 }
1102
1103 for (size_t i = 0; i < entities.size(); i++) {
1104 if(entities[i]) {
1105 EVENT_SENDER = ValidIONum(source) ? entities[source] : NULL;
1106 char param[128];
1107 sprintf(param,"%s %ld",spell,(long)spells[num].caster_level);
1108 SendIOScriptEvent(entities[i],SM_SPELLEND,param);
1109 }
1110 }
1111 }
1112
ReCenterSequence(char * _pcSequence,int & _iMinX,int & _iMinY,int & _iMaxX,int & _iMaxY)1113 void ReCenterSequence(char *_pcSequence, int & _iMinX, int & _iMinY,
1114 int & _iMaxX, int & _iMaxY) {
1115
1116 int iSizeX=0,iSizeY=0;
1117 _iMinX=_iMinY=0;
1118 _iMaxX=_iMaxY=0;
1119 int iLenght=strlen(_pcSequence);
1120
1121 for(int iI=0;iI<iLenght;iI++)
1122 {
1123 Vec2s es2dVector;
1124 GetSymbVector(_pcSequence[iI],&es2dVector);
1125 iSizeX+=es2dVector.x;
1126 iSizeY+=es2dVector.y;
1127 _iMinX=std::min(_iMinX,iSizeX);
1128 _iMinY=std::min(_iMinY,iSizeY);
1129 _iMaxX=std::max(_iMaxX,iSizeX);
1130 _iMaxY=std::max(_iMaxY,iSizeY);
1131 }
1132 }
1133
ARX_SPELLS_UpdateSymbolDraw()1134 void ARX_SPELLS_UpdateSymbolDraw() {
1135
1136 unsigned long curtime = (unsigned long)(arxtime);
1137
1138 for(size_t i = 0; i < entities.size(); i++) {
1139 Entity * io = entities[i];
1140 if (io)
1141 {
1142 if (io->spellcast_data.castingspell != SPELL_NONE)
1143 {
1144 if (io->symboldraw==NULL)
1145 {
1146 long tst=0;
1147
1148 if (!(io->spellcast_data.spell_flags & SPELLCAST_FLAG_NOANIM) && (io->ioflags & IO_NPC))
1149 {
1150 ANIM_USE * ause1=&io->animlayer[1];
1151
1152 if (ause1->cur_anim==io->anims[ANIM_CAST_START] && (ause1->flags & EA_ANIMEND))
1153 {
1154 FinishAnim(io,ause1->cur_anim);
1155 ANIM_Set(ause1,io->anims[ANIM_CAST_CYCLE]);
1156 tst=1;
1157 }
1158 else if (ause1->cur_anim==io->anims[ANIM_CAST_CYCLE]) tst=1;
1159 else if (ause1->cur_anim!=io->anims[ANIM_CAST_START])
1160 io->spellcast_data.castingspell = SPELL_NONE;
1161 }
1162 else tst=1;
1163
1164 if ((io->spellcast_data.symb[0] != RUNE_NONE) && tst )
1165 {
1166 Rune symb = io->spellcast_data.symb[0];
1167
1168 for (long j=0;j<3;j++)
1169 io->spellcast_data.symb[j]=io->spellcast_data.symb[j+1];
1170
1171 io->spellcast_data.symb[3] = RUNE_NONE;
1172 ARX_SPELLS_RequestSymbolDraw2(io, symb, (1000-(io->spellcast_data.spell_level*60))*std::max(io->speed_modif+io->basespeed,0.01f));
1173 io->gameFlags &=~GFLAG_INVISIBILITY;
1174 }
1175 else if (tst)// cast spell !!!
1176 {
1177 io->gameFlags &=~GFLAG_INVISIBILITY;
1178 ARX_SPELLS_Launch(io->spellcast_data.castingspell,i,io->spellcast_data.spell_flags,io->spellcast_data.spell_level,io->spellcast_data.target,io->spellcast_data.duration);
1179
1180 if (!(io->spellcast_data.spell_flags & SPELLCAST_FLAG_NOANIM)
1181 && (io->ioflags & IO_NPC))
1182 {
1183 ANIM_USE * ause1=&io->animlayer[1];
1184 AcquireLastAnim(io);
1185 FinishAnim(io,ause1->cur_anim);
1186 ANIM_Set(ause1,io->anims[ANIM_CAST]);
1187 }
1188
1189 io->spellcast_data.castingspell = SPELL_NONE;
1190 }
1191 }
1192 }
1193
1194 float rr=rnd();
1195
1196 if (io->flarecount)
1197 {
1198 if (io->dynlight==-1) io->dynlight=(short)GetFreeDynLight();
1199
1200 if (io->dynlight!=-1)
1201 {
1202 DynLight[io->dynlight].pos.x=io->pos.x-EEsin(radians(MAKEANGLE(io->angle.b-45.f)))*60.f;
1203 DynLight[io->dynlight].pos.y=io->pos.y-120.f;
1204 DynLight[io->dynlight].pos.z=io->pos.z+EEcos(radians(MAKEANGLE(io->angle.b-45.f)))*60.f;
1205 DynLight[io->dynlight].fallstart=140.f+(float)io->flarecount*0.333333f+rr*5.f;
1206 DynLight[io->dynlight].fallend=220.f+(float)io->flarecount*0.5f+rr*5.f;
1207 DynLight[io->dynlight].intensity=1.6f;
1208 DynLight[io->dynlight].exist=1;
1209 DynLight[io->dynlight].rgb.r=0.01f*io->flarecount*2;
1210 DynLight[io->dynlight].rgb.g=0.009f*io->flarecount*2;
1211 DynLight[io->dynlight].rgb.b=0.008f*io->flarecount*2;
1212 }
1213 }
1214 else if (io->dynlight>-1)
1215 {
1216 DynLight[io->dynlight].exist=0;
1217 io->dynlight=-1;
1218 }
1219
1220 if(io->symboldraw) {
1221 SYMBOL_DRAW * sd = entities[i]->symboldraw;
1222 long tim=curtime-sd->starttime;
1223
1224
1225
1226 if (tim>sd->duration)
1227 {
1228 if (io->dynlight!=-1)
1229 {
1230 DynLight[io->dynlight].time_creation = (unsigned long)(arxtime);
1231 DynLight[io->dynlight].duration = 600;
1232 io->dynlight=-1;
1233 }
1234
1235 free(io->symboldraw);
1236 io->symboldraw=NULL;
1237 continue;
1238 }
1239
1240 long nbcomponents=strlen(sd->sequence);
1241
1242 if (nbcomponents<=0)
1243 {
1244 free(io->symboldraw);
1245 io->symboldraw=NULL;
1246 continue;
1247 }
1248
1249 float ti=((float)sd->duration/(float)nbcomponents);
1250
1251 if (ti<=0) ti=1;
1252
1253 Vec2s pos1, vect, old_pos;
1254 long newtime=tim;
1255 long oldtime=sd->lasttim;
1256
1257 if (oldtime>sd->duration) oldtime=sd->duration;
1258
1259 if (newtime>sd->duration) newtime=sd->duration;
1260
1261 sd->lasttim=(short)tim;
1262
1263 pos1.x = (short)subj.center.x - OFFSET_X * 2 + sd->cPosStartX * OFFSET_X;
1264 pos1.y = (short)subj.center.y - OFFSET_Y * 2 + sd->cPosStartY * OFFSET_Y;
1265
1266 float div_ti=1.f/ti;
1267
1268 if (io != entities.player())
1269 {
1270 old_pos = pos1;
1271
1272 for (long j=0;j<nbcomponents;j++)
1273 {
1274 GetSymbVector(sd->sequence[j],&vect);
1275 vect += vect / 2;
1276
1277 if(oldtime <= ti) {
1278 float ratio = float(oldtime)*div_ti;
1279 old_pos += (vect.to<float>() * ratio).to<short>();
1280 break;
1281 }
1282
1283 old_pos += vect;
1284 oldtime-=(long)ti;
1285 }
1286
1287 for (int j=0;j<nbcomponents;j++)
1288 {
1289 GetSymbVector(sd->sequence[j],&vect);
1290 vect += vect / 2;
1291
1292 if (newtime<=ti)
1293 {
1294 float ratio = float(newtime) * div_ti;
1295 pos1 += (vect.to<float>() * ratio).to<short>();
1296 AddFlare(&pos1,0.1f,1,entities[i]);
1297 FlareLine(&old_pos,&pos1,entities[i]);
1298 break;
1299 }
1300
1301 pos1 += vect;
1302 newtime-=(long)ti;
1303 }
1304 }
1305 else
1306 {
1307 int iMinX,iMinY,iMaxX,iMaxY;
1308 int iSizeX,iSizeY;
1309 ReCenterSequence(sd->sequence,iMinX,iMinY,iMaxX,iMaxY);
1310 iSizeX=iMaxX-iMinX;
1311 iSizeY=iMaxY-iMinY;
1312 pos1.x = 97;
1313 pos1.y = 64;
1314
1315
1316 long lPosX = (((513>>1)-lMaxSymbolDrawSizeX)>>1);
1317 long lPosY = (313-(((313*3/4)-lMaxSymbolDrawSizeY)>>1));
1318
1319 pos1.x = checked_range_cast<short>(pos1.x + lPosX);
1320 pos1.y = checked_range_cast<short>(pos1.y + lPosY);
1321
1322
1323
1324 lPosX = ((lMaxSymbolDrawSizeX-iSizeX)>>1);
1325 lPosY = ((lMaxSymbolDrawSizeY-iSizeY)>>1);
1326
1327 pos1.x = checked_range_cast<short>(pos1.x + lPosX);
1328 pos1.y = checked_range_cast<short>(pos1.y + lPosY);
1329
1330
1331
1332 int iX = pos1.x-iMinX;
1333 int iY = pos1.y-iMinY;
1334
1335 pos1.x = checked_range_cast<short>(iX);
1336 pos1.y = checked_range_cast<short>(iY);
1337
1338
1339 for (long j=0;j<nbcomponents;j++)
1340 {
1341
1342 GetSymbVector(sd->sequence[j],&vect);
1343
1344 if (newtime<ti)
1345 {
1346 float ratio = (float)(newtime) * div_ti;
1347
1348
1349 float fX = pos1.x + (ratio*vect.x)*0.5f;
1350 float fY = pos1.y + (ratio*vect.y)*0.5f;
1351
1352 pos1.x = checked_range_cast<short>(fX);
1353 pos1.y = checked_range_cast<short>(fY);
1354
1355
1356 Vec2s pos;
1357 pos.x=(short)(pos1.x*Xratio);
1358 pos.y=(short)(pos1.y*Yratio);
1359
1360 if (io == entities.player())
1361 AddFlare2(&pos,0.1f,1,entities[i]);
1362 else
1363 AddFlare(&pos,0.1f,1,entities[i]);
1364
1365
1366 break;
1367 }
1368
1369 pos1 += vect;
1370
1371 newtime-=(long)ti;
1372 }
1373 }
1374 }
1375 }
1376 }
1377 }
1378
ARX_SPELLS_ClearAllSymbolDraw()1379 void ARX_SPELLS_ClearAllSymbolDraw() {
1380 BOOST_FOREACH(Entity * e, entities) {
1381 if(e && e->symboldraw) {
1382 free(e->symboldraw), e->symboldraw = NULL;
1383 }
1384 }
1385 }
1386
ARX_SPELLS_AnalyseSYMBOL()1387 static void ARX_SPELLS_AnalyseSYMBOL() {
1388
1389 long sm = 0;
1390 try {
1391 sm = boost::lexical_cast<long>(SpellMoves);
1392 } catch(...) {
1393 LogDebug("bad spell moves: " << SpellMoves);
1394 }
1395
1396 switch(sm) {
1397
1398 // COSUM
1399 case 62148 :
1400 case 632148 :
1401 case 62498 :
1402 case 62748 :
1403 case 6248 :
1404 SpellSymbol[CurrSpellSymbol++] = RUNE_COSUM;
1405
1406 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1407 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1408 }
1409
1410 ARX_SOUND_PlaySFX(SND_SYMB_COSUM);
1411 break;
1412
1413 // COMUNICATUM
1414 case 632426 :
1415 case 627426 :
1416 case 634236 :
1417 case 624326 :
1418 case 62426 :
1419 SpellSymbol[CurrSpellSymbol++] = RUNE_COMUNICATUM;
1420
1421 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1422 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1423 }
1424
1425 ARX_SOUND_PlaySFX(SND_SYMB_COMUNICATUM);
1426 break;
1427
1428 // FOLGORA
1429 case 9823 :
1430 case 9232 :
1431 case 983 :
1432 case 963 :
1433 case 923 :
1434 case 932 :
1435 case 93 :
1436 SpellSymbol[CurrSpellSymbol++] = RUNE_FOLGORA;
1437
1438 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1439 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1440 }
1441
1442 ARX_SOUND_PlaySFX(SND_SYMB_FOLGORA);
1443 break;
1444
1445 // SPACIUM
1446 case 42368 :
1447 case 42678 :
1448 case 42698 :
1449 case 4268 :
1450 SpellSymbol[CurrSpellSymbol++] = RUNE_SPACIUM;
1451
1452 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1453 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1454 }
1455
1456 ARX_SOUND_PlaySFX(SND_SYMB_SPACIUM);
1457 break;
1458
1459 // TERA
1460 case 9826 :
1461 case 92126 :
1462 case 9264 :
1463 case 9296 :
1464 case 926 :
1465 SpellSymbol[CurrSpellSymbol++] = RUNE_TERA;
1466
1467 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1468 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1469 }
1470
1471 ARX_SOUND_PlaySFX(SND_SYMB_TERA);
1472 break;
1473
1474 // CETRIUS
1475 case 286 :
1476 case 3286 :
1477 case 23836 :
1478 case 38636 :
1479 case 2986 :
1480 case 2386 :
1481 case 386 :
1482 SpellSymbol[CurrSpellSymbol++] = RUNE_CETRIUS;
1483
1484 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1485 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1486 }
1487
1488 ARX_SOUND_PlaySFX(SND_SYMB_CETRIUS);
1489 break;
1490
1491 // RHAA
1492 case 28 :
1493 case 2 :
1494 SpellSymbol[CurrSpellSymbol++] = RUNE_RHAA;
1495
1496 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1497 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1498 }
1499
1500 ARX_SOUND_PlaySFX(SND_SYMB_RHAA);
1501 break;
1502
1503 // FRIDD
1504 case 98362 :
1505 case 8362 :
1506 case 8632 :
1507 case 8962 :
1508 case 862 :
1509 SpellSymbol[CurrSpellSymbol++] = RUNE_FRIDD;
1510
1511 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1512 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1513 }
1514
1515 ARX_SOUND_PlaySFX(SND_SYMB_FRIDD);
1516 break;
1517
1518 // KAOM
1519 case 41236 :
1520 case 23 :
1521 case 236 :
1522 case 2369 :
1523 case 136 :
1524 case 12369 :
1525 case 1236 :
1526
1527 if ((cur_arm>=0) && (cur_arm & 1) )
1528 {
1529 cur_arm++;
1530
1531 if (cur_arm>20)
1532 ApplySPArm();
1533 }
1534 else
1535 cur_arm=-1;
1536
1537 SpellSymbol[CurrSpellSymbol++] = RUNE_KAOM;
1538
1539 if((size_t)CurrSpellSymbol >= MAX_SPELL_SYMBOLS) {
1540 CurrSpellSymbol = MAX_SPELL_SYMBOLS - 1;
1541 }
1542
1543 ARX_SOUND_PlaySFX(SND_SYMB_KAOM);
1544 break;
1545
1546 // STREGUM
1547 case 82328 :
1548 case 8328 :
1549 case 2328 :
1550 case 8938 :
1551 case 8238 :
1552 case 838 :
1553 SpellSymbol[CurrSpellSymbol++] = RUNE_STREGUM;
1554
1555 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1556
1557 ARX_SOUND_PlaySFX(SND_SYMB_STREGUM);
1558 break;
1559
1560 // MORTE
1561 case 628 :
1562 case 621 :
1563 case 62 :
1564 SpellSymbol[CurrSpellSymbol++] = RUNE_MORTE;
1565
1566 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1567
1568 ARX_SOUND_PlaySFX(SND_SYMB_MORTE);
1569 break;
1570
1571 // TEMPUS
1572 case 962686 :
1573 case 862686 :
1574 case 8626862 :
1575 SpellSymbol[CurrSpellSymbol++] = RUNE_TEMPUS;
1576
1577 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1578
1579 ARX_SOUND_PlaySFX(SND_SYMB_TEMPUS);
1580 break;
1581
1582 // MOVIS
1583 case 6316:
1584 case 61236:
1585 case 6146:
1586 case 61216:
1587 case 6216:
1588 case 6416:
1589 case 62126:
1590 case 61264:
1591 case 6126:
1592 case 6136:
1593 case 616:
1594 SpellSymbol[CurrSpellSymbol++] = RUNE_MOVIS;
1595
1596 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1597
1598 ARX_SOUND_PlaySFX(SND_SYMB_MOVIS);
1599 break;
1600
1601 // NHI
1602 case 46:
1603 case 4:
1604 SpellSymbol[CurrSpellSymbol++] = RUNE_NHI;
1605
1606 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1607
1608 ARX_SOUND_PlaySFX(SND_SYMB_NHI);
1609 break;
1610
1611 // AAM
1612 case 64:
1613 case 6:
1614 SpellSymbol[CurrSpellSymbol++] = RUNE_AAM;
1615
1616 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1617
1618 ARX_SOUND_PlaySFX(SND_SYMB_AAM);
1619 break;
1620
1621 // YOK
1622 case 412369:
1623 case 2687:
1624 case 2698:
1625 case 2638:
1626 case 26386:
1627 case 2368:
1628 case 2689:
1629 case 268:
1630 SpellSymbol[CurrSpellSymbol++] = RUNE_YOK;
1631
1632 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1633
1634 ARX_SOUND_PlaySFX(SND_SYMB_YOK);
1635 break;
1636
1637 // TAAR
1638 case 6236:
1639 case 6264:
1640 case 626:
1641 SpellSymbol[CurrSpellSymbol++] = RUNE_TAAR;
1642
1643 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1644
1645 ARX_SOUND_PlaySFX(SND_SYMB_TAAR);
1646 break;
1647
1648 // MEGA
1649 case 82:
1650 case 8:
1651
1652 if ((cur_arm>=0) && !(cur_arm & 1) )
1653 {
1654 cur_arm++;
1655 }
1656 else
1657 cur_arm=-1;
1658
1659 SpellSymbol[CurrSpellSymbol++] = RUNE_MEGA;
1660
1661 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1662
1663 ARX_SOUND_PlaySFX(SND_SYMB_MEGA);
1664 break;
1665
1666 // VISTA
1667 case 3614:
1668 case 361:
1669 case 341:
1670 case 3212:
1671 case 3214:
1672 case 312:
1673 case 314:
1674 case 321:
1675 case 31:
1676 SpellSymbol[CurrSpellSymbol++] = RUNE_VISTA;
1677
1678 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1679
1680 ARX_SOUND_PlaySFX(SND_SYMB_VISTA);
1681 break;
1682
1683 // VITAE
1684 case 698:
1685 case 68:
1686 SpellSymbol[CurrSpellSymbol++] = RUNE_VITAE;
1687
1688 if (CurrSpellSymbol>=MAX_SPELL_SYMBOLS) CurrSpellSymbol=MAX_SPELL_SYMBOLS-1;
1689
1690 ARX_SOUND_PlaySFX(SND_SYMB_VITAE);
1691 break;
1692
1693 //--------------------------------------------------------------------------------------------------------------------
1694
1695 // Special UW mode
1696 case 238:
1697 case 2398:
1698 case 23898:
1699 case 236987:
1700 case 23698:
1701
1702 if (uw_mode_pos == 0) uw_mode_pos++;
1703
1704 goto failed;
1705 break;
1706 case 2382398:
1707 case 2829:
1708 case 23982398:
1709 case 39892398:
1710 case 2398938:
1711 case 28239898:
1712 case 238982398:
1713 case 238923898:
1714 case 28982398:
1715 case 3923989:
1716 case 292398:
1717 case 398329:
1718 case 38923898:
1719 case 2398289:
1720 case 289823898:
1721 case 2989238:
1722 case 29829:
1723 case 2393239:
1724 case 38239:
1725 case 239829:
1726 case 2898239:
1727 case 28982898:
1728 case 389389:
1729 case 3892389:
1730 case 289289:
1731 case 289239:
1732 case 239289:
1733 case 2989298:
1734 case 2392398:
1735 case 238929:
1736 case 28923898:
1737 case 2929:
1738 case 2398298:
1739 case 239823898:
1740 case 28238:
1741 case 2892398:
1742 case 28298:
1743 case 298289:
1744 case 38929:
1745 case 289298989:
1746 case 23892398:
1747 case 238239:
1748 case 29298:
1749 case 2329298:
1750 case 232389829:
1751 case 2389829:
1752 case 239239:
1753 case 282398:
1754 case 2389239:
1755 case 2929898:
1756 case 3292398:
1757 case 23923298:
1758 case 23898239:
1759 case 3232929:
1760 case 2982398:
1761 case 238298:
1762 case 3939:
1763
1764 if (uw_mode_pos == 1)
1765 {
1766 ApplySPuw();
1767 }
1768
1769 goto failed;
1770 break;
1771 case 161:
1772 case 1621:
1773 case 1261:
1774
1775 if (cur_sm==0) cur_sm++;
1776
1777 if (cur_bh==0) cur_bh++;
1778
1779 if (cur_bh==2) cur_bh++;
1780
1781 if (cur_sos==0) cur_sos++;
1782
1783 if (cur_sos == 2)
1784 {
1785 cur_sos = 0;
1786 ApplyCurSOS();
1787 }
1788
1789 goto failed;
1790 break;
1791 case 83614:
1792 case 8361:
1793 case 8341:
1794 case 83212:
1795 case 83214:
1796 case 8312:
1797 case 8314:
1798 case 8321:
1799 case 831:
1800 case 82341:
1801 case 834:
1802 case 823:
1803 case 8234:
1804 case 8231:
1805
1806 if (cur_pom==0) cur_pom++;
1807
1808 if (cur_pnux==0) cur_pnux++;
1809
1810 if (cur_pnux==2) cur_pnux++;
1811
1812 if (cur_bh == 1)
1813 {
1814 cur_bh++;
1815 }
1816
1817 if (cur_bh == 3)
1818 {
1819 cur_bh = 0;
1820 EERIE_OBJECT_SetBHMode();
1821 }
1822
1823 goto failed;
1824 break;
1825 break;
1826
1827 case 83692:
1828 case 823982:
1829 case 83982:
1830 case 82369892:
1831 case 82392:
1832 case 83892:
1833 case 823282:
1834 case 8392:
1835 {
1836 if (cur_sm == 2)
1837 {
1838 cur_sm++;
1839 ApplySPBow();
1840 }
1841
1842 if (cur_mx == 0)
1843 {
1844 cur_mx = 1;
1845 }
1846
1847 if (cur_mr == 0)
1848 {
1849 cur_mr = 1;
1850 }
1851
1852 if (cur_pom == 2)
1853 {
1854 cur_pom++;
1855 ApplySPWep();
1856 }
1857
1858 goto failed;
1859 }
1860 break;
1861 case 98324:
1862 case 92324:
1863 case 89324:
1864 case 9324:
1865 case 9892324:
1866 case 9234:
1867 case 934:
1868 {
1869 if (cur_mr == 1)
1870 {
1871 cur_mr = 2;
1872 MakeCoolFx(&player.pos);
1873 }
1874
1875 if (cur_mx == 1)
1876 {
1877 cur_mx = 2;
1878 MakeCoolFx(&player.pos);
1879 }
1880
1881 if (cur_rf == 1)
1882 {
1883 cur_rf = 2;
1884 MakeCoolFx(&player.pos);
1885 }
1886
1887 if (cur_sm==1) cur_sm++;
1888
1889 goto failed;
1890 }
1891 break;
1892 case 3249:
1893 case 2349:
1894 case 323489:
1895 case 23249:
1896 case 3489:
1897 case 32498:
1898 case 349:
1899 {
1900 if (cur_mx == 2)
1901 {
1902 cur_mx = 3;
1903 ApplySPMax();
1904 }
1905
1906 goto failed;
1907 }
1908 break;
1909
1910 case 26:
1911 {
1912 if (cur_pnux == 1)
1913 {
1914 cur_pnux++;
1915 }
1916
1917 if (cur_pnux == 3)
1918 {
1919 cur_pnux++;
1920 ApplyCurPNux();
1921 }
1922
1923 goto failed;
1924 }
1925 break;
1926 case 9232187:
1927 case 93187:
1928 case 9234187:
1929 case 831878:
1930 case 923187:
1931 case 932187:
1932 case 93217:
1933 case 9317:
1934 {
1935 if (cur_pom==1) cur_pom++;
1936
1937 if (cur_sos==1) cur_sos++;
1938
1939 goto failed;
1940 }
1941 break;
1942 case 82313:
1943 case 8343:
1944 case 82343:
1945 case 83413:
1946 case 8313:
1947 {
1948 if (cur_mr == 2)
1949 {
1950 cur_mr = 3;
1951 MakeCoolFx(&player.pos);
1952 ApplyCurMr();
1953 }
1954
1955 if (cur_rf == 0)
1956 {
1957 cur_rf = 1;
1958 }
1959
1960 goto failed;
1961 break;
1962 }
1963 case 86:
1964
1965 if (cur_rf == 2)
1966 {
1967 cur_rf = 3;
1968 MakeCoolFx(&player.pos);
1969 ApplySPRf();
1970 }
1971
1972 goto failed;
1973 break;
1974
1975 case 626262:
1976 {
1977 passwall++;
1978
1979 if (passwall==3)
1980 {
1981 passwall=0;
1982 ApplyPasswall();
1983 }
1984 }
1985 break;
1986 case 828282:
1987 {
1988 player.skin++;
1989
1990 if ((player.skin==4) && (rnd()<0.9f))
1991 player.skin++;
1992
1993 if (player.skin>5)
1994 player.skin=0;
1995
1996 ARX_EQUIPMENT_RecreatePlayerMesh();
1997 goto failed;
1998 }
1999 break;
2000
2001 default:
2002 {
2003 failed:
2004 ;
2005 std::string tex;
2006
2007 if (SpellMoves.length()>=127)
2008 SpellMoves.resize(127);
2009
2010 LAST_FAILED_SEQUENCE = SpellMoves;
2011
2012 LogDebug("Unknown Symbol - " + SpellMoves);
2013 }
2014 }
2015
2016 bPrecastSpell = false;
2017
2018 // wanna precast?
2019 if (GInput->actionPressed(CONTROLS_CUST_STEALTHMODE))
2020 {
2021 bPrecastSpell = true;
2022 }
2023 }
2024
2025 struct SpellDefinition {
2026 SpellDefinition * next[RUNE_COUNT];
2027 Spell spell;
SpellDefinitionSpellDefinition2028 SpellDefinition() : spell(SPELL_NONE) {
2029 for(size_t i = 0; i < RUNE_COUNT; i++) {
2030 next[i] = NULL;
2031 }
2032 }
2033
~SpellDefinitionSpellDefinition2034 ~SpellDefinition() {
2035 for(size_t i = 0; i < RUNE_COUNT; i++) {
2036 delete next[i];
2037 }
2038 }
2039 };
2040
2041 static SpellDefinition definedSpells;
2042 typedef std::map<string, Spell> SpellNames;
2043 static SpellNames spellNames;
2044
addSpell(const Rune symbols[MAX_SPELL_SYMBOLS],Spell spell,const string & name)2045 static void addSpell(const Rune symbols[MAX_SPELL_SYMBOLS], Spell spell, const string & name) {
2046
2047 typedef std::pair<SpellNames::const_iterator, bool> Res;
2048 Res res = spellNames.insert(std::make_pair(name, spell));
2049 if(!res.second) {
2050 LogWarning << "Duplicate spell name: " + name;
2051 }
2052
2053 if(symbols[0] == RUNE_NONE) {
2054 return;
2055 }
2056
2057 SpellDefinition * def = &definedSpells;
2058
2059 for(size_t i = 0; i < MAX_SPELL_SYMBOLS; i++) {
2060 if(symbols[i] == RUNE_NONE) {
2061 break;
2062 }
2063 arx_assert(symbols[i] >= 0 && (size_t)symbols[i] < RUNE_COUNT);
2064 if(def->next[symbols[i]] == NULL) {
2065 def->next[symbols[i]] = new SpellDefinition();
2066 }
2067 def = def->next[symbols[i]];
2068 }
2069
2070 arx_assert(def->spell == SPELL_NONE);
2071
2072 def->spell = spell;
2073 }
2074
getSpell(const Rune symbols[MAX_SPELL_SYMBOLS])2075 static Spell getSpell(const Rune symbols[MAX_SPELL_SYMBOLS]) {
2076
2077 const SpellDefinition * def = &definedSpells;
2078
2079 for(size_t i = 0; i < MAX_SPELL_SYMBOLS; i++) {
2080 if(symbols[i] == RUNE_NONE) {
2081 break;
2082 }
2083 arx_assert(symbols[i] >= 0 && (size_t)symbols[i] < RUNE_COUNT);
2084 if(def->next[symbols[i]] == NULL) {
2085 return SPELL_NONE;
2086 }
2087 def = def->next[symbols[i]];
2088 }
2089
2090 return def->spell;
2091 }
2092
GetSpellId(const string & spell)2093 Spell GetSpellId(const string & spell) {
2094
2095 SpellNames::const_iterator it = spellNames.find(spell);
2096
2097 return (it == spellNames.end()) ? SPELL_NONE : it->second;
2098 }
2099
2100 struct RawSpellDefinition {
2101 Rune symbols[MAX_SPELL_SYMBOLS];
2102 Spell spell;
2103 std::string name;
2104 };
2105
2106 // TODO move to external file
2107 static const RawSpellDefinition allSpells[] = {
2108 {{RUNE_RHAA, RUNE_STREGUM, RUNE_VITAE, RUNE_NONE}, SPELL_CURSE, "curse"}, // level 4
2109 {{RUNE_RHAA, RUNE_TEMPUS, RUNE_NONE}, SPELL_FREEZE_TIME, "freeze_time"}, // level 10
2110 {{RUNE_RHAA, RUNE_KAOM, RUNE_NONE}, SPELL_LOWER_ARMOR, "lower_armor"}, // level 2
2111 {{RUNE_RHAA, RUNE_MOVIS, RUNE_NONE}, SPELL_SLOW_DOWN, "slowdown"}, // level 6
2112 {{RUNE_RHAA, RUNE_VITAE, RUNE_NONE}, SPELL_HARM, "harm"}, // level 2
2113 {{RUNE_RHAA, RUNE_VISTA, RUNE_NONE}, SPELL_CONFUSE, "confuse"}, // level 7
2114 {{RUNE_MEGA, RUNE_NHI, RUNE_MOVIS, RUNE_NONE}, SPELL_MASS_PARALYSE, "mass_paralyse"}, // level 9
2115 {{RUNE_MEGA, RUNE_KAOM, RUNE_NONE}, SPELL_ARMOR, "armor"}, // level 2
2116 {{RUNE_MEGA, RUNE_VISTA, RUNE_NONE}, SPELL_MAGIC_SIGHT, "magic_sight"}, // level 1
2117 {{RUNE_MEGA, RUNE_VITAE, RUNE_NONE}, SPELL_HEAL, "heal"}, // level 2
2118 {{RUNE_MEGA, RUNE_MOVIS, RUNE_NONE}, SPELL_SPEED, "speed"}, // level 3
2119 {{RUNE_MEGA, RUNE_STREGUM, RUNE_VITAE, RUNE_NONE}, SPELL_BLESS, "bless"}, // level 4
2120 {{RUNE_MEGA, RUNE_STREGUM, RUNE_COSUM, RUNE_NONE}, SPELL_ENCHANT_WEAPON, "enchant_weapon"}, // level 8
2121 {{RUNE_MEGA, RUNE_AAM, RUNE_MEGA, RUNE_YOK, RUNE_NONE}, SPELL_MASS_INCINERATE, "mass_incinerate"}, // level 10
2122 {{RUNE_MEGA, RUNE_SPACIUM, RUNE_NONE}, SPELL_ACTIVATE_PORTAL, "activate_portal"}, // level ?
2123 {{RUNE_MEGA, RUNE_SPACIUM, RUNE_MOVIS, RUNE_NONE}, SPELL_LEVITATE, "levitate"}, // level 5
2124 {{RUNE_NHI, RUNE_MOVIS, RUNE_NONE}, SPELL_PARALYSE, "paralyse"}, // level 6
2125 {{RUNE_NHI, RUNE_CETRIUS, RUNE_NONE}, SPELL_CURE_POISON, "cure_poison"}, // level 5
2126 {{RUNE_NHI, RUNE_YOK, RUNE_NONE}, SPELL_DOUSE, "douse"}, // level 1
2127 {{RUNE_NHI, RUNE_STREGUM, RUNE_VISTA, RUNE_NONE}, SPELL_DISPELL_ILLUSION, "dispell_illusion"}, // level 3
2128 {{RUNE_NHI, RUNE_STREGUM, RUNE_SPACIUM, RUNE_NONE}, SPELL_NEGATE_MAGIC, "negate_magic"}, // level 9
2129 {{RUNE_NHI, RUNE_SPACIUM, RUNE_NONE}, SPELL_DISPELL_FIELD, "dispell_field"}, // level 4
2130 {{RUNE_NHI, RUNE_MORTE, RUNE_COSUM, RUNE_NONE}, SPELL_DISARM_TRAP, "disarm_trap"}, // level 6
2131 {{RUNE_NHI, RUNE_VISTA, RUNE_NONE}, SPELL_INVISIBILITY, "invisibility"}, // level ?
2132 {{RUNE_VISTA, RUNE_MOVIS, RUNE_NONE}, SPELL_FLYING_EYE, "flying_eye"}, // level 7
2133 {{RUNE_MORTE, RUNE_KAOM, RUNE_NONE}, SPELL_REPEL_UNDEAD, "repel_undead"}, // level 5
2134 {{RUNE_MORTE, RUNE_COSUM, RUNE_VISTA, RUNE_NONE}, SPELL_DETECT_TRAP, "detect_trap"}, // level 2
2135 {{RUNE_MOVIS, RUNE_COMUNICATUM, RUNE_NONE}, SPELL_CONTROL_TARGET, "control"}, // level 10
2136 {{RUNE_STREGUM, RUNE_MOVIS, RUNE_NONE}, SPELL_MANA_DRAIN, "mana_drain"}, // level 8
2137 {{RUNE_AAM, RUNE_MEGA, RUNE_YOK, RUNE_NONE}, SPELL_INCINERATE, "incinerate"}, // level 9
2138 {{RUNE_AAM, RUNE_MEGA, RUNE_MORTE, RUNE_NONE}, SPELL_EXPLOSION, "explosion"}, // level 8
2139 {{RUNE_AAM, RUNE_KAOM, RUNE_SPACIUM, RUNE_NONE}, SPELL_CREATE_FIELD, "create_field"}, // level 6
2140 {{RUNE_AAM, RUNE_MORTE, RUNE_VITAE, RUNE_NONE}, SPELL_RISE_DEAD, "raise_dead"}, // level 6
2141 {{RUNE_AAM, RUNE_MORTE, RUNE_COSUM, RUNE_NONE}, SPELL_RUNE_OF_GUARDING, "rune_of_guarding"}, // level 5
2142 {{RUNE_AAM, RUNE_VITAE, RUNE_TERA, RUNE_NONE}, SPELL_SUMMON_CREATURE, "summon_creature"}, // level 9
2143 {{RUNE_AAM, RUNE_VITAE, RUNE_COSUM, RUNE_NONE}, SPELL_CREATE_FOOD, "create_food"}, // level 3
2144 {{RUNE_AAM, RUNE_FOLGORA, RUNE_TAAR, RUNE_NONE}, SPELL_LIGHTNING_STRIKE, "lightning_strike"}, // level 7
2145 {{RUNE_AAM, RUNE_FOLGORA, RUNE_SPACIUM, RUNE_NONE}, SPELL_MASS_LIGHTNING_STRIKE, "mass_lightning_strike"}, // level 10
2146 {{RUNE_AAM, RUNE_YOK, RUNE_NONE}, SPELL_IGNIT, "ignit"}, // level 1
2147 {{RUNE_AAM, RUNE_YOK, RUNE_SPACIUM, RUNE_NONE}, SPELL_FIRE_FIELD, "fire_field"}, // level 7
2148 {{RUNE_AAM, RUNE_YOK, RUNE_TAAR, RUNE_NONE}, SPELL_FIREBALL, "fireball"}, // level 3
2149 {{RUNE_AAM, RUNE_FRIDD, RUNE_SPACIUM, RUNE_NONE}, SPELL_ICE_FIELD, "ice_field"}, // level 7
2150 {{RUNE_AAM, RUNE_FRIDD, RUNE_TAAR, RUNE_NONE}, SPELL_ICE_PROJECTILE, "ice_projectile"}, // level 3
2151 {{RUNE_AAM, RUNE_CETRIUS, RUNE_TAAR, RUNE_NONE}, SPELL_POISON_PROJECTILE, "poison_projectile"}, // level 5
2152 {{RUNE_AAM, RUNE_TAAR, RUNE_NONE}, SPELL_MAGIC_MISSILE, "magic_missile"}, // level 1
2153 {{RUNE_YOK, RUNE_KAOM, RUNE_NONE}, SPELL_FIRE_PROTECTION, "fire_protection"}, // level 4
2154 {{RUNE_FRIDD, RUNE_KAOM, RUNE_NONE}, SPELL_COLD_PROTECTION, "cold_protection"}, // level 4
2155 {{RUNE_VITAE, RUNE_MOVIS, RUNE_NONE}, SPELL_LIFE_DRAIN, "life_drain"}, // level 8
2156 {{RUNE_SPACIUM, RUNE_COMUNICATUM, RUNE_NONE}, SPELL_TELEKINESIS, "telekinesis"}, // level 4
2157 {{RUNE_NONE}, SPELL_FAKE_SUMMON, "fake_summon"}
2158 };
2159
2160 //! Plays the sound of Fizzling spell
ARX_SPELLS_Fizzle(long num)2161 static void ARX_SPELLS_Fizzle(long num) {
2162 if(num < 0) {
2163 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE); // player fizzle
2164 } else {
2165 spells[num].tolive = 0;
2166
2167 if(spells[num].caster >= 0) {
2168 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &spells[num].caster_pos);
2169 }
2170 }
2171 }
2172
ARX_SPELLS_AnalyseSPELL()2173 static bool ARX_SPELLS_AnalyseSPELL() {
2174
2175 long caster = 0; // Local Player
2176 SpellcastFlags flags = 0;
2177
2178 if(GInput->actionPressed(CONTROLS_CUST_STEALTHMODE) || bPrecastSpell) {
2179 flags |= SPELLCAST_FLAG_PRECAST;
2180 }
2181
2182 bPrecastSpell = false;
2183
2184 Spell spell;
2185
2186 if(SpellSymbol[0] == RUNE_MEGA && SpellSymbol[1] == RUNE_MEGA
2187 && SpellSymbol[2] == RUNE_MEGA && SpellSymbol[3] == RUNE_AAM
2188 && SpellSymbol[4] == RUNE_VITAE && SpellSymbol[5] == RUNE_TERA) {
2189 cur_mega = 10;
2190 spell = SPELL_SUMMON_CREATURE;
2191 } else {
2192 spell = getSpell(SpellSymbol);
2193 }
2194
2195 if(spell == SPELL_NONE) {
2196
2197 ARX_SPELLS_Fizzle(-1);
2198
2199 if(player.SpellToMemorize.bSpell) {
2200 CurrSpellSymbol = 0;
2201 player.SpellToMemorize.bSpell = false;
2202 }
2203
2204 return false;
2205 }
2206
2207 return ARX_SPELLS_Launch(spell, caster, flags);
2208
2209 }
2210
2211
No_MagicAllowed()2212 bool No_MagicAllowed()
2213 {
2214 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
2215 return false;
2216 }
2217 extern long PLAYER_PARALYSED;
2218
2219
ARX_SPELLS_Analyse()2220 static void ARX_SPELLS_Analyse() {
2221
2222 unsigned char dirs[MAX_POINTS];
2223 unsigned char lastdir = 255;
2224 long cdir = 0;
2225
2226 for(long i = 1; i < CurrPoint ; i++) {
2227
2228 Vec2s d = plist[i-1] - plist[i];
2229
2230 if(d.lengthSqr() > 100) {
2231
2232 float a = (float)abs(d.x);
2233 float b = (float)abs(d.y);
2234
2235 if(b != 0.f && a / b > 0.4f && a / b < 2.5f) {
2236 // Diagonal movemement.
2237
2238 if(d.x < 0 && d.y < 0) {
2239 if(lastdir != ADOWNRIGHT) {
2240 lastdir = dirs[cdir++] = ADOWNRIGHT;
2241 }
2242 } else if(d.x > 0 && d.y < 0) {
2243 if(lastdir != ADOWNLEFT) {
2244 lastdir = dirs[cdir++] = ADOWNLEFT;
2245 }
2246 } else if(d.x < 0 && d.y > 0) {
2247 if(lastdir != AUPRIGHT) {
2248 lastdir = dirs[cdir++] = AUPRIGHT;
2249 }
2250 } else if(d.x > 0 && d.y > 0) {
2251 if(lastdir != AUPLEFT) {
2252 lastdir = dirs[cdir++] = AUPLEFT;
2253 }
2254 }
2255
2256 } else if(a > b) {
2257 // Horizontal movement.
2258
2259 if(d.x < 0) {
2260 if(lastdir != ARIGHT) {
2261 lastdir = dirs[cdir++] = ARIGHT;
2262 }
2263 } else {
2264 if(lastdir != ALEFT) {
2265 lastdir = dirs[cdir++] = ALEFT;
2266 }
2267 }
2268
2269 } else {
2270 // Vertical movement.
2271
2272 if(d.y < 0) {
2273 if(lastdir != ADOWN) {
2274 lastdir = dirs[cdir++] = ADOWN;
2275 }
2276 } else {
2277 if(lastdir != AUP) {
2278 lastdir = dirs[cdir++] = AUP;
2279 }
2280 }
2281 }
2282 }
2283 }
2284
2285 SpellMoves.clear();
2286
2287 if ( cdir > 0 )
2288 {
2289
2290 for (long i = 0 ; i < cdir ; i++ )
2291 {
2292 switch ( dirs[i] )
2293 {
2294 case AUP:
2295 SpellMoves += "8"; //uses PAD values
2296 break;
2297
2298 case ADOWN:
2299 SpellMoves += "2";
2300 break;
2301
2302 case ALEFT:
2303 SpellMoves += "4";
2304 break;
2305
2306 case ARIGHT:
2307 SpellMoves += "6";
2308 break;
2309
2310 case AUPRIGHT:
2311 SpellMoves += "9";
2312 break;
2313
2314 case ADOWNRIGHT:
2315 SpellMoves += "3";
2316 break;
2317
2318 case AUPLEFT:
2319 SpellMoves += "7";
2320 break;
2321
2322 case ADOWNLEFT:
2323 SpellMoves += "1";
2324 break;
2325 }
2326 }
2327 }
2328 }
2329
ARX_SPELLS_ManageMagic()2330 void ARX_SPELLS_ManageMagic()
2331 {
2332 if (ARXmenu.currentmode!=AMCM_OFF)
2333 return;
2334
2335 Entity * io=entities.player();
2336
2337 if (!io) return;
2338
2339 if ((io->animlayer[1].cur_anim == io->anims[ANIM_BARE_UNREADY]) ||
2340 (io->animlayer[1].cur_anim == io->anims[ANIM_DAGGER_UNREADY_PART_1]) ||
2341 (io->animlayer[1].cur_anim == io->anims[ANIM_1H_UNREADY_PART_1]) ||
2342 (io->animlayer[1].cur_anim == io->anims[ANIM_2H_UNREADY_PART_1]) ||
2343 (io->animlayer[1].cur_anim == io->anims[ANIM_MISSILE_UNREADY_PART_1]) ||
2344 (io->animlayer[1].cur_anim == io->anims[ANIM_DAGGER_UNREADY_PART_2]) ||
2345 (io->animlayer[1].cur_anim == io->anims[ANIM_1H_UNREADY_PART_2]) ||
2346 (io->animlayer[1].cur_anim == io->anims[ANIM_2H_UNREADY_PART_2]) ||
2347 (io->animlayer[1].cur_anim == io->anims[ANIM_MISSILE_UNREADY_PART_2]))
2348 return;
2349
2350 snip++;
2351
2352 if ((!(player.Current_Movement & PLAYER_CROUCH)) && (!BLOCK_PLAYER_CONTROLS &&
2353 (GInput->actionPressed(CONTROLS_CUST_MAGICMODE))) && (!PLAYER_PARALYSED))
2354 {
2355
2356 if (player.Interface & INTER_COMBATMODE)
2357 {
2358 WILLRETURNTOCOMBATMODE=1;
2359
2360 ARX_INTERFACE_Combat_Mode(0);
2361 bGToggleCombatModeWithKey=false;
2362
2363
2364 ResetAnim(&entities.player()->animlayer[1]);
2365 entities.player()->animlayer[1].flags&=~EA_LOOP;
2366 }
2367
2368 if (TRUE_PLAYER_MOUSELOOK_ON)
2369 {
2370 WILLRETURNTOFREELOOK = 1;
2371 TRUE_PLAYER_MOUSELOOK_ON = false;
2372 }
2373
2374 if (player.doingmagic!=2)
2375 {
2376 player.doingmagic=2;
2377
2378 if (entities.player()->anims[ANIM_CAST_START])
2379 {
2380 AcquireLastAnim(entities.player());
2381 ANIM_Set(&entities.player()->animlayer[1],entities.player()->anims[ANIM_CAST_START]);
2382 MAGICMODE = 1;
2383 }
2384 }
2385
2386 if (snip >= 2)
2387 {
2388 if ((!EERIEMouseButton & 1) && (ARX_FLARES_broken==0)) // TODO should this be !(EERIEMouseButton & 1)?
2389 {
2390 ARX_FLARES_broken=2;
2391 PIPOrgb++;
2392
2393 if (PIPOrgb>2) PIPOrgb=0;
2394 }
2395
2396 if(EERIEMouseButton & 1) {
2397
2398 Vec2s pos = DANAEMouse;
2399 if(TRUE_PLAYER_MOUSELOOK_ON) {
2400 pos = MemoMouse;
2401 }
2402
2403 Vec2s pos2 = Lm;
2404
2405 if (!ARX_FLARES_broken) FlareLine(&pos2,&pos);
2406
2407 if (rnd()>0.6) AddFlare(&pos,1.f,-1);
2408 else AddFlare(&pos,1.f,3);
2409
2410 OPIPOrgb = PIPOrgb;
2411
2412 Lm = DANAEMouse;
2413 if(TRUE_PLAYER_MOUSELOOK_ON) {
2414 Lm = MemoMouse;
2415 }
2416
2417 ARX_FLARES_broken=0;
2418
2419 if (!ARX_SOUND_IsPlaying(SND_MAGIC_DRAW))
2420 ARX_SOUND_PlaySFX(SND_MAGIC_DRAW, NULL, 1.0F, ARX_SOUND_PLAY_LOOPED);
2421 }
2422 else
2423 {
2424 ARX_SOUND_Stop(SND_MAGIC_DRAW);
2425 }
2426
2427 snip=0;
2428 }
2429 }
2430 else
2431 {
2432 ARX_FLARES_broken=1;
2433 PIPOrgb++;
2434
2435 if (PIPOrgb>2) PIPOrgb=0;
2436
2437 if (player.doingmagic!=0)//==2)
2438 {
2439 player.doingmagic=0;//1
2440
2441 if (entities.player()->anims[ANIM_CAST_END])
2442 {
2443 AcquireLastAnim(entities.player());
2444 ANIM_Set(&entities.player()->animlayer[1],entities.player()->anims[ANIM_CAST_END]);
2445 }
2446
2447 ARX_FLARES_broken=3;
2448 }
2449 }
2450
2451
2452 if (ARX_FLARES_broken==3)
2453 {
2454 cur_arm=0;
2455 cur_mega=0;
2456 passwall=0;
2457
2458 if (cur_mr!=3)
2459 cur_mr=0;
2460
2461 if (cur_mx!=3)
2462 cur_mx=0;
2463
2464 if (cur_rf!=3)
2465 cur_rf=0;
2466
2467 if (cur_pom!=3)
2468 cur_pom=0;
2469
2470 if (cur_pnux<3)
2471 cur_pnux=0;
2472
2473 if (cur_sm<3)
2474 cur_sm=0;
2475
2476 cur_bh=0;
2477 cur_sos=0;
2478
2479 if (CurrSpellSymbol != 0)
2480 {
2481 if (!ARX_SPELLS_AnalyseSPELL())
2482 {
2483 if (entities.player()->anims[ANIM_CAST])
2484 {
2485 AcquireLastAnim(entities.player());
2486 ANIM_Set(&entities.player()->animlayer[1],entities.player()->anims[ANIM_CAST]);
2487 }
2488 }
2489 }
2490
2491 ARX_FLARES_broken=1;
2492
2493 if (WILLRETURNTOCOMBATMODE)
2494 {
2495 player.Interface|=INTER_COMBATMODE;
2496 player.Interface|=INTER_NO_STRIKE;
2497
2498 ARX_EQUIPMENT_LaunchPlayerReadyWeapon();
2499 player.doingmagic=0;
2500 WILLRETURNTOCOMBATMODE=0;
2501
2502 TRUE_PLAYER_MOUSELOOK_ON = true;
2503 bRenderInCursorMode=false;
2504 }
2505
2506 if (WILLRETURNTOFREELOOK)
2507 {
2508 TRUE_PLAYER_MOUSELOOK_ON = true;
2509 WILLRETURNTOFREELOOK = 0;
2510 }
2511
2512 ARX_SPELLS_ResetRecognition();
2513 }
2514 else if (ARX_FLARES_broken==2)
2515 {
2516 ARX_SPELLS_Analyse();
2517
2518 if (!SpellMoves.empty())
2519 ARX_SPELLS_AnalyseSYMBOL();
2520
2521 ARX_FLARES_broken = 1;
2522 }
2523 }
2524
2525 /*!
2526 * Plays the sound of Fizzling spell plus "NO MANA" speech
2527 */
ARX_SPELLS_FizzleNoMana(long num)2528 static void ARX_SPELLS_FizzleNoMana(long num) {
2529 if(num < 0) {
2530 return;
2531 }
2532 if(spells[num].caster >= 0) {
2533 spells[num].tolive = 0;
2534 ARX_SPELLS_Fizzle(num);
2535 }
2536 }
2537
CanPayMana(long num,float cost,bool _bSound=true)2538 long CanPayMana(long num, float cost, bool _bSound = true) {
2539
2540 if (num<0) return 0;
2541
2542 if (spells[num].flags & SPELLCAST_FLAG_NOMANA) return 1;
2543
2544 if (spells[num].caster==0)
2545 {
2546 if (player.mana<cost)
2547 {
2548 ARX_SPELLS_FizzleNoMana(num);
2549
2550 if(_bSound) {
2551 ARX_SPEECH_Add(getLocalised("player_cantcast"));
2552 ARX_SPEECH_AddSpeech(entities.player(), "player_cantcast", ANIM_TALK_NEUTRAL);
2553 }
2554
2555 return 0;
2556 }
2557
2558 player.mana -= cost;
2559 return 1;
2560 }
2561 else if(ValidIONum(spells[num].caster)) {
2562 if(entities[spells[num].caster]->ioflags & IO_NPC) {
2563 if(entities[spells[num].caster]->_npcdata->mana < cost) {
2564 ARX_SPELLS_FizzleNoMana(num);
2565 return 0;
2566 }
2567 entities[spells[num].caster]->_npcdata->mana -= cost;
2568 return 1;
2569 }
2570 }
2571
2572 return 0;
2573 }
2574
2575 //-----------------------------------------------------------------------------
2576 // Resets Spell Recognition
ARX_SPELLS_ResetRecognition()2577 void ARX_SPELLS_ResetRecognition() {
2578
2579 for(size_t i = 0; i < MAX_SPELL_SYMBOLS; i++) {
2580 SpellSymbol[i] = RUNE_NONE;
2581 }
2582
2583 for(size_t i = 0; i < 6; i++) {
2584 player.SpellToMemorize.iSpellSymbols[i] = RUNE_NONE;
2585 }
2586
2587 CurrSpellSymbol = 0;
2588 }
2589
2590 // Adds a 2D point to currently drawn spell symbol
ARX_SPELLS_AddPoint(const Vec2s & pos)2591 void ARX_SPELLS_AddPoint(const Vec2s & pos) {
2592 plist[CurrPoint] = pos;
2593 CurrPoint++;
2594 if(CurrPoint >= MAX_POINTS) {
2595 CurrPoint = MAX_POINTS - 1;
2596 }
2597 }
2598
TemporaryGetSpellTarget(const Vec3f * from)2599 long TemporaryGetSpellTarget(const Vec3f * from) {
2600
2601 float mindist = std::numeric_limits<float>::max();
2602 long found = 0;
2603 for(size_t i = 1; i < entities.size(); i++) {
2604 if(entities[i] && entities[i]->ioflags & IO_NPC) {
2605 float dist = distSqr(*from, entities[i]->pos);
2606 if(dist < mindist) {
2607 found = i;
2608 mindist = dist;
2609 }
2610 }
2611 }
2612
2613 return found;
2614 }
2615
ARX_SPEELS_GetMaxRect(const char * _pcName)2616 static void ARX_SPEELS_GetMaxRect(const char *_pcName)
2617 {
2618 char tcTxt[32];
2619 int iMinX,iMinY,iMaxX,iMaxY;
2620 long iSizeX,iSizeY;
2621
2622 ARX_SPELLS_RequestSymbolDraw3(_pcName,tcTxt);
2623 ReCenterSequence(tcTxt,iMinX,iMinY,iMaxX,iMaxY);
2624 iSizeX=iMaxX-iMinX;
2625 iSizeY=iMaxY-iMinY;
2626 lMaxSymbolDrawSizeX=std::max(iSizeX,lMaxSymbolDrawSizeX);
2627 lMaxSymbolDrawSizeY=std::max(iSizeY,lMaxSymbolDrawSizeY);
2628 }
2629 //-----------------------------------------------------------------------------
2630 // Initializes Spell engine (Called once at DANAE startup)
ARX_SPELLS_Init_Rects()2631 void ARX_SPELLS_Init_Rects() {
2632 lMaxSymbolDrawSizeX = std::numeric_limits<long>::min();
2633 lMaxSymbolDrawSizeY = std::numeric_limits<long>::min();
2634
2635 ARX_SPEELS_GetMaxRect("aam");
2636 ARX_SPEELS_GetMaxRect("cetrius");
2637 ARX_SPEELS_GetMaxRect("comunicatum");
2638 ARX_SPEELS_GetMaxRect("cosum");
2639 ARX_SPEELS_GetMaxRect("folgora");
2640 ARX_SPEELS_GetMaxRect("fridd");
2641 ARX_SPEELS_GetMaxRect("kaom");
2642 ARX_SPEELS_GetMaxRect("mega");
2643 ARX_SPEELS_GetMaxRect("morte");
2644 ARX_SPEELS_GetMaxRect("movis");
2645 ARX_SPEELS_GetMaxRect("nhi");
2646 ARX_SPEELS_GetMaxRect("rhaa");
2647 ARX_SPEELS_GetMaxRect("spacium");
2648 ARX_SPEELS_GetMaxRect("stregum");
2649 ARX_SPEELS_GetMaxRect("taar");
2650 ARX_SPEELS_GetMaxRect("tempus");
2651 ARX_SPEELS_GetMaxRect("tera");
2652 ARX_SPEELS_GetMaxRect("vista");
2653 ARX_SPEELS_GetMaxRect("vitae");
2654 ARX_SPEELS_GetMaxRect("yok");
2655 ARX_SPEELS_GetMaxRect("akbaa");
2656 }
2657
2658 //-----------------------------------------------------------------------------
ARX_SPELLS_Init()2659 void ARX_SPELLS_Init() {
2660
2661 for(size_t i = 0; i < MAX_SPELLS; i++) {
2662 spells[i].tolive = 0;
2663 spells[i].exist = false;
2664 spells[i].pSpellFx = NULL;
2665 }
2666
2667 for(size_t i = 0; i < ARRAY_SIZE(allSpells); i++) {
2668 addSpell(allSpells[i].symbols, allSpells[i].spell, allSpells[i].name);
2669 }
2670
2671 }
2672
2673 // Clears All Spells.
ARX_SPELLS_ClearAll()2674 void ARX_SPELLS_ClearAll() {
2675
2676 for(size_t i = 0; i < MAX_SPELLS; i++) {
2677 if(spells[i].exist) {
2678 spells[i].tolive = 0;
2679 spells[i].exist = false;
2680 delete spells[i].pSpellFx, spells[i].pSpellFx = NULL;
2681 }
2682 }
2683
2684 BOOST_FOREACH(Entity * e, entities) {
2685 if(e) {
2686 ARX_SPELLS_RemoveAllSpellsOn(e);
2687 }
2688 }
2689 }
2690
2691 // Obtains a Free Spell slot
ARX_SPELLS_GetFree()2692 static long ARX_SPELLS_GetFree() {
2693
2694 for(size_t i = 0; i < MAX_SPELLS; i++) {
2695 if(!spells[i].exist) {
2696 spells[i].longinfo = spells[i].longinfo2 = -1;
2697 spells[i].misc = NULL;
2698 return i;
2699 }
2700 }
2701
2702 return -1;
2703 }
2704
ARX_SPELLS_GetInstance(Spell typ)2705 long ARX_SPELLS_GetInstance(Spell typ) {
2706
2707 for(size_t i = 0; i < MAX_SPELLS; i++) {
2708 if(spells[i].exist && spells[i].type == typ) {
2709 return i;
2710 }
2711 }
2712
2713 return -1;
2714 }
2715
2716 // Checks for an existing instance of this spelltype
ARX_SPELLS_ExistAnyInstance(Spell typ)2717 bool ARX_SPELLS_ExistAnyInstance(Spell typ) {
2718 return (ARX_SPELLS_GetInstance(typ) != -1);
2719 }
2720
ARX_SPELLS_GetInstanceForThisCaster(Spell typ,long caster)2721 long ARX_SPELLS_GetInstanceForThisCaster(Spell typ, long caster) {
2722
2723 for(size_t i = 0; i < MAX_SPELLS; i++) {
2724 if(spells[i].exist && spells[i].type == typ && spells[i].caster == caster) {
2725 return i;
2726 }
2727 }
2728
2729 return -1;
2730 }
2731
ARX_SPELLS_ExistAnyInstanceForThisCaster(Spell typ,long caster)2732 static bool ARX_SPELLS_ExistAnyInstanceForThisCaster(Spell typ, long caster) {
2733 return (ARX_SPELLS_GetInstanceForThisCaster(typ, caster) != -1);
2734 }
2735
2736 // Plays the sound of aborted spell
ARX_SPELLS_AbortSpellSound()2737 void ARX_SPELLS_AbortSpellSound() {
2738 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
2739 }
2740
ARX_SPELLS_FizzleAllSpellsFromCaster(long num_caster)2741 void ARX_SPELLS_FizzleAllSpellsFromCaster(long num_caster) {
2742
2743 for(size_t i = 0; i < MAX_SPELLS; i++) {
2744 if(spells[i].exist && spells[i].caster == num_caster) {
2745 spells[i].tolive = 0;
2746 }
2747 }
2748 }
2749
2750 PRECAST_STRUCT Precast[MAX_PRECAST];
2751
ARX_SPELLS_Precast_Reset()2752 void ARX_SPELLS_Precast_Reset() {
2753 for(size_t i = 0; i < MAX_PRECAST; i++) {
2754 Precast[i].typ = SPELL_NONE;
2755 }
2756 }
2757
ARX_SPELLS_Precast_Add(Spell typ,long _level,SpellcastFlags flags,long duration)2758 void ARX_SPELLS_Precast_Add(Spell typ, long _level, SpellcastFlags flags, long duration) {
2759
2760 long found = -1;
2761
2762 for(size_t i = 0; i < MAX_PRECAST; i++) {
2763 if(Precast[i].typ == SPELL_NONE) {
2764 found = i;
2765 break;
2766 }
2767 }
2768
2769 if(found == -1) {
2770 for(size_t i = 1; i < MAX_PRECAST; i++) {
2771 memcpy(&Precast[i - 1], &Precast[i], sizeof(PRECAST_STRUCT));
2772 }
2773
2774 found = MAX_PRECAST - 1;
2775 }
2776
2777 Precast[found].typ = typ;
2778 Precast[found].level = _level;
2779 Precast[found].launch_time = 0;
2780 Precast[found].flags = flags;
2781 Precast[found].duration = duration;
2782 }
2783
2784 unsigned long LAST_PRECAST_TIME=0;
PrecastCheckCanPayMana(long num,float cost,bool _bSound=true)2785 long PrecastCheckCanPayMana(long num, float cost, bool _bSound = true)
2786 {
2787 if (num<0) return 0;
2788
2789 if (Precast[num].flags & SPELLCAST_FLAG_NOMANA) return 1;
2790
2791 if (player.mana>=cost)
2792 {
2793 return 1;
2794 }
2795
2796 ARX_SPELLS_FizzleNoMana(num);
2797
2798 if(_bSound) {
2799 ARX_SPEECH_Add(getLocalised("player_cantcast"));
2800 ARX_SPEECH_AddSpeech(entities.player(), "player_cantcast", ANIM_TALK_NEUTRAL);
2801 }
2802
2803 return 0;
2804 }
2805
ARX_SPELLS_Precast_Launch(long num)2806 void ARX_SPELLS_Precast_Launch(long num) {
2807
2808 if (float(arxtime) >= LAST_PRECAST_TIME+1000)
2809 {
2810 Spell iNumSpells=Precast[num].typ;
2811 float cost=ARX_SPELLS_GetManaCost(iNumSpells,-1);
2812
2813 if( (iNumSpells != SPELL_NONE)
2814 && (!PrecastCheckCanPayMana(num,cost) ) )
2815 return;
2816
2817 LAST_PRECAST_TIME = (unsigned long)(arxtime);
2818
2819 if ((Precast[num].typ != SPELL_NONE) && (Precast[num].launch_time==0))
2820 {
2821 Precast[num].launch_time = (unsigned long)(arxtime);
2822 ARX_SOUND_PlaySFX(SND_SPELL_CREATE_FIELD);
2823 }
2824 }
2825 }
ARX_SPELLS_Precast_Check()2826 void ARX_SPELLS_Precast_Check()
2827 {
2828 for (size_t i = 0; i < MAX_PRECAST; i++)
2829 {
2830 if ((Precast[i].typ != SPELL_NONE) && (Precast[i].launch_time>0) &&(float(arxtime) >= Precast[i].launch_time))
2831 {
2832 ANIM_USE *ause1 = &entities.player()->animlayer[1];
2833
2834 if (player.Interface & INTER_COMBATMODE)
2835 {
2836 WILLRETURNTOCOMBATMODE=1;
2837 ARX_INTERFACE_Combat_Mode(0);
2838 bGToggleCombatModeWithKey=false;
2839 ResetAnim(&entities.player()->animlayer[1]);
2840 entities.player()->animlayer[1].flags&=~EA_LOOP;
2841 }
2842
2843 if ((ause1->cur_anim) && (ause1->cur_anim==entities.player()->anims[ANIM_CAST]))
2844 {
2845 if (ause1->ctime>ause1->cur_anim->anims[ause1->altidx_cur]->anim_time-550)
2846 {
2847 ARX_SPELLS_Launch( Precast[i].typ,
2848 0,
2849 Precast[i].flags | SPELLCAST_FLAG_LAUNCHPRECAST,
2850 Precast[i].level,
2851 -1,
2852 Precast[i].duration);
2853 Precast[i].typ = SPELL_NONE;
2854
2855 for (size_t li=i; li < MAX_PRECAST - 1; li++)
2856 {
2857 if (Precast[li + 1].typ != SPELL_NONE)
2858 {
2859 memcpy(&Precast[li], &Precast[li + 1], sizeof(PRECAST_STRUCT));
2860 Precast[li + 1].typ = SPELL_NONE;
2861 }
2862 }
2863 }
2864 } else {
2865 ANIM_USE * ause1 = &entities.player()->animlayer[1];
2866 AcquireLastAnim(entities.player());
2867 FinishAnim(entities.player(), ause1->cur_anim);
2868 ANIM_Set(ause1, entities.player()->anims[ANIM_CAST]);
2869 }
2870 }
2871 }
2872 }
2873
2874 struct TARGETING_SPELL {
2875 Spell typ;
2876 long source;
2877 SpellcastFlags flags;
2878 long level;
2879 long target;
2880 long duration;
2881 };
2882
2883 static TARGETING_SPELL t_spell;
2884
2885 long LOOKING_FOR_SPELL_TARGET=0;
2886 unsigned long LOOKING_FOR_SPELL_TARGET_TIME=0;
ARX_SPELLS_CancelSpellTarget()2887 void ARX_SPELLS_CancelSpellTarget() {
2888 t_spell.typ = SPELL_NONE;
2889 LOOKING_FOR_SPELL_TARGET=0;
2890 }
2891
ARX_SPELLS_LaunchSpellTarget(Entity * io)2892 void ARX_SPELLS_LaunchSpellTarget(Entity * io) {
2893 if(io) {
2894 ARX_SPELLS_Launch(t_spell.typ, t_spell.source, t_spell.flags, t_spell.level, io->index(), t_spell.duration);
2895 }
2896 }
2897
ARX_SPELLS_GetManaCost(Spell spell,long index)2898 static float ARX_SPELLS_GetManaCost(Spell spell, long index) {
2899
2900 // Calculate the player's magic level
2901 float playerCasterLevel = player.Full_Skill_Casting + player.Full_Attribute_Mind;
2902 playerCasterLevel = clamp(playerCasterLevel * 0.1f, 1.f, 10.f);
2903
2904 float casterLevel = ((index < 0) ? playerCasterLevel : spells[index].caster_level);
2905
2906 // TODO this data should not be hardcoded
2907
2908 switch(spell) {
2909
2910 default: return 0.f;
2911
2912 case SPELL_TELEKINESIS: return 0.001f;
2913 case SPELL_CURSE: return 0.001f;
2914 case SPELL_ARMOR: return 0.01f;
2915 case SPELL_LOWER_ARMOR: return 0.01f;
2916 case SPELL_SPEED: return 0.01f;
2917 case SPELL_BLESS: return 0.01f;
2918 case SPELL_DETECT_TRAP: return 0.03f;
2919 case SPELL_MAGIC_SIGHT: return 0.3f;
2920 case SPELL_HARM: return 0.4f;
2921 case SPELL_MANA_DRAIN: return 0.4f;
2922 case SPELL_IGNIT: return 1.f;
2923 case SPELL_DOUSE: return 1.f;
2924 case SPELL_FIRE_PROTECTION: return 1.f;
2925 case SPELL_COLD_PROTECTION: return 1.f;
2926 case SPELL_LEVITATE: return 1.f;
2927 case SPELL_CREATE_FIELD: return 1.2f;
2928 case SPELL_SLOW_DOWN: return 1.2f;
2929 case SPELL_ACTIVATE_PORTAL: return 2.f;
2930 case SPELL_NEGATE_MAGIC: return 2.f;
2931 case SPELL_INVISIBILITY: return 3.f;
2932 case SPELL_LIFE_DRAIN: return 3.f;
2933 case SPELL_HEAL: return 4.f;
2934 case SPELL_FLYING_EYE: return 4.f;
2935 case SPELL_CREATE_FOOD: return 5.f;
2936 case SPELL_DISPELL_ILLUSION: return 7.f;
2937 case SPELL_DISPELL_FIELD: return 7.f;
2938 case SPELL_RUNE_OF_GUARDING: return 9.f;
2939 case SPELL_CURE_POISON: return 10.f;
2940 case SPELL_TELEPORT: return 10.f;
2941 case SPELL_RISE_DEAD: return 12.f;
2942 case SPELL_DISARM_TRAP: return 15.f;
2943 case SPELL_FIRE_FIELD: return 15.f;
2944 case SPELL_ICE_FIELD: return 15.f;
2945 case SPELL_REPEL_UNDEAD: return 18.f;
2946 case SPELL_ENCHANT_WEAPON: return 35.f;
2947 case SPELL_INCINERATE: return 40.f;
2948 case SPELL_CONTROL_TARGET: return 40.f;
2949 case SPELL_EXPLOSION: return 45.f;
2950 case SPELL_FREEZE_TIME: return 60.f;
2951 case SPELL_MASS_INCINERATE: return 160.f;
2952
2953 case SPELL_CONFUSE: return casterLevel * 0.1f;
2954 case SPELL_MAGIC_MISSILE: return casterLevel * 1.f;
2955 case SPELL_ICE_PROJECTILE: return casterLevel * 1.5f;
2956 case SPELL_POISON_PROJECTILE: return casterLevel * 2.f;
2957 case SPELL_FIREBALL: return casterLevel * 3.f;
2958 case SPELL_PARALYSE: return casterLevel * 3.f;
2959 case SPELL_MASS_PARALYSE: return casterLevel * 3.f;
2960 case SPELL_LIGHTNING_STRIKE: return casterLevel * 6.f;
2961 case SPELL_MASS_LIGHTNING_STRIKE: return casterLevel * 8.f;
2962
2963 case SPELL_SUMMON_CREATURE: return (casterLevel < 9) ? 20.f : 80.f;
2964 case SPELL_FAKE_SUMMON: return (casterLevel < 9) ? 20.f : 80.f;
2965
2966 }
2967 }
2968
ARX_SPELLS_Launch(Spell typ,long source,SpellcastFlags flagss,long levell,long target,long duration)2969 bool ARX_SPELLS_Launch(Spell typ, long source, SpellcastFlags flagss, long levell, long target, long duration) {
2970
2971 SpellcastFlags flags = flagss;
2972 long level = levell;
2973
2974 if ( cur_rf == 3 )
2975 {
2976 flags |= SPELLCAST_FLAG_NOCHECKCANCAST | SPELLCAST_FLAG_NOMANA;
2977 }
2978
2979 if ( sp_max )
2980 {
2981 level = std::max( level, 15L );
2982 }
2983
2984 if(source == 0 && !(flags & SPELLCAST_FLAG_NOCHECKCANCAST)) {
2985 for(size_t i = 0; i < MAX_SPELL_SYMBOLS; i++) {
2986 if(SpellSymbol[i] != RUNE_NONE) {
2987 if(!( player.rune_flags & (RuneFlag)(1 << SpellSymbol[i]))) {
2988 ARX_SOUND_PlaySpeech("player_cantcast");
2989 CurrSpellSymbol = 0;
2990 ARX_SPELLS_ResetRecognition();
2991 return false;
2992 }
2993 }
2994 }
2995 }
2996
2997 float Player_Magic_Level = 0;
2998
2999 if ( !source )
3000 {
3001 ARX_SPELLS_ResetRecognition();
3002
3003 if ( player.SpellToMemorize.bSpell )
3004 {
3005 CurrSpellSymbol = 0;
3006 player.SpellToMemorize.bSpell = false;
3007 }
3008
3009 ARX_PLAYER_ComputePlayerFullStats();
3010
3011 if ( level == -1 )
3012 {
3013 Player_Magic_Level = (float) player.Full_Skill_Casting + player.Full_Attribute_Mind;
3014 Player_Magic_Level = clamp(Player_Magic_Level * 0.1f, 1.0f, 10.0f);
3015 }
3016 else
3017 {
3018 Player_Magic_Level = static_cast<float>(level);
3019 }
3020 }
3021
3022 arx_assert( !( source && (flags & SPELLCAST_FLAG_PRECAST) ) );
3023
3024
3025 if ( flags & SPELLCAST_FLAG_PRECAST )
3026 {
3027 int l = level;
3028
3029 if(l <= 0) {
3030 l = checked_range_cast<int>(Player_Magic_Level);
3031 }
3032
3033 SpellcastFlags flgs=flags;
3034 flgs&=~SPELLCAST_FLAG_PRECAST;
3035 ARX_SPELLS_Precast_Add( typ, l, flgs, duration);
3036 return true;
3037 }
3038
3039 static TextureContainer * tc4 = TextureContainer::Load("graph/particles/smoke");
3040
3041
3042 if ((target < 0)
3043 && ( source == 0 ) )
3044 switch ( typ )
3045 {
3046 case SPELL_LOWER_ARMOR:
3047 case SPELL_CURSE:
3048 case SPELL_PARALYSE:
3049 case SPELL_INCINERATE:
3050 case SPELL_SLOW_DOWN:
3051 case SPELL_CONFUSE:
3052 {
3053 LOOKING_FOR_SPELL_TARGET_TIME = (unsigned long)(arxtime);
3054 LOOKING_FOR_SPELL_TARGET = 1;
3055 t_spell.typ = typ;
3056 t_spell.source = source;
3057 t_spell.flags = flags;
3058 t_spell.level = level;
3059 t_spell.target = target;
3060 t_spell.duration = duration;
3061 return false;
3062 }
3063 case SPELL_ENCHANT_WEAPON:
3064 {
3065 LOOKING_FOR_SPELL_TARGET_TIME = (unsigned long)(arxtime);
3066 LOOKING_FOR_SPELL_TARGET = 2;
3067 t_spell.typ = typ;
3068 t_spell.source = source;
3069 t_spell.flags = flags;
3070 t_spell.level = level;
3071 t_spell.target = target;
3072 t_spell.duration = duration;
3073 return false;
3074 }
3075 break;
3076 case SPELL_CONTROL_TARGET:
3077 {
3078 long tcount = 0;
3079
3080 if ( !ValidIONum( source ) )
3081 return false;
3082
3083 Vec3f cpos = entities[source]->pos;
3084
3085 for(size_t ii = 1 ; ii < entities.size(); ii++) {
3086 Entity * ioo = entities[ii];
3087 if(ioo && (ioo->ioflags & IO_NPC) && ioo->_npcdata->life > 0.f
3088 && ioo->show == SHOW_FLAG_IN_SCENE
3089 && ioo->groups.find("demon") != ioo->groups.end()
3090 && closerThan(ioo->pos, cpos, 900.f)) {
3091 tcount++;
3092 }
3093 }
3094
3095 if ( tcount == 0 )
3096 {
3097 ARX_SOUND_PlaySFX( SND_MAGIC_FIZZLE, &cpos );
3098 return false;
3099 }
3100
3101 ARX_SOUND_PlaySpeech("player_follower_attack");
3102 LOOKING_FOR_SPELL_TARGET_TIME = (unsigned long)(arxtime);
3103 LOOKING_FOR_SPELL_TARGET = 1;
3104 t_spell.typ = typ;
3105 t_spell.source = source;
3106 t_spell.flags = flags;
3107 t_spell.level = level;
3108 t_spell.target = target;
3109 t_spell.duration = duration;
3110 return false;
3111 }
3112 break;
3113 default: break;
3114 }
3115
3116 if ( source == 0 )
3117 {
3118 ARX_SPELLS_CancelSpellTarget();
3119 }
3120
3121
3122 // Try to create a new spell instance
3123 long i = ARX_SPELLS_GetFree();
3124
3125 if ( i < 0 )
3126 {
3127 return false;
3128 }
3129
3130 if(ValidIONum(source) && spellicons[typ].bAudibleAtStart) {
3131 ARX_NPC_SpawnAudibleSound(&entities[source]->pos, entities[source]);
3132 }
3133
3134 spells[i].caster = source; // Caster...
3135 spells[i].target = target; // No target if <0
3136
3137 if ( target < 0 )
3138 spells[i].target = TemporaryGetSpellTarget( &entities[spells[i].caster]->pos );
3139
3140 // Create hand position if a hand is defined
3141 if ( spells[i].caster == 0 )
3142 {
3143 spells[i].hand_group = entities[spells[i].caster]->obj->fastaccess.primary_attach;
3144 }
3145 else
3146 {
3147 spells[i].hand_group = entities[spells[i].caster]->obj->fastaccess.left_attach;
3148 }
3149
3150 if(spells[i].hand_group != -1) {
3151 spells[i].hand_pos = entities[spells[i].caster]->obj->vertexlist3[spells[i].hand_group].v;
3152 }
3153
3154 if(source == 0) {
3155 // Player source
3156 spells[i].caster_level = Player_Magic_Level; // Level of caster
3157 spells[i].caster_pos = player.pos;
3158 } else {
3159 // IO source
3160 spells[i].caster_level = (float)clamp(level, 1l, 10l);
3161 spells[i].caster_pos = entities[source]->pos;
3162 }
3163
3164 if(flags & SPELLCAST_FLAG_LAUNCHPRECAST) {
3165 spells[i].caster_level = static_cast<float>(level);
3166 }
3167
3168 if(cur_rf == 3) {
3169 spells[i].caster_level += 2;
3170 }
3171
3172 // Checks target TODO if ( target < 0 ) is already handled above!
3173 if (target<0) // no target... targeted by sight
3174 {
3175 if (source==0) // no target... player spell targeted by sight
3176 {
3177 spells[i].target_pos.x=player.pos.x-EEsin(radians(player.angle.b))*60.f;
3178 spells[i].target_pos.y=player.pos.y+EEsin(radians(player.angle.a))*60.f;
3179 spells[i].target_pos.z=player.pos.z+EEcos(radians(player.angle.b))*60.f;
3180 }
3181 else
3182 {
3183 // TODO entities[target] with target < 0 ??? - uh oh!
3184 spells[i].target_pos.x=entities[target]->pos.x-EEsin(radians(entities[target]->angle.b))*60.f;
3185 spells[i].target_pos.y=entities[target]->pos.y-120.f;
3186 spells[i].target_pos.z=entities[target]->pos.z+EEcos(radians(entities[target]->angle.b))*60.f;
3187 }
3188 } else if (target==0) {
3189 // player target
3190 spells[i].target_pos = player.pos;
3191 } else {
3192 // IO target
3193 spells[i].target_pos = entities[target]->pos;
3194 }
3195
3196 spells[i].flags=flags;
3197 spells[i].pSpellFx=NULL;
3198 spells[i].type = typ;
3199 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
3200
3201
3202 // Check spell-specific preconditions
3203 switch(typ) {
3204
3205 case SPELL_MAGIC_SIGHT: {
3206 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3207 return false;
3208 }
3209 break;
3210 }
3211
3212 case SPELL_HEAL: {
3213 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3214 return false;
3215 }
3216 break;
3217 }
3218
3219 case SPELL_BLESS: {
3220 if(ARX_SPELLS_ExistAnyInstance(typ)) {
3221 return false;
3222 }
3223 break;
3224 }
3225
3226 case SPELL_TELEKINESIS: {
3227 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3228 return false;
3229 }
3230 break;
3231 }
3232
3233 case SPELL_FLYING_EYE: {
3234 if(eyeball.exist) {
3235 return false;
3236 }
3237 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) {
3238 return false;
3239 }
3240 break;
3241 }
3242
3243 case SPELL_INVISIBILITY: {
3244 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3245 return false;
3246 }
3247 break;
3248 }
3249
3250 case SPELL_MANA_DRAIN: {
3251 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3252 return false;
3253 }
3254 break;
3255 }
3256
3257 case SPELL_LIFE_DRAIN: {
3258 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3259 return false;
3260 }
3261 break;
3262 }
3263
3264 case SPELL_CONTROL_TARGET: {
3265 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3266 return false;
3267 }
3268 break;
3269 }
3270
3271 case SPELL_FREEZE_TIME: {
3272 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3273 return false;
3274 }
3275 break;
3276 }
3277
3278 case SPELL_TELEPORT: {
3279 if(ARX_SPELLS_ExistAnyInstanceForThisCaster(typ, spells[i].caster)) {
3280 return false;
3281 }
3282 break;
3283 }
3284
3285 default: break; // no preconditions to check
3286 }
3287
3288 if(!CanPayMana(i, ARX_SPELLS_GetManaCost(typ, i))) {
3289 return false;
3290 }
3291
3292 if(!GLOBAL_MAGIC_MODE) {
3293 return No_MagicAllowed();
3294 }
3295
3296 bool notifyAll = true;
3297
3298 switch(typ) {
3299
3300 case SPELL_NONE: return true;
3301
3302 // level 1 spells
3303
3304 case SPELL_MAGIC_SIGHT: {
3305
3306 spells[i].exist = true;
3307 spells[i].fManaCostPerSecond = 0.36f;
3308 spells[i].bDuration = true;
3309 spells[i].tolive = (duration > -1) ? duration : 6000000l;
3310
3311 ARX_SOUND_PlaySFX(SND_SPELL_VISION_START, &spells[i].caster_pos);
3312
3313 if(spells[i].caster == 0) {
3314 Project.improve = 1;
3315 spells[i].snd_loop = SND_SPELL_VISION_LOOP;
3316 ARX_SOUND_PlaySFX(spells[i].snd_loop, &spells[i].caster_pos, 1.f,
3317 ARX_SOUND_PLAY_LOOPED);
3318 }
3319
3320 break;
3321 }
3322
3323 case SPELL_MAGIC_MISSILE: {
3324
3325 spells[i].exist = true;
3326 spells[i].tolive = 20000; // TODO probably never read
3327
3328 long number;
3329 if(sp_max || cur_rf == 3) {
3330 number = long(spells[i].caster_level);
3331 } else {
3332 number = clamp(long(spells[i].caster_level + 1) / 2, 1l, 5l);
3333 }
3334
3335 CMultiMagicMissile * effect = new CMultiMagicMissile(number);
3336 effect->spellinstance = i;
3337 effect->SetDuration(6000ul);
3338 effect->Create();
3339 spells[i].pSpellFx = effect;
3340 spells[i].tolive = effect->GetDuration();
3341
3342 break;
3343 }
3344
3345 case SPELL_IGNIT: {
3346
3347 spells[i].exist = true;
3348 spells[i].tolive = 20000; // TODO probably never read
3349
3350 CIgnit * effect = new CIgnit();
3351 effect->spellinstance = i;
3352
3353 Vec3f target;
3354 if(spells[i].hand_group != -1) {
3355 target = spells[i].hand_pos;
3356 } else {
3357 target = spells[i].caster_pos - Vec3f(0.f, 50.f, 0.f);
3358 }
3359
3360 long id = GetFreeDynLight();
3361 if(id != -1) {
3362 DynLight[id].exist = 1;
3363 DynLight[id].intensity = 1.8f;
3364 DynLight[id].fallend = 450.f;
3365 DynLight[id].fallstart = 380.f;
3366 DynLight[id].rgb = Color3f(1.f, 0.75f, 0.5f);
3367 DynLight[id].pos = target;
3368 DynLight[id].duration = 300;
3369 }
3370
3371 float fPerimeter = 400.f + spells[i].caster_level * 30.f;
3372
3373 effect->Create(&target, fPerimeter, 500);
3374 CheckForIgnition(&target, fPerimeter, 1, 1);
3375
3376 for(size_t ii = 0; ii < MAX_LIGHTS; ii++) {
3377
3378 if(!GLight[ii] || !(GLight[ii]->extras & EXTRAS_EXTINGUISHABLE)) {
3379 continue;
3380 }
3381
3382 if(spells[i].caster == 0 && (GLight[ii]->extras & EXTRAS_NO_IGNIT)) {
3383 continue;
3384 }
3385
3386 if(!(GLight[ii]->extras & EXTRAS_SEMIDYNAMIC)
3387 && !(GLight[ii]->extras & EXTRAS_SPAWNFIRE)
3388 && !(GLight[ii]->extras & EXTRAS_SPAWNSMOKE)) {
3389 continue;
3390 }
3391
3392 if(GLight[ii]->status) {
3393 continue;
3394 }
3395
3396 if(!fartherThan(target, GLight[ii]->pos, effect->GetPerimetre())) {
3397 effect->AddLight(ii);
3398 }
3399 }
3400
3401 for(size_t n = 0; n < MAX_SPELLS; n++) {
3402 if(!spells[n].exist) {
3403 continue;
3404 }
3405 if(spells[n].type == SPELL_FIREBALL) {
3406 CSpellFx * pCSpellFX = spells[n].pSpellFx;
3407 if(pCSpellFX) {
3408 CFireBall * pCF = (CFireBall *)pCSpellFX;
3409 float radius = std::max(spells[i].caster_level * 2.f, 12.f);
3410 if(closerThan(target, pCF->eCurPos,
3411 effect->GetPerimetre() + radius)) {
3412 spells[n].caster_level += 1;
3413 }
3414 }
3415 }
3416 }
3417
3418 spells[i].pSpellFx = effect;
3419 spells[i].tolive = effect->GetDuration();
3420
3421 break;
3422 }
3423
3424 case SPELL_DOUSE: {
3425
3426 spells[i].exist = true;
3427 spells[i].tolive = 20000;
3428
3429 CDoze * effect = new CDoze();
3430 effect->spellinstance = i;
3431
3432 Vec3f target;
3433 if(spells[i].hand_group >= 0) {
3434 target = spells[i].hand_pos;
3435 } else {
3436 target = spells[i].caster_pos;
3437 target.y -= 50.f;
3438 }
3439
3440 float fPerimeter = 400.f + spells[i].caster_level * 30.f;
3441 effect->CreateDoze(&target, fPerimeter, 500);
3442 CheckForIgnition(&target, fPerimeter, 0, 1);
3443
3444 for(size_t ii = 0; ii < MAX_LIGHTS; ii++) {
3445
3446 if(!GLight[ii] || !(GLight[ii]->extras & EXTRAS_EXTINGUISHABLE)) {
3447 continue;
3448 }
3449
3450 if(!(GLight[ii]->extras & EXTRAS_SEMIDYNAMIC)
3451 && !(GLight[ii]->extras & EXTRAS_SPAWNFIRE)
3452 && !(GLight[ii]->extras & EXTRAS_SPAWNSMOKE)) {
3453 continue;
3454 }
3455
3456 if(!GLight[ii]->status) {
3457 continue;
3458 }
3459
3460 if(!fartherThan(target, GLight[ii]->pos, effect->GetPerimetre())) {
3461 effect->AddLightDoze(ii);
3462 }
3463 }
3464
3465 if(CURRENT_TORCH
3466 && closerThan(target, player.pos, effect->GetPerimetre())) {
3467 ARX_PLAYER_ClickedOnTorch(CURRENT_TORCH);
3468 }
3469
3470 for(size_t n = 0; n < MAX_SPELLS; n++) {
3471
3472 if(!spells[n].exist) {
3473 continue;
3474 }
3475
3476 switch(spells[n].type) {
3477
3478 case SPELL_FIREBALL: {
3479 CSpellFx * pCSpellFX = spells[n].pSpellFx;
3480 if(pCSpellFX) {
3481 CFireBall * pCF = (CFireBall *)pCSpellFX;
3482 float radius = std::max(spells[i].caster_level * 2.f, 12.f);
3483 if(closerThan(target, pCF->eCurPos,
3484 effect->GetPerimetre() + radius)) {
3485 spells[n].caster_level -= spells[i].caster_level;
3486 if(spells[n].caster_level < 1) {
3487 spells[n].tolive = 0;
3488 }
3489 }
3490 }
3491 break;
3492 }
3493
3494 case SPELL_FIRE_FIELD: {
3495 Vec3f pos;
3496 if(GetSpellPosition(&pos, n)) {
3497 if(closerThan(target, pos, effect->GetPerimetre() + 200)) {
3498 spells[n].caster_level -= spells[i].caster_level;
3499 if(spells[n].caster_level < 1) {
3500 spells[n].tolive=0;
3501 }
3502 }
3503 }
3504 break;
3505 }
3506
3507 default: break;
3508 }
3509 }
3510
3511 spells[i].pSpellFx = effect;
3512 spells[i].tolive = effect->GetDuration();
3513
3514 break;
3515 }
3516
3517 case SPELL_ACTIVATE_PORTAL: {
3518
3519 ARX_SOUND_PlayInterface(SND_SPELL_ACTIVATE_PORTAL);
3520 spells[i].exist = true;
3521 spells[i].tolive = 20;
3522
3523 break;
3524 }
3525
3526 // level 2 spells
3527
3528 case SPELL_HEAL: {
3529
3530 if(!(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3531 ARX_SOUND_PlaySFX(SND_SPELL_HEALING, &spells[i].caster_pos);
3532 }
3533
3534 spells[i].exist = true;
3535 spells[i].bDuration = true;
3536 spells[i].fManaCostPerSecond = 0.4f * spells[i].caster_level;
3537 spells[i].tolive = (duration > -1) ? duration : 3500;
3538
3539 CHeal * effect = new CHeal();
3540 effect->spellinstance = i;
3541 effect->Create();
3542 effect->SetDuration(spells[i].tolive);
3543
3544 spells[i].pSpellFx = effect;
3545 spells[i].tolive = effect->GetDuration();
3546
3547 break;
3548 }
3549
3550 case SPELL_DETECT_TRAP: {
3551
3552 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
3553 if(iCancel > -1) {
3554 spells[iCancel].tolive = 0;
3555 }
3556
3557 if(spells[i].caster == 0) {
3558 spells[i].target = spells[i].caster;
3559 if(!(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3560 ARX_SOUND_PlayInterface(SND_SPELL_DETECT_TRAP);
3561 }
3562 }
3563
3564 spells[i].snd_loop = SND_SPELL_DETECT_TRAP_LOOP;
3565 if(spells[i].caster == 0 && !(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3566 ARX_SOUND_PlaySFX(spells[i].snd_loop, &spells[i].caster_pos, 1.f,
3567 ARX_SOUND_PLAY_LOOPED);
3568 }
3569
3570 spells[i].exist = true;
3571 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
3572 spells[i].tolive = 60000;
3573 spells[i].fManaCostPerSecond = 0.4f;
3574 spells[i].bDuration = true;
3575
3576 ARX_SPELLS_AddSpellOn(spells[i].target, i);
3577
3578 break;
3579 }
3580
3581 case SPELL_ARMOR: {
3582
3583 long idx = ARX_SPELLS_GetSpellOn(entities[spells[i].target], typ);
3584 if(idx >= 0) {
3585 spells[idx].tolive = 0;
3586 }
3587
3588 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,
3589 spells[i].caster);
3590 if(iCancel > -1) {
3591 spells[iCancel].tolive = 0;
3592 }
3593
3594 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,
3595 spells[i].caster);
3596 if(iCancel > -1) {
3597 spells[iCancel].tolive = 0;
3598 }
3599
3600 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,
3601 spells[i].caster);
3602 if(iCancel > -1) {
3603 spells[iCancel].tolive = 0;
3604 }
3605
3606 if(!(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3607 ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_START, &spells[i].target_pos);
3608 }
3609
3610 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_LOOP,
3611 &spells[i].caster_pos, 1.f,
3612 ARX_SOUND_PLAY_LOOPED);
3613
3614 spells[i].exist = true;
3615 if(duration > -1) {
3616 spells[i].tolive = duration;
3617 } else {
3618 spells[i].tolive = (spells[i].caster == 0) ? 20000000 : 20000;
3619 }
3620
3621 if(spells[i].caster == 0) {
3622 spells[i].target = spells[i].caster;
3623 }
3624
3625 spells[i].bDuration = true;
3626 spells[i].fManaCostPerSecond = 0.2f * spells[i].caster_level;
3627
3628 CArmor * effect = new CArmor();
3629 effect->spellinstance = i;
3630 effect->Create(spells[i].tolive);
3631
3632 spells[i].pSpellFx = effect;
3633 spells[i].tolive = effect->GetDuration();
3634
3635 ARX_SPELLS_AddSpellOn(spells[i].target, i);
3636
3637 break;
3638 }
3639
3640 case SPELL_LOWER_ARMOR: {
3641
3642 long idx = ARX_SPELLS_GetSpellOn(entities[spells[i].target], typ);
3643 if(idx >= 0) {
3644 spells[idx].tolive = 0;
3645 }
3646
3647 if(spells[i].target < 0) {
3648 return false;
3649 }
3650
3651 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,
3652 spells[i].caster);
3653 if(iCancel > -1) {
3654 spells[iCancel].tolive = 0;
3655 }
3656
3657 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,
3658 spells[i].caster);
3659 if(iCancel > -1) {
3660 spells[iCancel].tolive = 0;
3661 }
3662
3663 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,
3664 spells[i].caster);
3665 if(iCancel > -1) {
3666 spells[iCancel].tolive = 0;
3667 }
3668
3669 if(!(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3670 ARX_SOUND_PlaySFX(SND_SPELL_LOWER_ARMOR, &spells[i].caster_pos);
3671 }
3672
3673 spells[i].exist = true;
3674 if(duration > -1) {
3675 spells[i].tolive = duration;
3676 } else {
3677 spells[i].tolive = (spells[i].caster == 0) ? 20000000 : 20000;
3678 }
3679
3680 spells[i].bDuration = true;
3681 spells[i].fManaCostPerSecond = 0.2f * spells[i].caster_level;
3682
3683 CLowerArmor * effect = new CLowerArmor();
3684 effect->spellinstance = i;
3685 effect->Create(spells[i].tolive);
3686
3687 spells[i].pSpellFx = effect;
3688 spells[i].tolive = effect->GetDuration();
3689
3690 ARX_SPELLS_AddSpellOn(spells[i].target, i);
3691
3692 break;
3693 }
3694
3695 case SPELL_HARM: {
3696
3697 if(!(spells[i].flags & SPELLCAST_FLAG_NOSOUND)) {
3698 ARX_SOUND_PlaySFX(SND_SPELL_HARM, &spells[i].caster_pos);
3699 }
3700
3701 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD,
3702 &spells[i].caster_pos, 1.f,
3703 ARX_SOUND_PLAY_LOOPED);
3704
3705 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LIFE_DRAIN,
3706 spells[i].caster);
3707 if(iCancel > -1) {
3708 spells[iCancel].tolive = 0;
3709 }
3710
3711 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_MANA_DRAIN,
3712 spells[i].caster);
3713 if(iCancel > -1) {
3714 spells[iCancel].tolive = 0;
3715 }
3716
3717 spells[i].exist = true;
3718 spells[i].tolive = (duration >-1) ? duration : 6000000;
3719 spells[i].bDuration = true;
3720 spells[i].fManaCostPerSecond = 0.4f;
3721
3722 spells[i].longinfo = ARX_DAMAGES_GetFree();
3723 if(spells[i].longinfo != -1) {
3724 damages[spells[i].longinfo].radius = 150.f;
3725 damages[spells[i].longinfo].damages = 4.f;
3726 damages[spells[i].longinfo].area = DAMAGE_FULL;
3727 damages[spells[i].longinfo].duration = 100000000;
3728 damages[spells[i].longinfo].source = spells[i].caster;
3729 damages[spells[i].longinfo].flags = DAMAGE_FLAG_DONT_HURT_SOURCE
3730 | DAMAGE_FLAG_FOLLOW_SOURCE
3731 | DAMAGE_FLAG_ADD_VISUAL_FX;
3732 damages[spells[i].longinfo].type = DAMAGE_TYPE_FAKEFIRE
3733 | DAMAGE_TYPE_MAGICAL;
3734 damages[spells[i].longinfo].exist = true;
3735 }
3736
3737 spells[i].longinfo2 = GetFreeDynLight();
3738 if(spells[i].longinfo2 != -1) {
3739 long id = spells[i].longinfo2;
3740 DynLight[id].exist = 1;
3741 DynLight[id].intensity = 2.3f;
3742 DynLight[id].fallend = 700.f;
3743 DynLight[id].fallstart = 500.f;
3744 DynLight[id].rgb = Color3f::red;
3745 DynLight[id].pos = spells[i].caster_pos;
3746 }
3747
3748 break;
3749 }
3750
3751 // level 3 spells
3752
3753 case SPELL_SPEED: {
3754
3755 spells[i].bDuration = true;
3756 spells[i].fManaCostPerSecond = 2.f;
3757
3758 ARX_SOUND_PlaySFX(SND_SPELL_SPEED_START, &spells[i].caster_pos);
3759
3760 if(spells[i].caster == 0) {
3761 spells[i].target = spells[i].caster;
3762 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_SPEED_LOOP,
3763 &spells[i].caster_pos, 1.f,
3764 ARX_SOUND_PLAY_LOOPED);
3765 }
3766
3767 spells[i].exist = true;
3768 spells[i].tolive = (spells[i].caster == 0) ? 200000000 : 20000;
3769 if(duration > -1) {
3770 spells[i].tolive = duration;
3771 }
3772
3773 CSpeed * effect = new CSpeed();
3774 effect->spellinstance = i;
3775 effect->Create(spells[i].target, spells[i].tolive);
3776
3777 spells[i].pSpellFx = effect;
3778 spells[i].tolive = effect->GetDuration();
3779
3780 ARX_SPELLS_AddSpellOn(spells[i].target, i);
3781
3782 if(spells[i].caster >= 0 && spells[i].target < long(entities.size())) {
3783 Entity * t = entities[spells[i].target];
3784 if(t) {
3785 t->speed_modif += spells[i].caster_level * 0.1f;
3786 }
3787 }
3788
3789 break;
3790 }
3791
3792 case SPELL_DISPELL_ILLUSION: {
3793
3794 ARX_SOUND_PlaySFX(SND_SPELL_DISPELL_ILLUSION);
3795 spells[i].exist = true;
3796 spells[i].tolive = 1000;
3797
3798 for(size_t n = 0; n < MAX_SPELLS; n++) {
3799
3800 if(!spells[n].exist || spells[n].target == spells[i].caster) {
3801 continue;
3802 }
3803
3804 if(spells[n].caster_level > spells[i].caster_level) {
3805 continue;
3806 }
3807
3808 if(spells[n].type == SPELL_INVISIBILITY) {
3809 if(ValidIONum(spells[n].target) && ValidIONum(spells[i].caster)) {
3810 if(closerThan(entities[spells[n].target]->pos,
3811 entities[spells[i].caster]->pos, 1000.f)) {
3812 spells[n].tolive = 0;
3813 }
3814 }
3815 }
3816 }
3817
3818 break;
3819 }
3820
3821 case SPELL_FIREBALL: {
3822
3823 spells[i].exist = true;
3824 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
3825 spells[i].tolive = 20000; // TODO probably never read
3826
3827 CFireBall * effect = new CFireBall();
3828 effect->spellinstance = i;
3829
3830 if(spells[i].caster != 0) {
3831 spells[i].hand_group = -1;
3832 }
3833
3834 Vec3f target;
3835 if(spells[i].hand_group >= 0) {
3836 target = spells[i].hand_pos;
3837 } else {
3838 target = spells[i].caster_pos;
3839 if(ValidIONum(spells[i].caster)) {
3840 Entity * c = entities[spells[i].caster];
3841 if(c->ioflags & IO_NPC) {
3842 target.x -= EEsin(radians(c->angle.b)) * 30.f;
3843 target.y -= 80.f;
3844 target.z += EEcos(radians(c->angle.b)) * 30.f;
3845 }
3846 }
3847 }
3848
3849 effect->SetDuration(6000ul);
3850
3851 float anglea = 0, angleb;
3852 if(spells[i].caster == 0) {
3853 anglea = player.angle.a, angleb = player.angle.b;
3854 } else {
3855
3856 Vec3f start = entities[spells[i].caster]->pos;
3857 if(ValidIONum(spells[i].caster)
3858 && (entities[spells[i].caster]->ioflags & IO_NPC)) {
3859 start.y -= 80.f;
3860 }
3861
3862 Entity * _io = entities[spells[i].caster];
3863 if(ValidIONum(_io->targetinfo)) {
3864 const Vec3f & end = entities[_io->targetinfo]->pos;
3865 float d = dist(Vec2f(end.x, end.z), Vec2f(start.x, start.z));
3866 anglea = degrees(getAngle(start.y, start.z, end.y, end.z + d));
3867 }
3868
3869 angleb = entities[spells[i].caster]->angle.b;
3870 }
3871
3872 effect->Create(target, MAKEANGLE(angleb), anglea, spells[i].caster_level);
3873
3874 spells[i].pSpellFx = effect;
3875 spells[i].tolive = effect->GetDuration();
3876
3877 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_LAUNCH, &spells[i].caster_pos);
3878 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_FIRE_WIND,
3879 &spells[i].caster_pos, 1.f,
3880 ARX_SOUND_PLAY_LOOPED);
3881
3882 break;
3883 }
3884
3885 case SPELL_CREATE_FOOD: {
3886
3887 ARX_SOUND_PlaySFX(SND_SPELL_CREATE_FOOD, &spells[i].caster_pos);
3888 spells[i].exist = true;
3889 spells[i].tolive = (duration > -1) ? duration : 3500;
3890
3891 if(spells[i].caster == 0 || spells[i].target == 0) {
3892 player.hunger = 100;
3893 }
3894
3895 CCreateFood * effect = new CCreateFood();
3896 effect->spellinstance = i;
3897 effect->Create();
3898 effect->SetDuration(spells[i].tolive);
3899 spells[i].pSpellFx = effect;
3900 spells[i].tolive = effect->GetDuration();
3901
3902 break;
3903 }
3904
3905 case SPELL_ICE_PROJECTILE: {
3906
3907 ARX_SOUND_PlaySFX(SND_SPELL_ICE_PROJECTILE_LAUNCH, &spells[i].caster_pos);
3908 spells[i].exist = true;
3909 spells[i].tolive = 4200;
3910
3911 CIceProjectile * effect = new CIceProjectile();
3912 effect->spellinstance = i;
3913
3914 Vec3f target;
3915 float angleb;
3916 if(spells[i].caster == 0) {
3917 target = player.pos + Vec3f(0.f, 160.f, 0.f);
3918 angleb = player.angle.b;
3919 } else {
3920 target = entities[spells[i].caster]->pos;
3921 angleb = entities[spells[i].caster]->angle.b;
3922 }
3923 angleb = MAKEANGLE(angleb);
3924 target.x -= EEsin(radians(angleb)) * 150.0f;
3925 target.z += EEcos(radians(angleb)) * 150.0f;
3926 effect->Create(target, angleb, spells[i].caster_level);
3927
3928 effect->SetDuration(spells[i].tolive);
3929 spells[i].pSpellFx = effect;
3930 spells[i].tolive = effect->GetDuration();
3931
3932 break;
3933 }
3934
3935 // level 4 spells
3936
3937 case SPELL_BLESS: {
3938
3939 if(spells[i].caster == 0) {
3940 spells[i].target = 0;
3941 }
3942
3943 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].target);
3944 if(iCancel > -1) {
3945 spells[iCancel].tolive = 0;
3946 }
3947
3948 ARX_SOUND_PlaySFX(SND_SPELL_BLESS);
3949 spells[i].exist = true;
3950 // TODO this tolive value is probably never read
3951 spells[i].tolive = (duration > -1) ? duration : 2000000;
3952 spells[i].bDuration = true;
3953 spells[i].fManaCostPerSecond = 0.5f * spells[i].caster_level * 0.6666f;
3954
3955 CBless * effect = new CBless();
3956 effect->spellinstance = i;
3957 Vec3f target = entities[spells[i].caster]->pos;
3958 effect->Create(target, MAKEANGLE(player.angle.b));
3959 effect->SetDuration(20000);
3960 spells[i].pSpellFx = effect;
3961 spells[i].tolive = effect->GetDuration();
3962
3963 ARX_SPELLS_AddSpellOn(spells[i].target, i);
3964
3965 break;
3966 }
3967
3968 case SPELL_DISPELL_FIELD: {
3969
3970 spells[i].tolive = 10;
3971
3972 long valid = 0, dispelled = 0;
3973
3974 for(size_t n = 0; n < MAX_SPELLS; n++) {
3975
3976 if(!spells[n].exist || !spells[n].pSpellFx) {
3977 continue;
3978 }
3979
3980 bool cancel = false;
3981 Vec3f pos;
3982
3983 switch(spells[n].type) {
3984
3985 case SPELL_CREATE_FIELD: {
3986 if(spells[i].caster != 0 || spells[n].caster == 0) {
3987 pos = static_cast<CCreateField *>(spells[n].pSpellFx)->eSrc;
3988 cancel = true;
3989 }
3990 break;
3991 }
3992
3993 case SPELL_FIRE_FIELD: {
3994 pos = static_cast<CFireField *>(spells[n].pSpellFx)->pos;
3995 cancel = true;
3996 break;
3997 }
3998
3999 case SPELL_ICE_FIELD: {
4000 pos = static_cast<CIceField *>(spells[n].pSpellFx)->eSrc;
4001 cancel = true;
4002 break;
4003 }
4004
4005 default: break;
4006 }
4007
4008 Entity * caster = entities[spells[i].caster];
4009 if(cancel && closerThan(pos, caster->pos, 400.f)) {
4010 valid++;
4011 if(spells[n].caster_level <= spells[i].caster_level) {
4012 spells[n].tolive = 0;
4013 dispelled++;
4014 }
4015 }
4016 }
4017
4018 if(valid > dispelled) {
4019 // Some fileds could not be dispelled
4020 ARX_SPEECH_AddSpeech(entities.player(), "player_not_skilled_enough",
4021 ANIM_TALK_NEUTRAL, ARX_SPEECH_FLAG_NOTEXT);
4022 }
4023
4024 if(dispelled > 0) {
4025 ARX_SOUND_PlaySFX(SND_SPELL_DISPELL_FIELD);
4026 } else {
4027 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &spells[i].caster_pos);
4028 }
4029
4030 break;
4031 }
4032
4033 case SPELL_FIRE_PROTECTION: {
4034
4035 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_PROTECTION);
4036
4037 long idx = ARX_SPELLS_GetSpellOn(entities[spells[i].target], typ);
4038 if(idx >= 0) {
4039 spells[idx].tolive = 0;
4040 }
4041
4042 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,
4043 spells[i].caster);
4044 if(iCancel > -1) {
4045 spells[iCancel].tolive = 0;
4046 }
4047
4048 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,
4049 spells[i].caster);
4050 if(iCancel > -1) {
4051 spells[iCancel].tolive = 0;
4052 }
4053
4054 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,
4055 spells[i].caster);
4056 if(iCancel > -1) {
4057 spells[iCancel].tolive = 0;
4058 }
4059
4060 spells[i].exist = true;
4061 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4062 if(duration > -1) {
4063 spells[i].tolive = duration;
4064 } else {
4065 spells[i].tolive = (spells[i].caster == 0) ? 2000000 : 20000;
4066 }
4067
4068 if(spells[i].caster == 0) {
4069 spells[i].target = 0;
4070 }
4071
4072 spells[i].bDuration = true;
4073 spells[i].fManaCostPerSecond = 1.f;
4074
4075 CFireProtection * effect = new CFireProtection();
4076 effect->spellinstance = i;
4077 effect->Create(spells[i].tolive);
4078 spells[i].pSpellFx = effect;
4079 spells[i].tolive = effect->GetDuration();
4080
4081 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4082
4083 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_FIRE_PROTECTION_LOOP,
4084 &spells[i].caster_pos, 1.f,
4085 ARX_SOUND_PLAY_LOOPED);
4086
4087 break;
4088 }
4089
4090 case SPELL_COLD_PROTECTION: {
4091
4092 long idx = ARX_SPELLS_GetSpellOn(entities[spells[i].target], typ);
4093 if(idx >= 0) {
4094 spells[idx].tolive = 0;
4095 }
4096
4097 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,
4098 spells[i].caster);
4099 if(iCancel > -1) {
4100 spells[iCancel].tolive = 0;
4101 }
4102
4103 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,
4104 spells[i].caster);
4105 if(iCancel > -1) {
4106 spells[iCancel].tolive = 0;
4107 }
4108
4109 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,
4110 spells[i].caster);
4111 if(iCancel > -1) {
4112 spells[iCancel].tolive = 0;
4113 }
4114
4115 ARX_SOUND_PlaySFX(SND_SPELL_COLD_PROTECTION_START);
4116
4117 spells[i].exist = true;
4118 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4119 if(duration > -1) {
4120 spells[i].tolive = duration;
4121 } else {
4122 spells[i].tolive = (spells[i].caster == 0) ? 2000000 : 20000;
4123 }
4124
4125 if(spells[i].caster == 0) {
4126 spells[i].target = 0;
4127 }
4128
4129 spells[i].bDuration = true;
4130 spells[i].fManaCostPerSecond = 1.f;
4131
4132 CColdProtection * effect = new CColdProtection();
4133 effect->spellinstance=i;
4134 effect->Create(spells[i].tolive, spells[i].target);
4135 spells[i].pSpellFx = effect;
4136 spells[i].tolive = effect->GetDuration();
4137
4138 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_COLD_PROTECTION_LOOP,
4139 &spells[i].caster_pos, 1.f,
4140 ARX_SOUND_PLAY_LOOPED);
4141
4142 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4143
4144 break;
4145 }
4146
4147 case SPELL_TELEKINESIS: {
4148
4149 spells[i].exist = true;
4150 spells[i].tolive = (duration > -1) ? duration : 6000000;
4151 spells[i].bDuration = true;
4152 spells[i].fManaCostPerSecond = 0.9f;
4153
4154 if(spells[i].caster == 0) {
4155 Project.telekinesis = 1;
4156 }
4157
4158 ARX_SOUND_PlaySFX(SND_SPELL_TELEKINESIS_START, &spells[i].caster_pos);
4159
4160 break;
4161 }
4162
4163 case SPELL_CURSE: {
4164
4165 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].target);
4166 if(iCancel > -1) {
4167 spells[iCancel].tolive = 0;
4168 }
4169
4170 ARX_SOUND_PlaySFX(SND_SPELL_CURSE, &spells[i].caster_pos);
4171
4172 spells[i].exist = true;
4173 spells[i].tolive = (duration > -1) ? duration : 2000000;
4174 spells[i].bDuration = true;
4175 spells[i].fManaCostPerSecond = 0.5f * spells[i].caster_level;
4176
4177 CCurse * effect = new CCurse();
4178 effect->spellinstance = i;
4179
4180 Vec3f target = spells[i].target_pos;
4181 if(spells[i].target == 0) {
4182 target.y -= 200.f;
4183 } else if(spells[i].target > 0 && entities[spells[i].target]) {
4184 target.y += entities[spells[i].target]->physics.cyl.height - 50.f;
4185 }
4186
4187 effect->Create(target, MAKEANGLE(player.angle.b));
4188 effect->SetDuration(spells[i].tolive);
4189 spells[i].pSpellFx = effect;
4190 spells[i].tolive = effect->GetDuration();
4191
4192 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4193
4194 break;
4195 }
4196
4197 // level 5 spells
4198
4199 case SPELL_RUNE_OF_GUARDING: {
4200
4201 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
4202 if(iCancel > -1) {
4203 spells[iCancel].tolive = 0;
4204 }
4205
4206 ARX_SOUND_PlaySFX(SND_SPELL_RUNE_OF_GUARDING);
4207 spells[i].exist = true;
4208 spells[i].tolive = (duration > -1) ? duration : 99999999;
4209
4210 CRuneOfGuarding * effect = new CRuneOfGuarding();
4211 effect->spellinstance = i;
4212 effect->Create(entities[spells[i].caster]->pos, 0);
4213 effect->SetDuration(spells[i].tolive);
4214 spells[i].pSpellFx = effect;
4215 spells[i].tolive = effect->GetDuration();
4216
4217 break;
4218 }
4219
4220 case SPELL_LEVITATE: {
4221
4222 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
4223 if(iCancel > -1) {
4224 spells[iCancel].tolive = 0;
4225 }
4226
4227 ARX_SOUND_PlaySFX(SND_SPELL_LEVITATE_START);
4228 spells[i].exist = true;
4229 spells[i].tolive = (duration > -1) ? duration : 2000000000;
4230 spells[i].bDuration = true;
4231 spells[i].fManaCostPerSecond = 1.f;
4232
4233 CLevitate * effect = new CLevitate();
4234 effect->spellinstance = i;
4235
4236 Vec3f target;
4237 if(spells[i].caster == 0 || spells[i].target == 0) {
4238 target = player.pos + Vec3f(0.f, 150.f, 0.f);
4239 spells[i].target = 0;
4240 spells[i].tolive = 200000000;
4241 player.levitate = 1;
4242 } else {
4243 target = entities[spells[i].target]->pos;
4244 }
4245
4246 effect->Create(16, 50.f, 100.f, 80.f, &target, spells[i].tolive);
4247 spells[i].pSpellFx = effect;
4248 spells[i].tolive = effect->GetDuration();
4249
4250 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4251
4252 break;
4253 }
4254
4255 case SPELL_CURE_POISON: {
4256
4257 if(spells[i].caster == 0) {
4258 spells[i].target = 0;
4259 }
4260
4261 float cure = spells[i].caster_level * 10;
4262 if(spells[i].target == 0) {
4263 player.poison -= std::min(player.poison, cure);
4264 ARX_SOUND_PlaySFX(SND_SPELL_CURE_POISON);
4265 } else if (ValidIONum(spells[i].target)) {
4266 Entity * io = entities[spells[i].target];
4267 if(io->ioflags & IO_NPC) {
4268 io->_npcdata->poisonned -= std::min(io->_npcdata->poisonned, cure);
4269 }
4270 ARX_SOUND_PlaySFX(SND_SPELL_CURE_POISON, &io->pos);
4271 }
4272
4273 spells[i].exist = true;
4274 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4275 spells[i].tolive = 3500;
4276
4277 CCurePoison * effect = new CCurePoison();
4278 effect->spellinstance = i;
4279 effect->Create();
4280 effect->SetDuration(spells[i].tolive);
4281 spells[i].pSpellFx = effect;
4282 spells[i].tolive = effect->GetDuration();
4283
4284 break;
4285 }
4286
4287 case SPELL_REPEL_UNDEAD: {
4288
4289 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_REPEL_UNDEAD, spells[i].caster);
4290 if(iCancel > -1) {
4291 spells[iCancel].tolive = 0;
4292 }
4293
4294 if(spells[i].caster == 0) {
4295 spells[i].target = 0;
4296 }
4297
4298 ARX_SOUND_PlaySFX(SND_SPELL_REPEL_UNDEAD);
4299 if(spells[i].target == 0) {
4300 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_REPEL_UNDEAD_LOOP,
4301 &spells[i].caster_pos, 1.f,
4302 ARX_SOUND_PLAY_LOOPED);
4303 }
4304
4305 spells[i].exist = true;
4306 spells[i].tolive = (duration > -1) ? duration : 20000000;
4307 spells[i].bDuration = true;
4308 spells[i].fManaCostPerSecond = 1.f;
4309
4310 CRepelUndead * effect = new CRepelUndead();
4311 effect->spellinstance = i;
4312 effect->Create(player.pos, MAKEANGLE(player.angle.b));
4313 effect->SetDuration(spells[i].tolive);
4314 spells[i].pSpellFx = effect;
4315 spells[i].tolive = effect->GetDuration();
4316
4317 break;
4318 }
4319
4320 case SPELL_POISON_PROJECTILE: {
4321
4322 ARX_SOUND_PlaySFX(SND_SPELL_POISON_PROJECTILE_LAUNCH,
4323 &spells[i].caster_pos);
4324
4325 spells[i].exist = true;
4326 spells[i].tolive = 900000000; // TODO probably never read
4327
4328 long level = std::max(long(spells[i].caster_level), 1l);
4329 CMultiPoisonProjectile * effect = new CMultiPoisonProjectile(level);
4330 effect->spellinstance = i;
4331 effect->SetDuration(8000ul);
4332 float ang;
4333 if(spells[i].caster == 0) {
4334 ang = player.angle.b;
4335 } else {
4336 ang = entities[spells[i].caster]->angle.b;
4337 }
4338 effect->Create(Vec3f::ZERO, MAKEANGLE(ang));
4339 spells[i].pSpellFx = effect;
4340 spells[i].tolive = effect->GetDuration();
4341
4342 break;
4343 }
4344
4345 // level 6 spells
4346
4347 case SPELL_RISE_DEAD: {
4348
4349 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
4350 if(iCancel > -1) {
4351 spells[iCancel].tolive = 0;
4352 }
4353
4354 float beta;
4355 Vec3f target;
4356 bool displace = true;
4357 if(spells[i].caster == 0) {
4358 target = player.basePosition();
4359 beta = MAKEANGLE(player.angle.b);
4360 } else {
4361 target = entities[spells[i].caster]->pos;
4362 beta = MAKEANGLE(entities[spells[i].caster]->angle.b);
4363 displace = (entities[spells[i].caster]->ioflags & IO_NPC) == IO_NPC;
4364 }
4365 if(displace) {
4366 target.x -= EEsin(radians(beta)) * 300.f;
4367 target.z += EEcos(radians(beta)) * 300.f;
4368 }
4369 if(!ARX_INTERACTIVE_ConvertToValidPosForIO(NULL, &target)) {
4370 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
4371 return false;
4372 }
4373
4374 ARX_SOUND_PlaySFX(SND_SPELL_RAISE_DEAD, &spells[i].caster_pos);
4375
4376 spells[i].target_pos = target;
4377 spells[i].exist = true;
4378 // TODO this tolive value is probably never read
4379 spells[i].tolive = (duration > -1) ? duration : 2000000;
4380 spells[i].bDuration = true;
4381 spells[i].fManaCostPerSecond = 1.2f;
4382 spells[i].longinfo = -1;
4383
4384 CRiseDead * effect = new CRiseDead();
4385 effect->spellinstance = i;
4386 effect->Create(target, beta);
4387 effect->SetDuration(2000, 500, 1800);
4388 effect->SetColorBorder(0.5, 0.5, 0.5);
4389 effect->SetColorRays1(0.5, 0.5, 0.5);
4390 effect->SetColorRays2(1, 0, 0);
4391
4392 if(effect->lLightId == -1) {
4393 effect->lLightId = GetFreeDynLight();
4394 }
4395 if(effect->lLightId != -1) {
4396 long id = effect->lLightId;
4397 DynLight[id].exist = 1;
4398 DynLight[id].intensity = 1.3f;
4399 DynLight[id].fallend = 450.f;
4400 DynLight[id].fallstart = 380.f;
4401 DynLight[id].rgb = Color3f::black;
4402 DynLight[id].pos = target - Vec3f(0.f, 100.f, 0.f);
4403 DynLight[id].duration = 200;
4404 DynLight[id].time_creation = (unsigned long)(arxtime);
4405 }
4406
4407 spells[i].pSpellFx = effect;
4408 spells[i].tolive = effect->GetDuration();
4409
4410 break;
4411 }
4412
4413 case SPELL_PARALYSE: {
4414
4415 ARX_SOUND_PlaySFX(SND_SPELL_PARALYSE, &spells[i].caster_pos);
4416
4417 spells[i].exist = true;
4418 spells[i].tolive = (duration > -1) ? duration : 5000;
4419
4420 float resist_magic = 0.f;
4421 if(spells[i].target == 0 && spells[i].caster_level <= player.level) {
4422 resist_magic = player.resist_magic;
4423 } else if(entities[spells[i].target]->ioflags & IO_NPC) {
4424 resist_magic = entities[spells[i].target]->_npcdata->resist_magic;
4425 }
4426 if(rnd() * 100.f < resist_magic) {
4427 float mul = max(0.5f, 1.f - (resist_magic * 0.005f));
4428 spells[i].tolive = long(spells[i].tolive * mul);
4429 }
4430
4431 entities[spells[i].target]->ioflags |= IO_FREEZESCRIPT;
4432
4433 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4434 ARX_NPC_Kill_Spell_Launch(entities[spells[i].target]);
4435
4436 break;
4437 }
4438
4439 case SPELL_CREATE_FIELD: {
4440
4441 spells[i].exist = true;
4442
4443 unsigned long start = (unsigned long)(arxtime);
4444 if(flags & SPELLCAST_FLAG_RESTORE) {
4445 start -= std::min(start, 4000ul);
4446 }
4447 spells[i].lastupdate = spells[i].timcreation = start;
4448
4449 spells[i].tolive = (duration > -1) ? duration : 800000;
4450 spells[i].bDuration = true;
4451 spells[i].fManaCostPerSecond = 1.2f;
4452
4453 Vec3f target;
4454 float beta;
4455 bool displace = false;
4456 if(spells[i].caster == 0) {
4457 target = entities.player()->pos;
4458 beta = player.angle.b;
4459 displace = true;
4460 } else {
4461 if(ValidIONum(spells[i].caster)) {
4462 Entity * io = entities[spells[i].caster];
4463 target = io->pos;
4464 beta = io->angle.b;
4465 displace = (io->ioflags & IO_NPC) == IO_NPC;
4466 } else {
4467 ARX_DEAD_CODE();
4468 }
4469 }
4470 if(displace) {
4471 target.x -= EEsin(radians(MAKEANGLE(beta))) * 250.f;
4472 target.z += EEcos(radians(MAKEANGLE(beta))) * 250.f;
4473 }
4474
4475 ARX_SOUND_PlaySFX(SND_SPELL_CREATE_FIELD, &target);
4476
4477 CCreateField * effect = new CCreateField();
4478 effect->spellinstance = i;
4479
4480 res::path cls = "graph/obj3d/interactive/fix_inter/blue_cube/blue_cube";
4481 Entity * io = AddFix(cls, -1, IO_IMMEDIATELOAD);
4482 if(io) {
4483
4484 ARX_INTERACTIVE_HideGore(io);
4485 RestoreInitialIOStatusOfIO(io);
4486 spells[i].longinfo = io->index();
4487 io->scriptload = 1;
4488 io->ioflags |= IO_NOSAVE | IO_FIELD;
4489 io->initpos = io->pos = target;
4490 SendInitScriptEvent(io);
4491
4492 effect->Create(target, 0);
4493 effect->SetDuration(spells[i].tolive);
4494 effect->lLightId = GetFreeDynLight();
4495
4496 if(effect->lLightId != -1) {
4497 long id = effect->lLightId;
4498 DynLight[id].exist = 1;
4499 DynLight[id].intensity = 0.7f + 2.3f;
4500 DynLight[id].fallend = 500.f;
4501 DynLight[id].fallstart = 400.f;
4502 DynLight[id].rgb = Color3f(0.8f, 0.0f, 1.0f);
4503 DynLight[id].pos = effect->eSrc - Vec3f(0.f, 150.f, 0.f);
4504 }
4505
4506 spells[i].pSpellFx = effect;
4507 spells[i].tolive = effect->GetDuration();
4508
4509 if(flags & SPELLCAST_FLAG_RESTORE) {
4510 effect->Update(4000);
4511 }
4512
4513 } else {
4514 spells[i].tolive = 0;
4515 }
4516
4517 break;
4518 }
4519
4520 case SPELL_DISARM_TRAP: {
4521
4522 ARX_SOUND_PlaySFX(SND_SPELL_DISARM_TRAP);
4523
4524 spells[i].exist = true;
4525 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4526 spells[i].tolive = 1;
4527
4528 CDisarmTrap * effect = new CDisarmTrap();
4529 effect->spellinstance = i;
4530
4531 effect->Create(player.pos, MAKEANGLE(player.angle.b));
4532 effect->SetDuration(spells[i].tolive);
4533 spells[i].pSpellFx = effect;
4534 spells[i].tolive = effect->GetDuration();
4535
4536 EERIE_SPHERE sphere;
4537 sphere.origin = player.pos;
4538 sphere.radius = 400.f;
4539
4540 for(size_t n = 0; n < MAX_SPELLS; n++) {
4541
4542 if(!spells[n].exist || spells[n].type != SPELL_RUNE_OF_GUARDING) {
4543 continue;
4544 }
4545
4546 if(!spells[n].pSpellFx) {
4547 continue;
4548 }
4549
4550 CSpellFx * effect = spells[n].pSpellFx;
4551 if(sphere.contains(static_cast<CRuneOfGuarding *>(effect)->eSrc)) {
4552 spells[n].caster_level -= spells[i].caster_level;
4553 if(spells[n].caster_level <= 0) {
4554 spells[n].tolive = 0;
4555 }
4556 }
4557 }
4558
4559 break;
4560 }
4561
4562 case SPELL_SLOW_DOWN: {
4563
4564 long target = spells[i].target;
4565
4566 Entity * io = entities[target];
4567 for(int il = 0; il < io->nb_spells_on; il++) {
4568 if(spells[io->spells_on[il]].type == SPELL_SLOW_DOWN) {
4569 spells[i].exist = false;
4570 return false;
4571 }
4572 }
4573
4574 ARX_SOUND_PlaySFX(SND_SPELL_SLOW_DOWN, &spells[i].caster_pos);
4575
4576 spells[i].exist = true;
4577 spells[i].tolive = (spells[i].caster == 0) ? 10000000 : 10000;
4578 if(duration > -1) {
4579 spells[i].tolive=duration;
4580 }
4581 spells[i].pSpellFx = NULL;
4582 spells[i].bDuration = true;
4583 spells[i].fManaCostPerSecond = 1.2f;
4584
4585 CSlowDown * effect = new CSlowDown();
4586 effect->spellinstance = i;
4587 effect->Create(spells[i].target_pos, MAKEANGLE(player.angle.b));
4588 effect->SetDuration(spells[i].tolive);
4589 spells[i].pSpellFx = effect;
4590 spells[i].tolive = effect->GetDuration();
4591
4592 ARX_SPELLS_AddSpellOn(target, i);
4593
4594 if(ValidIONum(target)) {
4595 entities[target]->speed_modif -= spells[i].caster_level * 0.05f;
4596 }
4597
4598 break;
4599 }
4600
4601 // level 7 spells
4602
4603 case SPELL_FLYING_EYE: {
4604
4605 if(spells[i].caster == 0) {
4606 spells[i].target = 0;
4607 }
4608
4609 if(spells[i].target != 0) {
4610 return false;
4611 }
4612
4613 ARX_SOUND_PlaySFX(SND_SPELL_EYEBALL_IN);
4614
4615 spells[i].exist = true;
4616 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4617 spells[i].tolive = 1000000;
4618 spells[i].bDuration = true;
4619 spells[i].fManaCostPerSecond = 3.2f;
4620 eyeball.exist = 1;
4621 float angleb = MAKEANGLE(player.angle.b);
4622 eyeball.pos.x = player.pos.x - EEsin(radians(angleb)) * 200.f;
4623 eyeball.pos.y = player.pos.y + 50.f;
4624 eyeball.pos.z = player.pos.z + EEcos(radians(angleb)) * 200.f;
4625 eyeball.angle = player.angle;
4626
4627 for(long n = 0; n < 12; n++) {
4628
4629 PARTICLE_DEF * pd = createParticle();
4630 if(!pd) {
4631 continue;
4632 }
4633
4634 pd->ov = eyeball.pos + randomVec(-5.f, 5.f);
4635 pd->move = randomVec(-2.f, 2.f);
4636 pd->siz = 28.f;
4637 pd->tolive = Random::get(2000, 6000);
4638 pd->scale = Vec3f::repeat(12.f);
4639 pd->tc = tc4;
4640 pd->special = FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION
4641 | DISSIPATING;
4642 pd->fparam = 0.0000001f;
4643 pd->rgb = Color3f(0.7f, 0.7f, 1.f);
4644 }
4645
4646 TRUE_PLAYER_MOUSELOOK_ON = true;
4647 SLID_START = float(arxtime);
4648 bOldLookToggle = config.input.mouseLookToggle;
4649 config.input.mouseLookToggle = true;
4650
4651 break;
4652 }
4653
4654 case SPELL_FIRE_FIELD: {
4655
4656 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
4657 if(iCancel > -1) {
4658 spells[iCancel].tolive = 0;
4659 }
4660
4661 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_FIELD_START);
4662
4663 spells[i].exist = true;
4664 spells[i].tolive = (duration > -1) ? duration : 100000;
4665 spells[i].bDuration = true;
4666 spells[i].fManaCostPerSecond = 2.8f;
4667 spells[i].longinfo2 = -1;
4668
4669 CFireField * effect = new CFireField();
4670 effect->spellinstance = i;
4671
4672 Vec3f target;
4673 float beta;
4674 float displace = false;
4675 if(spells[i].caster == 0) {
4676 target = player.basePosition();
4677 beta = player.angle.b;
4678 displace = true;
4679 } else {
4680 if(ValidIONum(spells[i].caster)) {
4681 Entity * io = entities[spells[i].caster];
4682 target = io->pos;
4683 beta = io->angle.b;
4684 displace = (io->ioflags & IO_NPC);
4685 } else {
4686 ARX_DEAD_CODE();
4687 }
4688 }
4689 if(displace) {
4690 target.x -= EEsin(radians(MAKEANGLE(beta))) * 250.f;
4691 target.z += EEcos(radians(MAKEANGLE(beta))) * 250.f;
4692 }
4693
4694 spells[i].longinfo = ARX_DAMAGES_GetFree();
4695 if(spells[i].longinfo != -1) {
4696 damages[spells[i].longinfo].radius = 150.f;
4697 damages[spells[i].longinfo].damages = 10.f;
4698 damages[spells[i].longinfo].area = DAMAGE_FULL;
4699 damages[spells[i].longinfo].duration = 100000000;
4700 damages[spells[i].longinfo].source = spells[i].caster;
4701 damages[spells[i].longinfo].flags = 0;
4702 damages[spells[i].longinfo].type = DAMAGE_TYPE_MAGICAL
4703 | DAMAGE_TYPE_FIRE
4704 | DAMAGE_TYPE_FIELD;
4705 damages[spells[i].longinfo].exist = true;
4706 damages[spells[i].longinfo].pos = target;
4707 }
4708
4709 effect->Create(200.f, &target, spells[i].tolive);
4710 spells[i].pSpellFx = effect;
4711 spells[i].tolive = effect->GetDuration();
4712
4713 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_FIRE_FIELD_LOOP,
4714 &target, 1.f,
4715 ARX_SOUND_PLAY_LOOPED);
4716
4717 break;
4718 }
4719
4720 case SPELL_ICE_FIELD: {
4721
4722 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(typ, spells[i].caster);
4723 if(iCancel > -1) {
4724 spells[iCancel].tolive = 0;
4725 }
4726
4727 ARX_SOUND_PlaySFX(SND_SPELL_ICE_FIELD);
4728
4729 spells[i].exist = true;
4730 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4731 spells[i].tolive = (duration > -1) ? duration : 100000;
4732 spells[i].bDuration = true;
4733 spells[i].fManaCostPerSecond = 2.8f;
4734 spells[i].longinfo2 =-1;
4735
4736 CIceField * effect = new CIceField();
4737 effect->spellinstance = i;
4738
4739 Vec3f target;
4740 float beta;
4741 float displace = false;
4742 if(spells[i].caster == 0) {
4743 target = player.basePosition();
4744 beta = player.angle.b;
4745 displace = true;
4746 } else {
4747 if(ValidIONum(spells[i].caster)) {
4748 Entity * io = entities[spells[i].caster];
4749 target = io->pos;
4750 beta = io->angle.b;
4751 displace = (io->ioflags & IO_NPC);
4752 } else {
4753 ARX_DEAD_CODE();
4754 }
4755 }
4756 if(displace) {
4757 target.x -= EEsin(radians(MAKEANGLE(beta))) * 250.f;
4758 target.z += EEcos(radians(MAKEANGLE(beta))) * 250.f;
4759 }
4760
4761 spells[i].longinfo = ARX_DAMAGES_GetFree();
4762 if(spells[i].longinfo != -1) {
4763 damages[spells[i].longinfo].radius = 150.f;
4764 damages[spells[i].longinfo].damages = 10.f;
4765 damages[spells[i].longinfo].area = DAMAGE_FULL;
4766 damages[spells[i].longinfo].duration = 100000000;
4767 damages[spells[i].longinfo].source = spells[i].caster;
4768 damages[spells[i].longinfo].flags = 0;
4769 damages[spells[i].longinfo].type = DAMAGE_TYPE_MAGICAL
4770 | DAMAGE_TYPE_COLD
4771 | DAMAGE_TYPE_FIELD;
4772 damages[spells[i].longinfo].exist = true;
4773 damages[spells[i].longinfo].pos = target;
4774 }
4775
4776 effect->Create(target, MAKEANGLE(player.angle.b));
4777 effect->SetDuration(spells[i].tolive);
4778 spells[i].pSpellFx = effect;
4779 spells[i].tolive = effect->GetDuration();
4780
4781 spells[i].snd_loop = ARX_SOUND_PlaySFX( SND_SPELL_ICE_FIELD_LOOP,
4782 &target, 1.f,
4783 ARX_SOUND_PLAY_LOOPED );
4784
4785 break;
4786 }
4787
4788 case SPELL_LIGHTNING_STRIKE: {
4789
4790 spells[i].exist = true;
4791
4792 CLightning * effect = new CLightning();
4793 effect->spellinstance = i;
4794 Vec3f target(0.f, 0.f, -500.f);
4795 effect->Create(Vec3f::ZERO, target, MAKEANGLE(player.angle.b));
4796 effect->SetDuration(long(500 * spells[i].caster_level));
4797 effect->lSrc = 0;
4798 spells[i].pSpellFx = effect;
4799 spells[i].tolive = effect->GetDuration();
4800
4801 ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_START, &spells[i].caster_pos);
4802
4803 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_LOOP,
4804 &spells[i].caster_pos, 1.f,
4805 ARX_SOUND_PLAY_LOOPED);
4806
4807 break;
4808 }
4809
4810 case SPELL_CONFUSE: {
4811
4812 ARX_SOUND_PlaySFX(SND_SPELL_CONFUSE);
4813
4814 spells[i].exist = true;
4815 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4816 spells[i].bDuration = true;
4817 spells[i].fManaCostPerSecond = 1.5f;
4818 if(duration > -1) {
4819 spells[i].tolive = duration;
4820 } else {
4821 // TODO what then?
4822 }
4823
4824 CConfuse * effect = new CConfuse();
4825 effect->spellinstance = i;
4826 effect->Create(player.pos, MAKEANGLE(player.angle.b));
4827 effect->SetDuration(spells[i].tolive);
4828 spells[i].pSpellFx = effect;
4829 spells[i].tolive = effect->GetDuration();
4830
4831 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4832
4833 notifyAll = false; // TODO inconsistent use of the SM_SPELLCAST event
4834
4835 break;
4836 }
4837
4838 // level 8 spells
4839
4840 case SPELL_INVISIBILITY: {
4841
4842 spells[i].exist = true;
4843 spells[i].tolive = (duration > -1) ? duration : 6000000;
4844 spells[i].bDuration = true;
4845 spells[i].fManaCostPerSecond = 3.f;
4846
4847 if(spells[i].caster == 0) {
4848 spells[i].target = 0;
4849 }
4850
4851 entities[spells[i].target]->gameFlags |= GFLAG_INVISIBILITY;
4852 entities[spells[i].target]->invisibility = 0.f;
4853
4854 ARX_SOUND_PlaySFX(SND_SPELL_INVISIBILITY_START, &spells[i].caster_pos);
4855
4856 ARX_SPELLS_AddSpellOn(spells[i].target, i);
4857
4858 break;
4859 }
4860
4861 case SPELL_MANA_DRAIN: {
4862
4863 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LIFE_DRAIN,
4864 spells[i].caster);
4865 if(iCancel > -1) {
4866 spells[iCancel].tolive = 0;
4867 }
4868
4869 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_HARM,
4870 spells[i].caster);
4871 if(iCancel > -1) {
4872 spells[iCancel].tolive = 0;
4873 }
4874
4875 spells[i].exist = true;
4876 spells[i].tolive = (duration > -1) ? duration : 6000000;
4877 spells[i].bDuration = true;
4878 spells[i].fManaCostPerSecond = 2.f;
4879
4880 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD,
4881 &spells[i].caster_pos, 1.2f,
4882 ARX_SOUND_PLAY_LOOPED);
4883
4884 spells[i].longinfo = ARX_DAMAGES_GetFree();
4885 if(spells[i].longinfo != -1) {
4886 damages[spells[i].longinfo].radius = 150.f;
4887 damages[spells[i].longinfo].damages = 8.f;
4888 damages[spells[i].longinfo].area = DAMAGE_FULL;
4889 damages[spells[i].longinfo].duration = 100000000;
4890 damages[spells[i].longinfo].source = spells[i].caster;
4891 damages[spells[i].longinfo].flags = DAMAGE_FLAG_DONT_HURT_SOURCE
4892 | DAMAGE_FLAG_FOLLOW_SOURCE
4893 | DAMAGE_FLAG_ADD_VISUAL_FX;
4894 damages[spells[i].longinfo].type = DAMAGE_TYPE_FAKEFIRE
4895 | DAMAGE_TYPE_MAGICAL
4896 | DAMAGE_TYPE_DRAIN_MANA;
4897 damages[spells[i].longinfo].exist = true;
4898 }
4899
4900 spells[i].longinfo2 = GetFreeDynLight();
4901 if(spells[i].longinfo2 != -1) {
4902 long id = spells[i].longinfo2;
4903 DynLight[id].exist = 1;
4904 DynLight[id].intensity = 2.3f;
4905 DynLight[id].fallend = 700.f;
4906 DynLight[id].fallstart = 500.f;
4907 DynLight[id].rgb = Color3f::blue;
4908 DynLight[id].pos = spells[i].caster_pos;
4909 DynLight[id].duration=900;
4910 }
4911
4912 break;
4913 }
4914
4915 case SPELL_EXPLOSION: {
4916
4917 ARX_SOUND_PlaySFX(SND_SPELL_EXPLOSION);
4918
4919 spells[i].exist = true;
4920 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
4921 spells[i].tolive = 2000;
4922
4923 Vec3f target = entities[spells[i].caster]->pos;
4924 if(spells[i].caster == 0) {
4925 target.y += 60.f;
4926 } else {
4927 target.y -= 60.f;
4928 }
4929
4930 spells[i].longinfo = ARX_DAMAGES_GetFree();
4931 if(spells[i].longinfo != -1) {
4932 damages[spells[i].longinfo].radius = 350.f;
4933 damages[spells[i].longinfo].damages = 10.f;
4934 damages[spells[i].longinfo].area = DAMAGE_AREA;
4935 damages[spells[i].longinfo].duration = spells[i].tolive;
4936 damages[spells[i].longinfo].source = spells[i].caster;
4937 damages[spells[i].longinfo].flags = DAMAGE_FLAG_DONT_HURT_SOURCE
4938 | DAMAGE_FLAG_FOLLOW_SOURCE
4939 | DAMAGE_FLAG_ADD_VISUAL_FX;
4940 damages[spells[i].longinfo].type = DAMAGE_TYPE_FAKEFIRE
4941 | DAMAGE_TYPE_MAGICAL;
4942 damages[spells[i].longinfo].exist = true;
4943 damages[spells[i].longinfo].pos = target;
4944 }
4945
4946 spells[i].longinfo2 = GetFreeDynLight();
4947 if(spells[i].longinfo2 != -1) {
4948 long id = spells[i].longinfo2;
4949 DynLight[id].exist = 1;
4950 DynLight[id].intensity = 2.3f;
4951 DynLight[id].fallend = 700.f;
4952 DynLight[id].fallstart = 500.f;
4953 DynLight[id].rgb.r = 0.1f + rnd() * (1.f / 3);
4954 DynLight[id].rgb.g = 0.1f + rnd() * (1.f / 3);
4955 DynLight[id].rgb.b = 0.8f + rnd() * (1.f / 5);
4956 DynLight[id].pos = target;
4957 DynLight[id].duration = 200;
4958 }
4959
4960 AddQuakeFX(300, 2000, 400, 1);
4961
4962 for(long i_angle = 0 ; i_angle < 360 ; i_angle += 12) {
4963 for(long j = -100 ; j < 100 ; j += 50) {
4964 float rr = radians(float(i_angle));
4965 Vec3f pos(target.x - EEsin(rr) * 360.f, target.y,
4966 target.z + EEcos(rr) * 360.f);
4967 Vec3f dir = Vec3f(pos.x - target.x, 0.f,
4968 pos.z - target.z).getNormalized() * 60.f;
4969 Color3f rgb(0.1f + rnd() * (1.f/3), 0.1f + rnd() * (1.f/3),
4970 0.8f + rnd() * (1.f/5));
4971 Vec3f posi = target + Vec3f(0.f, j * 2, 0.f);
4972 LaunchFireballBoom(&posi, 16, &dir, &rgb);
4973 }
4974 }
4975
4976 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_WIND);
4977
4978 break;
4979 }
4980
4981 case SPELL_ENCHANT_WEAPON: {
4982
4983 spells[i].exist = true;
4984 spells[i].tolive = 20;
4985
4986 notifyAll = false; // TODO inconsistent use of the SM_SPELLCAST event
4987
4988 break;
4989 }
4990
4991 case SPELL_LIFE_DRAIN: {
4992
4993 long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_HARM,
4994 spells[i].caster);
4995 if(iCancel > -1) {
4996 spells[iCancel].tolive = 0;
4997 }
4998
4999 iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_MANA_DRAIN,
5000 spells[i].caster);
5001 if(iCancel > -1) {
5002 spells[iCancel].tolive = 0;
5003 }
5004
5005 spells[i].exist = true;
5006 spells[i].tolive = (duration > -1) ? duration : 6000000;
5007 spells[i].bDuration = true;
5008 spells[i].fManaCostPerSecond = 12.f;
5009
5010 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD,
5011 &spells[i].caster_pos, 0.8f,
5012 ARX_SOUND_PLAY_LOOPED);
5013
5014 spells[i].longinfo = ARX_DAMAGES_GetFree();
5015 if(spells[i].longinfo != -1) {
5016 long id = spells[i].longinfo;
5017 damages[id].radius = 150.f;
5018 damages[id].damages = spells[i].caster_level * 0.08f;
5019 damages[id].area = DAMAGE_AREA;
5020 damages[id].duration = 100000000;
5021 damages[id].source = spells[i].caster;
5022 damages[id].flags = DAMAGE_FLAG_DONT_HURT_SOURCE
5023 | DAMAGE_FLAG_FOLLOW_SOURCE
5024 | DAMAGE_FLAG_ADD_VISUAL_FX;
5025 damages[id].type = DAMAGE_TYPE_FAKEFIRE | DAMAGE_TYPE_MAGICAL
5026 | DAMAGE_TYPE_DRAIN_LIFE;
5027 damages[id].exist = true;
5028 }
5029
5030 spells[i].longinfo2 = GetFreeDynLight();
5031 if(spells[i].longinfo2 != -1) {
5032 long id = spells[i].longinfo2;
5033 DynLight[id].exist = 1;
5034 DynLight[id].intensity = 2.3f;
5035 DynLight[id].fallend = 700.f;
5036 DynLight[id].fallstart = 500.f;
5037 DynLight[id].rgb = Color3f::red;
5038 DynLight[id].pos = spells[i].caster_pos;
5039 DynLight[id].duration = 900;
5040 }
5041
5042 break;
5043 }
5044
5045 // level 9 spells
5046
5047 case SPELL_SUMMON_CREATURE: {
5048
5049 ARX_SOUND_PlaySFX(SND_SPELL_SUMMON_CREATURE);
5050
5051 spells[i].exist = true;
5052 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5053 spells[i].bDuration = true;
5054 spells[i].fManaCostPerSecond = 1.9f;
5055 spells[i].longinfo = 0;
5056 spells[i].longinfo2 = 0;
5057 spells[i].tolive = (duration > -1) ? duration : 2000000;
5058
5059 Vec3f target;
5060 float beta;
5061 bool displace = false;
5062 if(spells[i].caster == 0) {
5063 target = player.basePosition();
5064 beta = player.angle.b;
5065 displace = true;
5066 } else {
5067 target = entities[spells[i].caster]->pos;
5068 beta = entities[spells[i].caster]->angle.b;
5069 displace = (entities[spells[i].caster]->ioflags & IO_NPC) == IO_NPC;
5070 }
5071 if(displace) {
5072 target.x -= EEsin(radians(MAKEANGLE(beta))) * 300.f;
5073 target.z += EEcos(radians(MAKEANGLE(beta))) * 300.f;
5074 }
5075
5076 if(!ARX_INTERACTIVE_ConvertToValidPosForIO(NULL, &target)) {
5077 spells[i].exist = false;
5078 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
5079 return false;
5080 }
5081
5082 spells[i].fdata = (spells[i].caster == 0 && cur_mega == 10) ? 1.f : 0.f;
5083 spells[i].target_pos = target;
5084
5085 CSummonCreature * effect = new CSummonCreature();
5086 effect->spellinstance = i;
5087 effect->Create(target, MAKEANGLE(player.angle.b));
5088 effect->SetDuration(2000, 500, 1500);
5089 effect->SetColorBorder(Color3f::red);
5090 effect->SetColorRays1(Color3f::red);
5091 effect->SetColorRays2(Color3f::yellow * .5f);
5092
5093 effect->lLightId = GetFreeDynLight();
5094 if(effect->lLightId > -1) {
5095 long id = effect->lLightId;
5096 DynLight[id].exist = 1;
5097 DynLight[id].intensity = 0.3f;
5098 DynLight[id].fallend = 500.f;
5099 DynLight[id].fallstart = 400.f;
5100 DynLight[id].rgb = Color3f::red;
5101 DynLight[id].pos = effect->eSrc;
5102 }
5103
5104 spells[i].pSpellFx = effect;
5105
5106 break;
5107 }
5108
5109 case SPELL_FAKE_SUMMON: {
5110
5111 if(spells[i].caster <= 0 || !ValidIONum(spells[i].target)) {
5112 return false;
5113 }
5114
5115 ARX_SOUND_PlaySFX(SND_SPELL_SUMMON_CREATURE);
5116
5117 spells[i].exist = true;
5118 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5119 spells[i].bDuration = true;
5120 spells[i].fManaCostPerSecond = 1.9f;
5121 spells[i].tolive = 4000;
5122
5123 Vec3f target = entities[spells[i].target]->pos;
5124 if(spells[i].target != 0) {
5125 target.y += player.baseHeight();
5126 }
5127 spells[i].target_pos = target;
5128
5129 CSummonCreature * effect = new CSummonCreature();
5130 effect->spellinstance = i;
5131 effect->Create(target, MAKEANGLE(player.angle.b));
5132 effect->SetDuration(2000, 500, 1500);
5133 effect->SetColorBorder(Color3f::red);
5134 effect->SetColorRays1(Color3f::red);
5135 effect->SetColorRays2(Color3f::yellow * .5f);
5136
5137 effect->lLightId = GetFreeDynLight();
5138
5139 if(effect->lLightId > -1) {
5140 long id = effect->lLightId;
5141 DynLight[id].exist = 1;
5142 DynLight[id].intensity = 0.3f;
5143 DynLight[id].fallend = 500.f;
5144 DynLight[id].fallstart = 400.f;
5145 DynLight[id].rgb = Color3f::red;
5146 DynLight[id].pos = effect->eSrc;
5147 }
5148
5149 spells[i].pSpellFx = effect;
5150
5151 break;
5152 }
5153
5154 case SPELL_NEGATE_MAGIC: {
5155
5156 ARX_SOUND_PlaySFX(SND_SPELL_NEGATE_MAGIC);
5157
5158 spells[i].exist = true;
5159 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5160 spells[i].bDuration = true;
5161 spells[i].fManaCostPerSecond = 2.f;
5162 spells[i].tolive = (duration > -1) ? duration : 1000000;
5163
5164 CNegateMagic * effect = new CNegateMagic();
5165 effect->spellinstance = i;
5166 effect->Create(player.pos, MAKEANGLE(player.angle.b));
5167 effect->SetDuration(spells[i].tolive);
5168 spells[i].pSpellFx = effect;
5169 spells[i].tolive = effect->GetDuration();
5170
5171 if(spells[i].caster == 0) {
5172 spells[i].target = 0;
5173 }
5174
5175 if(ValidIONum(spells[i].target)) {
5176 LaunchAntiMagicField(i);
5177 }
5178
5179 break;
5180 }
5181
5182 case SPELL_INCINERATE: {
5183
5184 Entity * tio = entities[spells[i].target];
5185 if((tio->ioflags & IO_NPC) && tio->_npcdata->life <= 0.f) {
5186 return false;
5187 }
5188
5189 ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE);
5190
5191 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE_LOOP,
5192 &spells[i].caster_pos, 1.f,
5193 ARX_SOUND_PLAY_LOOPED);
5194
5195 spells[i].exist = true;
5196 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5197 spells[i].tolive = 20000;
5198
5199 tio->sfx_flag |= SFX_TYPE_YLSIDE_DEATH | SFX_TYPE_INCINERATE;
5200 tio->sfx_time = (unsigned long)(arxtime);
5201
5202 ARX_SPELLS_AddSpellOn(spells[i].target, i);
5203
5204 break;
5205 }
5206
5207 case SPELL_MASS_PARALYSE: {
5208
5209 ARX_SOUND_PlaySFX(SND_SPELL_MASS_PARALYSE);
5210
5211 spells[i].exist = true;
5212 spells[i].tolive = (duration > -1) ? duration : 10000;
5213 spells[i].longinfo2 = 0;
5214
5215 for(size_t ii = 0; ii < entities.size(); ii++) {
5216
5217 Entity * tio = entities[ii];
5218 if(long(ii) == spells[i].caster || !tio || !(tio->ioflags & IO_NPC)) {
5219 continue;
5220 }
5221
5222 if(tio->show != SHOW_FLAG_IN_SCENE) {
5223 continue;
5224 }
5225
5226 if(tio->ioflags & IO_FREEZESCRIPT) {
5227 continue;
5228 }
5229
5230 if(fartherThan(tio->pos, entities[spells[i].caster]->pos, 500.f)) {
5231 continue;
5232 }
5233
5234 tio->ioflags |= IO_FREEZESCRIPT;
5235
5236 ARX_NPC_Kill_Spell_Launch(tio);
5237 ARX_SPELLS_AddSpellOn(ii, i);
5238
5239 spells[i].longinfo2++;
5240 spells[i].misc = realloc(spells[i].misc,
5241 sizeof(long) * spells[i].longinfo2);
5242 long * ptr = (long *)spells[i].misc;
5243 ptr[spells[i].longinfo2 - 1] = ii;
5244 }
5245
5246 break;
5247 }
5248
5249 // level 10 spells
5250
5251 case SPELL_MASS_LIGHTNING_STRIKE: {
5252
5253 for(size_t ii = 0; ii < MAX_SPELLS; ii++) {
5254 if(spells[ii].exist && spells[ii].type == typ) {
5255 if(spells[ii].longinfo != -1) {
5256 DynLight[spells[ii].longinfo].exist = 0;
5257 }
5258 spells[ii].longinfo = -1;
5259 spells[ii].tolive = 0;
5260 }
5261 }
5262
5263 spells[i].exist = true;
5264 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5265 spells[i].tolive = 5000; // TODO probably never read
5266 spells[i].siz = 0;
5267
5268 spells[i].longinfo = GetFreeDynLight();
5269 if(spells[i].longinfo != -1) {
5270 long id = spells[i].longinfo;
5271 DynLight[id].exist = 1;
5272 DynLight[id].intensity = 1.8f;
5273 DynLight[id].fallend = 450.f;
5274 DynLight[id].fallstart = 380.f;
5275 DynLight[id].rgb = Color3f(1.f, 0.75f, 0.75f);
5276 DynLight[id].pos = spells[i].vsource;
5277 }
5278
5279 long count = std::max(long(spells[i].caster_level), 1l);
5280 CMassLightning * effect = new CMassLightning(count);
5281 effect->spellinstance=i;
5282
5283 Vec3f target;
5284 float beta;
5285 if(spells[i].caster == 0) {
5286 target = player.pos + Vec3f(0.f, 150.f, 0.f);
5287 beta = player.angle.b;
5288 } else {
5289 Entity * io = entities[spells[i].caster];
5290 target = io->pos + Vec3f(0.f, -20.f, 0.f);
5291 beta = io->angle.b;
5292 }
5293 target.x -= EEsin(radians(MAKEANGLE(beta))) * 500.f;
5294 target.z += EEcos(radians(MAKEANGLE(beta))) * 500.f;
5295
5296 effect->SetDuration(long(500 * spells[i].caster_level));
5297 effect->Create(target, MAKEANGLE(player.angle.b));
5298 spells[i].pSpellFx = effect;
5299 spells[i].tolive = effect->GetDuration();
5300
5301 ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_START);
5302 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_LOOP, &target,
5303 1.f, ARX_SOUND_PLAY_LOOPED);
5304
5305 // Draws White Flash on Screen
5306 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
5307 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
5308 EERIEDrawBitmap(0.f, 0.f, float(DANAESIZX), float(DANAESIZY), 0.00009f,
5309 NULL, Color::white);
5310 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
5311
5312 break;
5313 }
5314
5315 case SPELL_CONTROL_TARGET: {
5316
5317 if(!ValidIONum(spells[i].target)) {
5318 return false;
5319 }
5320
5321 long tcount = 0;
5322 for(size_t ii = 1; ii < entities.size(); ii++) {
5323
5324 Entity * ioo = entities[ii];
5325 if(!ioo || !(ioo->ioflags & IO_NPC)) {
5326 continue;
5327 }
5328
5329 if(ioo->_npcdata->life <= 0.f || ioo->show != SHOW_FLAG_IN_SCENE) {
5330 continue;
5331 }
5332
5333 if(ioo->groups.find("demon") == ioo->groups.end()) {
5334 continue;
5335 }
5336
5337 if(closerThan(ioo->pos, spells[i].caster_pos, 900.f)) {
5338 tcount++;
5339 std::ostringstream oss;
5340 oss << entities[spells[i].target]->long_name();
5341 oss << ' ' << long(spells[i].caster_level);
5342 SendIOScriptEvent(ioo, SM_NULL, oss.str(), "npc_control");
5343 }
5344 }
5345 if(tcount == 0) {
5346 return false;
5347 }
5348
5349 ARX_SOUND_PlaySFX(SND_SPELL_CONTROL_TARGET);
5350
5351 spells[i].exist = true;
5352 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5353 spells[i].tolive = 1000;
5354
5355 CControlTarget * effect = new CControlTarget();
5356 effect->spellinstance = i;
5357 effect->Create(player.pos, MAKEANGLE(player.angle.b));
5358 effect->SetDuration(spells[i].tolive);
5359 spells[i].pSpellFx = effect;
5360
5361 break;
5362 }
5363
5364 case SPELL_FREEZE_TIME: {
5365
5366 ARX_SOUND_PlaySFX(SND_SPELL_FREEZETIME);
5367
5368 float max_slowdown = std::max(0.f, GLOBAL_SLOWDOWN - 0.01f);
5369 spells[i].siz = clamp(spells[i].caster_level * 0.08f, 0.f, max_slowdown);
5370 GLOBAL_SLOWDOWN -= spells[i].siz;
5371
5372 spells[i].exist = true;
5373 spells[i].tolive = (duration > -1) ? duration : 200000;
5374 spells[i].bDuration = true;
5375 spells[i].fManaCostPerSecond = 30.f * spells[i].siz;
5376 spells[i].longinfo = (long)arxtime.get_updated();
5377
5378 break;
5379 }
5380
5381 case SPELL_MASS_INCINERATE: {
5382
5383 ARX_SOUND_PlaySFX(SND_SPELL_MASS_INCINERATE);
5384
5385 spells[i].exist = true;
5386 spells[i].lastupdate = spells[i].timcreation = (unsigned long)(arxtime);
5387 spells[i].tolive = 20000;
5388
5389 long nb_targets=0;
5390 for(size_t ii = 0; ii < entities.size(); ii++) {
5391
5392 Entity * tio = entities[ii];
5393 if(long(ii) == spells[i].caster || !tio || !(tio->ioflags & IO_NPC)) {
5394 continue;
5395 }
5396
5397 if(tio->_npcdata->life <= 0.f || tio->show != SHOW_FLAG_IN_SCENE) {
5398 continue;
5399 }
5400
5401 if(fartherThan(tio->pos, entities[spells[i].caster]->pos, 500.f)) {
5402 continue;
5403 }
5404
5405 tio->sfx_flag |= SFX_TYPE_YLSIDE_DEATH | SFX_TYPE_INCINERATE;
5406 tio->sfx_time = (unsigned long)(arxtime);
5407 nb_targets++;
5408 ARX_SPELLS_AddSpellOn(ii, i);
5409 }
5410
5411 if(nb_targets) {
5412 spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE_LOOP,
5413 &spells[i].caster_pos, 1.f,
5414 ARX_SOUND_PLAY_LOOPED);
5415 } else {
5416 spells[i].snd_loop = -1;
5417 }
5418
5419 break;
5420 }
5421
5422 case SPELL_TELEPORT: {
5423
5424 spells[i].exist = true;
5425 spells[i].tolive = 7000;
5426
5427 ARX_SOUND_PlaySFX(SND_SPELL_TELEPORT, &spells[i].caster_pos);
5428
5429 if(spells[i].caster == 0) {
5430 LASTTELEPORT = 0.f;
5431 }
5432
5433 break;
5434 }
5435 }
5436
5437 if(notifyAll) {
5438 SPELLCAST_Notify(i);
5439 } else {
5440 SPELLCAST_NotifyOnlyTarget(i);
5441 }
5442
5443 return true;
5444 }
5445
5446 // Used for specific Spell-End FX
ARX_SPELLS_Kill(long i)5447 void ARX_SPELLS_Kill(long i) {
5448
5449 static TextureContainer * tc4=TextureContainer::Load("graph/particles/smoke");
5450
5451 if (!spells[i].exist) return;
5452
5453 spells[i].exist=false;
5454
5455 // All Levels - Kill Light
5456 if (spells[i].pSpellFx && spells[i].pSpellFx->lLightId != -1)
5457 {
5458 DynLight[spells[i].pSpellFx->lLightId].duration = 500;
5459 DynLight[spells[i].pSpellFx->lLightId].time_creation = (unsigned long)(arxtime);
5460 }
5461
5462 switch(spells[i].type) {
5463
5464 case SPELL_FIREBALL: {
5465
5466 if(spells[i].longinfo != -1) {
5467 DynLight[spells[i].longinfo].duration = 500;
5468 DynLight[spells[i].longinfo].time_creation = (unsigned long)(arxtime);
5469 }
5470 spells[i].longinfo = -1;
5471
5472 break;
5473 }
5474
5475 case SPELL_LIGHTNING_STRIKE: {
5476
5477 if(spells[i].longinfo != -1) {
5478 DynLight[spells[i].longinfo].duration = 200;
5479 DynLight[spells[i].longinfo].time_creation = (unsigned long)(arxtime);
5480 }
5481 spells[i].longinfo = -1;
5482
5483 ARX_SOUND_Stop(spells[i].snd_loop);
5484 ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_END);
5485
5486 break;
5487 }
5488
5489 case SPELL_MASS_LIGHTNING_STRIKE: {
5490
5491 if(spells[i].longinfo != -1) {
5492 DynLight[spells[i].longinfo].duration = 200;
5493 DynLight[spells[i].longinfo].time_creation = (unsigned long)(arxtime);
5494 }
5495 spells[i].longinfo = -1;
5496
5497 ARX_SOUND_Stop(spells[i].snd_loop);
5498 ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_END);
5499
5500 break;
5501 }
5502
5503 case SPELL_REPEL_UNDEAD: {
5504
5505 if(spells[i].longinfo != -1) {
5506 DynLight[spells[i].longinfo].duration = 200;
5507 DynLight[spells[i].longinfo].time_creation = (unsigned long)(arxtime);
5508 }
5509 spells[i].longinfo = -1;
5510
5511 ARX_SOUND_Stop(spells[i].snd_loop);
5512
5513 break;
5514 }
5515
5516 case SPELL_HARM:
5517 case SPELL_LIFE_DRAIN:
5518 case SPELL_MANA_DRAIN: {
5519
5520 if(spells[i].longinfo != -1) {
5521 damages[spells[i].longinfo].exist = false;
5522 }
5523
5524 if(spells[i].longinfo2 != -1) {
5525 DynLight[spells[i].longinfo2].time_creation = (unsigned long)(arxtime);
5526 DynLight[spells[i].longinfo2].duration = 600;
5527 }
5528
5529 ARX_SOUND_Stop(spells[i].snd_loop);
5530 break;
5531 }
5532
5533 case SPELL_FLYING_EYE : {
5534
5535 ARX_SOUND_PlaySFX(SND_SPELL_EYEBALL_OUT);
5536 eyeball.exist = -100;
5537
5538 for(long n = 0; n < 12; n++) {
5539
5540 PARTICLE_DEF * pd = createParticle();
5541 if(!pd) {
5542 break;
5543 }
5544
5545 pd->ov = eyeball.pos + randomVec(-5.f, 5.f);
5546 pd->move = randomVec(-2.f, 2.f);
5547 pd->siz = 28.f;
5548 pd->tolive = Random::get(2000, 6000);
5549 pd->scale = Vec3f::repeat(12.f);
5550 pd->timcreation = spells[i].lastupdate;
5551 pd->tc = tc4;
5552 pd->special = FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
5553 pd->fparam = 0.0000001f;
5554 pd->rgb = Color3f(0.7f, 0.7f, 1.f);
5555 }
5556
5557 config.input.mouseLookToggle = bOldLookToggle;
5558
5559 break;
5560 }
5561
5562 // Level 06
5563
5564 case SPELL_PARALYSE: {
5565 ARX_SOUND_PlaySFX(SND_SPELL_PARALYSE_END);
5566 break;
5567 }
5568
5569 // Level 7
5570
5571 case SPELL_FIRE_FIELD: {
5572 ARX_SOUND_Stop(spells[i].snd_loop);
5573 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_FIELD_END);
5574 break;
5575 }
5576
5577 case SPELL_ICE_FIELD: {
5578 ARX_SOUND_Stop(spells[i].snd_loop);
5579 ARX_SOUND_PlaySFX(SND_SPELL_ICE_FIELD_END);
5580 break;
5581 }
5582
5583 case SPELL_MASS_PARALYSE: {
5584 ARX_SOUND_PlaySFX(SND_SPELL_PARALYSE_END);
5585 break;
5586 }
5587
5588 case SPELL_SUMMON_CREATURE: {
5589
5590 if(spells[i].pSpellFx->lLightId > -1) {
5591 long id = spells[i].pSpellFx->lLightId;
5592 DynLight[id].exist = 0;
5593 spells[i].pSpellFx->lLightId=-1;
5594 }
5595
5596 if(ValidIONum(spells[i].longinfo2) && spells[i].longinfo2 != 0) {
5597
5598 if(entities[spells[i].longinfo2]->scriptload
5599 && (entities[spells[i].longinfo2]->ioflags & IO_NOSAVE)) {
5600
5601 AddRandomSmoke(entities[spells[i].longinfo2], 100);
5602 Vec3f posi = entities[spells[i].longinfo2]->pos;
5603 posi.y -= 100.f;
5604 MakeCoolFx(&posi);
5605
5606 long nn = GetFreeDynLight();
5607 if(nn >= 0) {
5608 DynLight[nn].exist = 1;
5609 DynLight[nn].intensity = 0.7f + 2.f * rnd();
5610 DynLight[nn].fallend = 600.f;
5611 DynLight[nn].fallstart = 400.f;
5612 DynLight[nn].rgb = Color3f(1.0f, 0.8f, 0.0f);
5613 DynLight[nn].pos = posi;
5614 DynLight[nn].duration = 600;
5615 }
5616
5617 ARX_INTERACTIVE_DestroyIO(entities[spells[i].longinfo2]);
5618 }
5619 }
5620
5621 spells[i].longinfo2 = 0;
5622 break;
5623 }
5624
5625 case SPELL_FAKE_SUMMON: {
5626
5627 if(spells[i].pSpellFx->lLightId > -1) {
5628 long id = spells[i].pSpellFx->lLightId;
5629 DynLight[id].exist = 0;
5630 spells[i].pSpellFx->lLightId = -1;
5631 }
5632
5633 break;
5634 }
5635
5636 default: break;
5637 }
5638
5639 delete spells[i].pSpellFx, spells[i].pSpellFx = NULL;
5640 }
5641
5642
5643 EYEBALL_DEF eyeball;
5644
5645 Anglef cabalangle;
5646 Vec3f cabalpos;
5647 Vec3f cabalscale;
5648 Color3f cabalcolor;
5649
5650
ARX_SPELLS_ApplyFireProtection(Entity * io,float damages)5651 float ARX_SPELLS_ApplyFireProtection(Entity * io,float damages)
5652 {
5653 if (io)
5654 {
5655 long idx=ARX_SPELLS_GetSpellOn(io,SPELL_FIRE_PROTECTION);
5656
5657 if (idx>=0)
5658 {
5659 float modif=1.f-((float)spells[idx].caster_level*( 1.0f / 10 ));
5660
5661 if (modif>1.f) modif=1.f;
5662 else if (modif<0.f) modif=0.f;
5663
5664 damages*=modif;
5665 }
5666
5667 if (io->ioflags & IO_NPC)
5668 {
5669 damages-=io->_npcdata->resist_fire*( 1.0f / 100 )*damages;
5670
5671 if (damages<0.f) damages=0.f;
5672 }
5673 }
5674
5675 return damages;
5676 }
ARX_SPELLS_ApplyColdProtection(Entity * io,float damages)5677 float ARX_SPELLS_ApplyColdProtection(Entity * io,float damages)
5678 {
5679 long idx=ARX_SPELLS_GetSpellOn(io,SPELL_COLD_PROTECTION);
5680
5681 if (idx>=0)
5682 {
5683 float modif=1.f-((float)spells[idx].caster_level*( 1.0f / 10 ));
5684
5685 if (modif>1.f) modif=1.f;
5686 else if (modif<0.f) modif=0.f;
5687
5688 damages*=modif;
5689 }
5690
5691 return damages;
5692 }
5693
5694 //*************************************************************************************
5695 // Updates all currently working spells.
5696 //*************************************************************************************
ARX_SPELLS_Update()5697 void ARX_SPELLS_Update()
5698 {
5699
5700 unsigned long tim;
5701 long framediff,framediff3;
5702
5703 ucFlick++;
5704
5705 tim = (unsigned long)(arxtime);
5706
5707 for(size_t i = 0; i < MAX_SPELLS; i++) {
5708
5709 if (!GLOBAL_MAGIC_MODE) spells[i].tolive=0;
5710
5711 if (spells[i].exist)
5712 {
5713 if (spells[i].bDuration && !CanPayMana(i,spells[i].fManaCostPerSecond * (float)FrameDiff * ( 1.0f / 1000 ), false))
5714 ARX_SPELLS_Fizzle(i);
5715
5716 framediff=spells[i].timcreation+spells[i].tolive-tim;
5717 framediff3=tim-spells[i].lastupdate;
5718
5719 if (framediff<0)
5720 {
5721 SPELLEND_Notify(i);
5722
5723 switch (spells[i].type)
5724 {
5725 //----------------------------------------------------------------------------
5726 case SPELL_TELEPORT:
5727 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &spells[i].caster_pos);
5728 break;
5729 //----------------------------------------------------------------------------
5730
5731 //****************************************************************************
5732 // LEVEL 1 SPELLS -----------------------------------------------------------------------------
5733 //----------------------------------------------------------------------------
5734 case SPELL_MAGIC_SIGHT:
5735
5736 if (spells[i].caster==0)
5737 {
5738 Project.improve=0;
5739 ARX_SOUND_Stop(spells[i].snd_loop);
5740 }
5741
5742 ARX_SOUND_PlaySFX(SND_SPELL_VISION_START, &spells[i].caster_pos);
5743 break;
5744 //-----------------------------------------------------------------------------
5745 case SPELL_MAGIC_MISSILE:
5746 {
5747 if (spells[i].longinfo!=-1)
5748 DynLight[spells[i].longinfo].exist=0;
5749 }
5750 break;
5751 //----------------------------------------------------------------------------
5752 case SPELL_IGNIT:
5753 {
5754 CIgnit *pIgnit;
5755 pIgnit=(CIgnit *)spells[i].pSpellFx;
5756 pIgnit->Action(1);
5757 }
5758 break;
5759 //----------------------------------------------------------------------------
5760 case SPELL_DOUSE:
5761 {
5762 CDoze *pDoze;
5763 pDoze=(CDoze *)spells[i].pSpellFx;
5764 pDoze->Action(0);
5765 }
5766 break;
5767 //----------------------------------------------------------------------------------
5768 //**********************************************************************************
5769 // LEVEL 2 -------------------------------------------------------------------------
5770 //----------------------------------------------------------------------------------
5771 case SPELL_DETECT_TRAP:
5772
5773 if (spells[i].caster==0)
5774 {
5775 ARX_SOUND_Stop(spells[i].snd_loop);
5776 }
5777
5778 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5779
5780 break;
5781 //----------------------------------------------------------------------------
5782 case SPELL_ARMOR:
5783 {
5784 ARX_SOUND_Stop(spells[i].snd_loop);
5785 ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_END, &spells[i].caster_pos);
5786 Entity * io=entities[spells[i].target];
5787
5788 if (spells[i].longinfo)
5789 {
5790 io->halo.flags&=~HALO_ACTIVE;
5791 ARX_HALO_SetToNative(io);
5792 }
5793
5794 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5795 }
5796 break;
5797 //----------------------------------------------------------------------------
5798 case SPELL_LOWER_ARMOR:
5799 {
5800 Entity * io=entities[spells[i].target];
5801
5802 if (spells[i].longinfo)
5803 {
5804 io->halo.flags&=~HALO_ACTIVE;
5805 ARX_HALO_SetToNative(io);
5806 }
5807
5808 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5809 }
5810 break;
5811 //----------------------------------------------------------------------------------
5812 //**********************************************************************************
5813 // LEVEL 3 -------------------------------------------------------------------------
5814 //----------------------------------------------------------------------------------
5815 case SPELL_SPEED:
5816
5817 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5818
5819 if(spells[i].target >= 0 && spells[i].target < long(entities.size()))
5820 {
5821 if (entities[spells[i].target])
5822 entities[spells[i].target]->speed_modif-=spells[i].caster_level*( 1.0f / 10 );
5823 }
5824
5825 if (spells[i].caster == 0) ARX_SOUND_Stop(spells[i].snd_loop);
5826
5827 ARX_SOUND_PlaySFX(SND_SPELL_SPEED_END, &spells[i].caster_pos);
5828 break;
5829 //----------------------------------------------------------------------------------
5830 case SPELL_FIREBALL:
5831 ARX_SOUND_Stop(spells[i].snd_loop);
5832 break;
5833 //----------------------------------------------------------------------------------
5834 //**********************************************************************************
5835 // LEVEL 4 -------------------------------------------------------------------------
5836 //----------------------------------------------------------------------------------
5837 case SPELL_BLESS:
5838 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5839 break;
5840 case SPELL_CURSE:
5841 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5842 break;
5843 //----------------------------------------------------------------------------
5844 case SPELL_TELEKINESIS:
5845
5846 if (spells[i].caster==0)
5847 Project.telekinesis=0;
5848
5849 ARX_SOUND_PlaySFX(SND_SPELL_TELEKINESIS_END, &spells[i].caster_pos);
5850 break;
5851 case SPELL_FIRE_PROTECTION:
5852 ARX_SOUND_Stop(spells[i].snd_loop);
5853 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_PROTECTION_END);
5854 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);;
5855
5856 if (ValidIONum(spells[i].target))
5857 ARX_HALO_SetToNative(entities[spells[i].target]);
5858
5859 break;
5860 case SPELL_COLD_PROTECTION:
5861 ARX_SOUND_Stop(spells[i].snd_loop);
5862 ARX_SOUND_PlaySFX(SND_SPELL_COLD_PROTECTION_END);
5863 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);;
5864
5865 if (ValidIONum(spells[i].target))
5866 ARX_HALO_SetToNative(entities[spells[i].target]);
5867
5868 break;
5869 //----------------------------------------------------------------------------------
5870 //**********************************************************************************
5871 // LEVEL 5 -------------------------------------------------------------------------
5872 //----------------------------------------------------------------------------------
5873 //----------------------------------------------------------------------------
5874 case SPELL_LEVITATE:
5875 {
5876
5877 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5878
5879 if (spells[i].target==0)
5880 player.levitate=0;
5881 }
5882 break;
5883 //----------------------------------------------------------------------------------
5884 //**********************************************************************************
5885 // LEVEL 6 SPELLS ------------------------------------------------------------------
5886 //----------------------------------------------------------------------------------
5887 case SPELL_PARALYSE:
5888 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5889 entities[spells[i].target]->ioflags&=~IO_FREEZESCRIPT;
5890 break;
5891 //----------------------------------------------------------------------------------
5892 case SPELL_RISE_DEAD:
5893 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
5894
5895 if (ValidIONum(spells[i].longinfo) && spells[i].longinfo!=0)
5896 {
5897 if ( (entities[spells[i].longinfo]->scriptload)
5898 && (entities[spells[i].longinfo]->ioflags & IO_NOSAVE) )
5899 {
5900 AddRandomSmoke(entities[spells[i].longinfo],100);
5901 Vec3f posi = entities[spells[i].longinfo]->pos;
5902 posi.y-=100.f;
5903 MakeCoolFx(&posi);
5904 long nn=GetFreeDynLight();
5905
5906 if(nn >= 0) {
5907 DynLight[nn].exist=1;
5908 DynLight[nn].intensity = 0.7f + 2.f*rnd();
5909 DynLight[nn].fallend = 600.f;
5910 DynLight[nn].fallstart = 400.f;
5911 DynLight[nn].rgb = Color3f(1.0f, 0.8f, 0.f);
5912 DynLight[nn].pos = posi;
5913 DynLight[nn].duration = 600;
5914 }
5915
5916 ARX_INTERACTIVE_DestroyIO(entities[spells[i].longinfo]);
5917 }
5918 }
5919
5920 break;
5921 case SPELL_CREATE_FIELD:
5922 CCreateField * pCreateField;
5923 pCreateField = (CCreateField *) spells[i].pSpellFx;
5924
5925 if ( (pCreateField)
5926 && (pCreateField->lLightId != -1) )
5927 {
5928 long id=pCreateField->lLightId;
5929 DynLight[id].duration=800;
5930 }
5931
5932 if(ValidIONum(spells[i].longinfo)) {
5933 delete entities[spells[i].longinfo];
5934 }
5935
5936 break;
5937 //----------------------------------------------------------------------------
5938 case SPELL_SLOW_DOWN:
5939 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5940
5941 if(spells[i].target >= 0 && spells[i].target < long(entities.size()))
5942 {
5943 if (entities[spells[i].target])
5944 entities[spells[i].target]->speed_modif+=spells[i].caster_level*( 1.0f / 20 );
5945 }
5946
5947 break;
5948 //----------------------------------------------------------------------------------
5949 //**********************************************************************************
5950 // LEVEL 7 -------------------------------------------------------------------------
5951 //----------------------------------------------------------------------------------
5952 case SPELL_ICE_FIELD:
5953
5954 if (spells[i].longinfo!=-1)
5955 damages[spells[i].longinfo].exist=false;
5956
5957 break;
5958 case SPELL_FIRE_FIELD:
5959
5960 if (spells[i].longinfo!=-1)
5961 damages[spells[i].longinfo].exist=false;
5962
5963 break;
5964 //----------------------------------------------------------------------------
5965 case SPELL_LIGHTNING_STRIKE:
5966 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
5967 break;
5968 //----------------------------------------------------------------------------
5969 case SPELL_FLYING_EYE:
5970 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &entities[spells[i].caster]->pos);
5971 break;
5972 case SPELL_CONFUSE:
5973 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5974 break;
5975 //----------------------------------------------------------------------------------
5976 //**********************************************************************************
5977 // LEVEL 8 -------------------------------------------------------------------------
5978 //----------------------------------------------------------------------------------
5979 case SPELL_EXPLOSION:
5980 break;
5981 //----------------------------------------------------------------------------
5982 case SPELL_INVISIBILITY:
5983 {
5984 if (ValidIONum(spells[i].target))
5985 {
5986 entities[spells[i].target]->gameFlags&=~GFLAG_INVISIBILITY;
5987 ARX_SOUND_PlaySFX(SND_SPELL_INVISIBILITY_END, &entities[spells[i].target]->pos);
5988 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
5989 }
5990 }
5991 break;
5992 //----------------------------------------------------------------------------------
5993 //**********************************************************************************
5994 // LEVEL 9 -------------------------------------------------------------------------
5995 //----------------------------------------------------------------------------------
5996 //----------------------------------------------------------------------------
5997 case SPELL_MASS_PARALYSE:
5998 {
5999 long * ptr=(long *)spells[i].misc;
6000
6001 for (long in=0;in<spells[i].longinfo2;in++)
6002 {
6003
6004 if (ValidIONum(ptr[in]))
6005 {
6006 ARX_SPELLS_RemoveSpellOn(ptr[in],i);
6007 entities[ptr[in]]->ioflags&=~IO_FREEZESCRIPT;
6008 }
6009 }
6010
6011 if (ptr) free(spells[i].misc);
6012
6013 spells[i].misc=NULL;
6014 }
6015 break;
6016 case SPELL_SUMMON_CREATURE :
6017 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
6018
6019 if (spells[i].pSpellFx->lLightId > -1)
6020 {
6021 long id = spells[i].pSpellFx->lLightId;
6022 DynLight[id].exist = 0;
6023 spells[i].pSpellFx->lLightId=-1;
6024 }
6025
6026 // need to killio
6027 break;
6028 case SPELL_FAKE_SUMMON :
6029 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
6030
6031 if (spells[i].pSpellFx->lLightId > -1)
6032 {
6033 long id = spells[i].pSpellFx->lLightId;
6034 DynLight[id].exist = 0;
6035 spells[i].pSpellFx->lLightId=-1;
6036 }
6037
6038 break;
6039 case SPELL_INCINERATE:
6040 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
6041 ARX_SOUND_Stop(spells[i].snd_loop);
6042 ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE_END, &spells[i].caster_pos);
6043 break;
6044 //----------------------------------------------------------------------------------
6045 //**********************************************************************************
6046 // LEVEL 10 ------------------------------------------------------------------------
6047 //----------------------------------------------------------------------------------
6048 case SPELL_FREEZE_TIME: {
6049 GLOBAL_SLOWDOWN += spells[i].siz;
6050 ARX_SOUND_PlaySFX(SND_SPELL_TELEKINESIS_END, &spells[i].caster_pos);
6051 break;
6052 }
6053 case SPELL_MASS_INCINERATE:
6054 ARX_SPELLS_RemoveMultiSpellOn(i);
6055 ARX_SOUND_Stop(spells[i].snd_loop);
6056 ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE_END, &spells[i].caster_pos);
6057 break;
6058 default: break;
6059 //----------------------------------------------------------------------------------
6060 }
6061
6062 ARX_SPELLS_Kill(i);
6063 continue;
6064 }
6065
6066 //******************************************************************************************
6067 //******************************************************************************************
6068 //******************************************************************************************
6069 //******************************************************************************************
6070 //******************************************************************************************
6071 //******************************************************************************************
6072
6073 if (spells[i].exist)
6074 switch (spells[i].type)
6075 {
6076 case SPELL_DISPELL_FIELD: break;
6077 case SPELL_NONE: break;
6078 //**************************************************************************************
6079 // LEVEL 1 -----------------------------------------------------------------------------
6080 case SPELL_MAGIC_MISSILE:
6081 {
6082 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6083
6084 if (pCSpellFX)
6085 {
6086 CMultiMagicMissile *pMMM = (CMultiMagicMissile *) pCSpellFX;
6087 pMMM->CheckCollision();
6088
6089 // Update
6090 pCSpellFX->Update(FrameDiff);
6091
6092 if (pCSpellFX->Render()==-1)
6093 spells[i].tolive=0;
6094 }
6095 }
6096 break;
6097 //---------------------------------------------------------------------------------------
6098 case SPELL_IGNIT:
6099 case SPELL_DOUSE:
6100 {
6101 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6102
6103 if (pCSpellFX)
6104 {
6105 pCSpellFX->Update(FrameDiff);
6106 }
6107 }
6108 break;
6109 //---------------------------------------------------------------------------------------
6110 case SPELL_ACTIVATE_PORTAL:
6111 {
6112 }
6113 break;
6114 //---------------------------------------------------------------------------------------
6115 //***************************************************************************************
6116 // LEVEL 2 -----------------------------------------------------------------------------
6117 case SPELL_HEAL: // guérit les ennemis collés
6118 {
6119 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6120
6121 if (pCSpellFX)
6122 {
6123 pCSpellFX->Update(FrameDiff);
6124 pCSpellFX->Render();
6125 }
6126
6127 CHeal * ch=(CHeal *)pCSpellFX;
6128
6129 if (ch)
6130 for(size_t ii = 0; ii < entities.size(); ii++) {
6131 if ((entities[ii])
6132 && (entities[ii]->show==SHOW_FLAG_IN_SCENE)
6133 && (entities[ii]->gameFlags & GFLAG_ISINTREATZONE)
6134 && (entities[ii]->ioflags & IO_NPC)
6135 && (entities[ii]->_npcdata->life>0.f)
6136 )
6137 {
6138 float dist;
6139
6140 if (long(ii) == spells[i].caster) dist=0;
6141 else dist=fdist(ch->eSrc, entities[ii]->pos);
6142
6143 if (dist<300.f)
6144 {
6145 float gain=((rnd()*1.6f+0.8f)*spells[i].caster_level)*(300.f-dist)*( 1.0f / 300 )*framedelay*( 1.0f / 1000 );
6146
6147 if (ii==0)
6148 {
6149 if (!BLOCK_PLAYER_CONTROLS)
6150 player.life=std::min(player.life+gain,player.Full_maxlife);
6151 }
6152 else entities[ii]->_npcdata->life=std::min(entities[ii]->_npcdata->life+gain,entities[ii]->_npcdata->maxlife);
6153 }
6154 }
6155 }
6156 }
6157 break;
6158 //------------------------------------------------------------------------------------
6159 case SPELL_DETECT_TRAP:
6160 {
6161 if (spells[i].caster == 0)
6162 {
6163 ARX_SOUND_RefreshPosition(spells[i].snd_loop);
6164 }
6165
6166 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6167
6168 if (pCSpellFX)
6169 {
6170 pCSpellFX->Update(FrameDiff);
6171 pCSpellFX->Render();
6172 }
6173 }
6174 break;
6175 //------------------------------------------------------------------------------------
6176 case SPELL_ARMOR:
6177 case SPELL_LOWER_ARMOR:
6178 {
6179 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6180
6181 if (pCSpellFX)
6182 {
6183 pCSpellFX->Update(FrameDiff);
6184 pCSpellFX->Render();
6185 }
6186 }
6187 break;
6188 //--------------------------------------------------------------------------------------
6189 case SPELL_HARM:
6190 {
6191 if ( (cabal!=NULL) )
6192 {
6193 float refpos;
6194 float scaley;
6195
6196 if (spells[i].caster==0) scaley=90.f;
6197 else scaley=EEfabs(entities[spells[i].caster]->physics.cyl.height*( 1.0f / 2 ))+30.f;
6198
6199
6200 float mov=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ))*scaley;
6201
6202 if (spells[i].caster==0)
6203 {
6204 cabalpos.x = player.pos.x;
6205 cabalpos.y=player.pos.y+60.f-mov;
6206 cabalpos.z = player.pos.z;
6207 refpos=player.pos.y+60.f;
6208 }
6209 else
6210 {
6211 cabalpos.x = entities[spells[i].caster]->pos.x;
6212 cabalpos.y=entities[spells[i].caster]->pos.y-scaley-mov;
6213 cabalpos.z = entities[spells[i].caster]->pos.z;
6214 refpos=entities[spells[i].caster]->pos.y-scaley;
6215 }
6216
6217 float Es=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ) + radians(scaley));
6218
6219 if (spells[i].longinfo2!=-1)
6220 {
6221 DynLight[spells[i].longinfo2].pos.x = cabalpos.x;
6222 DynLight[spells[i].longinfo2].pos.y = refpos;
6223 DynLight[spells[i].longinfo2].pos.z = cabalpos.z;
6224 DynLight[spells[i].longinfo2].rgb.r=rnd()*0.2f+0.8f;
6225 DynLight[spells[i].longinfo2].rgb.g=rnd()*0.2f+0.6f;
6226 DynLight[spells[i].longinfo2].fallstart=Es*1.5f;
6227 }
6228
6229 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
6230 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
6231 GRenderer->SetRenderState(Renderer::DepthWrite, false);
6232 cabalangle.b=spells[i].fdata+(float)FrameDiff*0.1f;
6233 spells[i].fdata=cabalangle.b;
6234
6235 cabalangle.g = 0.f;
6236 cabalcolor.r = 0.8f;
6237 cabalcolor.g = 0.4f;
6238 cabalcolor.b = 0.f;
6239 cabalscale = Vec3f::repeat(Es);
6240 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
6241 mov=EEsin((float)(arxtime.get_frame_time()-30.f)*( 1.0f / 800 ))*scaley;
6242 cabalpos.y = refpos - mov;
6243 cabalcolor.b = 0.f;
6244 cabalcolor.g = 3.f;
6245 cabalcolor.r = 0.5f;
6246 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
6247 mov=EEsin((float)(arxtime.get_frame_time()-60.f)*( 1.0f / 800 ))*scaley;
6248 cabalpos.y=refpos-mov;
6249 cabalcolor.b = 0.f;
6250 cabalcolor.g = 0.1f;
6251 cabalcolor.r = 0.25f;
6252 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
6253 mov=EEsin((float)(arxtime.get_frame_time()-120.f)*( 1.0f / 800 ))*scaley;
6254 cabalpos.y=refpos-mov;
6255 cabalcolor.b = 0.f;
6256 cabalcolor.g = 0.1f;
6257 cabalcolor.r = 0.15f;
6258 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
6259 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
6260 GRenderer->SetRenderState(Renderer::DepthWrite, true);
6261 }
6262 }
6263 break;
6264 //--------------------------------------------------------------------------------------
6265 //**************************************************************************************
6266 // LEVEL 3 SPELLS -----------------------------------------------------------------------------
6267 case SPELL_FIREBALL:
6268 {
6269 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6270
6271 if (pCSpellFX)
6272 {
6273 CFireBall *pCF = (CFireBall*) pCSpellFX;
6274
6275 if (spells[i].longinfo==-1) spells[i].longinfo=GetFreeDynLight();
6276
6277 if (spells[i].longinfo!=-1)
6278 {
6279 long id=spells[i].longinfo;
6280 EERIE_LIGHT * el=&DynLight[id];
6281 el->exist=1;
6282 el->pos = pCF->eCurPos;
6283 el->intensity = 2.2f;
6284 el->fallend = 500.f;
6285 el->fallstart = 400.f;
6286 el->rgb.r = 1.0f-rnd()*0.3f;
6287 el->rgb.g = 0.6f-rnd()*0.1f;
6288 el->rgb.b = 0.3f-rnd()*0.1f;
6289 }
6290
6291 EERIE_SPHERE sphere;
6292 sphere.origin = pCF->eCurPos;
6293 sphere.radius=std::max(spells[i].caster_level*2.f,12.f);
6294 #define MIN_TIME_FIREBALL 2000
6295
6296 if (pCF->pPSFire.iParticleNbMax)
6297 {
6298 if (pCF->ulCurrentTime > MIN_TIME_FIREBALL)
6299 {
6300 SpawnFireballTail(&pCF->eCurPos,&pCF->eMove,(float)spells[i].caster_level,0);
6301 }
6302 else
6303 {
6304 if (rnd()<0.9f)
6305 {
6306 Vec3f move = Vec3f::ZERO;
6307 float dd=(float)pCF->ulCurrentTime / (float)MIN_TIME_FIREBALL*10;
6308
6309 if (dd>spells[i].caster_level) dd=spells[i].caster_level;
6310
6311 if (dd<1) dd=1;
6312
6313 SpawnFireballTail(&pCF->eCurPos,&move,(float)dd,1);
6314 }
6315 }
6316 }
6317
6318 if (pCF->bExplo == false)
6319 if (CheckAnythingInSphere(&sphere,spells[i].caster,CAS_NO_SAME_GROUP))
6320 {
6321 ARX_BOOMS_Add(&pCF->eCurPos);
6322 LaunchFireballBoom(&pCF->eCurPos,(float)spells[i].caster_level);
6323 pCF->pPSFire.iParticleNbMax = 0;
6324 pCF->pPSFire2.iParticleNbMax = 0;
6325 pCF->eMove *= 0.5f;
6326 pCF->pPSSmoke.iParticleNbMax = 0;
6327 pCF->SetTTL(1500);
6328 pCF->bExplo = true;
6329
6330 DoSphericDamage(&pCF->eCurPos,3.f*spells[i].caster_level,30.f*spells[i].caster_level,DAMAGE_AREA,DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL,spells[i].caster);
6331 spells[i].tolive=0;
6332 ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &sphere.origin);
6333 ARX_NPC_SpawnAudibleSound(&sphere.origin, entities[spells[i].caster]);
6334 }
6335
6336 pCSpellFX->Update(FrameDiff);
6337 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &pCF->eCurPos);
6338 }
6339 }
6340 break;
6341 //-----------------------------------------------------------------------------------------
6342 case SPELL_SPEED:
6343
6344 if (spells[i].pSpellFx)
6345 {
6346 spells[i].pSpellFx->Update(FrameDiff);
6347 spells[i].pSpellFx->Render();
6348
6349 if (spells[i].caster == 0) ARX_SOUND_RefreshPosition(spells[i].snd_loop);
6350 }
6351
6352 break;
6353 //-----------------------------------------------------------------------------------------
6354 case SPELL_CREATE_FOOD:
6355 case SPELL_ICE_PROJECTILE:
6356 case SPELL_DISPELL_ILLUSION:
6357
6358 if (spells[i].pSpellFx)
6359 {
6360 spells[i].pSpellFx->Update(FrameDiff);
6361 spells[i].pSpellFx->Render();
6362 }
6363
6364 break;
6365 //-----------------------------------------------------------------------------------------
6366 //*****************************************************************************************
6367 // LEVEL 4 SPELLS -----------------------------------------------------------------------------
6368 case SPELL_BLESS:
6369 {
6370 if (spells[i].pSpellFx)
6371 {
6372 CBless * pBless=(CBless *)spells[i].pSpellFx;
6373
6374 if (pBless)
6375 {
6376 if (ValidIONum(spells[i].target))
6377 {
6378 pBless->eSrc = entities[spells[i].target]->pos;
6379 Anglef angle = Anglef::ZERO;
6380
6381 if (spells[i].target==0)
6382 angle.b=player.angle.b;
6383 else
6384 angle.b=entities[spells[i].target]->angle.b;
6385
6386 pBless->Set_Angle(angle);
6387 }
6388 }
6389
6390 spells[i].pSpellFx->Update(FrameDiff);
6391 spells[i].pSpellFx->Render();
6392 }
6393 }
6394 break;
6395 //-----------------------------------------------------------------------------------------
6396 case SPELL_CURSE:
6397
6398 if (spells[i].pSpellFx)
6399 {
6400 CCurse * curse=(CCurse *)spells[i].pSpellFx;
6401 Vec3f target = Vec3f::ZERO;
6402
6403 if ((spells[i].target>=0) && (entities[spells[i].target]))
6404 {
6405 target = entities[spells[i].target]->pos;
6406
6407 if (spells[i].target==0) target.y-=200.f;
6408 else target.y+=entities[spells[i].target]->physics.cyl.height-30.f;
6409 }
6410
6411 curse->Update(checked_range_cast<unsigned long>(FrameDiff));
6412
6413 curse->eTarget = target;
6414 curse->Render();
6415 GRenderer->SetCulling(Renderer::CullNone);
6416 }
6417
6418 break;
6419 //-----------------------------------------------------------------------------------------
6420 case SPELL_FIRE_PROTECTION:
6421 spells[i].pSpellFx->Update(FrameDiff);
6422 spells[i].pSpellFx->Render();
6423 break;
6424 //-----------------------------------------------------------------------------------------
6425 case SPELL_COLD_PROTECTION:
6426 spells[i].pSpellFx->Update(FrameDiff);
6427 spells[i].pSpellFx->Render();
6428 break;
6429 //-----------------------------------------------------------------------------------------
6430 //*****************************************************************************************
6431 // LEVEL 5 SPELLS -----------------------------------------------------------------------------
6432 //-----------------------------------------------------------------------------------------
6433 case SPELL_CURE_POISON:
6434 {
6435 if (spells[i].pSpellFx)
6436 {
6437 spells[i].pSpellFx->Update(FrameDiff);
6438 spells[i].pSpellFx->Render();
6439 }
6440 }
6441 break;
6442 //-----------------------------------------------------------------------------------------
6443 case SPELL_RUNE_OF_GUARDING:
6444 {
6445 if (spells[i].pSpellFx)
6446 {
6447 spells[i].pSpellFx->Update(FrameDiff);
6448 spells[i].pSpellFx->Render();
6449 CRuneOfGuarding * pCRG=(CRuneOfGuarding *)spells[i].pSpellFx;
6450
6451 if (pCRG)
6452 {
6453 EERIE_SPHERE sphere;
6454 sphere.origin = pCRG->eSrc;
6455 sphere.radius=std::max(spells[i].caster_level*15.f,50.f);
6456
6457 if (CheckAnythingInSphere(&sphere,spells[i].caster,CAS_NO_SAME_GROUP | CAS_NO_BACKGROUND_COL | CAS_NO_ITEM_COL| CAS_NO_FIX_COL | CAS_NO_DEAD_COL))
6458 {
6459 ARX_BOOMS_Add(&pCRG->eSrc);
6460 LaunchFireballBoom(&pCRG->eSrc,(float)spells[i].caster_level);
6461 DoSphericDamage(&pCRG->eSrc,4.f*spells[i].caster_level,30.f*spells[i].caster_level,DAMAGE_AREA,DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL,spells[i].caster);
6462 spells[i].tolive=0;
6463 ARX_SOUND_PlaySFX(SND_SPELL_RUNE_OF_GUARDING_END, &sphere.origin);
6464 }
6465 }
6466 }
6467 }
6468 break;
6469 case SPELL_REPEL_UNDEAD:
6470 {
6471 if (spells[i].pSpellFx)
6472 {
6473 spells[i].pSpellFx->Update(FrameDiff);
6474 spells[i].pSpellFx->Render();
6475
6476 if (spells[i].target == 0)
6477 ARX_SOUND_RefreshPosition(spells[i].snd_loop);
6478 }
6479 }
6480 break;
6481 //-----------------------------------------------------------------------------------------
6482 case SPELL_POISON_PROJECTILE:
6483
6484 if (spells[i].pSpellFx)
6485 {
6486 spells[i].pSpellFx->Update(FrameDiff);
6487 spells[i].pSpellFx->Render();
6488 }
6489
6490 break;
6491 //-----------------------------------------------------------------------------------------
6492 case SPELL_LEVITATE:
6493 {
6494 CLevitate *pLevitate=(CLevitate *)spells[i].pSpellFx;
6495 Vec3f target;
6496
6497 if (spells[i].target==0)
6498 {
6499 target.x=player.pos.x;
6500 target.y=player.pos.y+150.f;
6501 target.z=player.pos.z;
6502 player.levitate=1;
6503 }
6504 else
6505 {
6506 target.x=entities[spells[i].caster]->pos.x;
6507 target.y = entities[spells[i].caster]->pos.y;
6508 target.z=entities[spells[i].caster]->pos.z;
6509 }
6510
6511 pLevitate->ChangePos(&target);
6512
6513 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6514
6515 if (pCSpellFX)
6516 {
6517 pCSpellFX->Update(FrameDiff);
6518 pCSpellFX->Render();
6519 GRenderer->SetCulling(Renderer::CullNone);
6520 }
6521 }
6522 break;
6523 //-----------------------------------------------------------------------------------------
6524 //*****************************************************************************************
6525 // LEVEL 6 SPELLS -----------------------------------------------------------------------------
6526 case SPELL_RISE_DEAD:
6527 {
6528 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6529
6530 if (pCSpellFX)
6531 {
6532 if (spells[i].longinfo==-2)
6533 {
6534 pCSpellFX->lLightId=-1;
6535 break;
6536 }
6537
6538 spells[i].tolive+=200;
6539
6540 pCSpellFX->Update(FrameDiff);
6541 pCSpellFX->Render();
6542
6543 if (pCSpellFX->lLightId > -1)
6544 {
6545 long id=pCSpellFX->lLightId;
6546 DynLight[id].exist=1;
6547 DynLight[id].intensity = 0.7f + 2.3f;
6548 DynLight[id].fallend = 500.f;
6549 DynLight[id].fallstart = 400.f;
6550 DynLight[id].rgb.r = 0.8f;
6551 DynLight[id].rgb.g = 0.2f;
6552 DynLight[id].rgb.b = 0.2f;
6553 DynLight[id].duration=800;
6554 DynLight[id].time_creation = (unsigned long)(arxtime);
6555 }
6556
6557 unsigned long tim=pCSpellFX->getCurrentTime();
6558
6559 if ((tim>3000) && (spells[i].longinfo==-1))
6560 {
6561 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
6562 CRiseDead *prise;
6563 prise= (CRiseDead *)spells[i].pSpellFx;
6564
6565 if (prise)
6566 {
6567 EERIE_CYLINDER phys;
6568 phys.height=-200;
6569 phys.radius=50;
6570 phys.origin=spells[i].target_pos;
6571
6572 float anything = CheckAnythingInCylinder(&phys, NULL, CFLAG_JUST_TEST);
6573
6574 if(EEfabs(anything) < 30) {
6575
6576 const char * cls =
6577 "graph/obj3d/interactive/npc/undead_base/undead_base";
6578 Entity * io = AddNPC(cls, -1, IO_IMMEDIATELOAD);
6579
6580 if(io) {
6581
6582 ARX_INTERACTIVE_HideGore(io);
6583 RestoreInitialIOStatusOfIO(io);
6584
6585 long lSpellsCaster = spells[i].caster;
6586 io->summoner = checked_range_cast<short>(lSpellsCaster);
6587
6588 io->ioflags|=IO_NOSAVE;
6589 spells[i].longinfo = io->index();
6590 io->scriptload=1;
6591
6592 ARX_INTERACTIVE_Teleport(io,&phys.origin,0);
6593 SendInitScriptEvent(io);
6594
6595 if(ValidIONum(spells[i].caster)) {
6596 EVENT_SENDER = entities[spells[i].caster];
6597 } else {
6598 EVENT_SENDER = NULL;
6599 }
6600
6601 SendIOScriptEvent(io,SM_SUMMONED);
6602
6603 Vec3f pos;
6604 {
6605 pos.x=prise->eSrc.x+rnd()*100.f-50.f;
6606 pos.y=prise->eSrc.y+100+rnd()*100.f-50.f;
6607 pos.z=prise->eSrc.z+rnd()*100.f-50.f;
6608 MakeCoolFx(&pos);
6609 }
6610 }
6611
6612 pCSpellFX->lLightId=-1;
6613 }
6614 else
6615 {
6616 ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
6617 spells[i].longinfo=-2;
6618 spells[i].tolive=0;
6619 }
6620 }
6621
6622 } else if(!arxtime.is_paused() && tim < 4000) {
6623 if(rnd() > 0.95f) {
6624 CRiseDead *pRD = (CRiseDead*)pCSpellFX;
6625 Vec3f pos = pRD->eSrc;
6626 MakeCoolFx(&pos);
6627 }
6628 }
6629
6630 }
6631 }
6632 break;
6633
6634 //-----------------------------------------------------------------------------------------
6635 case SPELL_SLOW_DOWN:
6636 {
6637 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6638
6639 if (pCSpellFX)
6640 {
6641 pCSpellFX->Update(FrameDiff);
6642 pCSpellFX->Render();
6643 }
6644 }
6645 break;
6646 case SPELL_DISARM_TRAP:
6647 {
6648 }
6649 break;
6650 case SPELL_PARALYSE:
6651 break;
6652 case SPELL_CREATE_FIELD:
6653 {
6654 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6655
6656 if (pCSpellFX)
6657 {
6658 if (ValidIONum(spells[i].longinfo))
6659 {
6660 Entity * io=entities[spells[i].longinfo];
6661 CCreateField * ccf=(CCreateField *)pCSpellFX;
6662 io->pos = ccf->eSrc;
6663
6664 if (IsAnyNPCInPlatform(io))
6665 {
6666 spells[i].tolive=0;
6667 }
6668
6669 pCSpellFX->Update(FrameDiff);
6670
6671 if (VisibleSphere(ccf->eSrc.x,ccf->eSrc.y-120.f,ccf->eSrc.z,400.f))
6672 pCSpellFX->Render();
6673 }
6674 }
6675 }
6676 break;
6677
6678 //-----------------------------------------------------------------------------------------
6679 //*****************************************************************************************
6680 // LEVEL 7 SPELLS -----------------------------------------------------------------------------
6681 case SPELL_CONFUSE:
6682 {
6683 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6684
6685 if (pCSpellFX)
6686 {
6687 pCSpellFX->Update(FrameDiff);
6688 pCSpellFX->Render();
6689 }
6690 }
6691 break;
6692
6693 case SPELL_FIRE_FIELD: {
6694
6695 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6696
6697 if (pCSpellFX)
6698 {
6699 CFireField *pf = (CFireField *) pCSpellFX;
6700 pCSpellFX->Update(FrameDiff);
6701
6702 if (spells[i].longinfo2==-1)
6703 spells[i].longinfo2=GetFreeDynLight();
6704
6705 if (spells[i].longinfo2!=-1)
6706 {
6707 EERIE_LIGHT * el=&DynLight[spells[i].longinfo2];
6708
6709 el->pos.x = pf->pos.x;
6710 el->pos.y = pf->pos.y-120.f;
6711 el->pos.z = pf->pos.z;
6712 el->exist = 1;
6713 el->intensity = 4.6f;
6714 el->fallstart = 150.f+rnd()*30.f;
6715 el->fallend = 290.f+rnd()*30.f;
6716 el->rgb.r = 1.f-rnd()*( 1.0f / 10 );
6717 el->rgb.g = 0.8f;
6718 el->rgb.b = 0.6f;
6719 el->duration = 600;
6720 el->extras=0;
6721 }
6722
6723 if(VisibleSphere(pf->pos.x, pf->pos.y - 120.f, pf->pos.z, 350.f)) {
6724
6725 pCSpellFX->Render();
6726 float fDiff = FrameDiff / 8.f;
6727 int nTime = checked_range_cast<int>(fDiff);
6728
6729 for(long nn=0;nn<=nTime+1;nn++) {
6730
6731 PARTICLE_DEF * pd = createParticle();
6732 if(!pd) {
6733 break;
6734 }
6735
6736 float t = rnd() * (PI * 2.f) - PI;
6737 float ts = EEsin(t);
6738 float tc = EEcos(t);
6739 pd->ov = pf->pos + Vec3f(120.f * ts, 15.f * ts, 120.f * tc) * randomVec();
6740 pd->move = Vec3f(2.f - 4.f * rnd(), 1.f - 8.f * rnd(), 2.f - 4.f * rnd());
6741 pd->siz = 7.f;
6742 pd->tolive = Random::get(500, 1500);
6743 pd->tc = fire2;
6744 pd->special = ROTATING | MODULATE_ROTATION | FIRE_TO_SMOKE;
6745 pd->fparam = 0.1f - rnd() * 0.2f;
6746 pd->scale = Vec3f::repeat(-8.f);
6747
6748 PARTICLE_DEF * pd2 = createParticle();
6749 if(!pd2) {
6750 break;
6751 }
6752
6753 *pd2 = *pd;
6754 pd2->delay = Random::get(60, 210);
6755 }
6756
6757 }
6758 }
6759
6760 break;
6761 }
6762
6763 case SPELL_ICE_FIELD:
6764 {
6765 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6766
6767 if (pCSpellFX)
6768 {
6769 pCSpellFX->Update(FrameDiff);
6770
6771 CIceField *pf = (CIceField *) pCSpellFX;
6772
6773 if (spells[i].longinfo2==-1)
6774 spells[i].longinfo2=GetFreeDynLight();
6775
6776 if (spells[i].longinfo2!=-1)
6777 {
6778 EERIE_LIGHT * el=&DynLight[spells[i].longinfo2];
6779
6780 el->pos.x = pf->eSrc.x;
6781 el->pos.y = pf->eSrc.y-120.f;
6782 el->pos.z = pf->eSrc.z;
6783 el->exist = 1;
6784 el->intensity = 4.6f;
6785 el->fallstart = 150.f+rnd()*30.f;
6786 el->fallend = 290.f+rnd()*30.f;
6787 el->rgb.r = 0.76f;
6788 el->rgb.g = 0.76f;
6789 el->rgb.b = 1.0f-rnd()*( 1.0f / 10 );
6790 el->duration = 600;
6791 el->extras=0;
6792 }
6793
6794
6795
6796 if (VisibleSphere(pf->eSrc.x,pf->eSrc.y-120.f,pf->eSrc.z,350.f))
6797 {
6798 pCSpellFX->Render();
6799 }
6800 }
6801
6802 GRenderer->SetCulling(Renderer::CullNone);
6803 }
6804 break;
6805 //-----------------------------------------------------------------------------------------
6806 case SPELL_LIGHTNING_STRIKE:
6807 {
6808 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6809
6810 if (pCSpellFX)
6811 {
6812 pCSpellFX->Update(FrameDiff);
6813 pCSpellFX->Render();
6814 }
6815 }
6816 break;
6817 //-----------------------------------------------------------------------------------------
6818 //*****************************************************************************************
6819 // LEVEL 8 SPELLS -----------------------------------------------------------------------------
6820 case SPELL_ENCHANT_WEAPON:
6821 {
6822 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6823
6824 if (pCSpellFX)
6825 {
6826 pCSpellFX->Update(FrameDiff);
6827 pCSpellFX->Render();
6828 }
6829 }
6830 case SPELL_EXPLOSION:
6831 {
6832 if (spells[i].longinfo2 == -1)
6833 spells[i].longinfo2=GetFreeDynLight();
6834
6835 if (spells[i].longinfo2 != -1)
6836 {
6837 long id = spells[i].longinfo2;
6838 DynLight[id].rgb.r = 0.1f+rnd()*( 1.0f / 3 );;
6839 DynLight[id].rgb.g = 0.1f+rnd()*( 1.0f / 3 );;
6840 DynLight[id].rgb.b = 0.8f+rnd()*( 1.0f / 5 );;
6841 DynLight[id].duration=200;
6842
6843 float rr,r2;
6844 Vec3f pos;
6845
6846 float choice = rnd();
6847 if(choice > .8f) {
6848 long lvl = Random::get(9, 13);
6849 rr=radians(rnd()*360.f);
6850 r2=radians(rnd()*360.f);
6851 pos.x=DynLight[id].pos.x-EEsin(rr)*260;
6852 pos.y=DynLight[id].pos.y-EEsin(r2)*260;
6853 pos.z=DynLight[id].pos.z+EEcos(rr)*260;
6854 Color3f rgb(0.1f + rnd()*(1.f/3), 0.1f + rnd()*(1.0f/3), 0.8f + rnd()*(1.0f/5));
6855 LaunchFireballBoom(&pos, static_cast<float>(lvl), NULL, &rgb);
6856 } else if(choice > .6f) {
6857 rr=radians(rnd()*360.f);
6858 r2=radians(rnd()*360.f);
6859 pos.x=DynLight[id].pos.x-EEsin(rr)*260;
6860 pos.y=DynLight[id].pos.y-EEsin(r2)*260;
6861 pos.z=DynLight[id].pos.z+EEcos(rr)*260;
6862 MakeCoolFx(&pos);
6863 } else if(choice > 0.4f) {
6864 rr=radians(rnd()*360.f);
6865 r2=radians(rnd()*360.f);
6866 pos.x=DynLight[id].pos.x-EEsin(rr)*160;
6867 pos.y=DynLight[id].pos.y-EEsin(r2)*160;
6868 pos.z=DynLight[id].pos.z+EEcos(rr)*160;
6869 ARX_PARTICLES_Add_Smoke(&pos, 2, 20); // flag 1 = randomize pos
6870 }
6871 }
6872 }
6873 break;
6874 //-----------------------------------------------------------------------------------------
6875 //*****************************************************************************************
6876 // LEVEL 9 SPELLS -------------------------------------------------------------------------
6877 //-----------------------------------------------------------------------------------------
6878 case SPELL_SUMMON_CREATURE:
6879 {
6880
6881
6882 if (!arxtime.is_paused())
6883 {
6884
6885 if (float(arxtime)-(float)spells[i].timcreation<=4000)
6886 {
6887 if (rnd()>0.7f)
6888 {
6889 CSummonCreature * pSummon = (CSummonCreature *)spells[i].pSpellFx;
6890 if(pSummon) {
6891 Vec3f pos = pSummon->eSrc;
6892 MakeCoolFx(&pos);
6893 }
6894 }
6895
6896 CSpellFx *pCSpellFX = spells[i].pSpellFx;
6897
6898 if (pCSpellFX)
6899 {
6900 pCSpellFX->Update(FrameDiff);
6901 pCSpellFX->Render();
6902 }
6903
6904 spells[i].longinfo=1;
6905 spells[i].longinfo2=-1;
6906 }
6907 else if (spells[i].longinfo)
6908 {
6909 if (spells[i].pSpellFx->lLightId > -1)
6910 {
6911 long id = spells[i].pSpellFx->lLightId;
6912 DynLight[id].exist = 0;
6913 spells[i].pSpellFx->lLightId=-1;
6914 }
6915
6916 spells[i].longinfo=0;
6917 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &spells[i].caster_pos);
6918 CSummonCreature *pSummon;
6919 pSummon= (CSummonCreature *)spells[i].pSpellFx;
6920
6921 if (pSummon)
6922 {
6923 EERIE_CYLINDER phys;
6924 phys.height=-200;
6925 phys.radius=50;
6926 phys.origin=spells[i].target_pos;
6927 float anything = CheckAnythingInCylinder(&phys, NULL, CFLAG_JUST_TEST);
6928
6929 if (EEfabs(anything)<30)
6930 {
6931
6932 long tokeep;
6933 res::path cls;
6934 if(spells[i].fdata == 1.f) {
6935 if(rnd() > 0.5) {
6936 tokeep = -1;
6937 cls = "graph/obj3d/interactive/npc/wrat_base/wrat_base";
6938 } else {
6939 tokeep = 0;
6940 cls = "graph/obj3d/interactive/npc/y_mx/y_mx";
6941 }
6942 } else if(rnd() > 0.997f || (sp_max && rnd() > 0.8f)
6943 || (cur_mr >= 3 && rnd() > 0.3f)) {
6944 tokeep = 0;
6945 cls = "graph/obj3d/interactive/npc/y_mx/y_mx";
6946 } else if(rnd() > 0.997f || (cur_rf >= 3 && rnd() > 0.8f)
6947 || (cur_mr >= 3 && rnd() > 0.3f)) {
6948 tokeep = -1;
6949 cls = "graph/obj3d/interactive/npc/wrat_base/wrat_base";
6950 } else if(spells[i].caster_level >= 9) {
6951 tokeep = 1;
6952 cls = "graph/obj3d/interactive/npc/demon/demon";
6953 } else if(rnd() > 0.98f) {
6954 tokeep = -1;
6955 cls = "graph/obj3d/interactive/npc/wrat_base/wrat_base";
6956 } else {
6957 tokeep = 0;
6958 cls = "graph/obj3d/interactive/npc/chicken_base/chicken_base";
6959 }
6960
6961 Entity * io = AddNPC(cls, -1, IO_IMMEDIATELOAD);
6962 if(!io) {
6963 cls = "graph/obj3d/interactive/npc/chicken_base/chicken_base";
6964 tokeep = 0;
6965 io = AddNPC(cls, -1, IO_IMMEDIATELOAD);
6966 }
6967
6968 if(io) {
6969
6970 RestoreInitialIOStatusOfIO(io);
6971
6972 long lSpellsCaster = spells[i].caster ;
6973 io->summoner = checked_range_cast<short>(lSpellsCaster);
6974
6975
6976 io->scriptload = 1;
6977
6978 if(tokeep == 1) {
6979 io->ioflags |= IO_NOSAVE;
6980 }
6981
6982 io->pos = phys.origin;
6983 SendInitScriptEvent(io);
6984
6985 if (tokeep<0)
6986 {
6987 io->scale=1.65f;
6988 io->physics.cyl.radius=25;
6989 io->physics.cyl.height=-43;
6990 io->speed_modif=1.f;
6991 }
6992
6993 if(ValidIONum(spells[i].caster)) {
6994 EVENT_SENDER = entities[spells[i].caster];
6995 } else {
6996 EVENT_SENDER = NULL;
6997 }
6998
6999 SendIOScriptEvent(io,SM_SUMMONED);
7000
7001 Vec3f pos;
7002
7003 for (long j=0;j<3;j++)
7004 {
7005 pos.x=pSummon->eSrc.x+rnd()*100.f-50.f;
7006 pos.y=pSummon->eSrc.y+100+rnd()*100.f-50.f;
7007 pos.z=pSummon->eSrc.z+rnd()*100.f-50.f;
7008 MakeCoolFx(&pos);
7009 }
7010
7011 if (tokeep==1) spells[i].longinfo2 = io->index();
7012 else spells[i].longinfo2=-1;
7013 }
7014 }
7015 }
7016 }
7017 else if (spells[i].longinfo2<=0)
7018 {
7019 spells[i].tolive=0;
7020 }
7021 }
7022 }
7023 break;
7024 case SPELL_FAKE_SUMMON:
7025 {
7026
7027
7028 if (!arxtime.is_paused())
7029 if(rnd() > 0.7f) {
7030 CSummonCreature * pSummon = (CSummonCreature *)spells[i].pSpellFx;
7031 if(pSummon) {
7032 Vec3f pos = pSummon->eSrc;
7033 MakeCoolFx(&pos);
7034 }
7035 }
7036
7037 CSpellFx *pCSpellFX = spells[i].pSpellFx;
7038
7039 if (pCSpellFX)
7040 {
7041 pCSpellFX->Update(FrameDiff);
7042 pCSpellFX->Render();
7043 }
7044 }
7045 break;
7046 //-----------------------------------------------------------------------------------------
7047
7048 case SPELL_INCINERATE:
7049 {
7050 if (ValidIONum(spells[i].caster))
7051 {
7052 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &entities[spells[i].caster]->pos);
7053 }
7054 }
7055 break;
7056 case SPELL_NEGATE_MAGIC:
7057 {
7058 if (ValidIONum(spells[i].target))
7059 LaunchAntiMagicField(i);
7060
7061 CSpellFx *pCSpellFX = spells[i].pSpellFx;
7062
7063 if (pCSpellFX)
7064 {
7065 pCSpellFX->Update(FrameDiff);
7066 pCSpellFX->Render();
7067 }
7068 }
7069 break;
7070 case SPELL_MASS_PARALYSE:
7071 break;
7072 //*******************************************************************************************
7073 // LEVEL 10 SPELLS -----------------------------------------------------------------------------
7074 //-----------------------------------------------------------------------------------------
7075 case SPELL_FREEZE_TIME:
7076 {
7077 }
7078 break;
7079 //-----------------------------------------------------------------------------------------
7080 case SPELL_CONTROL_TARGET:
7081 {
7082 CSpellFx *pCSpellFX = spells[i].pSpellFx;
7083
7084 if (pCSpellFX)
7085 {
7086 pCSpellFX->Update(FrameDiff);
7087 pCSpellFX->Render();
7088 }
7089 }
7090 break;
7091 case SPELL_MASS_INCINERATE:
7092 {
7093 if (ValidIONum(spells[i].caster))
7094 {
7095 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &entities[spells[i].caster]->pos);
7096 }
7097 }
7098 break;
7099 //-----------------------------------------------------------------------------------------
7100 case SPELL_MASS_LIGHTNING_STRIKE:
7101 {
7102 CSpellFx *pCSpellFX = spells[i].pSpellFx;
7103
7104 if (pCSpellFX)
7105 {
7106 pCSpellFX->Update(FrameDiff);
7107 pCSpellFX->Render();
7108 }
7109
7110 Vec3f _source = spells[i].vsource;
7111 float _fx;
7112 _fx = 0.5f;
7113 unsigned long _gct;
7114 _gct = 0;
7115
7116 Vec3f position;
7117
7118 spells[i].lastupdate=tim;
7119
7120 position = _source + randomVec(-250.f, 250.f);
7121 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &position);
7122 ARX_SOUND_RefreshVolume(spells[i].snd_loop, _fx + 0.5F);
7123 ARX_SOUND_RefreshPitch(spells[i].snd_loop, 0.8F + 0.4F * rnd());
7124
7125 if(rnd() > 0.62f) {
7126 position = _source + randomVec(-250.f, 250.f);
7127 ARX_SOUND_PlaySFX(SND_SPELL_SPARK, &position, 0.8F + 0.4F * rnd());
7128 }
7129
7130 if(rnd() > 0.82f) {
7131 position = _source + randomVec(-250.f, 250.f);
7132 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, &position, 0.8F + 0.4F * rnd());
7133 }
7134
7135 if ((_gct>spells[i].tolive-1800) && (spells[i].siz==0))
7136 {
7137 spells[i].siz=1;
7138 ARX_SOUND_PlaySFX(SND_SPELL_ELECTRIC, NULL, 0.8F + 0.4F * rnd());
7139 }
7140
7141 if (spells[i].longinfo!=-1)
7142 {
7143 float fxx;
7144
7145 if (_fx>0.2f) fxx=1.f;
7146 else fxx=_fx*5.f;
7147
7148 DynLight[spells[i].longinfo].intensity=1.3f+rnd()*1.f;
7149 DynLight[spells[i].longinfo].fallend=850.f;
7150 DynLight[spells[i].longinfo].fallstart=500.f;
7151 DynLight[spells[i].longinfo].rgb = Color3f::red * fxx;
7152 }
7153 }
7154 break;
7155 //-----------------------------------------------------------------------------------------
7156 case SPELL_TELEPORT:
7157 {
7158 float TELEPORT = (float)(((float)tim-(float)spells[i].timcreation)/(float)spells[i].tolive);
7159
7160 if(LASTTELEPORT < 0.5f && TELEPORT >= 0.5f) {
7161 Vec3f pos = lastteleport;
7162 lastteleport = player.pos;
7163 player.pos = pos;
7164 LASTTELEPORT = 32.f;
7165 ARX_SOUND_PlaySFX(SND_SPELL_TELEPORTED, &player.pos);
7166 } else {
7167 LASTTELEPORT = TELEPORT;
7168 }
7169 }
7170 break;
7171 //-----------------------------------------------------------------------------------------
7172 case SPELL_MAGIC_SIGHT:
7173
7174 if (spells[i].caster == 0)
7175 {
7176 ARX_SOUND_RefreshPosition(spells[i].snd_loop);
7177
7178 if (subj.focal>IMPROVED_FOCAL) subj.focal-=DEC_FOCAL;
7179 }
7180
7181 break;
7182 //-----------------------------------------------------------------------------------------
7183 case SPELL_TELEKINESIS:
7184 break;
7185 //-----------------------------------------------------------------------------------------
7186 case SPELL_INVISIBILITY:
7187
7188 if (spells[i].target!=0)
7189 {
7190 if (!(entities[spells[i].target]->gameFlags & GFLAG_INVISIBILITY))
7191 {
7192 ARX_SPELLS_RemoveSpellOn(spells[i].target,i);
7193 ARX_SPELLS_Fizzle(i);
7194 }
7195 }
7196 break;
7197 //-----------------------------------------------------------------------------------------
7198 case SPELL_MANA_DRAIN:
7199 {
7200
7201 if ( (cabal!=NULL) )
7202 {
7203 float refpos;
7204 float scaley;
7205
7206 if (spells[i].caster==0) scaley=90.f;
7207 else scaley=EEfabs(entities[spells[i].caster]->physics.cyl.height*( 1.0f / 2 ))+30.f;
7208
7209 float mov1=EEsin((float)arxtime.get_last_frame_time()*( 1.0f / 800 ))*scaley;
7210 float mov=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ))*scaley;
7211
7212 if ((mov1<scaley-10.f) && (mov>scaley-10.f)) ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD, &spells[i].caster_pos, 0.4F);
7213
7214 if ((mov1>-scaley+10.f) && (mov<-scaley+10.f)) ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD, &spells[i].caster_pos, 0.4F);
7215
7216 if (spells[i].caster==0)
7217 {
7218 cabalpos.x = player.pos.x;
7219 cabalpos.y=player.pos.y+60.f-mov;
7220 cabalpos.z = player.pos.z;
7221 refpos=player.pos.y+60.f;
7222 }
7223 else
7224 {
7225 cabalpos.x = entities[spells[i].caster]->pos.x;
7226 cabalpos.y=entities[spells[i].caster]->pos.y-scaley-mov;
7227 cabalpos.z = entities[spells[i].caster]->pos.z;
7228 refpos=entities[spells[i].caster]->pos.y-scaley;
7229 }
7230
7231 float Es=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ) + radians(scaley));
7232
7233 if (spells[i].longinfo2!=-1)
7234 {
7235 DynLight[spells[i].longinfo2].pos.x = cabalpos.x;
7236 DynLight[spells[i].longinfo2].pos.y = refpos;
7237 DynLight[spells[i].longinfo2].pos.z = cabalpos.z;
7238 DynLight[spells[i].longinfo2].rgb.b=rnd()*0.2f+0.8f;
7239 DynLight[spells[i].longinfo2].fallstart=Es*1.5f;
7240 }
7241
7242 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
7243 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
7244 GRenderer->SetRenderState(Renderer::DepthWrite, false);
7245 cabalangle.b=spells[i].fdata+(float)FrameDiff*0.1f;
7246 spells[i].fdata=cabalangle.b;
7247
7248 cabalangle.g = 0.f;
7249
7250 cabalcolor.r = cabalcolor.g = 0.4f;
7251 cabalcolor.b = 0.8f;
7252
7253 cabalscale = Vec3f::repeat(Es);
7254 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7255 mov=EEsin((float)(arxtime.get_frame_time()-30.f)*( 1.0f / 800 ))*scaley;
7256 cabalpos.y = refpos - mov;
7257 cabalcolor.r = cabalcolor.g = 0.2f;
7258 cabalcolor.b = 0.5f;
7259 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7260 mov=EEsin((float)(arxtime.get_frame_time()-60.f)*( 1.0f / 800 ))*scaley;
7261 cabalpos.y=refpos-mov;
7262 cabalcolor.r = cabalcolor.g = 0.1f;
7263 cabalcolor.b = 0.25f;
7264 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7265 mov=EEsin((float)(arxtime.get_frame_time()-120.f)*( 1.0f / 800 ))*scaley;
7266 cabalpos.y=refpos-mov;
7267 cabalcolor.r = cabalcolor.g = 0.f;
7268 cabalcolor.b = 0.15f;
7269 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7270 cabalangle.b=-cabalangle.b;
7271 cabalpos.y=refpos-mov;
7272 cabalscale = Vec3f::repeat(Es);
7273 cabalcolor.r = cabalcolor.g = 0.f;
7274 cabalcolor.b = 0.15f;
7275 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7276 mov=EEsin((float)(arxtime.get_frame_time()+30.f)*( 1.0f / 800 ))*scaley;
7277 cabalpos.y=refpos+mov;
7278 cabalcolor.r = cabalcolor.g = 0.1f;
7279 cabalcolor.b = 0.25f;
7280 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7281 mov=EEsin((float)(arxtime.get_frame_time()+60.f)*( 1.0f / 800 ))*scaley;
7282 cabalpos.y=refpos+mov;
7283 cabalcolor.r = cabalcolor.g = 0.2f;
7284 cabalcolor.b = 0.5f;
7285 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7286 mov=EEsin((float)(arxtime.get_frame_time()+120.f)*( 1.0f / 800 ))*scaley;
7287 cabalpos.y=refpos+mov;
7288 cabalcolor.r = cabalcolor.g = 0.4f;
7289 cabalcolor.b = 0.8f;
7290 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7291 cabalangle.b=-cabalangle.b;
7292 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
7293 GRenderer->SetRenderState(Renderer::DepthWrite, true);
7294
7295 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &cabalpos);
7296 }
7297 }
7298 break;
7299 //-----------------------------------------------------------------------------------------
7300 case SPELL_LIFE_DRAIN:
7301
7302 {
7303 if ( (cabal!=NULL) )
7304 {
7305 float refpos;
7306 float scaley;
7307
7308 if (spells[i].caster==0) scaley=90.f;
7309 else scaley=EEfabs(entities[spells[i].caster]->physics.cyl.height*( 1.0f / 2 ))+30.f;
7310
7311
7312 float mov=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ))*scaley;
7313
7314 if (spells[i].caster==0)
7315 {
7316 cabalpos.x = player.pos.x;
7317 cabalpos.y=player.pos.y+60.f-mov;
7318 cabalpos.z = player.pos.z;
7319 refpos=player.pos.y+60.f;
7320 }
7321 else
7322 {
7323 cabalpos.x = entities[spells[i].caster]->pos.x;
7324 cabalpos.y=entities[spells[i].caster]->pos.y-scaley-mov;
7325 cabalpos.z = entities[spells[i].caster]->pos.z;
7326 refpos=entities[spells[i].caster]->pos.y-scaley;
7327 }
7328
7329 float Es=EEsin((float)arxtime.get_frame_time()*( 1.0f / 800 ) + radians(scaley));
7330
7331 if (spells[i].longinfo2!=-1)
7332 {
7333 DynLight[spells[i].longinfo2].pos.x = cabalpos.x;
7334 DynLight[spells[i].longinfo2].pos.y = refpos;
7335 DynLight[spells[i].longinfo2].pos.z = cabalpos.z;
7336 DynLight[spells[i].longinfo2].rgb.r=rnd()*0.2f+0.8f;
7337 DynLight[spells[i].longinfo2].fallstart=Es*1.5f;
7338 }
7339
7340 GRenderer->SetCulling(Renderer::CullNone);
7341 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
7342 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
7343 GRenderer->SetRenderState(Renderer::DepthWrite, false);
7344 cabalangle.b=spells[i].fdata+(float)FrameDiff*0.1f;
7345 spells[i].fdata=cabalangle.b;
7346 cabalangle.g = 0.f;
7347 cabalcolor.r = 0.8f;
7348 cabalcolor.g = 0.f;
7349 cabalcolor.b = 0.f;
7350 cabalscale = Vec3f::repeat(Es);
7351 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7352 mov=EEsin((float)(arxtime.get_frame_time()-30.f)*( 1.0f / 800 ))*scaley;
7353 cabalpos.y=refpos-mov;
7354 cabalcolor.b = cabalcolor.g = 0.f;
7355 cabalcolor.r = 0.5f;
7356 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7357 mov=EEsin((float)(arxtime.get_frame_time()-60.f)*( 1.0f / 800 ))*scaley;
7358 cabalpos.y=refpos-mov;
7359 cabalcolor.b = cabalcolor.g = 0.f;
7360 cabalcolor.r = 0.25f;
7361 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7362 mov=EEsin((float)(arxtime.get_frame_time()-120.f)*( 1.0f / 800 ))*scaley;
7363 cabalpos.y=refpos-mov;
7364 cabalcolor.b = cabalcolor.g = 0.f;
7365 cabalcolor.r = 0.15f;
7366 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7367 cabalangle.b=-cabalangle.b;
7368 cabalpos.y=refpos-mov;
7369 cabalscale = Vec3f::repeat(Es);
7370 cabalcolor.b = cabalcolor.g = 0.f;
7371 cabalcolor.r = 0.15f;
7372 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7373 mov=EEsin((float)(arxtime.get_frame_time()+30.f)*( 1.0f / 800 ))*scaley;
7374 cabalpos.y=refpos+mov;
7375 cabalcolor.b = cabalcolor.g = 0.f;
7376 cabalcolor.r = 0.25f;
7377 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7378 mov=EEsin((float)(arxtime.get_frame_time()+60.f)*( 1.0f / 800 ))*scaley;
7379 cabalpos.y=refpos+mov;
7380 cabalcolor.b = cabalcolor.g = 0.f;
7381 cabalcolor.r = 0.5f;
7382 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7383 mov=EEsin((float)(arxtime.get_frame_time()+120.f)*( 1.0f / 800 ))*scaley;
7384 cabalpos.y=refpos+mov;
7385 cabalcolor.b = cabalcolor.g = 0.f;
7386 cabalcolor.r = 0.8f;
7387 DrawEERIEObjEx(cabal,&cabalangle,&cabalpos,&cabalscale,&cabalcolor);
7388 cabalangle.b=-cabalangle.b;
7389 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
7390 GRenderer->SetRenderState(Renderer::DepthWrite, true);
7391
7392 ARX_SOUND_RefreshPosition(spells[i].snd_loop, &cabalpos);
7393 }
7394 }
7395 break;
7396
7397 case SPELL_FLYING_EYE: {
7398
7399 eyeball.floating = EEsin(spells[i].lastupdate-spells[i].timcreation * 0.001f);
7400 eyeball.floating *= 10.f;
7401
7402 if(spells[i].lastupdate-spells[i].timcreation <= 3000) {
7403 eyeball.exist = spells[i].lastupdate - spells[i].timcreation * (1.0f / 30);
7404 eyeball.size = Vec3f::repeat(1.f - float(eyeball.exist) * 0.01f);
7405 eyeball.angle.b += framediff3 * 0.6f;
7406 } else {
7407 eyeball.exist = 2;
7408 }
7409
7410 spells[i].lastupdate=tim;
7411 break;
7412 }
7413
7414 }
7415 }
7416 }
7417 }
7418
7419 ////////////////////////////////////////////////////////////////////////////
7420 ////////////////////////////////////////////////////////////////////////////
7421 ////////////////////////////////////////////////////////////////////////////
7422 ////////////////////////////////////////////////////////////////////////////
7423 ////////////////////////////////////////////////////////////////////////////
7424 ////////////////////////////////////////////////////////////////////////////
TryToCastSpell(Entity * io,Spell spellid,long level,long target,SpellcastFlags flags,long duration)7425 void TryToCastSpell(Entity * io, Spell spellid, long level, long target, SpellcastFlags flags, long duration)
7426 {
7427 if (!io || io->spellcast_data.castingspell != SPELL_NONE) return;
7428
7429 if (!(flags & SPELLCAST_FLAG_NOMANA)
7430 && (io->ioflags & IO_NPC) && (io->_npcdata->mana<=0.f))
7431 return;
7432
7433 unsigned long i(0);
7434
7435 for (; i < SPELL_COUNT; i++)
7436 if (spellicons[i].spellid == spellid) break;
7437
7438 if ( i >= SPELL_COUNT) return; // not an existing spell...
7439
7440 for (unsigned long j(0); j < 4; j++) io->spellcast_data.symb[j] = RUNE_NONE;
7441
7442 // checks for symbol drawing...
7443 if (!(flags & SPELLCAST_FLAG_NOANIM) && io->ioflags & IO_NPC)
7444 {
7445 ANIM_USE *ause1 = &io->animlayer[1];
7446
7447 AcquireLastAnim(io);
7448 FinishAnim(io, ause1->cur_anim);
7449 ANIM_Set(ause1, io->anims[ANIM_CAST_START]);
7450
7451 for (unsigned long j(0); j < 4; j++)
7452 io->spellcast_data.symb[j] = spellicons[i].symbols[j];
7453 }
7454
7455 io->spellcast_data.castingspell = spellid;
7456
7457
7458 io->spellcast_data.spell_flags = flags;
7459 io->spellcast_data.spell_level = checked_range_cast<short>(level);
7460
7461
7462 io->spellcast_data.duration = duration;
7463 io->spellcast_data.target = target;
7464
7465 io->gameFlags &=~GFLAG_INVISIBILITY;
7466
7467 if ( ((io->spellcast_data.spell_flags & SPELLCAST_FLAG_NOANIM)
7468 && (io->spellcast_data.spell_flags & SPELLCAST_FLAG_NODRAW) )
7469 || (io->spellcast_data.spell_flags & SPELLCAST_FLAG_PRECAST))
7470 {
7471
7472 ARX_SPELLS_Launch(io->spellcast_data.castingspell, io->index(), io->spellcast_data.spell_flags,io->spellcast_data.spell_level,io->spellcast_data.target,io->spellcast_data.duration);
7473 io->spellcast_data.castingspell = SPELL_NONE;
7474 }
7475
7476 io->spellcast_data.spell_flags &=~SPELLCAST_FLAG_NODRAW; // temporary, removes colored flares
7477 }
7478
ApplySPWep()7479 static void ApplySPWep() {
7480
7481 if(!sp_wep) {
7482
7483 ARX_SPSound();
7484
7485 res::path cls = "graph/obj3d/interactive/items/weapons/sword_mx/sword_mx";
7486 Entity * ioo = AddItem(cls);
7487 if(ioo) {
7488
7489 sp_wep = 1;
7490 MakeCoolFx(&player.pos);
7491 MakeCoolFx(&player.pos);
7492 ioo->scriptload = 1;
7493 SendInitScriptEvent(ioo);
7494
7495 giveToPlayer(ioo);
7496
7497 MakeSpCol();
7498 strcpy(sp_max_ch,"!!!_Grosbillite_!!!");
7499 sp_max_nb=strlen(sp_max_ch);
7500 sp_max_start=arxtime.get_updated();
7501 }
7502 }
7503 }
7504
MakeSpCol()7505 void MakeSpCol() {
7506
7507 ARX_SPSound();
7508
7509 for(long i = 0; i < 64; i++) {
7510 sp_max_y[i] = 0;
7511 }
7512
7513 sp_max_col[0] = Color::fromRGBA(0x00FF0000);
7514 sp_max_col[1] = Color::fromRGBA(0x0000FF00);
7515 sp_max_col[2] = Color::fromRGBA(0x000000FF);
7516
7517 sp_max_col[3] = Color::fromRGBA(0x00FFFF00);
7518 sp_max_col[4] = Color::fromRGBA(0x00FF00FF);
7519 sp_max_col[5] = Color::fromRGBA(0x0000FFFF);
7520
7521 for(size_t i = 6; i < 24; i++) {
7522 sp_max_col[i] = sp_max_col[i - 6];
7523 }
7524
7525 for(size_t i = 24; i < 27; i++) {
7526 sp_max_col[i] = sp_max_col[i - 3];
7527 }
7528
7529 for(size_t i = 27; i < 33; i++) {
7530 sp_max_col[i] = sp_max_col[i - 9];
7531 }
7532
7533 }
7534
ApplyCurSOS()7535 static void ApplyCurSOS() {
7536 MakeSpCol();
7537 g_miniMap.reveal();
7538 strcpy(sp_max_ch,"!!!_Temple of Elemental Lavis_!!!");
7539 sp_max_nb=strlen(sp_max_ch);
7540 sp_max_start=arxtime.get_updated();
7541 }
7542
ApplySPBow()7543 static void ApplySPBow() {
7544
7545 ARX_SPSound();
7546
7547 const char * cls = "graph/obj3d/interactive/items/weapons/bow_mx/bow_mx";
7548 Entity * ioo = AddItem(cls);
7549 if(ioo) {
7550
7551 MakeCoolFx(&player.pos);
7552 MakeCoolFx(&player.pos);
7553
7554 ioo->scriptload = 1;
7555 SendInitScriptEvent(ioo);
7556
7557 giveToPlayer(ioo);
7558
7559 MakeSpCol();
7560 strcpy(sp_max_ch,"!!!_Bow to Samy & Anne_!!!");
7561 sp_max_nb=strlen(sp_max_ch);
7562 sp_max_start=arxtime.get_updated();
7563 }
7564 }
7565
ApplySPArm()7566 static void ApplySPArm() {
7567 ARX_SPSound();
7568
7569 res::path cls;
7570 switch (sp_arm) {
7571 case 0:
7572 cls = "graph/obj3d/interactive/items/armor/helmet_plate_cm/helmet_plate_cm";
7573 break;
7574 case 1:
7575 cls = "graph/obj3d/interactive/items/armor/legging_plate_cm/legging_plate_cm";
7576 break;
7577 case 2:
7578 cls = "graph/obj3d/interactive/items/armor/chest_plate_cm/chest_plate_cm";
7579 break;
7580 default:
7581 return;
7582 break;
7583 }
7584
7585 Entity * ioo = AddItem(cls);
7586 if(ioo) {
7587
7588 sp_wep = 1;
7589 MakeCoolFx(&player.pos);
7590 MakeCoolFx(&player.pos);
7591 ioo->scriptload = 1;
7592 SendInitScriptEvent(ioo);
7593
7594 giveToPlayer(ioo);
7595
7596 MakeSpCol();
7597 strcpy(sp_max_ch,"!! Toi aussi cherches les Cheats !!");
7598
7599 switch (sp_arm)
7600 {
7601 case 0:
7602 strcpy(sp_max_ch,"------ZoliChapo------");
7603 break;
7604 case 1:
7605 strcpy(sp_max_ch,"-----TiteBottine-----");
7606 break;
7607 case 2:
7608 strcpy(sp_max_ch,"-----Roooo-La-La-----");
7609 break;
7610 default:
7611 return;
7612 break;
7613 }
7614
7615 sp_max_nb=strlen(sp_max_ch);
7616 sp_max_start=arxtime.get_updated();
7617 }
7618
7619 sp_arm++;
7620 }
7621
7622 long SPECIAL_PNUX;
ApplyCurPNux()7623 static void ApplyCurPNux() {
7624
7625 MakeSpCol();
7626 strcpy(sp_max_ch,"! PhilNux & Gluonne !");
7627 sp_max_nb=strlen(sp_max_ch);
7628
7629 SPECIAL_PNUX = (SPECIAL_PNUX + 1) % 3;
7630
7631 // TODO-RENDERING: Create a post-processing effect for that cheat... see original source...
7632
7633 cur_pnux=0;
7634 sp_max_start=arxtime.get_updated();
7635 }
7636
ApplyPasswall()7637 static void ApplyPasswall() {
7638 MakeSpCol();
7639 strcpy(sp_max_ch,"!!! PassWall !!!");
7640 sp_max_nb=strlen(sp_max_ch);
7641 sp_max_start=arxtime.get_updated();
7642
7643 if (USE_PLAYERCOLLISIONS)
7644 USE_PLAYERCOLLISIONS=0;
7645 else
7646 USE_PLAYERCOLLISIONS=1;
7647 }
7648
ApplySPRf()7649 static void ApplySPRf() {
7650 if(cur_rf == 3) {
7651 MakeSpCol();
7652 strcpy(sp_max_ch,"!!! RaFMode !!!");
7653 sp_max_nb=strlen(sp_max_ch);
7654 sp_max_start=arxtime.get_updated();
7655 }
7656 }
7657
ApplyCurMr()7658 static void ApplyCurMr() {
7659 if(cur_mr == 3) {
7660 MakeSpCol();
7661 strcpy(sp_max_ch,"!!! Marianna !!!");
7662 sp_max_nb=strlen(sp_max_ch);
7663 sp_max_start=arxtime.get_updated();
7664 }
7665 }
7666
ApplySPuw()7667 static void ApplySPuw() {
7668 uw_mode_pos=0;
7669 uw_mode=~uw_mode;
7670 ARX_SOUND_PlayCinematic("menestrel_uw2", true);
7671 MakeCoolFx(&player.pos);
7672 if(uw_mode) {
7673 MakeSpCol();
7674 strcpy(sp_max_ch,"~-__-~~-__.U.W.__-~~-__-~");
7675 sp_max_nb=strlen(sp_max_ch);
7676 sp_max_start=arxtime.get_updated();
7677 }
7678 }
7679
ApplySPMax()7680 static void ApplySPMax() {
7681
7682 MakeCoolFx(&player.pos);
7683 sp_max=~sp_max;
7684
7685 if (sp_max)
7686 {
7687 MakeSpCol();
7688 strcpy(sp_max_ch,"!!!_FaNt0mAc1e_!!!");
7689 sp_max_nb=strlen(sp_max_ch);
7690 sp_max_start=arxtime.get_updated();
7691
7692 player.skin=4;
7693
7694 ARX_EQUIPMENT_RecreatePlayerMesh();
7695
7696 ARX_PLAYER_Rune_Add_All();
7697 std::string text = "!!!!!!! FanTomAciE !!!!!!!";
7698 ARX_SPEECH_Add(text);
7699 player.Attribute_Redistribute+=10;
7700 player.Skill_Redistribute+=50;
7701 player.level=std::max((int)player.level,10);
7702 player.xp=GetXPforLevel(10);
7703 }
7704 else
7705 {
7706 TextureContainer * tcm;
7707 tcm = TextureContainer::Load("graph/obj3d/textures/npc_human_cm_hero_head");
7708 if(tcm) {
7709 delete tcm;
7710 player.heads[0]
7711 = TextureContainer::Load("graph/obj3d/textures/npc_human_base_hero_head");
7712 player.heads[1]
7713 = TextureContainer::Load("graph/obj3d/textures/npc_human_base_hero2_head");
7714 player.heads[2]
7715 = TextureContainer::Load("graph/obj3d/textures/npc_human_base_hero3_head");
7716 ARX_EQUIPMENT_RecreatePlayerMesh();
7717 }
7718 }
7719 }
7720