[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Stratagus-CVS] stratagus/src clone/Module.make clone/ccl.c clo...,
Crestez Leonard <=