Added the spawn-missile action, removed fireball death-coil whirlwind runes flame-shield.

Added multiple spell actions.
This commit is contained in:
n0body 2003-10-22 18:28:05 +00:00
parent 7fa6d72094
commit 7ffdb1d7bd
5 changed files with 311 additions and 314 deletions

View file

@ -36,8 +36,9 @@
<li>Future 2.00 Release<p>
<ul>
<li>++
<li>Applied missile smoke patch #2133, fixed task #2786. (from Jarod Dauphin)
<li>Made lots of missile changes, removed Missile::Controller. (from Crestez Leonard)
<li>Added the spawn-missile action, removed fireball death-coil whirlwind runes flame-shield (from Crestez Leonard).
<li>Applied missile smoke patch #2133, fixed task #2786. (from Jarod Dauphin).
<li>Made lots of missile changes, removed Missile::Controller. (from Crestez Leonard).
<li>Fixed Bug #6006: Crash saving building not built yet (from Russell Smith).
<li>Fixed Bug: Failed Building Crashes Engine (from Russell Smith).
<li>Remove old Master Server Code, began implementing a new one (from Russell Smith).

View file

@ -238,8 +238,13 @@ If the unit dies however the caster will stop. (Some spells get casted until
there is no more mana left).
</dd>
<dt>action</dt>
<dd>The effect of the spells. This comes in the form of 'action '(operation-name parameters ... ) <br>
Here are the supported operations , their paramenters, and what they do.<p>
<dd>The effect of the spells. This comes in the following form:
<pre>'action '((operation-name-1 parameters ... )
(operation-name-2 parameters ... )
...
(operation-name-n parameters ... ))
</pre>
Here are the supported operations, their paramenters, and what they do.<p>
<dl>
<dt>area-bombardment</dt>
<dl>This will a number of missiles to be thrown in a square area. Here are
@ -336,6 +341,43 @@ Here are the supported operations , their paramenters, and what they do.<p>
like a chicken.
</dd>
</dl>
<dt>spawn-missile</dt>
<dl>This will spawn a missile in the game. It's one of the most versatile
spell variants. Here are the paramenters:
<dt>ttl</dt>
<dd>Time to live for the missile. Usually means that the missile is
gone after this time, but for some missile classes it means something else.
</dd>
<dt>damage</dt>
<dd>This is the damage for this missile, overriding the standard damage
defined for the missile.
</dd>
<dt>delay</dt>
<dd>This is the delay for the missile. it means the missile will only
appear after this many ticks.
</dd>
<dt>start-point/end-point</dt>
<dl>Point to point-ish missiles need a start and an end point for the
trajectory. it is defined like this:
<pre>start-point (base caster/target add-x add-y add-rand-x add-rand-y)</pre>
The individual tags should be self-explanatory, but here goes:
<dt>base</dt>
<dd>The base for the location calculation. Can be either caster or target.
</dd>
<dt>add-x</dt>
<dd>How much to add to the x coordinate, in pixels
</dd>
<dt>add-y</dt>
<dd>How much to add to the y coordinate, in pixels
</dd>
<dt>add-rand-x</dt>
<dd>Add a random from 0 to value-1 to the x coordinate, in pixels
</dd>
<dt>add-rand-y</dt>
<dd>Add a random from 0 to value-1 to the y coordinate, in pixels
</dd>
</dl>
</dl>
</dl>
</dd>
</dl>

View file

@ -51,47 +51,58 @@
-- Definitons
----------------------------------------------------------------------------*/
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,
TargetPosition,
TargetUnit
} TargetType;
typedef struct _spell_action_type_ SpellActionType;
/*
** Pointer on function that cast the spell.
*/
typedef int SpellFunc(Unit* caster, const struct _spell_type_* spell,
const struct _spell_action_type_* action, Unit* target, int x, int y);
/**
** Different targets.
*/
typedef enum {
TargetSelf,
TargetPosition,
TargetUnit
#if 0
,
TargetUnits
#endif
} TargetType;
LocBaseCaster,
LocBaseTarget
} LocBaseType;
/*
** Pointer on function that cast the spell.
*/
typedef int SpellFunc(Unit* caster, const struct _spell_type_* spell, Unit* target,int x, int y);
** This struct is used for defining a missile start/stop location.
**
** It's evaluated like this, and should be more or less flexible.:
** base coordinates(caster or target) + (AddX,AddY) + (rand()%AddRandX,rand()%AddRandY)
**
**/
typedef struct {
LocBaseType Base; /// The base for the location (caster/target)
int AddX; /// Add to the X coordinate
int AddY; /// Add to the X coordinate
int AddRandX; /// Random add to the X coordinate
int AddRandY; /// Random add to the X coordinate
} SpellActionMissileLocation;
typedef struct
{
struct _spell_action_type_ {
SpellFunc* CastFunction;
// FIXME" some time information doesn't work as it should.
union {
// FIXME time information doesn't work as it should.
struct {
int Damage; /// Missile damage
int TTL; /// Missile TTL
int Delay; /// Missile original delay
SpellActionMissileLocation StartPoint; /// Start point description
SpellActionMissileLocation EndPoint; /// Start point description
} SpawnMissile;
struct {
int Fields; /// The size of the affected square
int Shards; /// Number of shards thrown.
@ -105,16 +116,6 @@ typedef struct
UnitType *PortalType; /// The unit type spawned
} SpawnPortal;
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} Fireball;
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} FlameShield;
struct {
int HasteTicks; /// Number of ticks to set Haste to.
int SlowTicks; /// Number of ticks to set Slow to.
@ -143,18 +144,9 @@ typedef struct
int RequireCorpse; /// Corpse consumed while summoning.
} Summon;
// What about a resurection spell?
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} Runes;
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} Whirlwind;
} Data;
} SpellActionType;
SpellActionType* Next; /// Next action.
};
/*
** *******************
@ -331,15 +323,12 @@ extern unsigned CclGetSpellByIdent(SCM value);
SpellFunc CastAdjustVitals;
SpellFunc CastAdjustBuffs;
SpellFunc CastFireball;
SpellFunc CastFlameShield;
SpellFunc CastPolymorph;
SpellFunc CastAreaBombardment;
SpellFunc CastSummon;
SpellFunc CastRunes;
SpellFunc CastDeathCoil;
SpellFunc CastWhirlwind;
SpellFunc CastSpawnPortal;
SpellFunc CastSpawnMissile;
//@}

View file

@ -50,10 +50,57 @@
// Action parsers for spellAction
// **************************************************************************
/*
/**
** Parse the missile location description for a spell action.
**
** @param list SCM list object, with the description.
** @param location Pointer to missile location description.
**
** @note This is only here to avoid code duplication. You don't have
** any reason to USE this:)
*/
local void CclSpellMissileLocation(SCM list, SpellActionMissileLocation* location)
{
SCM value;
DebugCheck(location == NULL);
memset(location, 0, sizeof(*location));
//list = gh_cdr(list);
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("base"))) {
if (gh_eq_p(gh_car(list), gh_symbol2scm("caster"))) {
location->Base = LocBaseCaster;
} else if (gh_eq_p(gh_car(list), gh_symbol2scm("target"))) {
location->Base = LocBaseTarget;
} else {
errl("Unsupported missile location base flag.\n",gh_car(list));
}
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("add-x"))) {
location->AddX = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("add-y"))) {
location->AddY = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("add-rand-x"))) {
location->AddRandX = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("add-rand-y"))) {
location->AddRandY = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported missile location description flag.\n",value);
}
}
}
/**
** Parse the action for spell.
**
** @param list SCM list object, with somthing like (action-type params).
** @param list SCM list object, with something like (action-type params).
** @param spellaction Pointer to spellactopm.
*/
local void CclSpellAction(SCM list, SpellActionType* spellaction)
@ -66,8 +113,35 @@ local void CclSpellAction(SCM list, SpellActionType* spellaction)
value = gh_car(list);
list = gh_cdr(list);
memset(spellaction, 0, sizeof(*spellaction));
if (gh_eq_p(value, gh_symbol2scm("area-bombardment"))) {
if (gh_eq_p(value, gh_symbol2scm("spawn-missile"))) {
spellaction->CastFunction = CastSpawnMissile;
spellaction->Data.SpawnMissile.StartPoint.Base=LocBaseCaster;
spellaction->Data.SpawnMissile.EndPoint.Base=LocBaseTarget;
spellaction->Data.SpawnMissile.TTL=-1;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->Data.SpawnMissile.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("delay"))) {
spellaction->Data.SpawnMissile.Delay = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("ttl"))) {
spellaction->Data.SpawnMissile.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("start-point"))) {
CclSpellMissileLocation(gh_car(list),&spellaction->Data.SpawnMissile.StartPoint);
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("end-point"))) {
CclSpellMissileLocation(gh_car(list),&spellaction->Data.SpawnMissile.EndPoint);
list = gh_cdr(list);
} else {
errl("Unsupported area-bombardment tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("area-bombardment"))) {
spellaction->CastFunction = CastAreaBombardment;
while (!gh_null_p(list)) {
value = gh_car(list);
@ -91,67 +165,6 @@ local void CclSpellAction(SCM list, SpellActionType* spellaction)
errl("Unsupported area-bombardment tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("flame-shield"))) {
spellaction->CastFunction = CastFlameShield;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("duration"))) {
spellaction->Data.FlameShield.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
/// FIXME:damage, missiles, rotation speed?
} else if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->Data.FlameShield.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
}else {
errl("Unsupported flame-shield tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("fireball"))) {
spellaction->CastFunction = CastFireball;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->Data.Fireball.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("ttl"))) {
spellaction->Data.Fireball.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported fireball tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("runes"))) {
spellaction->CastFunction = CastRunes;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->Data.Runes.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("ttl"))) {
spellaction->Data.Runes.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported runes tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("whirlwind"))) {
spellaction->CastFunction = CastWhirlwind;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("duration"))) {
spellaction->Data.Whirlwind.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->Data.Whirlwind.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported runes tag", value);
}
}
} else if (gh_eq_p(value, gh_symbol2scm("adjust-buffs"))) {
spellaction->CastFunction = CastAdjustBuffs;
spellaction->Data.AdjustBuffs.HasteTicks = BUFF_NOT_AFFECTED;
@ -426,6 +439,8 @@ local SCM CclDefineSpell(SCM list)
char* str;
SpellType* spell;
SCM value;
SCM sublist;
SpellActionType* act;
identname = gh_scm2newstr(gh_car(list), NULL);
list = gh_cdr(list);
@ -473,10 +488,19 @@ local SCM CclDefineSpell(SCM list)
}
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("action"))) {
if (!spell->Action) {
spell->Action = (SpellActionType*)malloc(sizeof(SpellActionType));
spell->Action = (SpellActionType*)malloc(sizeof(SpellActionType));
act=spell->Action;
memset(act, 0, sizeof(SpellActionType));
sublist=gh_car(list);
CclSpellAction(gh_car(sublist), act);
sublist=gh_cdr(sublist);
while (!gh_null_p(gh_car(sublist))) {
act->Next = (SpellActionType*)malloc(sizeof(SpellActionType));
act=act->Next;
memset(act, 0, sizeof(SpellActionType));
CclSpellAction(gh_car(sublist), act);
sublist=gh_cdr(sublist);
}
CclSpellAction(gh_car(list), spell->Action);
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("condition"))) {
if (!spell->Condition) {
@ -549,17 +573,44 @@ global void SpellCclRegister(void)
*/
local void SaveSpellAction(CLFile *file,SpellActionType* action)
{
SpellActionMissileLocation * loc;
if (action->CastFunction == CastAreaBombardment) {
CLprintf(file, "(area-bombardment fields %d shards %d damage %d start-offset-x %d start-offset-y %d)",
action->Data.AreaBombardment.Fields,
action->Data.AreaBombardment.Shards,
action->Data.AreaBombardment.Damage,
action->Data.AreaBombardment.StartOffsetX,
action->Data.AreaBombardment.StartOffsetY);
} else if (action->CastFunction == CastFireball) {
CLprintf(file, "(fireball ttl %d damage %d)",
action->Data.Fireball.TTL,
action->Data.Fireball.Damage);
action->Data.AreaBombardment.Fields,
action->Data.AreaBombardment.Shards,
action->Data.AreaBombardment.Damage,
action->Data.AreaBombardment.StartOffsetX,
action->Data.AreaBombardment.StartOffsetY);
} else if (action->CastFunction == CastSpawnMissile) {
CLprintf(file, "(spawn-missile delay %d ttl %d damage %d ",
action->Data.SpawnMissile.Delay,
action->Data.SpawnMissile.TTL,
action->Data.SpawnMissile.Damage);
//
// Save start-point
//
loc=&action->Data.SpawnMissile.StartPoint;
CLprintf(file, "start-point (base ");
if (loc->Base==LocBaseCaster) {
CLprintf(file, "caster");
} else {
CLprintf(file, "target");
}
CLprintf(file, " add-x %d add-y %d add-rand-x %d add-rand-y %d) ",
loc->AddX,loc->AddY,loc->AddRandX,loc->AddRandY);
//
// Save end-point
//
loc=&action->Data.SpawnMissile.EndPoint;
CLprintf(file, "end-point (base ");
if (loc->Base==LocBaseCaster) {
CLprintf(file, "caster");
} else {
CLprintf(file, "target");
}
CLprintf(file, " add-x %d add-y %d add-rand-x %d add-rand-y %d)",
loc->AddX,loc->AddY,loc->AddRandX,loc->AddRandY);
CLprintf(file, ")");
} else if (action->CastFunction == CastAdjustVitals) {
CLprintf(file, "(adjust-vitals");
if (action->Data.AdjustVitals.HP) {
@ -574,8 +625,8 @@ local void SaveSpellAction(CLFile *file,SpellActionType* action)
CLprintf(file, ")\n");
} else if (action->CastFunction == CastSummon) {
CLprintf(file, "(summon unit-type %s time-to-live %d",
action->Data.Summon.UnitType->Ident,
action->Data.Summon.TTL);
action->Data.Summon.UnitType->Ident,
action->Data.Summon.TTL);
if (action->Data.Summon.RequireCorpse) {
CLprintf(file, " require-corpse ");
}
@ -600,20 +651,10 @@ local void SaveSpellAction(CLFile *file,SpellActionType* action)
CLprintf(file, ")");
} else if (action->CastFunction == CastPolymorph) {
CLprintf(file, "(polymorph new-form %s)",
action->Data.Polymorph.NewForm->Ident);
} else if (action->CastFunction == CastFlameShield) {
CLprintf(file, "(flame-shield duration %d)",
action->Data.FlameShield.TTL);
} else if (action->CastFunction == CastRunes) {
CLprintf(file, "(runes ttl %d damage %d)",
action->Data.Runes.TTL,
action->Data.Runes.Damage);
action->Data.Polymorph.NewForm->Ident);
} else if (action->CastFunction == CastSpawnPortal) {
CLprintf(file, "(spawn-portal portal-type %s)",
action->Data.SpawnPortal.PortalType->Ident);
} else if (action->CastFunction == CastWhirlwind) {
CLprintf(file, "(whirlwind duration %d damage %d)",
action->Data.Whirlwind.TTL, action->Data.Whirlwind.Damage);
action->Data.SpawnPortal.PortalType->Ident);
}
}
@ -717,6 +758,7 @@ void SaveSpellAutoCast(CLFile* file, AutoCastInfo* autocast)
global void SaveSpells(CLFile* file)
{
SpellType* spell;
SpellActionType* act;
DebugCheck(!file);
@ -756,9 +798,15 @@ global void SaveSpells(CLFile* file)
//
// Save the action(effect of the spell)
//
CLprintf(file, " 'action '");
SaveSpellAction(file, spell->Action);
CLprintf(file, "\n");
CLprintf(file, " 'action '(\n");
act=spell->Action;
while (act) {
CLprintf(file," ");
SaveSpellAction(file, act);
CLprintf(file,"\n");
act=act->Next;
}
CLprintf(file, ")\n");
//
// Save conditions
//

View file

@ -98,7 +98,7 @@ global int SpellTypeCount;
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((unused)),
Unit* target __attribute__((unused)), int x, int y)
const SpellActionType* action,Unit* target __attribute__((unused)), int x, int y)
{
// FIXME: vladi: cop should be placed only on explored land
Unit* portal;
@ -146,7 +146,7 @@ global int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((u
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastAreaBombardment(Unit* caster, const SpellType* spell,
Unit* target __attribute__((unused)), int x, int y)
const SpellActionType* action,Unit* target __attribute__((unused)), int x, int y)
{
int fields;
int shards;
@ -198,13 +198,47 @@ global int CastAreaBombardment(Unit* caster, const SpellType* spell,
caster->Refs++;
}
}
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
caster->Mana -= spell->ManaCost;
return caster->Mana > spell->ManaCost;
}
/**
** Cast fireball.
** Evaluate missile location description.
**
** @param caster Unit that casts the spell
** @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 resx pointer to X coord of the result
** @param resy pointer to Y coord of the result
*/
local void EvaluateMissileLocation(const SpellActionMissileLocation* location,
Unit* caster,Unit* target, int x, int y,int* resx, int* resy)
{
if (location->Base==LocBaseCaster) {
*resx = caster->X * TileSizeX + TileSizeX / 2;
*resy = caster->Y * TileSizeY + TileSizeY / 2;
} else {
if (target) {
*resx = target->X * TileSizeX + TileSizeX / 2;
*resy = target->Y * TileSizeY + TileSizeY / 2;
} else {
*resx = x * TileSizeX + TileSizeX / 2;
*resy = y * TileSizeY + TileSizeY / 2;
}
}
*resx += location->AddX;
if (location->AddRandX) {
*resx += rand()%location->AddRandX;
}
*resy += location->AddY;
if (location->AddRandY) {
*resy += rand()%location->AddRandY;
}
}
/**
** Cast spawn missile.
**
** @param caster Unit that casts the spell
** @param spell Spell-type pointer
@ -214,12 +248,14 @@ global int CastAreaBombardment(Unit* caster, const SpellType* spell,
**
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastFireball(Unit* caster, const SpellType* spell,
Unit* target __attribute__((unused)), int x, int y)
global int CastSpawnMissile(Unit* caster, const SpellType* spell,
const SpellActionType* action, Unit* target, int x, int y)
{
Missile* missile;
int sx;
int sy;
int dx;
int dy;
DebugCheck(!caster);
DebugCheck(!spell);
@ -228,63 +264,22 @@ global int CastFireball(Unit* caster, const SpellType* spell,
missile = NULL;
// NOTE: fireball can be casted on spot
sx = caster->X * TileSizeX + TileSizeX / 2;
sy = caster->Y * TileSizeY + TileSizeY / 2;
x = x * TileSizeX + TileSizeX / 2;
y = y * TileSizeY + TileSizeY / 2;
caster->Mana -= spell->ManaCost;
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
missile = MakeMissile(spell->Missile, sx, sy, x, y);
// missile->TTL = spell->Action->Data.Fireball.TTL;
missile->Damage = spell->Action->Data.Fireball.Damage;
EvaluateMissileLocation(&action->Data.SpawnMissile.StartPoint,
caster,target,x,y,&sx,&sy);
EvaluateMissileLocation(&action->Data.SpawnMissile.EndPoint,
caster,target,x,y,&dx,&dy);
missile = MakeMissile(spell->Missile, sx, sy, dx, dy);
missile->TTL = action->Data.SpawnMissile.TTL;
missile->Delay = action->Data.SpawnMissile.Delay;
missile->Damage = action->Data.SpawnMissile.Damage;
missile->SourceUnit = caster;
missile->TargetUnit = target;
RefsDebugCheck(!caster->Refs || caster->Destroyed);
caster->Refs++;
return 0;
}
/**
** Cast flame shield.
**
** @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 int CastFlameShield(Unit* caster, const SpellType* spell, Unit* target,
int x __attribute__((unused)), int y __attribute__((unused)))
{
Missile* mis;
int i;
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->Action);
DebugCheck(!target);
// DebugCheck(x in range, y in range);
DebugCheck(!spell->Missile);
mis = NULL;
// get mana cost
caster->Mana -= spell->ManaCost;
target->FlameShield = spell->Action->Data.FlameShield.TTL;
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
for (i = 0; i < 5; ++i) {
mis = MakeMissile(spell->Missile, 0, 0, 0, 0);
mis->TTL = spell->Action->Data.FlameShield.TTL + i * 7;
mis->TargetUnit = target;
mis->Damage = spell->Action->Data.FlameShield.Damage;
RefsDebugCheck(!target->Refs || target->Destroyed);
target->Refs++;
}
return 0;
}
/**
** Cast haste.
**
@ -296,17 +291,14 @@ global int CastFlameShield(Unit* caster, const SpellType* spell, Unit* target,
**
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastAdjustBuffs(Unit* caster, const SpellType* spell, Unit* target,
int x, int y)
global int CastAdjustBuffs(Unit* caster, const SpellType* spell,
const SpellActionType* action, Unit* target, int x, int y)
{
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->Action);
DebugCheck(!target);
// get mana cost
caster->Mana -= spell->ManaCost;
if (spell->Action->Data.AdjustBuffs.HasteTicks!=BUFF_NOT_AFFECTED) {
target->Haste = spell->Action->Data.AdjustBuffs.HasteTicks;
}
@ -323,7 +315,6 @@ global int CastAdjustBuffs(Unit* caster, const SpellType* spell, Unit* target,
target->UnholyArmor = spell->Action->Data.AdjustBuffs.InvincibilityTicks;
}
CheckUnitToBeDrawn(target);
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
MakeMissile(spell->Missile,
x * TileSizeX+TileSizeX / 2, y * TileSizeY+TileSizeY / 2,
x * TileSizeX+TileSizeX / 2, y * TileSizeY+TileSizeY / 2);
@ -341,8 +332,8 @@ global int CastAdjustBuffs(Unit* caster, const SpellType* spell, Unit* target,
**
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastAdjustVitals(Unit* caster, const SpellType* spell, Unit* target,
int x, int y)
global int CastAdjustVitals(Unit* caster, const SpellType* spell,
const SpellActionType* action,Unit* target,int x, int y)
{
int castcount;
int diffHP;
@ -415,7 +406,6 @@ global int CastAdjustVitals(Unit* caster, const SpellType* spell, Unit* target,
DebugLevel3Fn("Unit now has %d hp and %d mana.\n" _C_
target->HP _C_ target->Mana);
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
MakeMissile(spell->Missile,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
@ -433,8 +423,8 @@ global int CastAdjustVitals(Unit* caster, const SpellType* spell, Unit* target,
**
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastPolymorph(Unit* caster, const SpellType* spell, Unit* target,
int x, int y)
global int CastPolymorph(Unit* caster, const SpellType* spell,
const SpellActionType* action, Unit* target,int x, int y)
{
UnitType* type;
@ -466,64 +456,12 @@ global int CastPolymorph(Unit* caster, const SpellType* spell, Unit* target,
if (UnitTypeCanMoveTo(x, y, type)) {
MakeUnitAndPlace(x, y, type, Players + PlayerNumNeutral);
}
caster->Mana -= spell->ManaCost;
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
MakeMissile(spell->Missile,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
return 0;
}
/**
** Cast runes.
**
** @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 int CastRunes(Unit* caster, const SpellType* spell,
Unit* target __attribute__((unused)), int x, int y)
{
Missile* mis;
const int xx[] = {-1,+1, 0, 0, 0};
const int yy[] = { 0, 0, 0,-1,+1};
int oldx;
int oldy;
int i;
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->Action);
// DebugCheck(x in range, y in range);
mis = NULL;
oldx = x;
oldy = y;
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
for (i = 0; i < 5; ++i) {
x = oldx + xx[i];
y = oldy + yy[i];
if (IsMapFieldEmpty(x, y)) {
mis = MakeMissile(spell->Missile,
x * TileSizeX + TileSizeX / 2,
y * TileSizeY + TileSizeY / 2,
x * TileSizeX + TileSizeX / 2,
y * TileSizeY + TileSizeY / 2);
mis->TTL = spell->Action->Data.Runes.TTL;
mis->Damage = spell->Action->Data.Runes.Damage;
mis->SourceUnit = caster;
caster->Mana -= spell->ManaCost / 5;
}
}
return 0;
}
/**
** Cast summon spell.
**
@ -535,8 +473,8 @@ global int CastRunes(Unit* caster, const SpellType* spell,
**
** @return =!0 if spell should be repeated, 0 if not
*/
global int CastSummon(Unit* caster, const SpellType* spell, Unit* target,
int x, int y)
global int CastSummon(Unit* caster, const SpellType* spell,
const SpellActionType* action,Unit* target,int x, int y)
{
int ttl;
int cansummon;
@ -611,47 +549,12 @@ global int CastSummon(Unit* caster, const SpellType* spell, Unit* target,
caster->Mana -= spell->ManaCost;
}
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
MakeMissile(spell->Missile,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);
return 0;
}
/**
** Cast whirlwind.
**
** @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 int CastWhirlwind(Unit* caster, const SpellType* spell,
Unit* target __attribute__((unused)), int x, int y)
{
Missile* mis;
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->Action);
// DebugCheck(x in range, y in range);
mis = NULL;
caster->Mana -= spell->ManaCost;
PlayGameSound(spell->SoundWhenCast.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->Action->Data.Whirlwind.TTL;
mis->Damage = spell->Action->Data.Whirlwind.Damage;
mis->SourceUnit = caster;
return 0;
}
// ****************************************************************************
// Target constructor
// ****************************************************************************
@ -1144,6 +1047,7 @@ global int AutoCastSpell(Unit* caster, const SpellType* spell)
global int SpellCast(Unit* caster, const SpellType* spell, Unit* target,
int x, int y)
{
SpellActionType* act;
DebugCheck(!spell);
DebugCheck(!spell->Action->CastFunction);
DebugCheck(!caster);
@ -1159,8 +1063,21 @@ global int SpellCast(Unit* caster, const SpellType* spell, Unit* target,
}
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->Action->CastFunction(caster, spell, target, x, y);
if (CanCastSpell(caster, spell, target, x, y)) {
act=spell->Action;
//
// Ugly hack, CastAdjustVitals makes it's own mana calculation.
//
if (act->CastFunction!=CastAdjustVitals) {
caster->Mana -= spell->ManaCost;
}
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
while (act) {
act->CastFunction(caster, spell, act, target, x, y);
act=act->Next;
}
}
return 0;
}
/*