Added the spawn-missile action, removed fireball death-coil whirlwind runes flame-shield.
Added multiple spell actions.
This commit is contained in:
parent
7fa6d72094
commit
7ffdb1d7bd
5 changed files with 311 additions and 314 deletions
|
@ -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).
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
//@}
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue