Spell stuff. Autocast disabled. HolyVision implemented with summon. Save conditions.

This commit is contained in:
n0body 2003-09-29 23:27:53 +00:00
parent fb06d9d144
commit 7d4a583f6b
4 changed files with 309 additions and 289 deletions

View file

@ -74,7 +74,8 @@ global void AiCheckMagic(void)
if(unit->Type->CanCastSpell) {
for (j = 0; j < SpellTypeCount; j++) {
// Check if we can cast this spell. SpellIsAvailable checks for upgrades.
if (unit->Type->CanCastSpell[j] && SpellIsAvailable(player, j)) {
if (unit->Type->CanCastSpell[j] && SpellIsAvailable(player, j) &&
SpellTypeById(j)->AutoCast) {
#ifdef DEBUG
success = // Follow on next line (AutoCastSpell).
#endif

View file

@ -89,82 +89,81 @@ typedef enum {
#endif
} TargetType;
/*
** Pointer on function that cast the spell.
*/
typedef int SpellFunc(Unit* caster, const struct _spell_type_* spell, Unit* target,int x, int y);
typedef union
typedef struct
{
// FIXME rename structure more properly.
// TTL's below are in ticks: approx: 500=13sec, 1000=25sec, 2000=50sec
// FIXME use TTL, as in TICKS to live
struct {
int Fields; /// The size of the affected square
int Shards; /// Number of shards thrown.
int Damage; /// Damage for every shard.
/// The offset of the missile start point to the hit location.
int StartOffsetX;
int StartOffsetY;
} AreaBombardment;
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)
} FlameShield;
SpellFunc* CastFunction;
union {
// FIXME time information doesn't work as it should.
struct {
int Fields; /// The size of the affected square
int Shards; /// Number of shards thrown.
int Damage; /// Damage for every shard.
/// The offset of the missile start point to the hit location.
int StartOffsetX;
int StartOffsetY;
} AreaBombardment;
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)
} FlameShield;
struct {
int HasteTicks; /// Number of ticks to set Haste to.
int SlowTicks; /// Number of ticks to set Slow to.
int BloodlustTicks; /// Number of ticks to set Bloodlust to.
int InvisibilityTicks; /// Number of ticks to set Invisibility to.
int InvincibilityTicks; /// Number of ticks to set UnholyArmor to.
struct {
int HasteTicks; /// Number of ticks to set Haste to.
int SlowTicks; /// Number of ticks to set Slow to.
int BloodlustTicks; /// Number of ticks to set Bloodlust to.
int InvisibilityTicks; /// Number of ticks to set Invisibility to.
int InvincibilityTicks; /// Number of ticks to set UnholyArmor to.
#define BUFF_NOT_AFFECTED 0xC0FF33 /// Don't like the value? The value doesn't like you!
} AdjustBuffs;
struct {
int HP; /// Target HP gain.(can be negative)
int Mana; /// Target Mana gain.(can be negative)
/// This spell is designed to be used wit very small amounts. The spell
/// can scale up to MaxMultiCast times. Use 0 for infinite.
int MaxMultiCast;
} AdjustVitals;
struct {
UnitType *revealer; /// Type of unit to be summoned: (unit-revealer).
} HolyVision;
struct {
UnitType *NewForm; /// The new form
// TODO: temporary polymorphs would be awesome, but hard to implement
} Polymorph;
struct {
UnitType *UnitType; /// Type of unit to be summoned.
int TTL; /// Time to live for summoned unit. 0 means infinite
} Summon;
struct {
UnitType *UnitRaised; /// The unit to spawn from corpses
int TTL; /// Time to live for summon. 0 means infinite.
} RaiseDead;
// What about a resurection spell?
} AdjustBuffs;
struct {
int HP; /// Target HP gain.(can be negative)
int Mana; /// Target Mana gain.(can be negative)
/// This spell is designed to be used wit very small amounts. The spell
/// can scale up to MaxMultiCast times. Use 0 for infinite.
int MaxMultiCast;
} AdjustVitals;
struct {
UnitType *NewForm; /// The new form
// TODO: temporary polymorphs would be awesome, but hard to implement
} Polymorph;
struct {
UnitType *UnitType; /// Type of unit to be summoned.
int TTL; /// Time to live for summoned unit. 0 means infinite
} Summon;
struct {
UnitType *UnitRaised; /// The unit to spawn from corpses
int TTL; /// Time to live for summon. 0 means infinite.
} RaiseDead;
// What about a resurection spell?
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} Runes;
struct {
int TTL; /// time to live (ticks)
// FIXME: more configurations
} Whirlwind;
struct {
int TTL; /// time to live (ticks)
int Damage; /// Damage.
} Runes;
struct {
int TTL; /// time to live (ticks)
// FIXME: more configurations
} Whirlwind;
} Data;
} SpellActionType;
/*
@ -242,11 +241,6 @@ typedef struct {
struct _spell_type_;
/*
** Pointer on function that cast the spell.
*/
typedef int SpellFunc(Unit* caster, const struct _spell_type_* spell, Unit* target,int x, int y);
/**
** Base structure of a spell type.
*/
@ -258,8 +252,7 @@ typedef struct _spell_type_ {
// Spell Specifications
TargetType Target; /// Targetting information. See TargetType.
SpellFunc *CastFunction; /// function to cast the spell.
SpellActionType *SpellAction; /// More arguments for spell (damage, delay, additional sounds...).
SpellActionType *Action; /// More arguments for spell (damage, delay, additional sounds...).
#define INFINITE_RANGE 0xFFFFFFF
int Range; /// Max range of the target.
int ManaCost; /// required mana for each cast
@ -336,7 +329,6 @@ extern unsigned CclGetSpellByIdent(SCM value);
** Spelltype to cast.
*/
SpellFunc CastHolyVision;
SpellFunc CastAdjustVitals;
SpellFunc CastAdjustBuffs;
SpellFunc CastFireball;
@ -350,7 +342,6 @@ SpellFunc CastRaiseDead;
SpellFunc CastWhirlwind;
SpellFunc CastSpawnPortal;
//@}
#endif // !__SPELLS_H__

View file

@ -109,36 +109,36 @@ local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spel
memset(spellaction, 0, sizeof(*spellaction));
if (gh_eq_p(value,gh_symbol2scm("area-bombardment"))) {
spell->CastFunction=CastAreaBombardment;
spellaction->CastFunction=CastAreaBombardment;
while (!gh_null_p(list)) {
value = gh_car(list);
list=gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("fields"))) {
spellaction->AreaBombardment.Fields = gh_scm2int(gh_car(list));
spellaction->Data.AreaBombardment.Fields = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("shards"))) {
spellaction->AreaBombardment.Shards = gh_scm2int(gh_car(list));
spellaction->Data.AreaBombardment.Shards = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("damage"))) {
spellaction->AreaBombardment.Damage = gh_scm2int(gh_car(list));
spellaction->Data.AreaBombardment.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("start-offset-x"))) {
spellaction->AreaBombardment.StartOffsetX = gh_scm2int(gh_car(list));
spellaction->Data.AreaBombardment.StartOffsetX = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("start-offset-y"))) {
spellaction->AreaBombardment.StartOffsetY = gh_scm2int(gh_car(list));
spellaction->Data.AreaBombardment.StartOffsetY = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported area-bombardment tag",value);
}
}
} else if (gh_eq_p(value,gh_symbol2scm("flame-shield"))) {
spell->CastFunction=CastFlameShield;
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->FlameShield.TTL = gh_scm2int(gh_car(list));
spellaction->Data.FlameShield.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
/// FIXME:damage, missiles, rotation speed?
} else {
@ -146,107 +146,107 @@ local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spel
}
}
} else if (gh_eq_p(value,gh_symbol2scm("fireball"))) {
spell->CastFunction=CastFireball;
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->Fireball.Damage = gh_scm2int(gh_car(list));
spellaction->Data.Fireball.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("ttl"))) {
spellaction->Fireball.TTL = gh_scm2int(gh_car(list));
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"))) {
spell->CastFunction=CastRunes;
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->Fireball.Damage = gh_scm2int(gh_car(list));
spellaction->Data.Fireball.Damage = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("ttl"))) {
spellaction->Fireball.TTL = gh_scm2int(gh_car(list));
spellaction->Data.Fireball.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"))) {
spell->CastFunction=CastWhirlwind;
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->Whirlwind.TTL = gh_scm2int(gh_car(list));
spellaction->Data.Whirlwind.TTL = 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"))) {
spell->CastFunction=CastAdjustBuffs;
spellaction->AdjustBuffs.HasteTicks=BUFF_NOT_AFFECTED;
spellaction->AdjustBuffs.SlowTicks=BUFF_NOT_AFFECTED;
spellaction->AdjustBuffs.BloodlustTicks=BUFF_NOT_AFFECTED;
spellaction->AdjustBuffs.InvisibilityTicks=BUFF_NOT_AFFECTED;
spellaction->AdjustBuffs.InvincibilityTicks=BUFF_NOT_AFFECTED;
spellaction->CastFunction=CastAdjustBuffs;
spellaction->Data.AdjustBuffs.HasteTicks=BUFF_NOT_AFFECTED;
spellaction->Data.AdjustBuffs.SlowTicks=BUFF_NOT_AFFECTED;
spellaction->Data.AdjustBuffs.BloodlustTicks=BUFF_NOT_AFFECTED;
spellaction->Data.AdjustBuffs.InvisibilityTicks=BUFF_NOT_AFFECTED;
spellaction->Data.AdjustBuffs.InvincibilityTicks=BUFF_NOT_AFFECTED;
while (!gh_null_p(list)) {
value = gh_car(list);
list=gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("haste-ticks"))) {
spellaction->AdjustBuffs.HasteTicks = gh_scm2int(gh_car(list));
spellaction->Data.AdjustBuffs.HasteTicks = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("slow-ticks"))) {
spellaction->AdjustBuffs.SlowTicks = gh_scm2int(gh_car(list));
spellaction->Data.AdjustBuffs.SlowTicks = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("bloodlust-ticks"))) {
spellaction->AdjustBuffs.BloodlustTicks = gh_scm2int(gh_car(list));
spellaction->Data.AdjustBuffs.BloodlustTicks = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("invisibility-ticks"))) {
spellaction->AdjustBuffs.InvisibilityTicks = gh_scm2int(gh_car(list));
spellaction->Data.AdjustBuffs.InvisibilityTicks = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("invincibility-ticks"))) {
spellaction->AdjustBuffs.InvincibilityTicks = gh_scm2int(gh_car(list));
spellaction->Data.AdjustBuffs.InvincibilityTicks = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported adjust-buffs tag",value);
}
}
} else if (gh_eq_p(value,gh_symbol2scm("summon"))) {
spell->CastFunction=CastSummon;
spellaction->CastFunction=CastSummon;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("unit-type"))) {
str = gh_scm2newstr(gh_car(list),0);
spellaction->Summon.UnitType = UnitTypeByIdent(str);
if (!spellaction->Summon.UnitType) {
spellaction->Summon.UnitType = 0;
spellaction->Data.Summon.UnitType = UnitTypeByIdent(str);
if (!spellaction->Data.Summon.UnitType) {
spellaction->Data.Summon.UnitType = 0;
DebugLevel0("unit type \"%s\" not found for summon spell.\n" _C_ str);
}
free(str);
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("time-to-live"))) {
spellaction->Summon.TTL = gh_scm2int(gh_car(list));
spellaction->Data.Summon.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported summon tag",value);
}
}
} else if (gh_eq_p(value,gh_symbol2scm("spawn-portal"))) {
spell->CastFunction=CastSpawnPortal;
spellaction->CastFunction=CastSpawnPortal;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("portal-type"))) {
str = gh_scm2newstr(gh_car(list),0);
spellaction->SpawnPortal.PortalType = UnitTypeByIdent(str);
if (!spellaction->SpawnPortal.PortalType) {
spellaction->SpawnPortal.PortalType = 0;
spellaction->Data.SpawnPortal.PortalType = UnitTypeByIdent(str);
if (!spellaction->Data.SpawnPortal.PortalType) {
spellaction->Data.SpawnPortal.PortalType = 0;
DebugLevel0("unit type \"%s\" not found for spawn-portal.\n" _C_ str);
}
free(str);
@ -256,36 +256,36 @@ local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spel
}
}
} else if (gh_eq_p(value,gh_symbol2scm("raise-dead"))) {
spell->CastFunction=CastRaiseDead;
spellaction->CastFunction=CastRaiseDead;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("unit-raised"))) {
str = gh_scm2newstr(gh_car(list),0);
spellaction->RaiseDead.UnitRaised = UnitTypeByIdent(str);
if (!spellaction->RaiseDead.UnitRaised) {
spellaction->RaiseDead.UnitRaised = 0;
spellaction->Data.RaiseDead.UnitRaised = UnitTypeByIdent(str);
if (!spellaction->Data.RaiseDead.UnitRaised) {
spellaction->Data.RaiseDead.UnitRaised = 0;
DebugLevel0("unit type \"%s\" not found for summon spell.\n" _C_ str);
}
free(str);
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("time-to-live"))) {
spellaction->RaiseDead.TTL = gh_scm2int(gh_car(list));
spellaction->Data.RaiseDead.TTL = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported raise-dead tag",value);
}
}
} else if (gh_eq_p(value,gh_symbol2scm("polymorph"))) {
spell->CastFunction=CastPolymorph;
spellaction->CastFunction=CastPolymorph;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("new-form"))) {
str = gh_scm2newstr(gh_car(list),0);
spellaction->Summon.UnitType = UnitTypeByIdent(str);
if (!spellaction->Summon.UnitType) {
spellaction->Summon.UnitType = 0;
spellaction->Data.Summon.UnitType = UnitTypeByIdent(str);
if (!spellaction->Data.Summon.UnitType) {
spellaction->Data.Summon.UnitType = 0;
DebugLevel0("unit type \"%s\" not found for summon spell.\n" _C_ str);
}
free(str);
@ -296,18 +296,18 @@ local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spel
}
}
} else if (gh_eq_p(value,gh_symbol2scm("adjust-vitals"))) {
spell->CastFunction=CastAdjustVitals;
spellaction->CastFunction=CastAdjustVitals;
while (!gh_null_p(list)) {
value = gh_car(list);
list=gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("hit-points"))) {
spellaction->AdjustVitals.HP = gh_scm2int(gh_car(list));
spellaction->Data.AdjustVitals.HP = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("mana-points"))) {
spellaction->AdjustVitals.Mana = gh_scm2int(gh_car(list));
spellaction->Data.AdjustVitals.Mana = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("max-multi-cast"))) {
spellaction->AdjustVitals.MaxMultiCast = gh_scm2int(gh_car(list));
spellaction->Data.AdjustVitals.MaxMultiCast = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else {
errl("Unsupported adjust-vitals tag",value);
@ -396,7 +396,7 @@ local void CclSpellParseCondition(SCM list, ConditionInfo* condition)
condition->TargetSelf=Scm2Condition(gh_car(list));
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("min-hp-percent"))) {
condition->MaxHpPercent=gh_scm2int(gh_car(list));
condition->MinHpPercent=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("max-hp-percent"))) {
condition->MaxHpPercent=gh_scm2int(gh_car(list));
@ -525,8 +525,8 @@ local SCM CclDefineSpell(SCM list)
}
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("action"))) {
spell->SpellAction=(SpellActionType*)malloc(sizeof(SpellActionType));
CclParseSpellAction(gh_car(list),spell,spell->SpellAction);
spell->Action=(SpellActionType*)malloc(sizeof(SpellActionType));
CclParseSpellAction(gh_car(list),spell,spell->Action);
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("condition"))) {
spell->Conditions=(ConditionInfo*)malloc(sizeof(ConditionInfo));
@ -574,6 +574,136 @@ global void SpellCclRegister(void)
gh_new_procedureN("define-spell", CclDefineSpell);
}
/*
** Save a spell action to a file.
**
** @param file File pointer to save to
** @param action Pointer to action to save.
*/
local void SaveSpellCondition(CLFile *file,ConditionInfo* condition)
{
char condstrings [3][10] = {
"true", /// CONDITION_TRUE
"false", /// CONDITION_FALSE
"only" /// CONDITION_ONLY
};
DebugCheck(!file);
DebugCheck(!condition);
CLprintf(file,"'( ");
//
// First save data related to flags.
// NOTE: (int) is there to keep compilers happy.
//
CLprintf(file,"undead %s ",condstrings[(int)condition->Undead]);
CLprintf(file,"organic %s ",condstrings[(int)condition->Organic]);
CLprintf(file,"hero %s ",condstrings[(int)condition->Hero]);
CLprintf(file,"coward %s ",condstrings[(int)condition->Coward]);
CLprintf(file,"alliance %s ",condstrings[(int)condition->Alliance]);
CLprintf(file,"building %s ",condstrings[(int)condition->Building]);
CLprintf(file,"self %s ",condstrings[(int)condition->TargetSelf]);
//
// Min/Max vital percents
//
CLprintf(file,"min-hp-percent %d ",condition->MinHpPercent);
CLprintf(file,"max-hp-percent %d ",condition->MaxHpPercent);
CLprintf(file,"min-mana-percent %d ",condition->MinManaPercent);
CLprintf(file,"max-mana-percent %d ",condition->MaxManaPercent);
//
// Max buff ticks stuff
//
CLprintf(file,"max-slow-ticks %d ",condition->MaxSlowTicks);
CLprintf(file,"max-haste-ticks %d ",condition->MaxHasteTicks);
CLprintf(file,"max-bloodlust-ticks %d ",condition->MaxBloodlustTicks);
CLprintf(file,"max-invisibility-ticks %d ",condition->MaxInvisibilityTicks);
CLprintf(file,"max-invincibility-ticks %d ",condition->MaxInvincibilityTicks);
//
// The end.
//
CLprintf(file,")\n");
}
/*
** Save a spell action to a file.
**
** @param file File pointer to save to
** @param action Pointer to action to save.
*/
local void SaveSpellAction(CLFile *file,SpellActionType* action)
{
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);
} else if (action->CastFunction==CastAdjustVitals) {
CLprintf(file," '(adjust-vitals");
if (action->Data.AdjustVitals.HP) {
CLprintf(file," hit-points %d",action->Data.AdjustVitals.HP);
}
if (action->Data.AdjustVitals.Mana) {
CLprintf(file," mana-points %d",action->Data.AdjustVitals.Mana);
}
if (action->Data.AdjustVitals.MaxMultiCast) {
CLprintf(file," max-multi-cast %d",action->Data.AdjustVitals.MaxMultiCast);
}
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);
} else if (action->CastFunction==CastAdjustBuffs) {
CLprintf(file," '(adjust-buffs");
if (action->Data.AdjustBuffs.HasteTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," haste-ticks %d",action->Data.AdjustBuffs.HasteTicks);
}
if (action->Data.AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," slow-ticks %d",action->Data.AdjustBuffs.SlowTicks);
}
if (action->Data.AdjustBuffs.BloodlustTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," bloodlust-ticks %d",action->Data.AdjustBuffs.BloodlustTicks);
}
if (action->Data.AdjustBuffs.InvisibilityTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," invisibility-ticks %d",action->Data.AdjustBuffs.InvisibilityTicks);
}
if (action->Data.AdjustBuffs.InvincibilityTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," invincibility-ticks %d",action->Data.AdjustBuffs.InvincibilityTicks);
}
CLprintf(file,")");
} else if (action->CastFunction==CastPolymorph) {
CLprintf(file," '(polymorph new-form %s)",
action->Data.Polymorph.NewForm->Ident);
} else if (action->CastFunction==CastRaiseDead) {
CLprintf(file," '(raise-dead unit-raised %s time-to-live %d)",
action->Data.RaiseDead.UnitRaised->Ident,
action->Data.RaiseDead.TTL);
} 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);
} else if (action->CastFunction==CastSpawnPortal) {
CLprintf(file," '(spawn-portal portal-type %s)",
action->Data.SpawnPortal.PortalType->Ident);
} else if (action->CastFunction==CastDeathCoil) {
CLprintf(file," '(death-coil)");
// FIXME: more?
} else if (action->CastFunction==CastWhirlwind) {
CLprintf(file," '(whirlwind duration %d)",
action->Data.Whirlwind.TTL);
// FIXME: more?
}
}
/**
** Save spells to a CCL file.
**
@ -624,81 +754,17 @@ global void SaveSpells(CLFile *file)
//
// Save the action(effect of the spell)
//
CLprintf(file," 'action");
if (spell->CastFunction==CastAreaBombardment) {
CLprintf(file," '(area-bombardment fields %d shards %d damage %d start-offset-x %d start-offset-y %d)\n",
spell->SpellAction->AreaBombardment.Fields,
spell->SpellAction->AreaBombardment.Shards,
spell->SpellAction->AreaBombardment.Damage,
spell->SpellAction->AreaBombardment.StartOffsetX,
spell->SpellAction->AreaBombardment.StartOffsetY);
} else if (spell->CastFunction==CastFireball) {
CLprintf(file," '(fireball ttl %d damage %d)\n",
spell->SpellAction->Fireball.TTL,
spell->SpellAction->Fireball.Damage);
} else if (spell->CastFunction==CastAdjustVitals) {
CLprintf(file," '(adjust-vitals");
if (spell->SpellAction->AdjustVitals.HP) {
CLprintf(file," hit-points %d",spell->SpellAction->AdjustVitals.HP);
}
if (spell->SpellAction->AdjustVitals.Mana) {
CLprintf(file," mana-points %d",spell->SpellAction->AdjustVitals.Mana);
}
if (spell->SpellAction->AdjustVitals.MaxMultiCast) {
CLprintf(file," max-multi-cast %d",spell->SpellAction->AdjustVitals.MaxMultiCast);
}
CLprintf(file,")\n");
} else if (spell->CastFunction==CastSummon) {
CLprintf(file," '(summon unit-type %s time-to-live %d)\n",
spell->SpellAction->Summon.UnitType->Ident,
spell->SpellAction->Summon.TTL);
} else if (spell->CastFunction==CastAdjustBuffs) {
CLprintf(file," '(adjust-buffs");
if (spell->SpellAction->AdjustBuffs.HasteTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," haste-ticks %d",spell->SpellAction->AdjustBuffs.HasteTicks);
}
if (spell->SpellAction->AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," slow-ticks %d",spell->SpellAction->AdjustBuffs.SlowTicks);
}
if (spell->SpellAction->AdjustBuffs.BloodlustTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," bloodlust-ticks %d",spell->SpellAction->AdjustBuffs.BloodlustTicks);
}
if (spell->SpellAction->AdjustBuffs.InvisibilityTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," invisibility-ticks %d",spell->SpellAction->AdjustBuffs.InvisibilityTicks);
}
if (spell->SpellAction->AdjustBuffs.InvincibilityTicks!=BUFF_NOT_AFFECTED) {
CLprintf(file," invincibility-ticks %d",spell->SpellAction->AdjustBuffs.InvincibilityTicks);
}
CLprintf(file,")\n");
} else if (spell->CastFunction==CastPolymorph) {
CLprintf(file," '(polymorph new-form %s)\n",
spell->SpellAction->Polymorph.NewForm->Ident);
} else if (spell->CastFunction==CastRaiseDead) {
CLprintf(file," '(raise-dead unit-raised %s time-to-live %d)\n",
spell->SpellAction->RaiseDead.UnitRaised->Ident,
spell->SpellAction->RaiseDead.TTL);
} else if (spell->CastFunction==CastFlameShield) {
CLprintf(file," '(flame-shield duration %d)\n",
spell->SpellAction->FlameShield.TTL);
} else if (spell->CastFunction==CastRunes) {
CLprintf(file," '(runes ttl %d damage %d)\n",
spell->SpellAction->Runes.TTL,
spell->SpellAction->Runes.Damage);
} else if (spell->CastFunction==CastSpawnPortal) {
CLprintf(file," '(spawn-portal portal-type %s)\n",
spell->SpellAction->SpawnPortal.PortalType->Ident);
} else if (spell->CastFunction==CastDeathCoil) {
CLprintf(file," '(death-coil)\n");
// FIXME: more?
} else if (spell->CastFunction==CastWhirlwind) {
CLprintf(file," '(whirlwind duration %d)\n",
spell->SpellAction->Whirlwind.TTL);
// FIXME: more?
}
CLprintf(file," 'action ");
SaveSpellAction(file,spell->Action);
CLprintf(file,"\n");
//
// FIXME: Save conditions
//
if (spell->Conditions) {
CLprintf(file," 'condition ");
SaveSpellCondition(file,spell->Conditions);
CLprintf(file,"\n");
}
//
// FIXME: Save autocast and AI info
//

View file

@ -451,10 +451,10 @@ global int CastSpawnPortal(Unit *caster, const SpellType *spell __attribute__((u
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->SpellAction->SpawnPortal.PortalType);
DebugCheck(!spell->Action);
DebugCheck(!spell->Action->Data.SpawnPortal.PortalType);
ptype = spell->SpellAction->SpawnPortal.PortalType;
ptype = spell->Action->Data.SpawnPortal.PortalType;
portal = caster->Goal;
if (portal) {
@ -505,16 +505,16 @@ global int CastAreaBombardment(Unit *caster, const SpellType *spell,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
//assert(x in range, y in range);
mis = NULL;
fields = spell->SpellAction->AreaBombardment.Fields;
shards = spell->SpellAction->AreaBombardment.Shards;
damage = spell->SpellAction->AreaBombardment.Damage;
offsetx = spell->SpellAction->AreaBombardment.StartOffsetX;
offsety = spell->SpellAction->AreaBombardment.StartOffsetY;
fields = spell->Action->Data.AreaBombardment.Fields;
shards = spell->Action->Data.AreaBombardment.Shards;
damage = spell->Action->Data.AreaBombardment.Damage;
offsetx = spell->Action->Data.AreaBombardment.StartOffsetX;
offsety = spell->Action->Data.AreaBombardment.StartOffsetY;
while (fields--) {
// FIXME : radius configurable...
do {
@ -568,7 +568,7 @@ global int CastDeathCoil(Unit *caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
// assert(target);
// assert(x in range, y in range);
@ -615,7 +615,7 @@ global int CastFireball(Unit *caster, const SpellType *spell,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
DebugCheck(!spell->Missile);
missile = NULL;
@ -634,8 +634,8 @@ global int CastFireball(Unit *caster, const SpellType *spell,
caster->Mana -= spell->ManaCost;
PlayGameSound(spell->SoundWhenCast.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->State = spell->Action->Data.Fireball.TTL - (dist - 1) * 2;
missile->TTL = spell->Action->Data.Fireball.TTL;
missile->Controller = SpellFireballController;
missile->SourceUnit = caster;
RefsDebugCheck(!caster->Refs || caster->Destroyed);
@ -662,7 +662,7 @@ global int CastFlameShield(Unit* caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
DebugCheck(!target);
// assert(x in range, y in range);
DebugCheck(!spell->Missile);
@ -671,11 +671,11 @@ global int CastFlameShield(Unit* caster, const SpellType *spell, Unit *target,
// get mana cost
caster->Mana -= spell->ManaCost;
target->FlameShield = spell->SpellAction->FlameShield.TTL;
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->SpellAction->FlameShield.TTL + i * 7;
mis->TTL = spell->Action->Data.FlameShield.TTL + i * 7;
mis->TargetUnit = target;
mis->Controller = SpellFlameShieldController;
RefsDebugCheck(!target->Refs || target->Destroyed);
@ -700,26 +700,26 @@ global int CastAdjustBuffs(Unit *caster, const SpellType *spell, Unit *target,
{
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
DebugCheck(!target);
// get mana cost
caster->Mana -= spell->ManaCost;
if (spell->SpellAction->AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
target->Haste=spell->SpellAction->AdjustBuffs.HasteTicks;
if (spell->Action->Data.AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
target->Haste=spell->Action->Data.AdjustBuffs.HasteTicks;
}
if (spell->SpellAction->AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
target->Slow=spell->SpellAction->AdjustBuffs.SlowTicks;
if (spell->Action->Data.AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
target->Slow=spell->Action->Data.AdjustBuffs.SlowTicks;
}
if (spell->SpellAction->AdjustBuffs.BloodlustTicks!=BUFF_NOT_AFFECTED) {
target->Bloodlust=spell->SpellAction->AdjustBuffs.BloodlustTicks;
if (spell->Action->Data.AdjustBuffs.BloodlustTicks!=BUFF_NOT_AFFECTED) {
target->Bloodlust=spell->Action->Data.AdjustBuffs.BloodlustTicks;
}
if (spell->SpellAction->AdjustBuffs.InvisibilityTicks!=BUFF_NOT_AFFECTED) {
target->Invisible=spell->SpellAction->AdjustBuffs.InvisibilityTicks;
if (spell->Action->Data.AdjustBuffs.InvisibilityTicks!=BUFF_NOT_AFFECTED) {
target->Invisible=spell->Action->Data.AdjustBuffs.InvisibilityTicks;
}
if (spell->SpellAction->AdjustBuffs.InvincibilityTicks!=BUFF_NOT_AFFECTED) {
target->UnholyArmor=spell->SpellAction->AdjustBuffs.InvincibilityTicks;
if (spell->Action->Data.AdjustBuffs.InvincibilityTicks!=BUFF_NOT_AFFECTED) {
target->UnholyArmor=spell->Action->Data.AdjustBuffs.InvincibilityTicks;
}
CheckUnitToBeDrawn(target);
PlayGameSound(spell->SoundWhenCast.Sound,MaxSampleVolume);
@ -752,11 +752,11 @@ global int CastAdjustVitals(Unit *caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
DebugCheck(!target);
hp = spell->SpellAction->AdjustVitals.HP;
mana = spell->SpellAction->AdjustVitals.Mana;
hp = spell->Action->Data.AdjustVitals.HP;
mana = spell->Action->Data.AdjustVitals.Mana;
manacost = spell->ManaCost;
// Healing and harming
@ -784,8 +784,8 @@ global int CastAdjustVitals(Unit *caster, const SpellType *spell, Unit *target,
if (manacost) {
castcount=min(castcount,caster->Mana/manacost);
}
if (spell->SpellAction->AdjustVitals.MaxMultiCast) {
castcount=min(castcount,spell->SpellAction->AdjustVitals.MaxMultiCast);
if (spell->Action->Data.AdjustVitals.MaxMultiCast) {
castcount=min(castcount,spell->Action->Data.AdjustVitals.MaxMultiCast);
}
DebugCheck(castcount<0);
@ -817,43 +817,6 @@ global int CastAdjustVitals(Unit *caster, const SpellType *spell, Unit *target,
return 0;
}
/**
** Cast holy vision.
**
** @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 CastHolyVision(Unit *caster, const SpellType *spell, Unit *target,
int x, int y)
{
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
// assert(x in range, y in range);
caster->Mana -= spell->ManaCost; // get mana cost
// FIXME: compact with summon.
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;
target->CurrentSightRange = target->Stats->SightRange;
MapMarkUnitSight(target);
target->TTL = GameCycle + target->Type->DecayRate * 6 * CYCLES_PER_SECOND;
CheckUnitToBeDrawn(target);
PlayGameSound(spell->SoundWhenCast.Sound, MaxSampleVolume);
return 0;
}
/**
** Cast polymorph.
**
@ -872,10 +835,10 @@ global int CastPolymorph(Unit *caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
DebugCheck(!target);
type = spell->SpellAction->Polymorph.NewForm;
type = spell->Action->Data.Polymorph.NewForm;
DebugCheck(!type);
caster->Player->Score += target->Type->Points;
@ -926,10 +889,10 @@ global int CastRaiseDead(Unit *caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
// assert(x in range, y in range);
skeleton = spell->SpellAction->RaiseDead.UnitRaised;
skeleton = spell->Action->Data.RaiseDead.UnitRaised;
DebugCheck(!skeleton);
corpses = &CorpseList;
@ -992,7 +955,7 @@ global int CastRunes(Unit *caster, const SpellType *spell,
DebugCheck(!caster);
DebugCheck(spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
// assert(x in range, y in range);
mis = NULL;
@ -1010,7 +973,7 @@ global int CastRunes(Unit *caster, const SpellType *spell,
y * TileSizeY + TileSizeY / 2,
x * TileSizeX + TileSizeX / 2,
y * TileSizeY + TileSizeY / 2);
mis->TTL = spell->SpellAction->Runes.TTL;
mis->TTL = spell->Action->Data.Runes.TTL;
mis->Controller = SpellRunesController;
caster->Mana -= spell->ManaCost / 5;
}
@ -1036,14 +999,14 @@ global int CastSummon(Unit *caster, const SpellType *spell, Unit *target,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->SpellAction->Summon.UnitType);
DebugCheck(!spell->Action);
DebugCheck(!spell->Action->Data.Summon.UnitType);
DebugLevel0("Summoning\n");
ttl=spell->SpellAction->Summon.TTL;
ttl=spell->Action->Data.Summon.TTL;
caster->Mana -= spell->ManaCost;
// FIXME: johns: the unit is placed on the wrong position
target = MakeUnit(spell->SpellAction->Summon.UnitType, caster->Player);
target = MakeUnit(spell->Action->Data.Summon.UnitType, caster->Player);
target->X = x;
target->Y = y;
// set life span
@ -1090,7 +1053,7 @@ global int CastWhirlwind(Unit *caster, const SpellType *spell,
DebugCheck(!caster);
DebugCheck(!spell);
DebugCheck(!spell->SpellAction);
DebugCheck(!spell->Action);
// assert(x in range, y in range);
mis = NULL;
@ -1100,7 +1063,7 @@ global int CastWhirlwind(Unit *caster, const SpellType *spell,
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->TTL = spell->Action->Data.Whirlwind.TTL;
mis->Controller = SpellWhirlwindController;
return 0;
}
@ -1208,7 +1171,6 @@ local int PassCondition(const Unit* caster,const SpellType* spell,const Unit* ta
}
if (condition->Building!=CONDITION_TRUE) {
if ((condition->Building==CONDITION_ONLY)^(target->Type->Building)) {
DebugLevel0("QQQ\n");
return 0;
}
}
@ -1541,7 +1503,7 @@ global int SpellCast(Unit *caster, const SpellType *spell, Unit *target,
int x, int y)
{
DebugCheck(!spell);
DebugCheck(!spell->CastFunction);
DebugCheck(!spell->Action->CastFunction);
DebugCheck(!caster);
DebugCheck(!SpellIsAvailable(caster->Player, spell->Ident));
@ -1555,7 +1517,7 @@ 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->CastFunction(caster, spell, target, x, y);
return CanCastSpell(caster, spell, target, x, y) && spell->Action->CastFunction(caster, spell, target, x, y);
}