stratagus-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Stratagus-CVS] stratagus/src clone/Module.make clone/ccl.c clo...


From: Crestez Leonard
Subject: [Stratagus-CVS] stratagus/src clone/Module.make clone/ccl.c clo...
Date: Mon, 22 Sep 2003 06:40:54 -0400

CVSROOT:        /cvsroot/stratagus
Module name:    stratagus
Branch:         
Changes by:     Crestez Leonard <address@hidden>        03/09/22 06:40:53

Modified files:
        src/clone      : Module.make ccl.c spells.c 
        src/editor     : editloop.c edmap.c 
        src/game       : savegame.c 
        src/include    : spells.h unittype.h 
        src/siod       : slib.c 
        src/unit       : ccl_unittype.c unittype.c 

Log message:
        Merged jarod's spell patch.

Patches:
Index: stratagus/src/clone/Module.make
diff -u stratagus/src/clone/Module.make:1.5 stratagus/src/clone/Module.make:1.6
--- stratagus/src/clone/Module.make:1.5 Thu Jul  3 13:48:48 2003
+++ stratagus/src/clone/Module.make     Mon Sep 22 06:40:51 2003
@@ -25,7 +25,7 @@
 MODULE= src/clone
 MSRC=  ccl.c ccl_player.c clone.c construct.c groups.c iolib.c mainloop.c \
        mpq.c player.c pud.c scm.c selection.c spells.c unit.c unit_draw.c \
-       unit_find.c unitcache.c 
+       unit_find.c unitcache.c ccl_spell.c
 
 SRC+=  $(addprefix $(MODULE)/,$(MSRC))
 HDRS+=
Index: stratagus/src/clone/ccl.c
diff -u stratagus/src/clone/ccl.c:1.109 stratagus/src/clone/ccl.c:1.110
--- stratagus/src/clone/ccl.c:1.109     Thu Sep 18 07:59:20 2003
+++ stratagus/src/clone/ccl.c   Mon Sep 22 06:40:51 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: ccl.c,v 1.109 2003/09/18 11:59:20 mr-russ Exp $
+//     $Id: ccl.c,v 1.110 2003/09/22 10:40:51 n0body Exp $
 
 //@{
 
@@ -66,6 +66,7 @@
 #include "sound_server.h"
 #include "netconnect.h"
 #include "cdaudio.h"
+#include "spells.h"
 
 /*----------------------------------------------------------------------------
 --     Variables
@@ -862,6 +863,7 @@
     TriggerCclRegister();
     CreditsCclRegister();
     ObjectivesCclRegister();
+       SpellCclRegister();
 
     EditorCclRegister();
 
@@ -1023,7 +1025,7 @@
     }
 
     fprintf(fd,";;; -----------------------------------------\n");
-    fprintf(fd,";;; $Id: ccl.c,v 1.109 2003/09/18 11:59:20 mr-russ Exp $\n");
+    fprintf(fd,";;; $Id: ccl.c,v 1.110 2003/09/22 10:40:51 n0body Exp $\n");
 
     fprintf(fd,"(set-video-resolution! %d %d)\n", VideoWidth, VideoHeight);
     
@@ -1047,7 +1049,7 @@
     }
 
     fprintf(fd,";;; -----------------------------------------\n");
-    fprintf(fd,";;; $Id: ccl.c,v 1.109 2003/09/18 11:59:20 mr-russ Exp $\n");
+    fprintf(fd,";;; $Id: ccl.c,v 1.110 2003/09/22 10:40:51 n0body Exp $\n");
 
     // Global options
     if( OriginalFogOfWar ) {
@@ -1157,7 +1159,7 @@
     extern SCM oblistvar;
 
     CLprintf(file,"\n;;; -----------------------------------------\n");
-    CLprintf(file,";;; MODULE: CCL $Id: ccl.c,v 1.109 2003/09/18 11:59:20 
mr-russ Exp $\n\n");
+    CLprintf(file,";;; MODULE: CCL $Id: ccl.c,v 1.110 2003/09/22 10:40:51 
n0body Exp $\n\n");
 
     for(list = oblistvar; gh_list_p(list); list = gh_cdr(list) ) {
        SCM sym;
Index: stratagus/src/clone/spells.c
diff -u stratagus/src/clone/spells.c:1.94 stratagus/src/clone/spells.c:1.95
--- stratagus/src/clone/spells.c:1.94   Mon Aug 25 07:21:15 2003
+++ stratagus/src/clone/spells.c        Mon Sep 22 06:40:51 2003
@@ -4,14 +4,14 @@
 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
 //             \/                  \/          \//_____/            \/ 
-//  ______________________                          ______________________
+//  ______________________                           ______________________
 //                       T H E   W A R   B E G I N S
 //        Stratagus - A free fantasy real time strategy game engine
 //
 /address@hidden spells.c       -       The spell cast action. */
 //
 //     (c) Copyright 1998-2003 by Vladi Belperchinov-Shabanski, Lutz Sammer,
-//                                and Jimmy Salmon
+//                                Jimmy Salmon and Joris DAUPHIN
 //
 //      This program is free software; you can redistribute it and/or modify
 //      it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: spells.c,v 1.94 2003/08/25 11:21:15 mr-russ Exp $
+//     $Id: spells.c,v 1.95 2003/09/22 10:40:51 n0body Exp $
 
 /*
 **     And when we cast our final spell
@@ -50,6 +50,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
 #include "stratagus.h"
 
@@ -65,101 +66,30 @@
 --     Definitons
 ----------------------------------------------------------------------------*/
 
-#define FIREBALL_DAMAGE                20      /// Damage of center fireball
-#define WHIRLWIND_DAMAGE1       4      /// the center of the whirlwind
-#define WHIRLWIND_DAMAGE2       1      /// the periphery of the whirlwind
-#define BLIZZARD_DAMAGE                10      /// Damage of blizzard
-#define DEATHANDDECAY_DAMAGE   10      /// Damage of death & decay
-#define RUNE_DAMAGE            50      /// Rune damage
+// TODO Move this in missile.c and remove Hardcoded string.
+MissileType* MissileTypeRune = NULL; // MissileTypeByIdent("missile-rune");
 
 /*----------------------------------------------------------------------------
 --     Variables
 ----------------------------------------------------------------------------*/
 
-/*
-  NOTE: vladi:
-
-  The point to have variable unsorted list of spell-types and
-  dynamic id's and in the same time -- SpellAction id's is that
-  spell actions are hardcoded and cannot be changed at all.
-  On the other hand we can have different spell-types as with
-  different range, cost and time to live (possibly and other
-  parameters as extensions)
-
-  FIXME: this should be configurable by CCL.
-
-  FIXME: 0x7F as unlimited range is too less for big maps.
-*/
-
 /**
 **     Define the names and effects of all im play available spells.
 */
-global SpellType SpellTypeTable[]
-#ifndef laterUSE_CCL
-       = {
+global SpellType *SpellTypeTable = NULL;
 
-//TTL's below are in ticks: approx: 500=13sec, 1000=25sec, 2000=50sec
 
-// ident,                      name,                   range,mana,ttl, spell 
action,             sound config
-//     ---human paladins---
-{ "spell-holy-vision",         "holy vison",           0x7F,  70,  -1, 
SpellActionHolyVision   , { "holy vision", NULL }    , { NULL, NULL} },
-{ "spell-healing",             "healing",                 6,   6,  -1, 
SpellActionHealing      , { "healing", NULL }        , { NULL, NULL} },
-{ "spell-exorcism",            "exorcism",               10,   4,  -1, 
SpellActionExorcism     , { "exorcism", NULL }       , { NULL, NULL} },
-//     ---human mages---                                                
---human mages---
-{ "spell-fireball",            "fireball",                8, 100,1000, 
SpellActionFireball     , { "fireball throw", NULL } , { NULL, NULL} },
-{ "spell-slow",                        "slow",                   10,  50,1000, 
SpellActionSlow         , { "slow", NULL }           , { NULL, NULL} },
-{ "spell-flame-shield",                "flame shield",            6,  80, 600, 
SpellActionFlameShield  , { "flame shield", NULL }   , { 
"missile-flame-shield", NULL } },
-{ "spell-invisibility",                "invisibility",            6, 200,2000, 
SpellActionInvisibility , { "invisibility", NULL }   , { NULL, NULL} },
-{ "spell-polymorph",           "polymorph",              10, 200,  -1, 
SpellActionPolymorph    , { "polymorph", NULL }      , { NULL, NULL} },
-{ "spell-blizzard",            "blizzard",               12,  25,  -1, 
SpellActionBlizzard     , { "blizzard", NULL }       , { NULL, NULL} },
-//     ---orc ogres---                                                  ---orc 
ogres---
-{ "spell-eye-of-vision",       "eye of vision",           6,  70,  -1, 
SpellActionEyeOfVision  , { "eye of vision", NULL }  , { NULL, NULL} },
-{ "spell-bloodlust",           "bloodlust",               6,  50,1000, 
SpellActionBloodlust    , { "bloodlust", NULL }      , { NULL, NULL} },
-{ "spell-runes",               "runes",                  10, 200,2000, 
SpellActionRunes        , { "runes", NULL }          , { NULL, NULL} },
-//     ---orc death knights---                                          ---orc 
death knights-
-{ "spell-death-coil",          "death coil",             10, 100,  -1, 
SpellActionDeathCoil    , { "death coil", NULL }     , { NULL, NULL} },
-{ "spell-haste",               "haste",                   6,  50,1000, 
SpellActionHaste        , { "haste", NULL }          , { NULL, NULL} },
-{ "spell-raise-dead",          "raise dead",              6,  50,  -1, 
SpellActionRaiseDead    , { "raise dead", NULL }     , { NULL, NULL} },
-{ "spell-whirlwind",           "whirlwind",              12, 100, 801, 
SpellActionWhirlwind    , { "whirlwind", NULL }      , { NULL, NULL} },
-{ "spell-unholy-armor",                "unholy armor",            6, 100, 500, 
SpellActionUnholyArmor  , { "unholy armour", NULL }  , { NULL, NULL} },
-{ "spell-death-and-decay",     "death and decay",        12,  25,  -1, 
SpellActionDeathAndDecay, { "death and decay", NULL }, { NULL, NULL} },
-//     ---extensions---                                                 ---orc 
death knights-
-{ "spell-circle-of-power",     "circle of power",      0x7F,  25,  -1, 
SpellActionCircleOfPower, { "circle of power", NULL }, { NULL, NULL} },
-//     ---eot marker---                                                 ---eot 
marker---
-{ NULL,                                NULL,                      0,   0,   0, 
0                       , { NULL, NULL}              , { NULL, NULL} }
-};
-#else
-    ;
-#endif
-
-    /// How many spell-types are available
-local int SpellTypeCount;
-
-    /// missile-type for the custom missile
-local MissileType* MissileTypeCustom;
-    /// missile-type for the heal effect missile
-local MissileType* MissileTypeHealing;
-    /// missile-type for the exorcism effect missile
-local MissileType* MissileTypeExorcism;
-    /// missile-type for the fire ball missile
-local MissileType* MissileTypeFireball;
-    /// missile-type for generic spell missile
-local MissileType* MissileTypeSpell;
-    /// missile-type for the rune missile
-local MissileType* MissileTypeRune;
-    /// missile-type for the whirlwind missile
-local MissileType* MissileTypeWhirlwind;
-    /// missile-type for the blizzard missile
-local MissileType* MissileTypeBlizzard;
-    /// missile-type for the death decay missile
-local MissileType* MissileTypeDeathDecay;
-    /// missile-type for the death coil missile
-local MissileType* MissileTypeDeathCoil;
+/// How many spell-types are available
+global int SpellTypeCount = 0; // Usefull ?
 
 /*----------------------------------------------------------------------------
 --     Functions (Spells Controllers/Callbacks)
 ----------------------------------------------------------------------------*/
 
+// ****************************************************************************
+// Action of the missile of spells
+// ****************************************************************************
+
 /*
 ** Missile controllers
 **
@@ -168,6 +98,8 @@
 **
 */
 
+// FIXME Move this codes into missile.c
+
 /**
 **     Fireball controller
 **
@@ -188,25 +120,28 @@
     // explosions are on each tile on the way
 
     // approx
-    if (missile->TTL <= missile->State && missile->TTL % 2 == 0) {
+    if (missile->TTL <= missile->State && missile->TTL % 2 == 0)
+    {
        //+TileSize/2 to align gfx to baseline
-       x = missile->X + TileSizeX / 2;
-       y = missile->Y + TileSizeY / 2;
+               x = missile->X + TileSizeX / 2;
+               y = missile->Y + TileSizeY / 2;
 
-       MakeMissile(MissileTypeExplosion, x, y, x, y);
+               MakeMissile(MissileTypeExplosion, x, y, x, y);
 
-       x = x / TileSizeX;
-       y = y / TileSizeY;
+               x = x / TileSizeX;
+               y = y / TileSizeY;
 
        // Effect of the explosion on units
        // NOTE: vladi: this is slightly different than original
        //      now it hits all units in range 1
-       n = SelectUnits(x - 1, y - 1, x + 1, y + 1, table);
-       for (i = 0; i < n; ++i) {
-           if (table[i]->HP) {
-               HitUnit(missile->SourceUnit,table[i], FIREBALL_DAMAGE);
-           }
-       }
+               n = SelectUnits(x - 1, y - 1, x + 1, y + 1, table);
+               for (i = 0; i < n; ++i)
+               {
+                       if (table[i]->HP)
+                       {
+                               HitUnit(missile->SourceUnit, table[i], 
FIREBALL_DAMAGE); // Should be missile->damage
+                       }
+               }
     }
 }
 
@@ -219,105 +154,134 @@
 */
 local void SpellDeathCoilController(Missile * missile)
 {
-    Unit *table[UnitMax];
-    int i;
-    int n;
-    Unit *source;
+       Unit    *table[UnitMax];
+       int     i;
+       int     n;
+       Unit    *source;
 
     //
-    //  missile has reached target unit/spot
+    //  missile has not reached target unit/spot
     //
-    if (missile->X == missile->DX && missile->Y == missile->DY) {
+       if (!(missile->X == missile->DX && missile->Y == missile->DY))
+       {
+               return ;
+       }
        source = missile->SourceUnit;
-       if (!source->Destroyed) {       // source unit still exists
-           //
-           //  Target unit still exists and casted on a special target
-           //
-           if (missile->TargetUnit && !missile->TargetUnit->Destroyed
-                   && missile->TargetUnit->HP) {
-               if (missile->TargetUnit->HP <= 50) {
-                   source->Player->Score+=missile->TargetUnit->Type->Points;
-                   if( missile->TargetUnit->Type->Building ) {
-                       source->Player->TotalRazings++;
-                   } else {
-                       source->Player->TotalKills++;
-                   }
+       if (source->Destroyed)
+       {
+               return ;
+       }
+       // source unit still exists
+       //
+       //      Target unit still exists and casted on a special target
+       //
+       if (missile->TargetUnit && !missile->TargetUnit->Destroyed
+               && missile->TargetUnit->HP)
+       {
+               if (missile->TargetUnit->HP <= 50)      // 50 should be 
parametrable
+               {
+                       source->Player->Score += 
missile->TargetUnit->Type->Points;
+                       if( missile->TargetUnit->Type->Building)
+                       {
+                               source->Player->TotalRazings++;
+                       }
+                       else
+                       {
+                               source->Player->TotalKills++;
+                       }
 #ifdef USE_HP_FOR_XP
-                   source->XP+=missile->TargetUnit->HP;
+                       source->XP += missile->TargetUnit->HP;
 #else
-                   source->XP+=missile->TargetUnit->Type->Points;
+                       source->XP += missile->TargetUnit->Type->Points;
 #endif
-                   ++source->Kills;
-                   missile->TargetUnit->HP = 0;
-                   LetUnitDie(missile->TargetUnit);
-               } else {
+                       ++source->Kills;
+                       missile->TargetUnit->HP = 0;
+                       LetUnitDie(missile->TargetUnit);
+               }
+               else
+               {
 #ifdef USE_HP_FOR_XP
-                   source->XP+=50;
+                       source->XP += 50;
 #endif
-                   missile->TargetUnit->HP-=50;
+                       missile->TargetUnit->HP -= 50;
                }
-               if (source->Orders[0].Action!=UnitActionDie) {
-                   source->HP += 50;
-                   if (source->HP > source->Stats->HitPoints) {
-                       source->HP = source->Stats->HitPoints;
-                   }
+               if (source->Orders[0].Action != UnitActionDie)
+               {
+                       source->HP += 50;
+                       if (source->HP > source->Stats->HitPoints)
+                       {
+                               source->HP = source->Stats->HitPoints;
+                       }
                }
-           //
-           //  No target unit -- try enemies in range 5x5
-           //
-           } else {
+       }
+       else
+    //
+    // No target unit -- try enemies in range 5x5 // Must be parametrable
+    //
+       {
                int ec = 0;             // enemy count
                int x = missile->DX / TileSizeX;
                int y = missile->DY / TileSizeY;
 
                n = SelectUnits(x - 2, y - 2, x + 2, y + 2, table);
-               if (n > 0) {
-                   // calculate organic enemy count
-                   for (i = 0; i < n; ++i) {
+               if (n == 0)
+               {
+                       return ;
+               }
+           // calculate organic enemy count
+       for (i = 0; i < n; ++i)
+       {
                        ec += (IsEnemy(source->Player, table[i])
-                              && table[i]->Type->Organic != 0);
-                   }
-                   if (ec > 0) {       // yes organic enemies found
-                       for (i = 0; i < n; ++i) {
-                           if (IsEnemy(source->Player, table[i])
-                                   && table[i]->Type->Organic != 0) {
-                               // disperse damage between them
-                               //NOTE: 1 is the minimal damage
-                               if (table[i]->HP <= 50 / ec ) {
-                                   source->Player->Score +=
-                                           table[i]->Type->Points;
-                                   if( table[i]->Type->Building ) {
-                                       source->Player->TotalRazings++;
-                                   } else {
-                                       source->Player->TotalKills++;
-                                   }
+                       && table[i]->Type->Organic != 0);
+               }
+               if (ec > 0)
+               {       // yes organic enemies found
+                       for (i = 0; i < n; ++i)
+                       {
+                               if (IsEnemy(source->Player, table[i])
+                                   && table[i]->Type->Organic != 0)
+                               {
+                       // disperse damage between them
+                       //NOTE: 1 is the minimal damage
+                                       if (table[i]->HP <= 50 / ec )
+                                       {
+                                               source->Player->Score += 
table[i]->Type->Points;
+                                       if( table[i]->Type->Building )
+                                       {
+                                                       
source->Player->TotalRazings++;
+                                               }
+                                               else
+                                               {
+                                                       
source->Player->TotalKills++;
+                                               }
 #ifdef USE_HP_FOR_XP
-                                   source->XP += table[i]->HP;
+                                               source->XP += table[i]->HP;
 #else
-                                   source->XP += table[i]->Type->Points;
+                                               source->XP += 
table[i]->Type->Points;
 #endif
-                                   ++source->Kills;
-                                   table[i]->HP = 0;
-                                   LetUnitDie(table[i]); // too much damage
-                               } else {
+                                               ++source->Kills;
+                                               table[i]->HP = 0;
+                                               LetUnitDie(table[i]); // too 
much damage
+                                       }
+                                       else
+                                       {
 #ifdef USE_HP_FOR_XP
-                                   source->XP += 50/ec;
+                                               source->XP += 50/ec;
 #endif
-                                   table[i]->HP -= 50 / ec;
-                               }
+                                               table[i]->HP -= 50 / ec;
+                                       }
                            }
                        }
-                       if (source->Orders[0].Action!=UnitActionDie) {
-                           source->HP += 50;
-                           if (source->HP > source->Stats->HitPoints) {
-                               source->HP = source->Stats->HitPoints;
-                           }
+                       if (source->Orders[0].Action!=UnitActionDie)
+                       {
+                               source->HP += 50;
+                               if (source->HP > source->Stats->HitPoints)
+                               {
+                                       source->HP = source->Stats->HitPoints;
+                               }
                        }
-                   }
                }
-           }
        }
-    }
 }
 
 /**
@@ -340,31 +304,35 @@
     //
     x = (missile->X+TileSizeX/2+missile->Type->Width/2) / TileSizeX;
     y = (missile->Y+TileSizeY+missile->Type->Height/2) / TileSizeY;
-
-
     //
     // Every 4 cycles 4 points damage in tornado center
     //
-    if (!(missile->TTL % 4)) {
-       n = SelectUnitsOnTile(x, y, table);
-       for (i = 0; i < n; ++i) {
-           if (table[i]->HP) {
-               HitUnit(missile->SourceUnit,table[i], WHIRLWIND_DAMAGE1);
-           }
-       }
+    if (!(missile->TTL % 4))
+    {
+               n = SelectUnitsOnTile(x, y, table);
+               for (i = 0; i < n; ++i)
+               {
+                   if (table[i]->HP)
+                   {
+                               HitUnit(missile->SourceUnit,table[i], 
WHIRLWIND_DAMAGE1);// should be missile damage ?
+                   }
+               }
     }
-
     //
     // Every 1/10s 1 points damage on tornado periphery
     //
-    if (!(missile->TTL % (CYCLES_PER_SECOND/10))) {
-       n = SelectUnits(x - 1, y - 1, x + 1, y + 1, table);
-       DebugLevel3Fn("Damage on %d,%d-%d,%d = %d\n" _C_ x-1 _C_ y-1 _C_ x+1 
_C_ y+1 _C_ n);
-       for (i = 0; i < n; ++i) {
-           if( (table[i]->X!=x || table[i]->Y!=y) && table[i]->HP) {
-               HitUnit(missile->SourceUnit,table[i], WHIRLWIND_DAMAGE2);
-           }
-       }
+    if (!(missile->TTL % (CYCLES_PER_SECOND/10)))
+    {
+       // we should parameter this
+               n = SelectUnits(x - 1, y - 1, x + 1, y + 1, table);
+               DebugLevel3Fn("Damage on %d,%d-%d,%d = %d\n" _C_ x-1 _C_ y-1 
_C_ x+1 _C_ y+1 _C_ n);
+               for (i = 0; i < n; ++i)
+               {
+                   if( (table[i]->X != x || table[i]->Y != y) && table[i]->HP)
+                   {
+                               HitUnit(missile->SourceUnit,table[i], 
WHIRLWIND_DAMAGE2); // should be in missile
+                   }
+               }
     }
     DebugLevel3Fn( "Whirlwind: %d, %d, TTL: %d\n" _C_
            missile->X _C_ missile->Y _C_ missile->TTL );
@@ -407,21 +375,23 @@
     y = missile->Y / TileSizeY;
 
     n = SelectUnitsOnTile(x, y, table);
-    for (i = 0; i < n; ++i) {
-       if (table[i]->Type->UnitType!=UnitTypeFly && table[i]->HP) {
-           // FIXME: don't use ident!!!
-           PlayMissileSound(missile,SoundIdForName("explosion"));
-           MakeMissile(MissileTypeExplosion,missile->X, missile->Y,
-               missile->X, missile->Y);
-           HitUnit(missile->SourceUnit,table[i], RUNE_DAMAGE);
-           missile->TTL=0;             // Rune can only hit once
-       }
+    for (i = 0; i < n; ++i)
+    {
+               if (table[i]->Type->UnitType != UnitTypeFly && table[i]->HP)
+               {
+                   // FIXME: don't use ident!!!
+                   PlayMissileSound(missile, SoundIdForName("explosion"));
+                   MakeMissile(MissileTypeExplosion, missile->X, missile->Y,
+                                               missile->X, missile->Y);
+                   HitUnit(missile->SourceUnit, table[i], RUNE_DAMAGE);
+                   missile->TTL=0;             // Rune can only hit once
+               }
     }
-
     // show rune every 4 seconds (approx.)
-    if (missile->TTL % 100 == 0 || missile->TTL == 0) {
-       MakeMissile(MissileTypeRune, missile->X, missile->Y, missile->X,
-               missile->Y);
+    if (missile->TTL % 100 == 0)
+    {
+               MakeMissile(MissileTypeRune, missile->X, missile->Y,
+                                       missile->X, missile->Y);
     }
 }
 
@@ -456,41 +426,41 @@
     i = missile->TTL % 36;             // 36 positions on the circle
     dx = fs_dc[i * 2];
     dy = fs_dc[i * 2 + 1];
-
     ux = missile->TargetUnit->X;
     uy = missile->TargetUnit->Y;
-
     ix = missile->TargetUnit->IX;
     iy = missile->TargetUnit->IY;
-
     uw = missile->TargetUnit->Type->Width;
     uh = missile->TargetUnit->Type->Height;
-
     missile->X = ux * TileSizeX + ix + uw / 2 + dx - 32;
     missile->Y = uy * TileSizeY + iy + uh / 2 + dy - 32 - 16;
-
-    if (missile->TargetUnit->Orders[0].Action == UnitActionDie) {
-       missile->TTL = i;
-    }
-
-    if (missile->TTL == 0) {
-       missile->TargetUnit->FlameShield = 0;
+    if (missile->TargetUnit->Orders[0].Action == UnitActionDie)
+    {
+               missile->TTL = i;
+    }
+    if (missile->TTL == 0)
+    {
+               missile->TargetUnit->FlameShield = 0;
     }
     //vladi: still no have clear idea what is this about :)
     CheckMissileToBeDrawn(missile);
 
     // Only hit 1 out of 8 frames
-    if (missile->TTL & 7) {
-       return;
+    if (missile->TTL & 7)
+    {
+               return;
     }
     n = SelectUnits(ux - 1, uy - 1, ux + 1 + 1, uy + 1 + 1, table);
-    for (i = 0; i < n; ++i) {
-       if (table[i] == missile->TargetUnit) {  // cannot hit target unit
-           continue;
-       }
-       if (table[i]->HP) {
-           HitUnit(missile->SourceUnit, table[i], 1);
-       }
+    for (i = 0; i < n; ++i)
+    {
+               if (table[i] == missile->TargetUnit)
+               {       // cannot hit target unit
+                       continue;
+               }
+               if (table[i]->HP)
+               {
+                   HitUnit(missile->SourceUnit, table[i], 1);
+               }
     }
 }
 
@@ -498,2014 +468,1426 @@
 --     Functions
 ----------------------------------------------------------------------------*/
 
+// ****************************************************************************
+// Cast the Spell
+// ****************************************************************************
+
+//     Blizzard
+//   NOTE: vladi: blizzard differs than original in this way:
+//   original: launches 50 shards at 5 random spots x 10 for 25 mana.
+
 /**
-**     Spells constructor, inits spell id's and sounds
+**     Cast blizzard.
+**
+**     @param caster   Unit that casts the spell
+**     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
+**
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-global void InitSpells(void)
+global int CastBlizzard(Unit* caster, const SpellType* spell,
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    int z;
-
-    for( z=0; SpellTypeTable[z].Ident; ++z ) {
-       SpellTypeTable[z].Casted.Sound =
-               SoundIdForName(SpellTypeTable[z].Casted.Name);
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(x in range, y in range);
 
-       if (!SpellTypeTable[z].Casted.Sound) {
-           DebugLevel0Fn("cannot get SoundId for `%s'\n" _C_
-                         SpellTypeTable[z].Casted.Name);
-       }
+    int fields;
+    int shards;
+    int damage;
+    Missile *mis = NULL;
+    int sx;
+    int sy;
+    int dx;
+    int dy;
+    int i;
 
-       if( SpellTypeTable[z].Missile.Name ) {
-           SpellTypeTable[z].Missile.Missile =
-                   MissileTypeByIdent(SpellTypeTable[z].Missile.Name);
-       }
+    fields = spell->SpellAction->blizzard.fields;
+    shards = spell->SpellAction->blizzard.shards;
+       damage = spell->SpellAction->blizzard.damage;
+    while (fields--)
+    {
+       // FIXME : radius configurable...
+               do {
+                   // find new destination in the map
+                   dx = x + SyncRand() % 5 - 2;
+                   dy = y + SyncRand() % 5 - 2;
+               } while (dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= 
TheMap.Height);
+               sx = dx - 4;
+               sy = dy - 4;
+               for (i = 0; i < shards; ++i)
+               {
+                   mis = MakeMissile(spell->Missile,
+                                                           sx * TileSizeX + 
TileSizeX / 2,
+                                                           sy * TileSizeY + 
TileSizeY / 2,
+                                                           dx * TileSizeX + 
TileSizeX / 2,
+                                                           dy * TileSizeY + 
TileSizeY / 2);
+                       if (mis->Type->Speed)
+                       {
+                       mis->Delay = i * mis->Type->Sleep * 2 * TileSizeX / 
mis->Type->Speed;
+                       }
+                       else
+                       {
+                               DebugLevel0Fn("Missile-type '%s' must have 
speed non null" _C_ spell->Missile->Ident);
+                               // Or assert();
+                               // warning : bad conf.
+                       }
+                   mis->Damage = damage;
+                   // FIXME: not correct -- blizzard should continue even if 
mage is
+                   //       destroyed (though it will be quite short time...)
+                   mis->SourceUnit = caster;
+                   RefsDebugCheck(!caster->Refs || caster->Destroyed);
+                   caster->Refs++;
+               }
     }
-    SpellTypeCount = z;
-
-    MissileTypeCustom = MissileTypeByIdent("missile-custom");
-    MissileTypeHealing = MissileTypeByIdent("missile-heal-effect");
-    MissileTypeFireball = MissileTypeByIdent("missile-fireball");
-    MissileTypeSpell = MissileTypeByIdent("missile-normal-spell");
-    MissileTypeExorcism = MissileTypeByIdent("missile-exorcism");
-    MissileTypeRune = MissileTypeByIdent("missile-rune");
-    MissileTypeWhirlwind = MissileTypeByIdent("missile-whirlwind");
-    MissileTypeBlizzard = MissileTypeByIdent("missile-blizzard");
-    MissileTypeDeathCoil = MissileTypeByIdent("missile-death-coil");
-    MissileTypeDeathDecay = MissileTypeByIdent("missile-death-and-decay");
-
-    DebugCheck( !MissileTypeHealing );
-}
-
-/**
-**     Spells destructor (currently does nothing)
-*/
-global void DoneSpells()
-{
-    // nothing yet
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    caster->Mana -= spell->ManaCost;
+       return caster->Mana > spell->ManaCost;
 }
 
 /**
-**     Get the numeric spell id by string identifer.
+**     Cast circle of power.
 **
-**     @param ident    Spell identifier
+**     @param caster   Unit that casts the spell
+**     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         Spell id (index in spell-type table)
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-global int SpellIdByIdent(const char *ident)
+global int CastCircleOfPower(Unit* caster, const SpellType* spell 
__attribute__((unused)),
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    int z;
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(spell->SpellAction->circleofpower.goal);
+//     assert(x in range, y in range);
 
-    // FIXME: support hash
-    for (z = 0; SpellTypeTable[z].Ident; ++z) {
-       if (strcmp(SpellTypeTable[z].Ident, ident) == 0) {
-           return z;
-       }
-    }
-    return -1;
+    // FIXME: vladi: cop should be placed only on explored land
+    Unit *cop = NULL;
+       UnitType *ucop = spell->SpellAction->circleofpower.goal;
+
+    cop = caster->Goal;
+    if (cop)
+    {
+               // FIXME: if cop is already defined --> move it, but it doesn't 
work?
+               RemoveUnit(cop, NULL);
+               PlaceUnit(cop, x, y);
+    }
+    else
+    {
+               cop = MakeUnitAndPlace(x, y, ucop, &Players[PlayerMax - 1]);
+    }
+           MakeMissile(spell->Missile,
+               x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
+               x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
+    // Next is used to link to destination circle of power
+    caster->Goal = cop;
+    RefsDebugCheck(!cop->Refs || cop->Destroyed);
+    cop->Refs++;
+    //FIXME: setting destination circle of power should use mana
+    return 0;
 }
 
 /**
-**     Get spell-type struct pointer by string identifier.
+**     Cast death and decay.
 **
-**     @param ident    Spell identifier.
+**     @param caster   Unit that casts the spell
+**     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         spell-type struct pointer.
+**     @return         =!0 if spell should be repeated, 0 if not
+**     @todo   unify DeathAndDecay and blizzard function. (if possible)
 */
-global SpellType *SpellTypeByIdent(const char *ident)
+global int CastDeathAndDecay(Unit* caster, const SpellType* spell,
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    int z;
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(x in range, y in range);
+
+    int fields;                        // blizzard thing, yep :)
+    int shards;
+       int damage;
+    Missile *mis = NULL;
+    int dx;
+    int dy;
+    int i;
 
-    for (z = 0; SpellTypeTable[z].Ident; ++z) {
-       if (!strcmp(SpellTypeTable[z].Ident, ident)) {
-           return &SpellTypeTable[z];
+    fields = spell->SpellAction->deathanddecay.fields;
+    shards = spell->SpellAction->deathanddecay.shards;
+       damage = spell->SpellAction->deathanddecay.damage;
+    while (fields--)
+    {
+               do {
+                   // find new destination in the map
+                   dx = x + SyncRand() % 5 - 2;
+                   dy = y + SyncRand() % 5 - 2;
+               } while (dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= 
TheMap.Height);
+               for (i = 0; i < shards; ++i)
+               {
+                   mis = MakeMissile(spell->Missile,
+                           dx * TileSizeX + TileSizeX / 2, dy * TileSizeY + 
TileSizeY / 2,
+                           dx * TileSizeX + TileSizeX / 2, dy * TileSizeY + 
TileSizeY / 2);
+                   mis->Damage = damage;
+                   //FIXME: not correct -- death and decay should continue 
even if
+                   //       death knight is destroyed (though it will be quite
+                   //       short time...)
+                   mis->Delay = i * mis->Type->Sleep
+                           * VideoGraphicFrames(mis->Type->Sprite);
+                   mis->SourceUnit = caster;
+                   RefsDebugCheck(!caster->Refs || caster->Destroyed);
+                   caster->Refs++;
+               }
        }
-    }
-    return NULL;
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    caster->Mana -= spell->ManaCost;
+    return (caster->Mana > spell->ManaCost);
 }
 
-/*
-**     Get spell-type struct ptr by id
+/**
+**     Cast death coil.
 **
-**     @param id  Spell id (index in the spell-type table)
+**     @param caster   Unit that casts the spell
+**     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return spell-type struct ptr
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-global SpellType *SpellTypeById(int id)
+global int CastDeathCoil(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    DebugCheck(id < 0 || id >= SpellTypeCount);
-    // if ( id < 0 || id >= SpellTypeCount ) return NULL;
-    return &SpellTypeTable[id];
+    assert(caster);
+    assert(spell);
+    assert(spell->SpellAction);
+//     assert(target);
+//     assert(x in range, y in range);
+
+    Missile *mis = NULL;
+    int sx = caster->X;
+    int sy = caster->Y;
+
+    caster->Mana -= spell->ManaCost;
+
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    mis = MakeMissile(spell->Missile,
+       sx * TileSizeX + TileSizeX / 2, sy * TileSizeY + TileSizeY / 2,
+       x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
+    mis->SourceUnit = caster;
+    RefsDebugCheck(!caster->Refs || caster->Destroyed);
+    caster->Refs++;
+    if (target)
+    {
+       mis->TargetUnit = target;
+       RefsDebugCheck(!target->Refs || target->Destroyed);
+       target->Refs++;
+    }
+    mis->Controller = SpellDeathCoilController;
+    return 0;
 }
 
 /**
-**     Check if healing can be cast on the target.
+**     Cast fireball.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastHealing(const Unit* target,
-    const SpellType* spell __attribute__((unused)))
+global int CastFireball(Unit* caster, const SpellType* spell,
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    // only can heal organic units, with injury.
-    if (target && target->Type->Organic
-           && target->HP<target->Stats->HitPoints ) {
-       return 1;
-    }
-    // FIXME: johns: should we support healing near own units?
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(target);
+//     assert(x in range, y in range);
+       assert(spell->Missile);
+
+    Missile *missile = NULL;
+    int sx;
+    int sy;
+    int dist;
+
+    // NOTE: fireball can be casted on spot
+    sx = caster->X;
+    sy = caster->Y;
+    dist = MapDistance(sx, sy, x, y);
+       assert(dist != 0);
+    x += ((x - sx) * 10) / dist;
+    y += ((y - sy) * 10) / dist;
+    sx = sx * TileSizeX + TileSizeX / 2;
+    sy = sy * TileSizeY + TileSizeY / 2;
+    x = x * TileSizeX + TileSizeX / 2;
+    y = y * TileSizeY + TileSizeY / 2;
+    caster->Mana -= spell->ManaCost;
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    missile = MakeMissile(spell->Missile, sx, sy, x, y);
+    missile->State = spell->SpellAction->fireball.TTL - (dist - 1) * 2;
+    missile->TTL = spell->SpellAction->fireball.TTL;
+    missile->Controller = SpellFireballController;
+    missile->SourceUnit = caster;
+    RefsDebugCheck(!caster->Refs || caster->Destroyed);
+    caster->Refs++;
     return 0;
 }
 
 /**
-**     Check if exorcism can be cast on the target.
+**     Cast flame shield.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastExorcism(const Unit* target,
-    const SpellType* spell __attribute__((unused)))
+global int CastFlameShield(Unit* caster, const SpellType* spell, Unit* target,
+    int x __attribute__((unused)), int y __attribute__((unused)))
 {
-    // FIXME: johns: target is random selected within range of 6 fields
-    // exorcism works only on undead units
-    if (target && target->Type->IsUndead && target->HP ) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(target);
+//     assert(x in range, y in range);
+       assert(spell->Missile);
+
+       Missile* mis = NULL;
+       int     i;
+
+       // get mana cost
+       caster->Mana -= spell->ManaCost;
+       target->FlameShield = spell->SpellAction->flameshield.TTL;
+       PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+       for (i = 0; i < 5; i++)
+       {
+               mis = MakeMissile(spell->Missile, 0, 0, 0, 0);
+               mis->TTL = spell->SpellAction->flameshield.TTL + i * 7;
+               mis->TargetUnit = target;
+               mis->Controller = SpellFlameShieldController;
+               RefsDebugCheck(!target->Refs || target->Destroyed);
+               target->Refs++;
+       }
     return 0;
 }
 
 /**
-**     Check if slow can be cast on the target.
+**     Cast haste.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastSlow(const Unit* target, const SpellType* spell)
+global int CastHaste(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    // slow doesn't work on buildings
-    if (target && !target->Type->Building
-           && target->Slow < spell->TTL / CYCLES_PER_SECOND) {
-       return 1;
-    }
-    return 0;
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(target);
+
+       struct s_haste  *haste;
+       // get mana cost
+       caster->Mana -= spell->ManaCost;
+
+       for (haste = &spell->SpellAction->haste; haste != NULL; haste = 
haste->next)
+       {
+               // FIXME modify unit (slow, bloodlust, ..) -> flag[] ?
+               switch (haste->flag)
+               {
+                       case flag_slow:
+                       {
+                               target->Slow = haste->value / CYCLES_PER_SECOND;
+                               break;
+                       }
+                       case flag_haste:
+                       {
+                               target->Haste = haste->value / 
CYCLES_PER_SECOND;
+                               break;
+                       }
+                       case flag_bloodlust:
+                       {
+                               target->Bloodlust = haste->value / 
CYCLES_PER_SECOND;
+                               break;
+                       }
+                       case flag_HP:
+                       {
+                               target->HP = haste->value;
+                               if (target->HP <= 0)
+                               {
+                                       target->HP = 1; // could be to 0 ??
+                               }
+                               if (target->Stats->HitPoints < target->HP)
+                               {
+                                       target->HP = target->Stats->HitPoints;
+                               }
+                               break;
+                       }
+                       case flag_Mana:
+                       {
+                               target->Mana = haste->value;
+                               if (MaxMana < target->Mana) // What is Maxmana 
per unit.
+                               {
+                                       target->Mana = MaxMana;
+                               }
+                               break;
+                       }
+                       case flag_HP_percent:
+                       {
+                               target->HP = target->HP * haste->value / 100;
+                               if (target->HP < 0)
+                               {
+                                       target->HP = 1; // could be to 0 ??
+                               }
+                               if (target->Stats->HitPoints < target->HP)
+                               {
+                                       target->HP = target->Stats->HitPoints;
+                               }
+                               break;
+                       }
+                       case flag_Mana_percent:
+                       {
+                               target->Mana = target->Mana * haste->value / 
100;
+                               if (MaxMana < target->Mana)// What is Maxmana 
per unit.
+                               {
+                                       target->Mana = MaxMana;
+                               }
+                               break;
+                       }
+                       default:
+                       {
+                               // Warn devellopers
+                               assert(0);
+                       }
+               }
+       }
+       CheckUnitToBeDrawn(target);
+       PlayGameSound(spell->SoundWhenCasted.Sound,MaxSampleVolume);
+       MakeMissile(spell->Missile,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
+       return 0;
 }
 
 /**
-**     Check if flame shield can be cast on the target.
+**     Cast healing. (or exorcism)
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastFlameShield(const Unit* target, const SpellType* spell)
+global int CastHealing(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    // flame shield only on land and sea units
-    if (target && !target->Type->Building
-           && (target->Type->UnitType == UnitTypeLand
-               || target->Type->UnitType == UnitTypeNaval)
-           && target->FlameShield < spell->TTL ) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(target);
+
+       int     i;
+       int     diffHP;
+       int diffMana = caster->Mana;
+       int     HP = spell->SpellAction->healing.HP;
+       int Mana = spell->ManaCost;
+
+       // Healing or exorcism
+       diffHP = (HP > 0) ? target->Stats->HitPoints - target->HP : target->HP;
+       i = min(diffHP / HP + (diffHP % HP ? 1 : 0),
+                       diffMana / Mana + (diffMana % Mana ? 1 : 0));
+       // Stop when no mana or full HP
+    caster->Mana -= i * Mana;
+    target->HP += i * HP;
+       if (HP < 0)
+       {
+#ifdef USE_HP_FOR_XP
+               caster->XP += i * HP;
+#endif
+               if (!target->HP)
+               {
+                   caster->Player->Score += target->Type->Points;
+                   if (target->Type->Building)
+                   {
+                               caster->Player->TotalRazings++;
+                   }
+                   else
+                   {
+                               caster->Player->TotalKills++;
+                   }
+#ifndef USE_HP_FOR_XP
+                   caster->XP += target->Type->Points;
+#endif
+                   caster->Kills++;
+                   LetUnitDie(target);
+               }
+       }
+       PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+       MakeMissile(spell->Missile,
+                           x * TileSizeX + TileSizeX / 2, y * TileSizeY + 
TileSizeY / 2,
+                           x * TileSizeX + TileSizeX / 2, y * TileSizeY + 
TileSizeY / 2);
     return 0;
 }
 
 /**
-**     Check if invisibility can be cast on the target.
+**     Cast holy vision.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastInvisibility(const Unit* target, const SpellType* spell)
+global int CastHolyVision(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    // invisible doesn't work on buildings
-    if (target && !target->Type->Building
-           && target->Invisible < spell->TTL / CYCLES_PER_SECOND) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(x in range, y in range);
+
+    caster->Mana -= spell->ManaCost;   // get mana cost
+    // FIXME Do a fonction to reveal map (use for attack revealer) instead of 
create unit
+    target = MakeUnit(spell->SpellAction->holyvision.revealer, caster->Player);
+    target->Orders[0].Action = UnitActionStill;
+    target->HP = 0;
+    target->X = x;
+    target->Y = y;
+//    target->TTL = GameCycle + CYCLES_PER_SECOND + CYCLES_PER_SECOND / 2;
+    target->CurrentSightRange = target->Stats->SightRange;
+    target->Removed = 1;
+    MapMarkUnitSight(target);
+    target->TTL = GameCycle + target->Type->DecayRate * 6 * CYCLES_PER_SECOND;
+    CheckUnitToBeDrawn(target);
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
     return 0;
 }
 
 /**
-**     Check if polymorph can be cast on the target.
+**     Cast invisibility. (or CastUnholyArmor)
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastPolymorph(const Unit* target,
-    const SpellType* spell __attribute__((unused)))
+global int CastInvisibility(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    // only can polymorph organic units
-    if (target && target->Type->Organic) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(target);
+       assert(spell->SpellAction->invisibility.missile);
+
+       // get mana cost
+       caster->Mana -= spell->ManaCost;
+       if (target->Type->Volatile)
+       {
+           RemoveUnit(target,NULL);
+           UnitLost(target);
+           UnitClearOrders(target);
+           ReleaseUnit(target);
+           MakeMissile(spell->SpellAction->invisibility.missile,
+                                   x * TileSizeX + TileSizeX / 2, y * 
TileSizeY + TileSizeY / 2,
+                                   x * TileSizeX + TileSizeX / 2, y * 
TileSizeY + TileSizeY / 2);
+       }
+       else
+       {
+               switch (spell->SpellAction->invisibility.flag)
+               {
+                       case flag_invisibility:
+                       {
+                               target->Invisible = 
spell->SpellAction->invisibility.value;
+                               target->Invisible /= CYCLES_PER_SECOND;
+                       }
+                       case flag_unholyarmor:
+                       {
+                               target->UnholyArmor = 
spell->SpellAction->invisibility.value;
+                               target->UnholyArmor /= CYCLES_PER_SECOND;
+                       }
+                       default:
+                       {
+                               assert(0);
+                               // Warn devellopers
+                       }
+               }
+               CheckUnitToBeDrawn(target);
+       }
+       PlayGameSound(spell->SoundWhenCasted.Sound,MaxSampleVolume);
+       MakeMissile(spell->Missile,
+                               x * TileSizeX + TileSizeX / 2, y * TileSizeY + 
TileSizeY / 2,
+                               x * TileSizeX + TileSizeX / 2, y * TileSizeY + 
TileSizeY / 2 );
     return 0;
 }
 
 /**
-**     Check if bloodlust can be cast on the target.
+**     Cast polymorph.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastBloodlust(const Unit* target, const SpellType* spell)
+global int CastPolymorph(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    if (target && target->Type->Organic
-           && target->Bloodlust < spell->TTL / CYCLES_PER_SECOND) {
-       return 1;
-    }
-    // FIXME: should we support making bloodlust in range?
-    return 0;
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(target);
+       assert(spell->SpellAction->polymorph.unit);
+
+       UnitType* type = spell->SpellAction->polymorph.unit;
+
+       caster->Player->Score += target->Type->Points;
+       if (target->Type->Building)
+       {
+       caster->Player->TotalRazings++;
+       }
+       else
+       {
+       caster->Player->TotalKills++;
+       }
+#ifdef USE_HP_FOR_XP
+       caster->XP += target->HP;
+#else
+       caster->XP += target->Type->Points;
+#endif
+       caster->Kills++;
+       // as said somewhere else -- no corpses :)
+       RemoveUnit(target,NULL);
+       UnitLost(target);
+       UnitClearOrders(target);
+       ReleaseUnit(target);
+       if (UnitTypeCanMoveTo(x, y, type))
+       {
+           MakeUnitAndPlace(x, y, type, Players + PlayerNumNeutral);
+       }
+       caster->Mana -= spell->ManaCost;
+       PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+       MakeMissile(spell->Missile,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
+       return 0;
 }
 
 /**
-**     Check if death coil can be cast on the target.
+**     Cast raise dead.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastDeathCoil(const Unit* target,
-    const SpellType* spell __attribute__((unused)))
+global int CastRaiseDead(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    if ((target && target->Type->Organic) || (!target)) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(spell->SpellAction->raisedead.skeleton != NULL);
+//     assert(x in range, y in range);
+
+       Unit **corpses;
+    Unit *tempcorpse;
+
+    corpses = &CorpseList;
+       UnitType *skeleton = spell->SpellAction->raisedead.skeleton;
+
+    while (caster->Mana >= spell->ManaCost && *corpses)
+    {
+       // FIXME: this tries to raise all corps, ohje
+       // FIXME: I can raise ships?
+               if ((*corpses)->Orders[0].Action == UnitActionDie
+                       && !(*corpses)->Type->Building
+                       && (*corpses)->X >= x - 1 && (*corpses)->X <= x + 1
+                       && (*corpses)->Y >= y - 1 && (*corpses)->Y <= y + 1)
+               {
+                   // FIXME: did they count on food?
+                   // Can there be more than 1 skeleton created on the same 
tile? yes
+                   target = MakeUnit(skeleton, caster->Player);
+                   target->X = (*corpses)->X;
+                   target->Y = (*corpses)->Y;
+                   DropOutOnSide(target,LookingW,0,0);
+                   // set life span
+                   target->TTL = GameCycle + target->Type->DecayRate * 6 * 
CYCLES_PER_SECOND;
+                   CheckUnitToBeDrawn(target);
+                   tempcorpse = *corpses;
+                   corpses = &(*corpses)->Next;
+                   ReleaseUnit(tempcorpse);
+                   caster->Mana -= spell->ManaCost;
+                   corpses = &(*corpses)->Next;
+           }
+       }
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    MakeMissile(spell->Missile,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
+           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
     return 0;
 }
 
 /**
-**     Check if haste can be cast on the target.
+**     Cast runes.
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastHaste(const Unit* target, const SpellType* spell)
+global int CastRunes(Unit* caster, const SpellType* spell,
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    if (target && !target->Type->Building
-           && target->Haste < spell->TTL / CYCLES_PER_SECOND) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(x in range, y in range);
+
+    Missile *mis = NULL;
+       const int       xx[] = {-1, +1, 0, 0, 0};
+       const int       yy[] = {0, 0, 0, -1, +1};
+
+       int     oldx = x;
+       int     oldy = y;
+       int     i;
+
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+       for (i = 0; i < 5; i++)
+       {
+               x = oldx + xx[i];
+               y = oldy + yy[i];
+               
+           if (IsMapFieldEmpty(x - 1, y + 0))
+           {
+                       mis = MakeMissile(spell->Missile,
+                                                               x * TileSizeX + 
TileSizeX / 2,
+                                                               y * TileSizeY + 
TileSizeY / 2,
+                                                               x * TileSizeX + 
TileSizeX / 2,
+                                                               y * TileSizeY + 
TileSizeY / 2);
+                       mis->TTL = spell->SpellAction->runes.TTL;
+                       mis->Controller = SpellRunesController;
+                       caster->Mana -= spell->ManaCost / 5;
+           }
+       }
     return 0;
 }
 
 /**
-**     Check if unholy armor can be cast on the target.
+**     Cast eye of vision. (summon)
 **
-**     @param target   Target unit that spell is addressed to
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
+**     @param target   Target unit that spell is addressed to
+**     @param x        X coord of target spot when/if target does not exist
+**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-local int CanCastUnholyArmor(const Unit* target, const SpellType* spell)
+global int CastSummon(Unit* caster, const SpellType* spell, Unit* target,
+    int x, int y)
 {
-    if (target && !target->Type->Building
-           && target->UnholyArmor < spell->TTL / CYCLES_PER_SECOND) {
-       return 1;
-    }
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+       assert(spell->SpellAction->summon.unittype != NULL);
+//     assert(x in range, y in range);
+
+    caster->Mana -= spell->ManaCost;
+    // FIXME: johns: the unit is placed on the wrong position
+    target = MakeUnit(spell->SpellAction->summon.unittype, caster->Player);
+    target->X = x;
+    target->Y = y;
+    DropOutOnSide(target, LookingW, 0, 0);
+
+    // set life span
+    target->TTL = GameCycle + target->Type->DecayRate * 6 * CYCLES_PER_SECOND;
+    CheckUnitToBeDrawn(target);
+
+    PlayGameSound(spell->SoundWhenCasted.Sound,MaxSampleVolume);
+    MakeMissile(spell->Missile,
+               x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
+               x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
     return 0;
 }
 
 /**
-**     Check if unit can cast the spell.
+**     Cast whirlwind.
 **
-**     @param unit     Unit that casts the spell
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
 **     @param target   Target unit that spell is addressed to
 **     @param x        X coord of target spot when/if target does not exist
 **     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should/can casted, 0 if not
+**     @return         =!0 if spell should be repeated, 0 if not
 */
-global int CanCastSpell(const Unit* unit, const SpellType* spell,
-    const Unit* target, int x __attribute__((unused)),
-    int y __attribute__((unused)))
+global int CastWhirlwind(Unit* caster, const SpellType* spell,
+    Unit* target __attribute__((unused)), int x, int y)
 {
-    DebugCheck(spell == NULL);
-    DebugCheck(!unit->Type->CanCastSpell);     // NOTE: this must not happen
+       assert(caster);
+       assert(spell);
+       assert(spell->SpellAction);
+//     assert(x in range, y in range);
+
+    Missile *mis = NULL;
+
+    caster->Mana -= spell->ManaCost;
+    PlayGameSound(spell->SoundWhenCasted.Sound, MaxSampleVolume);
+    mis = MakeMissile(spell->Missile,
+               x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
+               x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
+    mis->TTL = spell->SpellAction->whirlwind.TTL;
+    mis->Controller = SpellWhirlwindController;
+    return 0;
+}
 
-    if (unit->Mana < spell->ManaCost) {                // mana is a must!
-       return 0;
-    }
+// ****************************************************************************
+//     Specific conditions
+// ****************************************************************************
+
+/* *************************************
+** property of unittype himself
+*/
+global int             CheckUnitTypeFlag(const t_Conditions    *condition,
+                                                                       const 
Unit* caster,
+                                                                       const 
Unit* target, int x, int y)
+{
+       assert(caster != NULL);
+       assert(condition != NULL);
+
+       if (target == NULL)
+               return !condition->expectvalue;
+       // FIXME Modify unit struture for an array of boolean ?
+       switch (condition->u.flag)
+       {
+               case flag_coward:
+               {
+                       return target->Type->Coward;
+               }
+               case flag_organic:
+               {
+                       return target->Type->Organic;
+               }
+               case flag_isundead:
+               {
+                       return target->Type->IsUndead;
+               }
+               case flag_canattack:
+               {
+                       return target->Type->CanAttack;
+               }
+               case flag_building:
+               {
+                       return target->Type->Building;
+               }
+               default:
+               {
+                       assert(0);
+                       // Warn devellopers
+               }
+       }
+}
 
-    switch (spell->Action) {
-       case SpellActionNone:
-           DebugLevel0Fn("No spell action\n");
-           return 0;
+/* *************************************
+** property of alliance
+*/
+global int             CheckAllied(const t_Conditions  *condition,
+                                                       const Unit* caster,
+                                                       const Unit* target, int 
x, int y)
+{
+       assert(caster != NULL);
+
+       return caster->Player == target->Player
+               ||IsAllied(caster->Player, target) ? 1 : 0;
+}
 
-//  ---human paladins---
-       case SpellActionHolyVision:
-           return 1;
+/* *************************************
+** property of alliance
+*/
+global int             Checkhimself(const t_Conditions *condition,
+                                                       const Unit* caster,
+                                                       const Unit* target, int 
x, int y)
+{
+       assert(caster != NULL);
 
-       case SpellActionHealing:
-           return CanCastHealing(target, spell);
+       return caster == target;
+}
 
-       case SpellActionExorcism:
-           return CanCastExorcism(target, spell);
+/* *************************************
+** property of target unit itself (no type specific)
+*/
+global int             CheckUnitDurationEffect(const t_Conditions      
*condition,
+                                                                               
const Unit* caster,
+                                                                               
const Unit* target, int x, int y)
+{
+       assert(condition);
 
-//  ---human mages---
-       case SpellActionFireball:
-           return 1;
+       if (target == NULL)
+               return !condition->expectvalue;
+       unsigned int    ttl = condition->u.durationeffect.ttl;
 
-       case SpellActionSlow:
-           return CanCastSlow(target, spell);
+       switch (condition->u.durationeffect.flag)
+       {
+               case flag_invisibility:
+               {
+                       return (target->Invisible >= ttl / CYCLES_PER_SECOND);
+               }
+               case flag_bloodlust:
+               {
+                       return (target->Bloodlust >= ttl / CYCLES_PER_SECOND);
+               }
+               case flag_slow:
+               {
+                       return (target->Slow >= ttl / CYCLES_PER_SECOND);
+               }
+               case flag_haste:
+               {
+                       return (target->Haste >= ttl / CYCLES_PER_SECOND);
+               }
+               case flag_unholyarmor:
+               {
+                       return (target->UnholyArmor >= ttl / CYCLES_PER_SECOND);
+               }
+               case flag_flameshield:
+               {
+                       return (target->FlameShield >= ttl);
+               }
+               case flag_HP:
+               {
+                       return (target->HP >= ttl);
+               }
+               case flag_Mana:
+               {
+                       return (target->Mana >= ttl);
+               }
+               case flag_HP_percent:
+               {
+                       return (target->HP * 100 >= ttl * 
target->Stats->HitPoints); // FIXME
+               }
+               case flag_Mana_percent:
+               {
+                       return (target->Mana * 100 >= ttl * MaxMana); // FIXME 
: MaxMana.
+               }
+               /// Add here the other cases
+               default:
+               {
+                       abort();
+                       // Warn devellopers
+               }
+       }
+}
 
-       case SpellActionFlameShield:
-           return CanCastFlameShield(target, spell);
+// ****************************************************************************
+//     Specific conditions
+// ****************************************************************************
+
+global int     CheckEnemyPresence(const t_Conditions   *condition,
+                                                       const Unit* caster)
+{
+       assert(condition != NULL);
+       assert(caster != NULL);
+       
+       Unit* table[UnitMax];
+    int i;
+    int n;
+       int range = condition->u.range;
+       int     x = caster->X;
+       int     y = caster->Y;
+
+// +1 should be + Caster_tile_Size ?
+    n = SelectUnits(x - range, y - range,
+                               x + range + 1, y + range + 1,
+                               table);
+    for (i = 0; i < n; ++i)
+    {
+               if (IsEnemy(caster->Player, table[i]))
+               {
+                   return 1;
+               }
+       }
+       return 0;
+}
 
-       case SpellActionInvisibility:
-           return CanCastInvisibility(target, spell);
+// ****************************************************************************
+// Target constructor
+// ****************************************************************************
 
-       case SpellActionPolymorph:
-           return CanCastPolymorph(target, spell);
+local Target *NewTarget(TargetType t, const Unit *unit, int x, int y)
+{
+    Target     *target = (Target *) malloc(sizeof(*target));
 
-       case SpellActionBlizzard:
-           return 1;
+    assert(!(unit == NULL && t == TargetUnit));
+    assert(!(!(0 <= x && x < TheMap.Width) && t == TargetPosition));
+    assert(!(!(0 <= y && y < TheMap.Height) && t == TargetPosition));
 
-//  ---orc ogres---
-       case SpellActionEyeOfVision:
-           return 1;
+    target->which_sort_of_target = t;
+    target->unit = (Unit *)unit;
+    target->X = x;
+    target->Y = y;
+    return target;
+}
 
-       case SpellActionBloodlust:
-           return CanCastBloodlust(target, spell);
+local Target *NewTargetNone()
+{
+    return NewTarget(TargetNone, NULL, 0, 0);
+}
 
-       case SpellActionRunes:
-           return 1;
+local Target   *NewTargetUnit(const Unit *unit)
+{
+    assert(unit != NULL);
 
-//  ---orc death knights---
-       case SpellActionDeathCoil:
-           return CanCastDeathCoil(target, spell);
+    return NewTarget(TargetUnit, unit, 0, 0);
+}
 
-       case SpellActionHaste:
-           return CanCastHaste(target, spell);
 
-       case SpellActionRaiseDead:
-           return 1;
+local Target   *NewTargetPosition(int x, int y)
+{
+    assert(0 <= x && x < TheMap.Width);
+    assert(0 <= y && y < TheMap.Height);
 
-       case SpellActionWhirlwind:
-           return 1;
+    return NewTarget(TargetPosition, NULL, x, y);
+}
 
-       case SpellActionUnholyArmor:
-           return CanCastUnholyArmor(target, spell);
+// ****************************************************************************
+//     Main local functions
+// ****************************************************************************
 
-       case SpellActionDeathAndDecay:
-           return 1;
+/**
+**     Check all generic conditions.
+*/
+local int PassGenericCondition(const Unit* caster,const SpellType* spell,const 
t_Conditions *condition)
+{
+       assert(caster != NULL);
+       assert(spell != NULL);
 
-       case SpellActionCircleOfPower:
-           return 1;
+//     const t_Conditions      *condition = NULL;
+       int     ret;
 
-       default:
-           DebugLevel0Fn("Unknown spell action `%d'\n" _C_ spell->Action);
-           return 0;
-    }
+       // FIXME : Move it in spell->Condition_generic ???
+       // mana is a must!
+    if (caster->Mana < spell->ManaCost)
+       {
+               return 0;
+       }
+       for (/*condition = spell->Condition_generic*/; condition != NULL; 
condition = condition->next)
+       {
+               assert(condition->f.generic != NULL);
+               ret = condition->f.generic(condition, caster);
+               assert(ret == 0 || ret == 1);
+               assert(condition->expectvalue == 0 || condition->expectvalue == 
1);
+               if (ret != condition->expectvalue)
+               {
+                       return 0;
+               }
+       }
+       return 1;
+}
 
-    return 1;
+/**
+**     Check all specific conditions.
+**     @return 1 if condition is ok.
+**     @return 0 else.
+*/
+local int              PassSpecificCondition(const Unit* caster,
+                                                                               
const SpellType* spell,
+                                                                           
const Unit* target,         // FIXME : Use an unique struture t_Target ?
+                                                                               
int x,
+                                                                           int 
y,
+                                                                               
const t_Conditions *condition)
+{
+       assert(caster != NULL);
+       assert(spell != NULL);
+
+//     const t_Conditions      *condition = NULL;
+       int     ret;
+
+       for (/*condition = spell->Condition_specific*/; condition != NULL; 
condition = condition->next)
+       {
+               assert(condition->f.specific != NULL);
+               ret = condition->f.specific(condition, caster, target, x, y);
+               assert(ret == 0 || ret == 1);
+               assert(condition->expectvalue == 0 || condition->expectvalue == 
1);
+               if (ret != condition->expectvalue)
+               {
+                       return 0;
+               }
+       }
+       return 1;
 }
 
+
 /**
-**     Auto cast holy vision if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
+**      Select the target for the autocast.
 **
-**     @return         =!0 if spell can be cast, 0 if not
+**     @param caster   Unit who would cast the spell.
+**     @param spell    Spell-type pointer.
+**     
+**     @return Target* choosen target or Null if spell can't be cast.
+**
+*/
+// should be global (for IA) ???
+local Target   *SelectTargetUnitsOfAutoCast(const Unit *caster,
+                                                                               
        const SpellType *spell)
+{
+       assert(spell != NULL);
+       assert(spell->AutoCast != NULL);
+       assert(caster != NULL);
+
+       switch (spell->which_sort_of_target)
+       {
+               case    TargetSelf :
+               {
+                       return NewTargetUnit(caster);
+               }
+               case    TargetNone :
+               {
+                       return NewTargetNone();
+               }
+               case    TargetPosition:
+               {
+                       int x, y;
+                       int range = spell->AutoCast->Range;
+
+                       do
+                       {
+                               x = caster->X + SyncRand() % (2 * range) - 
range;
+                               y = caster->Y + SyncRand() % (2 * range) - 
range;
+                       } while (x < 0 && x <= TheMap.Width
+                                       && y < 0 && y <= TheMap.Height);
+                       
+                       // FIXME : CHOOSE a better POSITION (add info in 
structure ???)
+                       // Just good enought for holyvision...
+                       return NewTargetPosition(SyncRand() % TheMap.Width,
+                                                                       
SyncRand() % TheMap.Height);
+               }
+               case    TargetUnit:
+               {
+                   Unit* table[UnitMax];
+                   int range = spell->AutoCast->Range;
+                   int nb_units;
+                       int     x = caster->X;
+                       int     y = caster->Y;
+                       int i, j;
+                       // ( + 1) would be ( + caster->size) ??
+                   nb_units = SelectUnits(caster->X - range, caster->Y - range,
+                                                               caster->X + 
range + 1, caster->Y + range + 1,
+                                                               table);
+                       // For all Unit, check if it is a possible target
+                   for (i = 0, j = 0; i < nb_units; i++)
+                       {
+                               if (PassSpecificCondition(caster, spell, 
table[i], x, y,
+                                               spell->Condition_specific)
+                                       && PassSpecificCondition(caster, spell, 
table[i], x, y,
+                                               
spell->AutoCast->Condition_specific))
+                               {
+                                       table[j++] = table[i];
+                               }
+                       }
+                       nb_units = j;
+                       if (nb_units != 0)
+                       {
+#if 0
+// For the best target
+                               sort(table, nb_units, spell->autocast->f_order);
+                               return NewTargetUnit(table[0]);
+#else
+// For a random valid target
+                               i = SyncRand() % nb_units;
+                               return NewTargetUnit(table[i]);
+#endif
+                       }
+               break;
+               }
+               default:
+               {
+                       // Error : add the new cases
+                       // FIXME : Warn developpers
+                       return NULL;
+                       break;
+               }
+       }
+       return NULL;    // Can't spell the auto-cast.
+}
+
+// ****************************************************************************
+//     Public spell functions
+// ****************************************************************************
+
+// ****************************************************************************
+// Constructor and destructor
+// ****************************************************************************
+
+/**
+**     Spells constructor, inits spell id's and sounds
 */
-local int AutoCastHolyVision(Unit* unit, SpellType* spell)
+global void InitSpells(void)
 {
-    int x;
-    int y;
-
-    x = SyncRand() % TheMap.Width;
-    y = SyncRand() % TheMap.Height;
-    CommandSpellCast(unit, x, y, NoUnitP, spell, FlushCommands);
-    return 1;
 }
 
 /**
-**     Auto cast healing if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
+**     Spells destructor (currently does nothing)
 */
-local int AutoCastHealing(Unit* unit, SpellType* spell)
+global void DoneSpells()
 {
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
+// FIXME
+#if 0
 
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
+#endif
+       free(SpellTypeTable);
+    // nothing yet
+}
 
-    for (i = 0, j = 0; i < n; ++i) {
-       // Only cast on ourselves or an ally
-       if (table[i] == unit || (unit->Player != table[i]->Player
-               && !IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
 
-       if (!CanCastHealing(table[i], spell)) {
-           continue;
-       }
+// ****************************************************************************
+// Get Spell.
+// ****************************************************************************
 
-       table[j++] = table[i];
-    }
+/**
+**     Get the numeric spell id by string identifer.
+**
+**     @param IdentName        Spell identifier
+**
+**     @return         Spell id (index in spell-type table)
+*/
+global int SpellIdByIdent(const char *IdentName)
+{
+    assert(IdentName != NULL);
+    int id;
 
-    if (j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
+    for (id = 0; id < SpellTypeCount; ++id) {
+       if (strcmp(SpellTypeTable[id].IdentName, IdentName) == 0) {
+           return id;
+       }
     }
-    return 0;
+    return -1;
 }
 
 /**
-**     Auto cast exorcism if possible.
+**     Get spell-type struct pointer by string identifier.
 **
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
+**     @param IdentName        Spell identifier.
 **
-**     @return         =!0 if spell can be cast, 0 if not
+**     @return         spell-type struct pointer.
 */
-local int AutoCastExorcism(Unit* unit, SpellType* spell)
+global SpellType *SpellTypeByIdent(const char *IdentName)
 {
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
+    assert(IdentName != NULL);
+    int id;
 
-    for (i = 0, j = 0; i < n; ++i) {
-       // Only cast on an enemy
-       if (table[i] == unit || (unit->Player == table[i]->Player
-               || IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
+    id = SpellIdByIdent(IdentName);
+    return (id == -1 ? NULL : &SpellTypeTable[id]);
+}
 
-       if (!CanCastExorcism(table[i], spell)) {
-           continue;
+global unsigned CclGetSpellByIdent(SCM value)
+{  
+    int i;
+    for( i=0; i<SpellTypeCount; ++i ) {
+       if( gh_eq_p(value,gh_symbol2scm(SpellTypeTable[i].IdentName)) ) {
+           return i;
        }
-
-       table[j++] = table[i];
-    }
-
-    if (j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
     }
-    return 0;
+    return 0xABCDEF;
 }
 
 /**
-**     Auto cast slow if possible.
+**     Get spell-type struct ptr by id
 **
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
+**     @param id  Spell id (index in the spell-type table)
 **
-**     @return         =!0 if spell can be cast, 0 if not
+**     @return spell-type struct ptr
 */
-local int AutoCastSlow(Unit* unit, SpellType* spell)
+global SpellType *SpellTypeById(int id)
 {
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-
-    for (i = 0, j = 0; i < n; ++i) {
-       // Only cast on an enemy
-       if (table[i] == unit || (unit->Player == table[i]->Player
-               || IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastSlow(table[i], spell)) {
-           continue;
-       }
-
-       // Skip slow units and units that can't attack
-       if (table[i]->Slow || !table[i]->Type->CanAttack) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast invisibility if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastInvisibility(Unit* unit, SpellType* spell)
-{
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-    int enemy;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-    enemy = 0;
-
-    for (i = 0, j = 0; i < n; ++i) {
-       if (!enemy && IsEnemy(unit->Player, table[i])) {
-           enemy = 1;
-       }
-
-       // Only cast on ourselves or an ally
-       if (table[i] == unit || (unit->Player != table[i]->Player
-               && !IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastInvisibility(table[i], spell)) {
-           continue;
-       }
-
-       // Skip invisible units and cowards
-       if (table[i]->Invisible || table[i]->Type->Coward) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (enemy && j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast eye of vision if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastEyeOfVision(Unit* unit, SpellType* spell)
-{
-    CommandSpellCast(unit, unit->X, unit->Y, NoUnitP, spell, FlushCommands);
-    return 1;
-}
-
-/**
-**     Auto cast bloodlust if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastBloodlust(Unit* unit, SpellType* spell)
-{
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-    int enemy;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-    enemy = 0;
-
-    for (i = 0, j = 0; i < n; ++i) {
-       if (!enemy && IsEnemy(unit->Player, table[i])) {
-           enemy = 1;
-       }
-
-       // Only cast on ourselves or an ally
-       if (table[i] == unit || (unit->Player != table[i]->Player
-               && !IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastBloodlust(table[i], spell)) {
-           continue;
-       }
-
-       // Skip bloodlusted units and cowards
-       if (table[i]->Bloodlust || table[i]->Type->Coward) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (enemy && j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast death coil if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastDeathCoil(Unit* unit, SpellType* spell)
-{
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-
-    for (i = 0, j = 0; i < n; ++i) {
-       // Only cast on an enemy
-       if (table[i] == unit || (unit->Player == table[i]->Player
-               || IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastDeathCoil(table[i], spell)) {
-           continue;
-       }
-
-       // Skip units that can't attack
-       if (!table[i]->Type->CanAttack) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast haste if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastHaste(Unit* unit, SpellType* spell)
-{
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-
-    for (i = 0, j = 0; i < n; ++i) {
-       // Only cast on ourselves or an ally
-       if (table[i] == unit || (unit->Player != table[i]->Player
-               && !IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastHaste(table[i], spell)) {
-           continue;
-       }
-
-       // Skip haste units and cowards
-       if (table[i]->Haste || table[i]->Type->Coward) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast unholy armor if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-local int AutoCastUnholyArmor(Unit* unit, SpellType* spell)
-{
-    Unit* table[UnitMax];
-    int r;
-    int i;
-    int j;
-    int n;
-    int enemy;
-
-    if (unit->Player->Type == PlayerPerson) {
-       r = unit->Type->ReactRangePerson;
-    } else {
-       r = unit->Type->ReactRangeComputer;
-    }
-    if (spell->Range < r) {
-       r = spell->Range;
-    }
-    n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
-       unit->Y + r + 1, table);
-    enemy = 0;
-
-    for (i = 0, j = 0; i < n; ++i) {
-       if (!enemy && IsEnemy(unit->Player, table[i])) {
-           enemy = 1;
-       }
-
-       // Only cast on ourselves or an ally
-       if (table[i] == unit || (unit->Player != table[i]->Player
-               && !IsAllied(unit->Player, table[i]))) {
-           continue;
-       }
-
-       if (!CanCastUnholyArmor(table[i], spell)) {
-           continue;
-       }
-
-       // Skip unholy armor units and cowards
-       if (table[i]->UnholyArmor || table[i]->Type->Coward) {
-           continue;
-       }
-
-       table[j++] = table[i];
-    }
-
-    if (enemy && j) {
-       j = SyncRand() % j;
-       CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
-       return 1;
-    }
-    return 0;
-}
-
-/**
-**     Auto cast the spell if possible.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-global int AutoCastSpell(Unit* unit, SpellType* spell)
-{
-    DebugCheck(spell == NULL);
-    DebugCheck(!unit->Type->CanCastSpell);     // NOTE: this must not happen
-
-    if (unit->Mana < spell->ManaCost) {                // mana is a must!
-       return 0;
-    }
-
-    switch (spell->Action) {
-       case SpellActionNone:
-           DebugLevel0Fn("No spell action\n");
-           return 0;
-
-//  ---human paladins---
-       case SpellActionHolyVision:
-           return AutoCastHolyVision(unit, spell);
-
-       case SpellActionHealing:
-           return AutoCastHealing(unit, spell);
-
-       case SpellActionExorcism:
-           return AutoCastExorcism(unit, spell);
-
-//  ---human mages---
-       case SpellActionFireball:
-           return 0;
-
-       case SpellActionSlow:
-           return AutoCastSlow(unit, spell);
-
-       case SpellActionFlameShield:
-           return 0;
-
-       case SpellActionInvisibility:
-           return AutoCastInvisibility(unit, spell);
-
-       case SpellActionPolymorph:
-           return 0;
-
-       case SpellActionBlizzard:
-           return 0;
-
-//  ---orc ogres---
-       case SpellActionEyeOfVision:
-           return AutoCastEyeOfVision(unit, spell);
-
-       case SpellActionBloodlust:
-           return AutoCastBloodlust(unit, spell);
-
-       case SpellActionRunes:
-           return 0;
-
-//  ---orc death knights---
-       case SpellActionDeathCoil:
-           return AutoCastDeathCoil(unit, spell);
-
-       case SpellActionHaste:
-           return AutoCastHaste(unit, spell);
-
-       case SpellActionRaiseDead:
-           return 0;
-
-       case SpellActionWhirlwind:
-           return 0;
-
-       case SpellActionUnholyArmor:
-           return AutoCastUnholyArmor(unit, spell);
-
-       case SpellActionDeathAndDecay:
-           return 0;
-
-       case SpellActionCircleOfPower:
-           return 0;
-
-       default:
-           DebugLevel0Fn("Unknown spell action `%d'\n" _C_ spell->Action);
-           return 0;
-    }
-
-    return 0;
-}
-
-/**
-**     Check if the spell can be auto cast.
-**
-**     @param spell    Spell-type pointer
-**
-**     @return         =!0 if spell can be cast, 0 if not
-*/
-global int CanAutoCastSpell(const SpellType* spell)
-{
-    DebugCheck(spell == NULL);
-
-    switch (spell->Action) {
-       case SpellActionNone:
-           DebugLevel0Fn("No spell action\n");
-           return 0;
-
-//  ---human paladins---
-       case SpellActionHolyVision:
-           return 1;
-
-       case SpellActionHealing:
-           return 1;
-
-       case SpellActionExorcism:
-           return 1;
-
-//  ---human mages---
-       case SpellActionFireball:
-           return 0;
-
-       case SpellActionSlow:
-           return 1;
-
-       case SpellActionFlameShield:
-           return 0;
-
-       case SpellActionInvisibility:
-           return 1;
-
-       case SpellActionPolymorph:
-           return 0;
-
-       case SpellActionBlizzard:
-           return 0;
-
-//  ---orc ogres---
-       case SpellActionEyeOfVision:
-           return 1;
-
-       case SpellActionBloodlust:
-           return 1;
-
-       case SpellActionRunes:
-           return 0;
-
-//  ---orc death knights---
-       case SpellActionDeathCoil:
-           return 1;
-
-       case SpellActionHaste:
-           return 1;
-
-       case SpellActionRaiseDead:
-           return 0;
-
-       case SpellActionWhirlwind:
-           return 0;
-
-       case SpellActionUnholyArmor:
-           return 1;
-
-       case SpellActionDeathAndDecay:
-           return 0;
-
-       case SpellActionCircleOfPower:
-           return 0;
-
-       default:
-           DebugLevel0Fn("Unknown spell action `%d'\n" _C_ spell->Action);
-           return 0;
-    }
-
-    return 0;
-}
-
-/**
-**     Cast holy vision.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastHolyVision(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    unit->Mana -= spell->ManaCost;     // get mana cost
-    // FIXME: Don't use UnitTypeByIdent during runtime.
-    target = MakeUnit(UnitTypeByIdent("unit-revealer"), unit->Player);
-    target->Orders[0].Action = UnitActionStill;
-    target->HP = 0;
-    target->X = x;
-    target->Y = y;
-    target->TTL=GameCycle+CYCLES_PER_SECOND+CYCLES_PER_SECOND/2;
-    target->CurrentSightRange=target->Stats->SightRange;
-
-    target->Removed=1;
-    MapMarkUnitSight(target);
-
-    target->TTL=GameCycle+target->Type->DecayRate*6*CYCLES_PER_SECOND;
-    CheckUnitToBeDrawn(target);
-    PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-
-    return 0;
-}
-
-/**
-**     Cast healing.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastHealing(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    // only can heal organic units
-    if (target && target->Type->Organic) {
-       // FIXME: johns this can be calculated
-       while (target->HP < target->Stats->HitPoints
-              && unit->Mana > spell->ManaCost) {
-           unit->Mana -= spell->ManaCost;      // get mana cost
-           target->HP++;
-       }
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeHealing,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    } else {
-       // FIXME: johns: should we support healing near own units?
-    }
-
-    return 0;
-}
-
-/**
-**     Cast exorcism.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastExorcism(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    // FIXME: johns: the target is random selected within range of 6 fields
-    // exorcism works only on undead units
-    if (target && target->Type->IsUndead) {
-       // FIXME: johns this can be calculated
-       while (target->HP && unit->Mana > spell->ManaCost) {
-           unit->Mana -= spell->ManaCost;      // get mana cost
-           target->HP--;
-#ifdef USE_HP_FOR_XP
-           unit->XP++;
-#endif
-       }
-       if (!target->HP) {
-           unit->Player->Score += target->Type->Points;
-           if (target->Type->Building) {
-               unit->Player->TotalRazings++;
-           } else {
-               unit->Player->TotalKills++;
-           }
-#ifndef USE_HP_FOR_XP
-           unit->XP += target->Type->Points;
-#endif
-           unit->Kills++;
-           LetUnitDie(target);
-       }
-       // FIXME: If another target is around do more damage on it.
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeExorcism,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    } else {
-       // FIXME: vladi: exorcism effect should be disperced on near units
-    }
-
-    return 0;
-}
-
-/**
-**     Cast fireball.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastFireball(Unit* unit, const SpellType* spell,
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    Missile *missile;
-    int sx;
-    int sy;
-    int dist;
-
-    // NOTE: fireball can be casted on spot
-    sx = unit->X;
-    sy = unit->Y;
-    dist = MapDistance(sx, sy, x, y);
-    x += ((x - sx) * 10) / dist;
-    y += ((y - sy) * 10) / dist;
-
-    sx = sx * TileSizeX + TileSizeX / 2;
-    sy = sy * TileSizeY + TileSizeY / 2;
-    x = x * TileSizeX + TileSizeX / 2;
-    y = y * TileSizeY + TileSizeY / 2;
-
-    unit->Mana -= spell->ManaCost;
-
-    PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
-    missile = MakeMissile(MissileTypeFireball, sx, sy, x, y);
-
-    missile->State = spell->TTL - (dist - 1) * 2;
-    missile->TTL = spell->TTL;
-    missile->Controller = SpellFireballController;
-    missile->SourceUnit = unit;
-    RefsDebugCheck(!unit->Refs || unit->Destroyed);
-    unit->Refs++;
-
-    return 0;
-}
-
-/**
-**     Cast slow.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastSlow(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    if (target && !target->Type->Building
-           && target->Slow < spell->TTL/CYCLES_PER_SECOND) {
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       target->Slow = spell->TTL/CYCLES_PER_SECOND;    // about 25 sec
-       target->Haste = 0;
-       CheckUnitToBeDrawn(target);
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    }
-
-    return 0;
-}
-
-/**
-**     Cast flame shield.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastFlameShield(Unit* unit, const SpellType* spell, Unit* target,
-    int x __attribute__((unused)), int y __attribute__((unused)))
-{
-    if (target && !target->Type->Building
-           && (target->Type->UnitType == UnitTypeLand
-               || target->Type->UnitType == UnitTypeNaval)
-           && target->FlameShield < spell->TTL) {
-       Missile* mis;
-
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       target->FlameShield = spell->TTL;       // about 15 sec
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       mis=MakeMissile(spell->Missile.Missile, 0, 0, 0, 0 );
-       mis->TTL = spell->TTL + 0*7;
-       mis->TargetUnit = target;
-       mis->Controller = SpellFlameShieldController;
-       RefsDebugCheck(!target->Refs || target->Destroyed);
-       target->Refs++;
-
-       mis=MakeMissile(spell->Missile.Missile, 0, 0, 0, 0 );
-       mis->TTL = spell->TTL + 1*7;
-       mis->TargetUnit = target;
-       mis->Controller = SpellFlameShieldController;
-       RefsDebugCheck(!target->Refs || target->Destroyed);
-       target->Refs++;
-
-       mis=MakeMissile(spell->Missile.Missile, 0, 0, 0, 0 );
-       mis->TTL = spell->TTL + 2*7;
-       mis->TargetUnit = target;
-       mis->Controller = SpellFlameShieldController;
-       RefsDebugCheck(!target->Refs || target->Destroyed);
-       target->Refs++;
-
-       mis=MakeMissile(spell->Missile.Missile, 0, 0, 0, 0 );
-       mis->TTL = spell->TTL + 3*7;
-       mis->TargetUnit = target;
-       mis->Controller = SpellFlameShieldController;
-       RefsDebugCheck(!target->Refs || target->Destroyed);
-       target->Refs++;
-
-       mis=MakeMissile(spell->Missile.Missile, 0, 0, 0, 0 );
-       mis->TTL = spell->TTL + 4*7;
-       mis->TargetUnit = target;
-       mis->Controller = SpellFlameShieldController;
-       RefsDebugCheck(!target->Refs || target->Destroyed);
-       target->Refs++;
-    }
-
-    return 0;
-}
-
-/**
-**     Cast invisibility.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastInvisibility(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    if (target && !target->Type->Building
-               && target->Invisible < spell->TTL/CYCLES_PER_SECOND) {
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       if (target->Type->Volatile) {
-           RemoveUnit(target,NULL);
-           UnitLost(target);
-           UnitClearOrders(target);
-           ReleaseUnit(target);
-           MakeMissile(MissileTypeExplosion,
-                   x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-                   x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-       } else {
-           // about 50 sec
-           target->Invisible = spell->TTL/CYCLES_PER_SECOND;
-           CheckUnitToBeDrawn(target);
-       }
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-               x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-               x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    }
-
-    return 0;
-}
-
-/**
-**     Cast polymorph.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastPolymorph(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    if (target && target->Type->Organic) {
-       UnitType* type;
-
-       unit->Player->Score+=target->Type->Points;
-       if (target->Type->Building) {
-           unit->Player->TotalRazings++;
-       } else {
-           unit->Player->TotalKills++;
-       }
-#ifdef USE_HP_FOR_XP
-       unit->XP += target->HP;
-#else
-       unit->XP += target->Type->Points;
-#endif
-       unit->Kills++;
-       // as said somewhere else -- no corpses :)
-       RemoveUnit(target,NULL);
-       UnitLost(target);
-       UnitClearOrders(target);
-       ReleaseUnit(target);
-       type=UnitTypeCritter;
-       if (UnitTypeCanMoveTo(x,y,type)) {
-           MakeUnitAndPlace(x, y, type, Players+PlayerNumNeutral);
-       }
-
-       unit->Mana -= spell->ManaCost;
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    }
-
-    return 0;
-}
-
-/**
-**     Cast blizzard.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastBlizzard(Unit* unit, const SpellType* spell,
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    int fields;
-    int shards;
-    Missile *mis;
-    int sx;
-    int sy;
-    int dx;
-    int dy;
-    int i;
-
-    //
-    //   NOTE: vladi: blizzard differs than original in this way:
-    //   original: launches 50 shards at 5 random spots x 10 for 25 mana
-    //
-
-    fields = 5;
-    shards = 10;
-
-    while (fields--) {
-       do {
-           // find new destination in the map
-           dx = x + SyncRand() % 5 - 2;
-           dy = y + SyncRand() % 5 - 2;
-       } while (dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= TheMap.Height);
-       //sx = dx - 1 - SyncRand() % 4;
-       //sy = dy - 1 - SyncRand() % 4;
-       sx = dx - 4;
-       sy = dy - 4;
-
-       for (i = 0; i < shards; ++i) {
-           mis = MakeMissile(MissileTypeBlizzard,
-                   sx * TileSizeX + TileSizeX / 2,
-                   sy * TileSizeY + TileSizeY / 2,
-                   dx * TileSizeX + TileSizeX / 2,
-                   dy * TileSizeY + TileSizeY / 2);
-           mis->Delay = i * mis->Type->Sleep * 2 * TileSizeX / 
mis->Type->Speed;
-           mis->Damage = BLIZZARD_DAMAGE;
-           // FIXME: not correct -- blizzard should continue even if mage is
-           //       destroyed (though it will be quite short time...)
-           mis->SourceUnit = unit;
-           RefsDebugCheck(!unit->Refs || unit->Destroyed);
-           unit->Refs++;
-       }
-    }
-
-    PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
-    unit->Mana -= spell->ManaCost;
-    if (unit->Mana > spell->ManaCost) {
-       return 1;
-    }
-
-    return 0;
-}
-
-/**
-**     Cast eye of vision.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastEyeOfVision(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    unit->Mana -= spell->ManaCost;
-
-    // FIXME: johns: the unit is placed on the wrong position
-    // FIXME: Don't use UnitTypeByIdent during runtime.
-    target=MakeUnit(UnitTypeByIdent("unit-eye-of-vision"),unit->Player);
-    target->X=x;
-    target->Y=y;
-    DropOutOnSide(target,LookingW,0,0);
-
-    // set life span
-    target->TTL=GameCycle+target->Type->DecayRate*6*CYCLES_PER_SECOND;
-    CheckUnitToBeDrawn(target);
-
-    PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-    MakeMissile(MissileTypeSpell,
-       x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-       x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-
-    return 0;
-}
-
-/**
-**     Cast bloodlust.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastBloodlust(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    if (target && target->Type->Organic
-           && target->Bloodlust < spell->TTL/CYCLES_PER_SECOND) {
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       target->Bloodlust = spell->TTL/CYCLES_PER_SECOND;       // about 25 sec
-       CheckUnitToBeDrawn(target);
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-    } else {
-       // FIXME: should we support making bloodlust in range?
-    }
-
-    return 0;
+    assert(0 <= id && id < SpellTypeCount);
+    return &SpellTypeTable[id];
 }
 
-/**
-**     Cast runes.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastRunes(Unit* unit, const SpellType* spell,
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    Missile *mis;
-
-    PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
-
-    if (IsMapFieldEmpty(x-1,y+0)) {
-       mis = MakeMissile(MissileTypeCustom,
-               x * TileSizeX + TileSizeX / 2 - TileSizeX,
-               y * TileSizeY + TileSizeY / 2,
-               x * TileSizeX + TileSizeX / 2 - TileSizeX,
-               y * TileSizeY + TileSizeY / 2);
-       mis->TTL = spell->TTL;
-       mis->Controller = SpellRunesController;
-       unit->Mana -= spell->ManaCost/5;
-    }
-
-    if (IsMapFieldEmpty(x+1,y+0)) {
-       mis = MakeMissile(MissileTypeCustom,
-               x * TileSizeX + TileSizeX / 2 + TileSizeX,
-               y * TileSizeY + TileSizeY / 2,
-               x * TileSizeX + TileSizeX / 2 + TileSizeX,
-               y * TileSizeY + TileSizeY / 2);
-       mis->TTL = spell->TTL;
-       mis->Controller = SpellRunesController;
-       unit->Mana -= spell->ManaCost/5;
-    }
-
-    if (IsMapFieldEmpty(x+0,y+0)) {
-       mis = MakeMissile(MissileTypeCustom,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2);
-       mis->TTL = spell->TTL;
-       mis->Controller = SpellRunesController;
-       unit->Mana -= spell->ManaCost/5;
-    }
-
-    if (IsMapFieldEmpty(x+0,y-1)) {
-       mis = MakeMissile(MissileTypeCustom,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2 - TileSizeY,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2 - TileSizeY);
-       mis->TTL = spell->TTL;
-       mis->Controller = SpellRunesController;
-       unit->Mana -= spell->ManaCost/5;
-    }
-
-    if (IsMapFieldEmpty(x+0,y+1)) {
-       mis = MakeMissile(MissileTypeCustom,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2 + TileSizeY,
-               x * TileSizeX + TileSizeX / 2,
-               y * TileSizeY + TileSizeY / 2 + TileSizeY);
-       mis->TTL = spell->TTL;
-       mis->Controller = SpellRunesController;
-       unit->Mana -= spell->ManaCost/5;
-    }
-
-    return 0;
-}
+// ****************************************************************************
+// CanAutoCastSpell, CanCastSpell, AutoCastSpell, CastSpell.
+// ****************************************************************************
 
 /**
-**     Cast death coil.
+**     Check if the spell can be auto cast.
 **
-**     @param unit     Unit that casts the spell
 **     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should be repeated, 0 if not
+**     @return         1 if spell can be cast, 0 if not
 */
-local int CastDeathCoil(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
+global int CanAutoCastSpell(const SpellType* spell)
 {
-    if ((target && target->Type->Organic) || (!target)) {
-       Missile *mis;
-       int sx = unit->X;
-       int sy = unit->Y;
-
-       unit->Mana -= spell->ManaCost;
-
-       PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
-       mis = MakeMissile(MissileTypeDeathCoil,
-           sx * TileSizeX + TileSizeX / 2, sy * TileSizeY + TileSizeY / 2,
-           x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
-
-       mis->SourceUnit = unit;
-       RefsDebugCheck(!unit->Refs || unit->Destroyed);
-       unit->Refs++;
-       if (target) {
-           mis->TargetUnit = target;
-           RefsDebugCheck(!target->Refs || target->Destroyed);
-           target->Refs++;
-       }
-       mis->Controller = SpellDeathCoilController;
-    }
+       assert(spell != NULL);
 
-    return 0;
+       return spell->AutoCast ? 1 : 0;
 }
 
 /**
-**     Cast haste.
+**     Check if unit can cast the spell.
 **
-**     @param unit     Unit that casts the spell
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
 **     @param target   Target unit that spell is addressed to
 **     @param x        X coord of target spot when/if target does not exist
 **     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should be repeated, 0 if not
+**     @return         =!0 if spell should/can casted, 0 if not
 */
-local int CastHaste(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
-{
-    if (target && !target->Type->Building
-           && target->Haste < spell->TTL/CYCLES_PER_SECOND) {
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       target->Slow = 0;
-       target->Haste = spell->TTL/CYCLES_PER_SECOND;   // about 25 sec
-       CheckUnitToBeDrawn(target);
-
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
+global int CanCastSpell(const Unit* caster,const SpellType* spell,
+               const Unit* target,             // FIXME : Use an unique 
struture t_Target ?
+               int x,int y)
+{
+    assert(caster != NULL);
+    assert(spell != NULL);
+// And caster must know the spell
+    // FIXME spell->Ident < MaxSpell
+    assert(caster->Type->CanCastSpell && 
caster->Type->CanCastSpell[spell->Ident]);
+
+    if (!caster->Type->CanCastSpell
+           || !caster->Type->CanCastSpell[spell->Ident]
+           || (spell->which_sort_of_target == TargetUnit && target == NULL)) {
+       return 0;
     }
 
-    return 0;
+    return PassGenericCondition(caster, spell, spell->Condition_generic)
+           && 
PassSpecificCondition(caster,spell,target,x,y,spell->Condition_specific);
 }
 
 /**
-**     Cast raise dead.
+**     Check if the spell can be auto cast and cast it.
 **
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
+**     @param caster   Unit who can cast the spell.
+**     @param spell    Spell-type pointer.
 **
-**     @return         =!0 if spell should be repeated, 0 if not
+**     @return         1 if spell is casted, 0 if not.
 */
-local int CastRaiseDead(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
+global int     AutoCastSpell(Unit *caster,
+                                                const SpellType* spell)
 {
-    Unit **corpses;
-    Unit *tempcorpse;
-
-    corpses = &CorpseList;
-
-    while (*corpses) {
-       // FIXME: this tries to raise all corps, ohje
-       // FIXME: I can raise ships?
-       if ((*corpses)->Orders[0].Action == UnitActionDie
-               && !(*corpses)->Type->Building
-               && (*corpses)->X >= x-1 && (*corpses)->X <= x+1
-               && (*corpses)->Y >= y-1 && (*corpses)->Y <= y+1) {
-
-           // FIXME: did they count on food?
-           // Can there be more than 1 skeleton created on the same tile? yes
-           // FIXME: Don't use UnitTypeByIdent during runtime.
-           target = MakeUnit(UnitTypeByIdent("unit-skeleton"), unit->Player);
-           target->X = (*corpses)->X;
-           target->Y = (*corpses)->Y;
-           DropOutOnSide(target,LookingW,0,0);
-           // set life span
-           target->TTL = GameCycle+
-                   target->Type->DecayRate * 6 * CYCLES_PER_SECOND;
-           CheckUnitToBeDrawn(target);
-
-           tempcorpse = *corpses;
-           corpses = &(*corpses)->Next;
+       assert(caster != NULL);
+       assert(spell != NULL);
+       assert(0 <= spell->Ident && spell->Ident < SpellTypeCount);
+    assert(caster->Type->CanCastSpell);
+    assert(caster->Type->CanCastSpell[spell->Ident]);
 
-           ReleaseUnit(tempcorpse);
+    Target                             *target = NULL;
 
-           unit->Mana -= spell->ManaCost;
-           if (unit->Mana < spell->ManaCost) {
-               break;
-           }
-       } else {
-           corpses = &(*corpses)->Next;
+       if (!PassGenericCondition(caster, spell, spell->Condition_generic)
+               || !PassGenericCondition(caster, spell, 
spell->AutoCast->Condition_generic))
+       {
+               return 0;
        }
-    }
-
-    PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-    MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-
-    return 0;
-}
-
-/**
-**     Cast whirlwind.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastWhirlwind(Unit* unit, const SpellType* spell,
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    Missile *mis;
-
-    unit->Mana -= spell->ManaCost;
-
-    PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
-    mis = MakeMissile(MissileTypeWhirlwind,
-       x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
-       x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
-
-    mis->TTL = spell->TTL;
-    mis->Controller = SpellWhirlwindController;
-
-    return 0;
+       target = SelectTargetUnitsOfAutoCast(caster, spell);
+       if (target == NULL)
+       {
+               return 0;
+       }
+       else
+       {
+               //      Must move before ?
+               //      FIXME SpellType* of CommandSpellCast must be const.
+               CommandSpellCast(caster, target->X, target->Y, target->unit, 
(SpellType*) spell, FlushCommands);
+               free(target);
+       }
+    return 1;
 }
 
 /**
-**     Cast unholy armor.
+**     Spell cast!
 **
-**     @param unit     Unit that casts the spell
+**     @param caster   Unit that casts the spell
 **     @param spell    Spell-type pointer
 **     @param target   Target unit that spell is addressed to
 **     @param x        X coord of target spot when/if target does not exist
 **     @param y        Y coord of target spot when/if target does not exist
 **
-**     @return         =!0 if spell should be repeated, 0 if not
+**     @return         !=0 if spell should/can continue or 0 to stop
 */
-local int CastUnholyArmor(Unit* unit, const SpellType* spell, Unit* target,
-    int x, int y)
+global int SpellCast(Unit* caster, const SpellType* spell,
+               Unit* target, int x, int y)
 {
-    if (target && !target->Type->Building
-           && target->UnholyArmor < spell->TTL/CYCLES_PER_SECOND) {
-       // get mana cost
-       unit->Mana -= spell->ManaCost;
-       if( target->Type->Volatile ) {
-           RemoveUnit(target,NULL);
-           UnitLost(target);
-           UnitClearOrders(target);
-           ReleaseUnit(target);
-           MakeMissile(MissileTypeExplosion,
-                   x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-                   x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
-       } else {
-           // about 13 sec
-           target->UnholyArmor = spell->TTL/CYCLES_PER_SECOND;
-           CheckUnitToBeDrawn(target);
-       }
+    assert(spell != NULL);
+    assert(spell->f != NULL);
+    assert(caster != NULL);
 
-       PlayGameSound(spell->Casted.Sound,MaxSampleVolume);
-       MakeMissile(MissileTypeSpell,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2,
-           x*TileSizeX+TileSizeX/2, y*TileSizeY+TileSizeY/2 );
+    caster->Invisible = 0;// unit is invisible until attacks // FIXME Must be 
configurable
+    if (target) {
+       x = target->X;
+       y = target->Y;
+    } else {
+       x += spell->Range;      // Why ??
+       y += spell->Range;      // Why ??
     }
-
-    return 0;
+    DebugLevel3Fn("Spell cast: (%s), %s -> %s (%d,%d)\n" _C_ spell->IdentName 
_C_
+           unit->Type->Name _C_ target ? target->Type->Name : "none" _C_ x _C_ 
y);
+    return CanCastSpell(caster, spell, target, x, y) && spell->f(caster, 
spell, target, x, y);
 }
 
-/**
-**     Cast death and decay.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastDeathAndDecay(Unit* unit, const SpellType* spell,
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    int fields;                        // blizzard thing, yep :)
-    int shards;
-    Missile *mis;
-    int dx;
-    int dy;
-    int i;
-
-    fields = 5;
-    shards = 10;
 
-    while (fields--) {
-       do {
-           // find new destination in the map
-           dx = x + SyncRand() % 5 - 2;
-           dy = y + SyncRand() % 5 - 2;
-       } while (dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= TheMap.Height);
-
-       for (i = 0; i < shards; ++i) {
-           mis = MakeMissile(MissileTypeDeathDecay,
-                   dx * TileSizeX + TileSizeX / 2,
-                   dy * TileSizeY + TileSizeY / 2,
-                   dx * TileSizeX + TileSizeX / 2,
-                   dy * TileSizeY + TileSizeY / 2);
-           mis->Damage = DEATHANDDECAY_DAMAGE;
-           //FIXME: not correct -- death and decay should continue even if
-           //       death knight is destroyed (though it will be quite
-           //       short time...)
-           mis->Delay = i * mis->Type->Sleep
-                   * VideoGraphicFrames(mis->Type->Sprite);
-           mis->SourceUnit = unit;
-           RefsDebugCheck(!unit->Refs || unit->Destroyed);
-           unit->Refs++;
-       }
-    }
+#if 0
 
-    PlayGameSound(spell->Casted.Sound, MaxSampleVolume);
+/*
+**      TODO :
+**     - Modify missile.c for better configurable and clear the code.
+** ccl info
 
-    unit->Mana -= spell->ManaCost;
-    if (unit->Mana > spell->ManaCost) {
-       return 1;
-    }
 
-    return 0;
-}
+// !!! Special deathcoil
 
-/**
-**     Cast circle of power.
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         =!0 if spell should be repeated, 0 if not
-*/
-local int CastCircleOfPower(Unit* unit, const SpellType* spell 
__attribute__((unused)),
-    Unit* target __attribute__((unused)), int x, int y)
-{
-    // FIXME: vladi: cop should be placed only on explored land
-    // FIXME: Don't use UnitTypeByIdent during runtime.
-    Unit *cop;
+// if (!target->Type->Building
+          && (target->Type->UnitType == UnitTypeLand || target->Type->UnitType 
== UnitTypeNaval)
+       && target->FlameShield < spell->TTL) // FlameShield
 
-    cop = unit->Goal;
-    if (cop) {
-       // FIXME: if cop is already defined --> move it, but it doesn't work?
-       RemoveUnit(cop, NULL);
-       PlaceUnit(cop, x, y);
-    } else {
-       cop = MakeUnitAndPlace(x, y, UnitTypeByIdent("unit-circle-of-power"),
-               &Players[PlayerMax-1]);
-    }
-    MakeMissile(MissileTypeSpell, x * TileSizeX + TileSizeX / 2,
-       y * TileSizeY + TileSizeY / 2, x * TileSizeX + TileSizeX / 2,
-       y * TileSizeY + TileSizeY / 2);
+       = {
 
-    // Next is used to link to destination circle of power
-    unit->Goal = cop;
-    RefsDebugCheck(!cop->Refs || cop->Destroyed);
-    cop->Refs++;
-    //FIXME: setting destination circle of power should use mana
+  NOTE: vladi:
 
-    return 0;
-}
+  The point to have variable unsorted list of spell-types and
+  dynamic id's and in the same time -- SpellAction id's is that
+  spell actions are hardcoded and cannot be changed at all.
+  On the other hand we can have different spell-types as with
+  different range, cost and time to live (possibly and other
+  parameters as extensions)
 
-/**
-**     Spell cast!
-**
-**     @param unit     Unit that casts the spell
-**     @param spell    Spell-type pointer
-**     @param target   Target unit that spell is addressed to
-**     @param x        X coord of target spot when/if target does not exist
-**     @param y        Y coord of target spot when/if target does not exist
-**
-**     @return         0 if spell should/can continue or =! 0 to stop
-*/
-global int SpellCast(Unit* unit, const SpellType* spell, Unit* target,
-       int x, int y)
-{
-    int repeat;
+  FIXME: this should be configurable by CCL.
 
-    unit->Invisible = 0;               // unit is invisible until attacks
-    repeat = 0;
-    if (target) {
-       x = target->X;
-       y = target->Y;
-    } else {
-       x += spell->Range;
-       y += spell->Range;
-    }
+  FIXME: 0x7F as unlimited range is too less for big maps.
 
-    DebugLevel3Fn("Spell cast: (%s), %s -> %s (%d,%d)\n" _C_ spell->Ident _C_
-       unit->Type->Name _C_ target ? target->Type->Name : "none" _C_
-       x _C_ y);
-
-    // the unit can collect mana during the move to target, so check is here...
-
-    switch (spell->Action) {
-    case SpellActionNone:
-       DebugLevel0Fn("No spell action\n");
-       break;
-
-//  ---human paladins---
-    case SpellActionHolyVision:
-       repeat = CastHolyVision(unit, spell, target, x, y);
-       break;
-
-    case SpellActionHealing:
-       repeat = CastHealing(unit, spell, target, x, y);
-       break;
-
-    case SpellActionExorcism:
-       repeat = CastExorcism(unit, spell, target, x, y);
-       break;
-
-//  ---human mages---
-    case SpellActionFireball:
-       repeat = CastFireball(unit, spell, target, x, y);
-       break;
-
-    case SpellActionSlow:
-       repeat = CastSlow(unit, spell, target, x, y);
-       break;
-
-    case SpellActionFlameShield:
-       repeat = CastFlameShield(unit, spell, target, x, y);
-       break;
-
-    case SpellActionInvisibility:
-       repeat = CastInvisibility(unit, spell, target, x, y);
-       break;
-
-    case SpellActionPolymorph:
-       repeat = CastPolymorph(unit, spell, target, x, y);
-       break;
-
-    case SpellActionBlizzard:
-       repeat = CastBlizzard(unit, spell, target, x, y);
-       break;
-
-//  ---orc ogres---
-    case SpellActionEyeOfVision:
-       repeat = CastEyeOfVision(unit, spell, target, x, y);
-       break;
-
-    case SpellActionBloodlust:
-       repeat = CastBloodlust(unit, spell, target, x, y);
-       break;
-
-    case SpellActionRunes:
-       repeat = CastRunes(unit, spell, target, x, y);
-       break;
-
-//  ---orc death knights---
-    case SpellActionDeathCoil:
-       repeat = CastDeathCoil(unit, spell, target, x, y);
-       break;
-
-    case SpellActionHaste:
-       repeat = CastHaste(unit, spell, target, x, y);
-       break;
-
-    case SpellActionRaiseDead:
-       repeat = CastRaiseDead(unit, spell, target, x, y);
-       break;
-
-    case SpellActionWhirlwind:
-       repeat = CastWhirlwind(unit, spell, target, x, y);
-       break;
-
-    case SpellActionUnholyArmor:
-       repeat = CastUnholyArmor(unit, spell, target, x, y);
-       break;
-
-    case SpellActionDeathAndDecay:
-       repeat = CastDeathAndDecay(unit, spell, target, x, y);
-       break;
-
-    case SpellActionCircleOfPower:
-       repeat = CastCircleOfPower(unit, spell, target, x, y);
-       break;
-
-    default:
-       DebugLevel0Fn("Unknown spell action `%d'\n" _C_ spell->Action);
-       break;
-    }
+ 
+*/
 
-    return repeat;
-}
+#endif
 
 //@}
Index: stratagus/src/editor/editloop.c
diff -u stratagus/src/editor/editloop.c:1.128 
stratagus/src/editor/editloop.c:1.129
--- stratagus/src/editor/editloop.c:1.128       Thu Sep 18 13:56:03 2003
+++ stratagus/src/editor/editloop.c     Mon Sep 22 06:40:52 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: editloop.c,v 1.128 2003/09/18 17:56:03 n0body Exp $
+//     $Id: editloop.c,v 1.129 2003/09/22 10:40:52 n0body Exp $
 
 //@{
 
@@ -87,7 +87,7 @@
 local int TileCursorSize;              /// Tile cursor size 1x1 2x2 ... 4x4
 local int TileCursor;                  /// Tile type number
 
-local int MirrorEdit = 0;                   /// Mirror editing enabled
+local int MirrorEdit = 0;              /// Mirror editing enabled
 local int UnitPlacedThisPress = 0;     ///Only allow one unit per press
 
 enum _mode_buttons_ {
Index: stratagus/src/editor/edmap.c
diff -u stratagus/src/editor/edmap.c:1.22 stratagus/src/editor/edmap.c:1.23
--- stratagus/src/editor/edmap.c:1.22   Thu Sep 18 13:56:03 2003
+++ stratagus/src/editor/edmap.c        Mon Sep 22 06:40:52 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: edmap.c,v 1.22 2003/09/18 17:56:03 n0body Exp $
+//     $Id: edmap.c,v 1.23 2003/09/22 10:40:52 n0body Exp $
 
 //@{
 
@@ -168,6 +168,8 @@
     int j;
     int n;
 
+    DebugLevel0Fn("base %X goal %X\n" _C_ base _C_ goal);
+
     //
     //  Find any mixed tile
     //
@@ -413,6 +415,8 @@
 **     @param x        X map tile coordinate.
 **     @param y        Y map tile coordinate.
 **     @param tile     Abstract tile type to edit.
+**
+**     @note  this is a rather dumb function, doesn't do any tile fixing.
 */
 global void ChangeTile(int x, int y, int tile)
 {
@@ -425,10 +429,10 @@
     mf->Tile = mf->SeenTile = TheMap.Tileset->Table[tile];
 }
 
-#define D_UP   8               /// Go up allowed
-#define D_DOWN 4               /// Go down allowed
-#define D_LEFT 2               /// Go left allowed
-#define D_RIGHT        1               /// Go right allowed
+#define DIR_UP         8       /// Go up allowed
+#define DIR_DOWN       4       /// Go down allowed
+#define DIR_LEFT       2       /// Go left allowed
+#define DIR_RIGHT      1       /// Go right allowed
 
 /**
 **     Editor change tile.
@@ -478,7 +482,7 @@
     MapField* mf;
 
     quad = QuadFromTile(x, y);
-    DebugLevel3Fn("%d,%d %08x %d\n" _C_ x _C_ y _C_ quad _C_
+    DebugLevel0Fn("%d,%d %08x %d\n" _C_ x _C_ y _C_ quad _C_
            TheMap.Fields[y * TheMap.Width + x].Tile);
 
     //
@@ -503,7 +507,13 @@
        return;
     }
 
-    if (d&D_UP && y) {
+    // 
+    //         How this works:
+    //         first get the quad of the neighbouring tile, then
+    //         check if the margin matches. otherwise, call 
+    //         EditorChangeTile again.
+    //
+    if (d&DIR_UP && y) {
        //
        //      Insert into the bottom the new tile.
        //
@@ -513,10 +523,10 @@
            DebugLevel3Fn("U+    %08x -> %08x\n" _C_ q2 _C_ u);
            tile = TileFromQuad(u & BH_QUAD_M, u);
            DebugLevel3Fn("= %08x\n" _C_ tile);
-           EditorChangeTile(x, y - 1, tile, d&~D_DOWN);
+           EditorChangeTile(x, y - 1, tile, d&~DIR_DOWN);
        }
     }
-    if (d&D_DOWN && y < TheMap.Height - 1) {
+    if (d&DIR_DOWN && y < TheMap.Height - 1) {
        //
        //      Insert into the top the new tile.
        //
@@ -525,10 +535,10 @@
        if (u != q2) {
            DebugLevel3Fn("D+    %08x -> %08x\n" _C_ q2 _C_ u);
            tile = TileFromQuad(u & TH_QUAD_M, u);
-           EditorChangeTile(x, y + 1, tile, d&~D_UP);
+           EditorChangeTile(x, y + 1, tile, d&~DIR_UP);
        }
     }
-    if (d&D_LEFT && x) {
+    if (d&DIR_LEFT && x) {
        //
        //      Insert into the left the new tile.
        //
@@ -537,10 +547,10 @@
        if (u != q2) {
            DebugLevel3Fn("L+    %08x -> %08x\n" _C_ q2 _C_ u);
            tile = TileFromQuad(u & RH_QUAD_M, u);
-           EditorChangeTile(x - 1, y, tile, d&~D_RIGHT);
+           EditorChangeTile(x - 1, y, tile, d&~DIR_RIGHT);
        }
     }
-    if (d&D_RIGHT && x < TheMap.Width - 1) {
+    if (d&DIR_RIGHT && x < TheMap.Width - 1) {
        //
        //      Insert into the right the new tile.
        //
@@ -549,7 +559,7 @@
        if (u != q2) {
            DebugLevel3Fn("R+    %08x -> %08x\n" _C_ q2 _C_ u);
            tile = TileFromQuad(u & LH_QUAD_M, u);
-           EditorChangeTile(x + 1, y, tile, d&~D_LEFT);
+           EditorChangeTile(x + 1, y, tile, d&~DIR_LEFT);
        }
     }
 }
Index: stratagus/src/game/savegame.c
diff -u stratagus/src/game/savegame.c:1.31 stratagus/src/game/savegame.c:1.32
--- stratagus/src/game/savegame.c:1.31  Sun Aug 17 11:57:07 2003
+++ stratagus/src/game/savegame.c       Mon Sep 22 06:40:52 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: savegame.c,v 1.31 2003/08/17 15:57:07 n0body Exp $
+//     $Id: savegame.c,v 1.32 2003/09/22 10:40:52 n0body Exp $
 
 //@{
 
@@ -59,6 +59,7 @@
 #include "trigger.h"
 #include "settings.h"
 #include "iolib.h"
+#include "spells.h"
 
 #include "ccl.h"
 
@@ -102,7 +103,7 @@
     CLprintf(file,";;;(save-game\n");
     CLprintf(file,";;;  'comment\t\"Generated by Stratagus Version " VERSION 
"\"\n");
     CLprintf(file,";;;  'comment\t\"Visit http://Stratagus.Org for more 
informations\"\n");
-    CLprintf(file,";;;  'comment\t\"$Id: savegame.c,v 1.31 2003/08/17 15:57:07 
n0body Exp $\"\n");
+    CLprintf(file,";;;  'comment\t\"$Id: savegame.c,v 1.32 2003/09/22 10:40:52 
n0body Exp $\"\n");
     CLprintf(file,";;;  'type\t\"%s\"\n","single-player");
     CLprintf(file,";;;  'date\t\"%s\"\n",s);
     CLprintf(file,";;;  'map\t\"%s\"\n",TheMap.Description);
@@ -134,11 +135,13 @@
     SaveTilesets(file);
     SaveConstructions(file);
     SaveDecorations(file);
+    SaveMissileTypes(file);
+    SaveUnitTypeDefs(file);
+    SaveSpells(file);
     SaveUnitTypes(file);
     SaveUpgrades(file);
     SaveDependencies(file);
     SaveButtons(file);
-    SaveMissileTypes(file);
     SavePlayers(file);
     SaveMap(file);
     SaveUnits(file);
Index: stratagus/src/include/spells.h
diff -u stratagus/src/include/spells.h:1.19 stratagus/src/include/spells.h:1.20
--- stratagus/src/include/spells.h:1.19 Fri Jul 11 10:35:30 2003
+++ stratagus/src/include/spells.h      Mon Sep 22 06:40:52 2003
@@ -10,7 +10,7 @@
 //
 /address@hidden spells.h       -       The Spells. */
 //
-//     (c) Copyright 1999-2003 by Vladi Belperchinov-Shabanski
+//     (c) Copyright 1999-2003 by Vladi Belperchinov-Shabanski and Joris 
DAUPHIN
 //
 //      This program is free software; you can redistribute it and/or modify
 //      it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: spells.h,v 1.19 2003/07/11 14:35:30 n0body Exp $
+//     $Id: spells.h,v 1.20 2003/09/22 10:40:52 n0body Exp $
 
 #ifndef __SPELLS_H__
 #define __SPELLS_H__
@@ -45,100 +45,324 @@
 #include "unittype.h"
 #include "unit.h"
 #include "missile.h"
+#include "ccl.h"
 
 /*----------------------------------------------------------------------------
 --     Definitons
 ----------------------------------------------------------------------------*/
 
+//     TODO : Remove, configure in ccl.
+#define FIREBALL_DAMAGE                20      /// Damage of center fireball
+#define WHIRLWIND_DAMAGE1       4      /// the center of the whirlwind
+#define WHIRLWIND_DAMAGE2       1      /// the periphery of the whirlwind
+#define RUNE_DAMAGE            50      /// Rune damage
+
+enum {
+    flag_slow,
+    flag_haste,
+    flag_bloodlust,
+    flag_invisibility,
+    flag_unholyarmor,
+    flag_flameshield,
+    flag_HP,
+    flag_Mana,
+    flag_HP_percent,
+    flag_Mana_percent,
+    flag_coward,
+    flag_organic,
+    flag_isundead,
+    flag_canattack,
+    flag_building
+};
+
+/**
+**     Different targets.
+*/
+typedef enum {
+       TargetSelf,
+       TargetNone,
+       TargetPosition,
+       TargetUnit
+#if 0
+               ,
+       TargetUnits
+#endif
+}      TargetType;
+
+
+
+
+typedef union
+{
+// FIXME rename structure more properly.
+// TTL's below are in ticks: approx: 500=13sec, 1000=25sec, 2000=50sec
+// FIXME use TTL or nb_of_second ?
+       struct {
+           int fields;                 /// FIXME doc
+           int shards;                 /// FIXME doc
+           int damage;                 /// damage
+       } blizzard;
+       
+       struct {
+           UnitType *goal;             /// FIXME: compact to Summon
+       } circleofpower;
+       
+       struct {
+           int fields;                 /// FIXME doc
+           int shards;                 /// FIXME doc
+           int damage;                 /// damage
+       } deathanddecay;
+       
+       struct {
+           int TTL;                    /// time to live (ticks)
+           int damage;                 /// Damage.
+       } fireball;
+       
+       struct {
+           int TTL;                    /// time to live (ticks)
+       } flameshield;
+
+       struct s_haste {
+           int flag;                   /// flag for know what variable to set.
+           int value;                  /// the set value. (nb sec).
+       struct s_haste  *next;          /// Other variable to set ?
+       } haste;
+       
+       struct {
+           int HP;                     /// HP gain for manacost.(negative for 
exorcism)
+       } healing;
+       
+       struct {
+           UnitType *revealer;         /// Type of unit to be summoned: 
(unit-revealer).
+       } holyvision;
+       
+       struct {
+           int flag;                   /// unholyarmor or invisibility.
+           int value;                  /// the set value. (nb sec).
+           MissileType *missile;       /// missile for the target.
+       } invisibility;
+       
+       struct {
+           UnitType *unit;             /// The new form :)
+       } polymorph;
+       
+       struct {
+           UnitType *skeleton;         /// The unit to spwan from corpses
+       } raisedead;
+       
+       struct {
+           int TTL;                    /// time to live (ticks)
+           int damage;                 /// Damage.
+       } runes;
+       
+       struct {
+           UnitType *unittype;         /// Type of unit to be summoned.
+       } summon;
+       
+       struct {
+           int  TTL;                   /// time to live (ticks)
+           // FIXME: more configurations
+       } whirlwind;
+}      t_SpellAction;
+
+/*
+** *******************
+** Target definition.
+** *******************
+*/
+
+typedef struct {
+    TargetType which_sort_of_target;   /// for identify what sort of target.
+    int X;                     /// x coord.
+    int Y;                     /// y coord.
+    Unit       *unit;  /// Unit target.
+} Target;
+
+/*
+** *******************
+** Conditions definition.
+** *******************
+*/
+
 /**
-**     Different spell actions, defines the behavior of the spells.
+**     Informations about the conditions of autocasting mode and simple cast.
+**
+**     @todo   Move more parameters into this structure.
 */
-typedef enum _spell_action_type_ {
-    SpellActionNone,                   /// No spell, shouldn't happen
-//     ---human paladins---
-    SpellActionHolyVision,             /// Holy vision
-    SpellActionHealing,                        /// Healing
-    SpellActionExorcism,               /// Exorcism
-//     ---human mages---
-    SpellActionFireball,               /// Fireball
-    SpellActionSlow,                   /// Slow down
-    SpellActionFlameShield,            /// Flame shield
-    SpellActionInvisibility,           /// Invisibility
-    SpellActionPolymorph,              /// Polymorph
-    SpellActionBlizzard,               /// Blizzard
-//     ---orc ogres---
-    SpellActionEyeOfVision,            /// Eye
-    SpellActionBloodlust,              /// Blood lust
-    SpellActionRunes,                  /// Runes
-//     ---orc death knights---
-    SpellActionDeathCoil,              /// Death coil
-    SpellActionHaste,                  /// Haste
-    SpellActionRaiseDead,              /// Raise dead
-    SpellActionWhirlwind,              /// Whirlwind
-    SpellActionUnholyArmor,            /// Unholy armor
-    SpellActionDeathAndDecay,          /// Death and decay
-
-//     ---new spells---
-    SpellActionCircleOfPower,          /// Circle of power
+struct s_Conditions;
 
-    // Here you can add new spell actions
+/*
+**      Specific conditions.
+*/
+typedef                int     f_specific_condition(const struct s_Conditions  
*condition,
+                                                                               
const Unit* caster,
+                                                                               
const Unit* target, int x, int y);
+
+typedef                int     f_generic_condition(const struct s_Conditions   
*condition,
+                                                                       const 
Unit* caster);
 
-} SpellActionType;
 
 /**
-**     Base structure of a spell type
+**     Informations about the condition of autocasting mode.
 **
 **     @todo   Move more parameters into this structure.
 */
-typedef struct _spell_type_ {
+typedef struct s_Conditions {
+       int                     expectvalue;                            ///< 
Value expected (condition is true or false)
+       union {
+               f_specific_condition    *specific;                      ///< 
Fonction that evaluate the condition.
+               f_generic_condition             *generic;                       
///< Fonction that evaluate the condition.
+       } f;
+       union   {
+                       int range;      ///< range
+//                     struct {
+//                             t_SpecificConditions c1;
+//                             t_SpecificConditions c2;
+//                     } or;           //
+                       unsigned int flag;      ///< flag
+                       struct {
+                               unsigned int    flag;
+                               unsigned int    ttl;
+                       } durationeffect;       ///< durationeffect
+       }       u;
+       struct s_Conditions     *next;  ///< for list.
+} t_Conditions;
 
-    char* Ident;               /// spell identifier
-    char* Name;                        /// spell name shown by the engine
 
-    int  Range;                        /// spell range
-    unsigned  ManaCost : 8;    /// required mana for each cast
-    int  TTL;                  /// time to live (ticks)
+/**
+**     Informations about the autocasting mode.
+**
+*/
+typedef struct {
+       t_Conditions    *Condition_generic;             ///< Conditions to cast 
the spell. (generic (no test for each target))
+       t_Conditions    *Condition_specific;    ///< Conditions to cast the 
spell. (target specific (ex:Hp full))
+// Something to have a position target
+       int                             Range;                                  
                /// Max range of the target.
+#if 0  // When sort supported
+       t_f_order                       *f;                                     
                /// Sort functions for the best target.
+#endif
+} t_AutoCast;
 
-    SpellActionType  Action;   /// SpellAction...
+struct _spell_type_;
 
-    SoundConfig Casted;                /// sound played if casted
-    MissileConfig Missile;     /// missile fired on cast
+/*
+**     Pointer on function that cast the spell.
+*/
+typedef int f_spell(Unit* caster, const struct _spell_type_* spell, Unit* 
target,
+       int x, int y);
+
+/**
+**     Base structure of a spell type.
+*/
+typedef struct _spell_type_ {
+    //  Identification stuff
+    unsigned int Ident;                        /// Spell numeric identifier
+    char *IdentName;                   /// Spell unique identifier 
(spell-holy-vision)
+    char *Name;                                /// Spell name shown by the 
engine
+
+    // Spell Specifications
+    TargetType which_sort_of_target;   /// for identify what sort of target is 
valid.
+    f_spell                    *f;     /// function to cast the spell.
+    t_SpellAction      *SpellAction;   /// More arguments for spell (damage, 
delay, additional sounds...).
+    int  Range;                                /// Max range of the target.
+    unsigned int ManaCost;             /// required mana for each cast
+
+    t_Conditions *Condition_generic;   /// Conditions to cast the spell. 
(generic (no test for each target))
+    t_Conditions *Condition_specific;  /// Conditions to cast the spell. 
(target specific (ex:Hp full))
+//     Autocast        // FIXME : can use different for AI ? Use it in this 
structure ?
+    t_AutoCast *AutoCast;                                      /// AutoCast 
information
+
+//     Uses for graphics and sounds
+    SoundConfig SoundWhenCasted;       /// sound played if casted
+    MissileType        *Missile;       /// missile fired on cast
 } SpellType;
 
 /*----------------------------------------------------------------------------
 --     Variables
 ----------------------------------------------------------------------------*/
 
+/**
+**     Define the names and effects of all available spells.
+*/
+extern SpellType *SpellTypeTable;
+
+/// How many spell-types are available
+extern int SpellTypeCount;
+
+
 /*----------------------------------------------------------------------------
 --     Functions
 ----------------------------------------------------------------------------*/
 
-    /// init spell tables
+///    register fonction.
+extern void SpellCclRegister(void);
+
+/// init spell tables
 extern void InitSpells(void);
 
-    /// done spell tables
+/// save spell tables
+extern void SaveSpells(CLFile * file);
+
+/// done spell tables
 extern void DoneSpells(void);
 
-    /// return spell id by ident string
-extern int SpellIdByIdent( const char* Ident );
+/// returns != 0 if spell can be casted (enough mana, valid target)
+extern int CanCastSpell(const Unit* caster, const SpellType*,
+                                               const Unit* target, int x, int 
y);
+
+/// cast spell on target unit or place at x,y
+extern int SpellCast(Unit* caster, const SpellType*,
+                                       Unit* target, int x, int y);
+
+/// auto cast the spell if possible
+extern int AutoCastSpell(Unit* caster, const SpellType* spell);
 
-    /// return spell type by ident string
-extern SpellType* SpellTypeByIdent( const char* Ident );
+/// returns != 0 if spell can be auto cast
+extern int CanAutoCastSpell(const SpellType* spell);
 
-    /// return spell type by spell id
-extern SpellType* SpellTypeById( int Id );
+/// return spell id by ident string
+extern int SpellIdByIdent(const char* Ident);
 
-    /// returns != 0 if spell can be casted by this unit, enough mana?
-extern int CanCastSpell( const Unit*, const SpellType*, const Unit*, int, int 
);
+/// return spell type by ident string
+extern SpellType* SpellTypeByIdent(const char* Ident);
 
-    /// fire spell on target unit or place at x,y
-extern int SpellCast( Unit*, const SpellType* , Unit* , int , int );
+/// return spell type by spell id
+extern SpellType* SpellTypeById(int Id);
 
-    /// auto cast the spell if possible
-extern int AutoCastSpell(Unit* unit, SpellType* spell);
+extern unsigned CclGetSpellByIdent(SCM value);
 
-    /// returns != 0 if spell can be auto cast
-extern int CanAutoCastSpell(const SpellType* spell);
+/*
+**     Spelltype to cast.
+*/
+
+f_spell        CastHolyVision;
+f_spell        CastHealing;
+f_spell        CastHaste;
+f_spell        CastFireball;
+f_spell        CastFlameShield;
+f_spell        CastInvisibility;
+f_spell        CastPolymorph;
+f_spell        CastBlizzard;
+f_spell        CastSummon;
+f_spell        CastRunes;
+f_spell        CastDeathCoil;
+f_spell        CastRaiseDead;
+f_spell        CastWhirlwind;
+f_spell        CastDeathAndDecay;
+f_spell        CastCircleOfPower;
+
+
+/*
+**     generic condition.
+*/
+f_generic_condition    CheckEnemyPresence;
+
+/*
+**     Specific condition.
+*/
+f_specific_condition   CheckUnitTypeFlag;
+f_specific_condition   CheckAllied;
+f_specific_condition   CheckUnitDurationEffect;
 
 //@}
 
Index: stratagus/src/include/unittype.h
diff -u stratagus/src/include/unittype.h:1.112 
stratagus/src/include/unittype.h:1.113
--- stratagus/src/include/unittype.h:1.112      Sun Sep 21 08:16:43 2003
+++ stratagus/src/include/unittype.h    Mon Sep 22 06:40:52 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: unittype.h,v 1.112 2003/09/21 12:16:43 mr-russ Exp $
+//     $Id: unittype.h,v 1.113 2003/09/22 10:40:52 n0body Exp $
 
 #ifndef __UNITTYPE_H__
 #define __UNITTYPE_H__
@@ -774,7 +774,7 @@
     unsigned GroundAttack : 1;         /// Can do command ground attack.
     unsigned IsUndead : 1;             /// Unit is already dead.
     unsigned ShoreBuilding : 1;                /// Building must be build on 
coast.
-    unsigned CanCastSpell : 1;         /// Unit is able to use spells.
+    char *CanCastSpell;                        /// Unit is able to use spells.
     unsigned CanAttack : 1;            /// Unit can attack.
     unsigned int DemolishRange;                /// Unit will Demolish around 
when dead.
     unsigned int DemolishDamage;       /// Damage dealt to unit affected by 
demolition.
@@ -863,6 +863,7 @@
     /// Get the animations structure by ident
 extern Animations* AnimationsByIdent(const char* ident);
 
+extern void SaveUnitTypeDefs(CLFile* file);            /// Declare the 
unit-type table first.
 extern void SaveUnitTypes(CLFile* file);               /// Save the unit-type 
table
 extern UnitType* NewUnitTypeSlot(char*);               /// Allocate an empty 
unit-type slot
     /// Draw the sprite frame of unit-type
Index: stratagus/src/siod/slib.c
diff -u stratagus/src/siod/slib.c:1.25 stratagus/src/siod/slib.c:1.26
--- stratagus/src/siod/slib.c:1.25      Sun Aug 17 11:57:07 2003
+++ stratagus/src/siod/slib.c   Mon Sep 22 06:40:53 2003
@@ -73,6 +73,7 @@
 #include <setjmp.h>
 #include <math.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #if !defined(_MSC_VER) || !defined(_WIN32_WCE)
 #include <signal.h>
@@ -93,7 +94,7 @@
 
 static void init_slib_version(void)
 {setvar(cintern("*slib-version*"),
-       cintern("$Id: slib.c,v 1.25 2003/08/17 15:57:07 n0body Exp $"),
+       cintern("$Id: slib.c,v 1.26 2003/09/22 10:40:53 n0body Exp $"),
        NIL);}
 
 char * __stdcall siod_version(void)
@@ -583,56 +584,68 @@
    (*repl_puts)(st);}
      
 long repl(struct repl_hooks *h)
-{LISP x,cw = 0;
- double rt,ct;
- while(1)
-   {if ((gc_kind_copying == 1) && ((gc_status_flag) || heap >= heap_end))
-     {rt = myruntime();
-      gc_stop_and_copy();
-      if (siod_verbose_level >= 2)
-       {sprintf(tkbuffer,
-                "GC took %g seconds, %ld compressed to %ld, %ld free\n",
-                
myruntime()-rt,old_heap_used,(long)(heap-heap_org),(long)(heap_end-heap));
-        grepl_puts(tkbuffer,h->repl_puts);}}
-    if (siod_verbose_level >= 2)
-      grepl_puts("> ",h->repl_puts);
-    if (h->repl_read == NULL)
-      x = lread(NIL);
-    else
-      x = (*h->repl_read)();
-    if EQ(x,eof_val) break;
-    rt = myruntime();
-    ct = myrealtime();
-    if (gc_kind_copying == 1)
-      cw = heap;
-    else
-      {gc_cells_allocated = 0;
-       gc_time_taken = 0.0;}
-    if (h->repl_eval == NULL)
-      x = leval(x,NIL);
-    else
-      x = (*h->repl_eval)(x);
-    if (gc_kind_copying == 1)
-      sprintf(tkbuffer,
-             "Evaluation took %g seconds %ld cons work, %g real.\n",
-             myruntime()-rt,
-             (long)(heap-cw),
-             myrealtime()-ct);
-    else
-      sprintf(tkbuffer,
-            "Evaluation took %g seconds (%g in gc) %ld cons work, %g real.\n",
-             myruntime()-rt,
-             gc_time_taken,
-             gc_cells_allocated,
-             myrealtime()-ct);
-    if (siod_verbose_level >= 2)
-      grepl_puts(tkbuffer,h->repl_puts);
-    if (h->repl_print == NULL)
-      {if (siod_verbose_level >= 2)
-        lprint(x,NIL);}
-    else
-      (*h->repl_print)(x);}
- return(0);}
+{
+       assert(h != NULL);
+
+       LISP x, cw = 0;
+       double rt,ct;
+       while(1)
+       {
+               if (gc_kind_copying == 1 &&
+                       ((gc_status_flag) || heap >= heap_end))
+       {
+               rt = myruntime();
+                       gc_stop_and_copy();
+                       if (siod_verbose_level >= 2)
+                       {sprintf(tkbuffer,
+                                "GC took %g seconds, %ld compressed to %ld, 
%ld free\n",
+                                
myruntime()-rt,old_heap_used,(long)(heap-heap_org),(long)(heap_end-heap));
+                                grepl_puts(tkbuffer, h->repl_puts);
+                       }
+               }
+               /*
+               if (siod_verbose_level >= 2)
+               grepl_puts("> ", h->repl_puts);
+       */
+               if (h->repl_read == NULL)
+                       x = lread(NIL);
+               else
+                       x = (*h->repl_read)();
+               if EQ(x,eof_val) break;
+               rt = myruntime();
+               ct = myrealtime();
+               if (gc_kind_copying == 1)
+                   cw = heap;
+               else
+                       {gc_cells_allocated = 0;
+                    gc_time_taken = 0.0;}
+               if (h->repl_eval == NULL)
+                       x = leval(x,NIL);
+               else
+                       x = (*h->repl_eval)(x);
+               if (gc_kind_copying == 1)
+                       sprintf(tkbuffer,
+                               "Evaluation took %g seconds %ld cons work, %g 
real.\n",
+                               myruntime()-rt,
+                           (long)(heap-cw),
+                           myrealtime()-ct);
+           else
+             sprintf(tkbuffer,
+                            "Evaluation took %g seconds (%g in gc) %ld cons 
work, %g real.\n",
+                             myruntime()-rt,
+                             gc_time_taken,
+                             gc_cells_allocated,
+                             myrealtime()-ct);
+           if (siod_verbose_level >= 2)
+             grepl_puts(tkbuffer,h->repl_puts);
+           if (h->repl_print == NULL)
+               {if (siod_verbose_level >= 2)
+                                lprint(x,NIL);}
+               else
+                 (*h->repl_print)(x);
+               }
+       return(0);
+}
 
 void set_fatal_exit_hook(void (*fcn)(void))
 {fatal_exit_hook = fcn;}
Index: stratagus/src/unit/ccl_unittype.c
diff -u stratagus/src/unit/ccl_unittype.c:1.87 
stratagus/src/unit/ccl_unittype.c:1.88
--- stratagus/src/unit/ccl_unittype.c:1.87      Sun Sep 21 08:13:42 2003
+++ stratagus/src/unit/ccl_unittype.c   Mon Sep 22 06:40:53 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: ccl_unittype.c,v 1.87 2003/09/21 12:13:42 mr-russ Exp $
+//     $Id: ccl_unittype.c,v 1.88 2003/09/22 10:40:53 n0body Exp $
 
 //@{
 
@@ -48,6 +48,7 @@
 #include "missile.h"
 #include "ccl.h"
 #include "construct.h"
+#include "spells.h"
 
 /*----------------------------------------------------------------------------
 --     Variables
@@ -120,7 +121,6 @@
        //Set some default values
        type->_RegenerationRate=0;
     }
-
     type->NumDirections=8;
 #ifdef NEW_UI
     type->AddButtonsHook = NIL;
@@ -521,7 +521,21 @@
        } else if( gh_eq_p(value,gh_symbol2scm("isundead")) ) {
            type->IsUndead=1;
        } else if( gh_eq_p(value,gh_symbol2scm("can-cast-spell")) ) {
-           type->CanCastSpell=1;
+           //
+           //    Warning: can-cast-spell should only be used AFTER all spells
+           //    have been defined. FIXME: MaxSpellType=500 or something?
+           //
+           if (!type->CanCastSpell) {
+               type->CanCastSpell=malloc(SpellTypeCount);
+               memset(type->CanCastSpell,0,SpellTypeCount);
+           }
+           sublist=gh_car(list);
+           list=gh_cdr(list);
+           while( !gh_null_p(sublist) ) {
+               DebugLevel3Fn("%d \n" _C_ CclGetSpellByIdent(gh_car(sublist)));
+               type->CanCastSpell[CclGetSpellByIdent(gh_car(sublist))]=1;
+               sublist=gh_cdr(sublist);
+           }
        } else if( gh_eq_p(value,gh_symbol2scm("organic")) ) {
            type->Organic=1;
        } else if( gh_eq_p(value,gh_symbol2scm("selectable-by-rectangle")) ) {
Index: stratagus/src/unit/unittype.c
diff -u stratagus/src/unit/unittype.c:1.103 stratagus/src/unit/unittype.c:1.104
--- stratagus/src/unit/unittype.c:1.103 Sun Sep 21 08:16:43 2003
+++ stratagus/src/unit/unittype.c       Mon Sep 22 06:40:53 2003
@@ -26,7 +26,7 @@
 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //      02111-1307, USA.
 //
-//     $Id: unittype.c,v 1.103 2003/09/21 12:16:43 mr-russ Exp $
+//     $Id: unittype.c,v 1.104 2003/09/22 10:40:53 n0body Exp $
 
 //@{
 
@@ -50,6 +50,7 @@
 #include "player.h"
 #include "missile.h"
 #include "ccl.h"
+#include "spells.h"
 
 #include "etlib/hash.h"
 
@@ -462,7 +463,8 @@
        unittype->GroundAttack=BIT(14,v);
        unittype->IsUndead=BIT(15,v);
        unittype->ShoreBuilding=BIT(16,v);
-       unittype->CanCastSpell=BIT(17,v);
+//     unittype->CanCastSpell=BIT(17,v);unittype->CanCastSpell = (char *) 
malloc(/*nb_spell*/);
+       unittype->CanCastSpell = NULL;//
        unittype->CanStore[WoodCost]=BIT(18,v);
        unittype->CanAttack=BIT(19,v);
        unittype->Hero=BIT(23,v);
@@ -997,7 +999,16 @@
        }
     if (flag)
        CLprintf(file,")");
-    
+   
+    if( type->CanCastSpell ) {
+       CLprintf(file,"  'can-cast-spell '( ");
+       for (i=0;i<SpellTypeCount;++i) {
+           if (type->CanCastSpell[i]) {
+               CLprintf(file,"%s ",SpellTypeTable[i].IdentName);
+           }
+       }
+       CLprintf(file,")\n");
+    }
     if( type->MustBuildOnTop ) {
        CLprintf(file,"  'must-build-on-top '%s\n",type->MustBuildOnTop->Ident);
     }
@@ -1017,9 +1028,6 @@
     if( type->IsUndead ) {
        CLprintf(file,"  'isundead\n");
     }
-    if( type->CanCastSpell ) {
-       CLprintf(file,"  'can-cast-spell\n");
-    }
     if( type->Organic ) {
        CLprintf(file,"  'organic\n");
     }
@@ -1102,6 +1110,22 @@
 }
 
 /**
+**     Save the names of all unit types, before actually defining anything 
about them.
+**     
+**     @param file     Output file.
+*/
+global void SaveUnitTypeDefs(CLFile* file)
+{
+    int i;
+    CLprintf(file,"\n;;; Declare all unit types in advance.\n");
+    //  Define all types in advance to avoid undefined unit problems.
+    for ( i=0; i<NumUnitTypes; ++i ) {
+       CLprintf(file,"(define-unit-type '%s)\n",UnitTypes[i]->Ident);
+    }
+    CLprintf(file,"\n");
+}
+
+/**
 **     Save state of the unit-type table to file.
 **
 **     @param file     Output file.
@@ -1113,7 +1137,7 @@
     char **sp;
 
     CLprintf(file,"\n;;; -----------------------------------------\n");
-    CLprintf(file,";;; MODULE: unittypes $Id: unittype.c,v 1.103 2003/09/21 
12:16:43 mr-russ Exp $\n\n");
+    CLprintf(file,";;; MODULE: unittypes $Id: unittype.c,v 1.104 2003/09/22 
10:40:53 n0body Exp $\n\n");
 
     // Original number to internal unit-type name.
 
@@ -1131,13 +1155,6 @@
     for( i=0; i<NumUnitTypes; ++i ) {
        SaveAnimations(UnitTypes[i],file);
     }
-
-    CLprintf(file,"\n;;; Declare all unit types in advance.\n");
-    //  Define all types in advance to avoid undefined unit problems.
-    for ( i=0; i<NumUnitTypes; ++i ) {
-       CLprintf(file,"(define-unit-type '%s)\n",UnitTypes[i]->Ident);
-    }
-    CLprintf(file,"\n");
 
     // Save all types
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]