Fixed autocast
This commit is contained in:
parent
e943c8a434
commit
138f7af072
3 changed files with 200 additions and 145 deletions
src
|
@ -235,6 +235,8 @@ typedef struct ConditionInfo {
|
|||
typedef struct {
|
||||
ConditionInfo *Condition; /// Conditions to cast the spell.
|
||||
int Range; /// Max range of the target.
|
||||
/// Combat mode is when there are hostile non-coward units around
|
||||
int Combat; /// If it should be casted in combat
|
||||
/// FIXME: Add stuff here for target preference.
|
||||
/// FIXME: Heal units with the lowest hit points first.
|
||||
} AutoCastInfo;
|
||||
|
|
|
@ -46,56 +46,17 @@
|
|||
#include "ccl_sound.h"
|
||||
#include "ccl.h"
|
||||
|
||||
// **************************************************************************
|
||||
// Direct affectation for spell
|
||||
// **************************************************************************
|
||||
|
||||
/**
|
||||
** Parse the dependency of spell.
|
||||
** list = (upgrade "upgradename")
|
||||
*/
|
||||
local void ccl_spell_dependency(const char *id, SCM list, SpellType *spell)
|
||||
{
|
||||
char *dependencyName;
|
||||
SCM value;
|
||||
int dependencyId;
|
||||
|
||||
DebugCheck(!id);
|
||||
DebugCheck(!spell);
|
||||
|
||||
dependencyName = NULL;
|
||||
dependencyId = -1;
|
||||
|
||||
value = gh_car(list);
|
||||
|
||||
if (!gh_eq_p(value, gh_symbol2scm("upgrade"))) {
|
||||
return;
|
||||
}
|
||||
list = gh_cdr(list);
|
||||
value = gh_car(list);
|
||||
|
||||
dependencyName = gh_scm2newstr(value, NULL);
|
||||
dependencyId = UpgradeIdByIdent(dependencyName);
|
||||
if (dependencyId == -1) {
|
||||
// warn user
|
||||
DebugLevel0Fn("Bad upgrade-name '%s'\n" _C_ dependencyName);
|
||||
free(dependencyName);
|
||||
return ;
|
||||
}
|
||||
spell->DependencyId = dependencyId;
|
||||
free(dependencyName);
|
||||
}
|
||||
|
||||
|
||||
// **************************************************************************
|
||||
// Action parsers for spellAction
|
||||
// **************************************************************************
|
||||
|
||||
/**
|
||||
/*
|
||||
** Parse the action for spell.
|
||||
** list = (action-type lots-of-parameters).
|
||||
**
|
||||
** @param list SCM list object, with somthing like (action-type params).
|
||||
** @param spellaction Pointer to spellactopm.
|
||||
*/
|
||||
local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spellaction)
|
||||
local void CclSpellAction(SCM list, SpellActionType *spellaction)
|
||||
{
|
||||
char* str;
|
||||
SCM value = list;
|
||||
|
@ -324,6 +285,8 @@ local void CclParseSpellAction(SCM list, SpellType* spell, SpellActionType *spel
|
|||
** @param value scm value to convert.
|
||||
**
|
||||
** @return CONDITION_TRUE, CONDITION_FALSE, CONDITION_ONLY or -1 on error.
|
||||
** @note This is a helper function to make CclSpellCondition shorter
|
||||
** and easier to understand.
|
||||
*/
|
||||
local char Scm2Condition(SCM value)
|
||||
{
|
||||
|
@ -347,7 +310,7 @@ local char Scm2Condition(SCM value)
|
|||
**
|
||||
** @notes: conditions must be allocated. All data already in is LOST.
|
||||
*/
|
||||
local void CclSpellParseCondition(SCM list, ConditionInfo* condition)
|
||||
local void CclSpellCondition(SCM list, ConditionInfo* condition)
|
||||
{
|
||||
SCM value;
|
||||
|
||||
|
@ -428,41 +391,40 @@ local void CclSpellParseCondition(SCM list, ConditionInfo* condition)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** FIXME: docu
|
||||
/*
|
||||
** Parse the Condition for spell.
|
||||
**
|
||||
** @param list SCM object to parse
|
||||
** @param autocast pointer to autocast to fill with data.
|
||||
**
|
||||
** @notes: autocast must be allocated. All data already in is LOST.
|
||||
*/
|
||||
local void ccl_spell_autocast(const char *id, SCM list, SpellType *spell)
|
||||
local void CclSpellAutocast(SCM list, AutoCastInfo* autocast)
|
||||
{
|
||||
SCM value;
|
||||
int range;
|
||||
|
||||
DebugCheck(!id);
|
||||
DebugCheck(!spell);
|
||||
DebugCheck(!list);
|
||||
DebugCheck(!autocast);
|
||||
|
||||
value = gh_car(list);
|
||||
if (!gh_eq_p(value, gh_symbol2scm("range"))) {
|
||||
return ;
|
||||
while (!gh_null_p(list)) {
|
||||
value = gh_car(list);
|
||||
list = gh_cdr(list);
|
||||
if (gh_eq_p(value,gh_symbol2scm("range"))) {
|
||||
autocast->Range=gh_scm2int(gh_car(list));
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("combat"))) {
|
||||
autocast->Combat=Scm2Condition(gh_car(list));
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("condition"))) {
|
||||
if (!autocast->Condition) {
|
||||
autocast->Condition=(ConditionInfo*)malloc(sizeof(ConditionInfo));
|
||||
}
|
||||
CclSpellCondition(gh_car(list),autocast->Condition);
|
||||
list=gh_cdr(list);
|
||||
} else {
|
||||
errl("Unsupported autocast tag",value);
|
||||
}
|
||||
}
|
||||
|
||||
list = gh_cdr(list);
|
||||
value = gh_car(list);
|
||||
range = gh_scm2int(value);
|
||||
if (range <= 0 && range != -1/*no limit*/) {
|
||||
// Warn : range <= 0 have no sens, must be strict positive. or = -1
|
||||
return ;
|
||||
}
|
||||
spell->AutoCast = malloc(sizeof(*spell->AutoCast));
|
||||
memset(spell->AutoCast, 0, sizeof(*spell->AutoCast));
|
||||
spell->AutoCast->Range = range;
|
||||
list = gh_cdr(list);
|
||||
value = gh_car(list);
|
||||
if (!gh_eq_p(value, gh_symbol2scm("condition"))) {
|
||||
return ;
|
||||
}
|
||||
list = gh_cdr(list);
|
||||
value = gh_car(list);
|
||||
spell->AutoCast->Condition=(ConditionInfo*)malloc(sizeof(ConditionInfo));
|
||||
CclSpellParseCondition(value,spell->AutoCast->Condition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,15 +487,23 @@ local SCM CclDefineSpell(SCM list)
|
|||
}
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("action"))) {
|
||||
spell->Action=(SpellActionType*)malloc(sizeof(SpellActionType));
|
||||
CclParseSpellAction(gh_car(list),spell,spell->Action);
|
||||
if (!spell->Action) {
|
||||
spell->Action=(SpellActionType*)malloc(sizeof(SpellActionType));
|
||||
}
|
||||
CclSpellAction(gh_car(list),spell->Action);
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("condition"))) {
|
||||
spell->Conditions=(ConditionInfo*)malloc(sizeof(ConditionInfo));
|
||||
CclSpellParseCondition(gh_car(list),spell->Conditions);
|
||||
if (!spell->Conditions) {
|
||||
spell->Conditions=(ConditionInfo*)malloc(sizeof(ConditionInfo));
|
||||
}
|
||||
CclSpellCondition(gh_car(list),spell->Conditions);
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("autocast"))) {
|
||||
ccl_spell_autocast("autocast",gh_car(list),spell);
|
||||
if (!spell->AutoCast) {
|
||||
spell->AutoCast=(AutoCastInfo*)malloc(sizeof(AutoCastInfo));
|
||||
memset(spell->AutoCast,0,sizeof(AutoCastInfo*));
|
||||
}
|
||||
CclSpellAutocast(gh_car(list),spell->AutoCast);
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("sound-when-cast"))) {
|
||||
// Free the old name, get the new one
|
||||
|
@ -555,11 +525,15 @@ local SCM CclDefineSpell(SCM list)
|
|||
}
|
||||
free(str);
|
||||
list=gh_cdr(list);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("depend"))) {
|
||||
ccl_spell_dependency("depend", gh_car(list), spell);
|
||||
} else if (gh_eq_p(value,gh_symbol2scm("depend-upgrade"))) {
|
||||
str = gh_scm2newstr(gh_car(list), NULL);
|
||||
spell->DependencyId = UpgradeIdByIdent(str);
|
||||
free(str);
|
||||
if (spell->DependencyId == -1) {
|
||||
errl("Bad upgrade name",gh_car(list));
|
||||
}
|
||||
list = gh_cdr(list);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
errl("Unsupported tag", value);
|
||||
}
|
||||
}
|
||||
|
@ -591,18 +565,32 @@ local void SaveSpellCondition(CLFile *file,ConditionInfo* condition)
|
|||
DebugCheck(!file);
|
||||
DebugCheck(!condition);
|
||||
|
||||
CLprintf(file,"'( ");
|
||||
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]);
|
||||
if (condition->Undead!=CONDITION_TRUE) {
|
||||
CLprintf(file,"undead %s ",condstrings[(int)condition->Undead]);
|
||||
}
|
||||
if (condition->Organic!=CONDITION_TRUE) {
|
||||
CLprintf(file,"organic %s ",condstrings[(int)condition->Organic]);
|
||||
}
|
||||
if (condition->Hero!=CONDITION_TRUE) {
|
||||
CLprintf(file,"hero %s ",condstrings[(int)condition->Hero]);
|
||||
}
|
||||
if (condition->Coward!=CONDITION_TRUE) {
|
||||
CLprintf(file,"coward %s ",condstrings[(int)condition->Coward]);
|
||||
}
|
||||
if (condition->Alliance!=CONDITION_TRUE) {
|
||||
CLprintf(file,"alliance %s ",condstrings[(int)condition->Alliance]);
|
||||
}
|
||||
if (condition->Building!=CONDITION_TRUE) {
|
||||
CLprintf(file,"building %s ",condstrings[(int)condition->Building]);
|
||||
}
|
||||
if (condition->TargetSelf!=CONDITION_TRUE) {
|
||||
CLprintf(file,"self %s ",condstrings[(int)condition->TargetSelf]);
|
||||
}
|
||||
//
|
||||
// Min/Max vital percents
|
||||
//
|
||||
|
@ -633,18 +621,18 @@ local void SaveSpellCondition(CLFile *file,ConditionInfo* condition)
|
|||
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)",
|
||||
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)",
|
||||
CLprintf(file,"(fireball ttl %d damage %d)",
|
||||
action->Data.Fireball.TTL,
|
||||
action->Data.Fireball.Damage);
|
||||
} else if (action->CastFunction==CastAdjustVitals) {
|
||||
CLprintf(file," '(adjust-vitals");
|
||||
CLprintf(file,"(adjust-vitals");
|
||||
if (action->Data.AdjustVitals.HP) {
|
||||
CLprintf(file," hit-points %d",action->Data.AdjustVitals.HP);
|
||||
}
|
||||
|
@ -656,11 +644,11 @@ 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)",
|
||||
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");
|
||||
CLprintf(file,"(adjust-buffs");
|
||||
if (action->Data.AdjustBuffs.HasteTicks!=BUFF_NOT_AFFECTED) {
|
||||
CLprintf(file," haste-ticks %d",action->Data.AdjustBuffs.HasteTicks);
|
||||
}
|
||||
|
@ -678,27 +666,27 @@ local void SaveSpellAction(CLFile *file,SpellActionType* action)
|
|||
}
|
||||
CLprintf(file,")");
|
||||
} else if (action->CastFunction==CastPolymorph) {
|
||||
CLprintf(file," '(polymorph new-form %s)",
|
||||
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)",
|
||||
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)",
|
||||
CLprintf(file,"(flame-shield duration %d)",
|
||||
action->Data.FlameShield.TTL);
|
||||
} else if (action->CastFunction==CastRunes) {
|
||||
CLprintf(file," '(runes ttl %d damage %d)",
|
||||
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)",
|
||||
CLprintf(file,"(spawn-portal portal-type %s)",
|
||||
action->Data.SpawnPortal.PortalType->Ident);
|
||||
} else if (action->CastFunction==CastDeathCoil) {
|
||||
CLprintf(file," '(death-coil)");
|
||||
CLprintf(file,"(death-coil)");
|
||||
// FIXME: more?
|
||||
} else if (action->CastFunction==CastWhirlwind) {
|
||||
CLprintf(file," '(whirlwind duration %d)",
|
||||
CLprintf(file,"(whirlwind duration %d)",
|
||||
action->Data.Whirlwind.TTL);
|
||||
// FIXME: more?
|
||||
}
|
||||
|
@ -754,20 +742,25 @@ global void SaveSpells(CLFile *file)
|
|||
//
|
||||
// Save the action(effect of the spell)
|
||||
//
|
||||
CLprintf(file," 'action ");
|
||||
CLprintf(file," 'action '");
|
||||
SaveSpellAction(file,spell->Action);
|
||||
CLprintf(file,"\n");
|
||||
//
|
||||
// FIXME: Save conditions
|
||||
//
|
||||
if (spell->Conditions) {
|
||||
CLprintf(file," 'condition ");
|
||||
CLprintf(file," 'condition '");
|
||||
SaveSpellCondition(file,spell->Conditions);
|
||||
CLprintf(file,"\n");
|
||||
}
|
||||
//
|
||||
// FIXME: Save autocast and AI info
|
||||
//
|
||||
if (spell->AutoCast) {
|
||||
CLprintf(file," 'autocast '(range %d condition ",spell->AutoCast->Range);
|
||||
SaveSpellCondition(file,spell->Conditions);
|
||||
CLprintf(file,")\n");
|
||||
}
|
||||
CLprintf(file,")\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -706,7 +706,7 @@ global int CastAdjustBuffs(Unit *caster, const SpellType *spell, Unit *target,
|
|||
// get mana cost
|
||||
caster->Mana -= spell->ManaCost;
|
||||
|
||||
if (spell->Action->Data.AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
|
||||
if (spell->Action->Data.AdjustBuffs.HasteTicks!=BUFF_NOT_AFFECTED) {
|
||||
target->Haste=spell->Action->Data.AdjustBuffs.HasteTicks;
|
||||
}
|
||||
if (spell->Action->Data.AdjustBuffs.SlowTicks!=BUFF_NOT_AFFECTED) {
|
||||
|
@ -790,7 +790,7 @@ global int CastAdjustVitals(Unit *caster, const SpellType *spell, Unit *target,
|
|||
|
||||
DebugCheck(castcount<0);
|
||||
|
||||
DebugLevel0Fn("Used to have %d hp and %d mana.\n" _C_ target->HP _C_ target->Mana);
|
||||
DebugLevel3Fn("Used to have %d hp and %d mana.\n" _C_ target->HP _C_ target->Mana);
|
||||
|
||||
caster->Mana-=castcount*manacost;
|
||||
if (hp < 0) {
|
||||
|
@ -809,7 +809,7 @@ global int CastAdjustVitals(Unit *caster, const SpellType *spell, Unit *target,
|
|||
target->Mana=target->Type->_MaxMana;
|
||||
}
|
||||
|
||||
DebugLevel0Fn("Unit now has %d hp and %d mana.\n" _C_ target->HP _C_ target->Mana);
|
||||
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,
|
||||
|
@ -1185,7 +1185,7 @@ local int PassCondition(const Unit* caster,const SpellType* spell,const Unit* ta
|
|||
}
|
||||
}
|
||||
if (condition->Alliance!=CONDITION_TRUE) {
|
||||
if ((condition->Alliance==CONDITION_ONLY)^(IsAllied(caster->Player,target))) {
|
||||
if ((condition->Alliance==CONDITION_ONLY)^(IsAllied(caster->Player,target)||target->Player==caster->Player)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1197,20 +1197,40 @@ local int PassCondition(const Unit* caster,const SpellType* spell,const Unit* ta
|
|||
//
|
||||
// Check vitals now.
|
||||
//
|
||||
if (condition->MinHpPercent*target->Stats->HitPoints>target->HP) {
|
||||
if (condition->MinHpPercent*target->Stats->HitPoints/100>target->HP) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxHpPercent*target->Stats->HitPoints<target->HP) {
|
||||
if (condition->MaxHpPercent*target->Stats->HitPoints/100<=target->HP) {
|
||||
return 0;
|
||||
}
|
||||
if (target->Type->CanCastSpell) {
|
||||
if (condition->MinManaPercent*target->Type->_MaxMana>target->Mana) {
|
||||
if (condition->MinManaPercent*target->Type->_MaxMana/100>target->Mana) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxManaPercent*target->Type->_MaxMana<target->Mana) {
|
||||
if (condition->MaxManaPercent*target->Type->_MaxMana/100<target->Mana) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Check for slow/haste stuff
|
||||
// This should be used mostly for ai, if you want to keep casting
|
||||
// slow to no effect I can't see why should we stop you.
|
||||
//
|
||||
if (condition->MaxSlowTicks<target->Slow) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxHasteTicks<target->Haste) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxBloodlustTicks<target->Bloodlust) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxInvisibilityTicks<target->Invisible) {
|
||||
return 0;
|
||||
}
|
||||
if (condition->MaxInvincibilityTicks<target->UnholyArmor) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -1231,59 +1251,98 @@ local Target *SelectTargetUnitsOfAutoCast(const Unit *caster, const SpellType *s
|
|||
int x;
|
||||
int y;
|
||||
int range;
|
||||
int nb_units;
|
||||
int nunits;
|
||||
int i;
|
||||
int j;
|
||||
int combat;
|
||||
|
||||
DebugCheck(!spell);
|
||||
DebugCheck(!spell->AutoCast);
|
||||
DebugCheck(!caster);
|
||||
|
||||
x=caster->X;
|
||||
y=caster->Y;
|
||||
range=spell->AutoCast->Range;
|
||||
|
||||
//
|
||||
// Select all units aroung the caster
|
||||
//
|
||||
nunits = SelectUnits(caster->X - range, caster->Y - range,
|
||||
caster->X + range + caster->Type->TileWidth, caster->Y + range + caster->Type->TileHeight, table);
|
||||
//
|
||||
// Check every unit if it is hostile
|
||||
//
|
||||
combat=0;
|
||||
for (i = 0; i < nunits; i++) {
|
||||
if (IsEnemy(caster->Player,table[i]) && !table[i]->Type->Coward) {
|
||||
combat=1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check generic conditions. FIXME: a better way to do this?
|
||||
//
|
||||
if (spell->AutoCast->Combat!=CONDITION_TRUE) {
|
||||
if ((spell->AutoCast->Combat==CONDITION_ONLY)^(combat)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (spell->Target) {
|
||||
case TargetSelf :
|
||||
return NewTargetUnit(caster);
|
||||
case TargetNone :
|
||||
// TargetNone?
|
||||
return NewTargetNone();
|
||||
case TargetSelf :
|
||||
if (PassCondition(caster, spell, caster, x, y, spell->Conditions) &&
|
||||
PassCondition(caster, spell, caster, x, y, spell->AutoCast->Condition)) {
|
||||
return NewTargetUnit(caster);
|
||||
}
|
||||
return 0;
|
||||
case TargetPosition:
|
||||
range = spell->AutoCast->Range;
|
||||
do {
|
||||
x = caster->X + SyncRand() % (2 * range) - range;
|
||||
y = caster->Y + SyncRand() % (2 * range) - range;
|
||||
} while (x < 0 && x <= TheMap.Width
|
||||
&& y < 0 && y <= TheMap.Height);
|
||||
|
||||
// FIXME : CHOOSE a better POSITION (add info in structure ???)
|
||||
// Just good enough for holyvision...
|
||||
return NewTargetPosition(x, y);
|
||||
return 0;
|
||||
// Autocast with a position? That's hard
|
||||
// Possibilities: cast reveal-map on a dark region
|
||||
// Cast raise dead on a bunch of corpses. That would rule.
|
||||
// Cast summon until out of mana in the heat of battle. Trivial?
|
||||
// Find a tight group of units and cast area-damage spells. HARD,
|
||||
// but it is a must-have for AI. What about area-heal?
|
||||
case TargetUnit:
|
||||
x=caster->X;
|
||||
y=caster->Y;
|
||||
range=spell->AutoCast->Range;
|
||||
// ( + 1) would be ( + caster->size) ??
|
||||
nb_units = SelectUnits(caster->X - range, caster->Y - range,
|
||||
caster->X + range + 1, caster->Y + range + 1,table);
|
||||
// For all Unit, check if it is a possible target
|
||||
for (i = 0, j = 0; i < nb_units; i++) {
|
||||
if (PassCondition(caster,spell,table[i],x,y,spell->Conditions)) {
|
||||
table[j++] = table[i];
|
||||
//
|
||||
// The units are already selected.
|
||||
// Check every unit if it is a possible target
|
||||
//
|
||||
for (i = 0, j = 0; i < nunits; i++) {
|
||||
// FIXME: autocast conditions should include normal conditions.
|
||||
// FIXME: no, really, they should.
|
||||
if (PassCondition(caster, spell, table[i], x, y, spell->Conditions) &&
|
||||
PassCondition(caster, spell, table[i], x, y, spell->AutoCast->Condition)) {
|
||||
table[j++] = table[i];
|
||||
}
|
||||
}
|
||||
nb_units = j;
|
||||
if (nb_units != 0) {
|
||||
nunits = j;
|
||||
//
|
||||
// Now select the best unit to target.
|
||||
// FIXME: Some really smart way to do this.
|
||||
// FIXME: Heal the unit with the lowest hit-points
|
||||
// FIXME: Bloodlust the unit with the highest hit-point
|
||||
// FIMXE: it will survive more
|
||||
//
|
||||
if (nunits != 0) {
|
||||
#if 0
|
||||
// For the best target
|
||||
// For the best target???
|
||||
sort(table, nb_units, spell->autocast->f_order);
|
||||
return NewTargetUnit(table[0]);
|
||||
#else
|
||||
// For a random valid target
|
||||
i = SyncRand() % nb_units;
|
||||
// Best unit, random unit, oh well, same stuff.
|
||||
i = SyncRand() % nunits;
|
||||
return NewTargetUnit(table[i]);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Error : add the new cases
|
||||
// FIXME : Warn developpers
|
||||
// Something is wrong
|
||||
DebugLevel0Fn("Spell is screwed up, unknown target type\n");
|
||||
DebugCheck(1);
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -1473,9 +1532,10 @@ global int AutoCastSpell(Unit *caster, const SpellType *spell)
|
|||
|
||||
target = NULL;
|
||||
|
||||
/* if (PassCondition(caster,spell,target,x,y,spell->Conditions))
|
||||
// Check for mana, trivial optimization.
|
||||
if (caster->Mana<spell->ManaCost) {
|
||||
return 0;
|
||||
}*/
|
||||
}
|
||||
target = SelectTargetUnitsOfAutoCast(caster, spell);
|
||||
if (target == NULL) {
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue