Ai uses it's own autocast. Added spell cleanup code.

This commit is contained in:
n0body 2003-10-03 09:37:08 +00:00
parent 9d42c9b96e
commit d52d89898a
6 changed files with 193 additions and 109 deletions

View file

@ -614,6 +614,7 @@ global void UnitActions(void)
HandleUnitAction(unit);
DebugCheck( *tpos!=unit ); // Removed is evil.
#define DEBUG_ACTIONS
#ifdef DEBUG_ACTIONS
//
// Dump the unit to find the network unsyncron bug.

View file

@ -75,7 +75,7 @@ global void AiCheckMagic(void)
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) &&
SpellTypeById(j)->AutoCast) {
(SpellTypeById(j)->AutoCast || SpellTypeById(j)->AICast)) {
#ifdef DEBUG
success = // Follow on next line (AutoCastSpell).
#endif

View file

@ -104,6 +104,7 @@ global void CleanModules(void)
CleanMap();
CleanReplayLog();
CleanCclCredits();
CleanSpells();
FreeVisionTable();
#ifdef HIERARCHIC_PATHFINDER
PfHierClean ();

View file

@ -233,10 +233,15 @@ typedef struct ConditionInfo {
**
*/
typedef struct {
ConditionInfo *Condition; /// Conditions to cast the spell.
/// FIXME: this below is SQUARE!!!
int Range; /// Max range of the target.
ConditionInfo *Condition; /// Conditions to cast the spell.
/// Detalied generic conditions (not per-target, where Condition is evaluated.)
/// 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;
@ -255,19 +260,21 @@ typedef struct _spell_type_ {
// Spell Specifications
TargetType Target; /// Targetting information. See TargetType.
SpellActionType *Action; /// More arguments for spell (damage, delay, additional sounds...).
#define INFINITE_RANGE 0xFFFFFFF
int Range; /// Max range of the target.
#define INFINITE_RANGE 0xFFFFFFF
int ManaCost; /// required mana for each cast
int DependencyId; /// Id of upgrade, -1 if no upgrade needed for cast the spell.
ConditionInfo *Conditions; /// Conditions to cast the spell. (generic (no test for each target))
ConditionInfo *Condition; /// Conditions to cast the spell. (generic (no test for each target))
// Autocast // FIXME : can use different for AI ? Use it in this structure ?
AutoCastInfo *AutoCast; /// AutoCast information
// Autocast informations. No AICast means the AI use AutoCast.
AutoCastInfo *AutoCast; /// AutoCast information for your own units
AutoCastInfo *AICast; /// AutoCast information for ai. More detalied.
// Uses for graphics and sounds
SoundConfig SoundWhenCast; /// sound played if cast
MissileType *Missile; /// missile fired on cast
// Graphics and sounds. Add something else here?
SoundConfig SoundWhenCast; /// Sound played if cast
MissileType *Missile; /// Missile fired on cast
} SpellType;
/*----------------------------------------------------------------------------
@ -297,7 +304,7 @@ extern void InitSpells(void);
extern void SaveSpells(CLFile * file);
/// done spell tables
extern void DoneSpells(void);
extern void CleanSpells(void);
/// return 1 if spell is availible, 0 if not (must upgrade)
extern int SpellIsAvailable(const Player* player, int SpellId);

View file

@ -493,18 +493,25 @@ local SCM CclDefineSpell(SCM list)
CclSpellAction(gh_car(list),spell->Action);
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("condition"))) {
if (!spell->Conditions) {
spell->Conditions=(ConditionInfo*)malloc(sizeof(ConditionInfo));
if (!spell->Condition) {
spell->Condition=(ConditionInfo*)malloc(sizeof(ConditionInfo));
}
CclSpellCondition(gh_car(list),spell->Conditions);
CclSpellCondition(gh_car(list),spell->Condition);
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("autocast"))) {
if (!spell->AutoCast) {
spell->AutoCast=(AutoCastInfo*)malloc(sizeof(AutoCastInfo));
memset(spell->AutoCast,0,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("ai-cast"))) {
if (!spell->AICast) {
spell->AICast=(AutoCastInfo*)malloc(sizeof(AutoCastInfo));
memset(spell->AICast,0,sizeof(AutoCastInfo));
}
CclSpellAutocast(gh_car(list),spell->AICast);
list=gh_cdr(list);
} else if (gh_eq_p(value,gh_symbol2scm("sound-when-cast"))) {
// Free the old name, get the new one
free(spell->SoundWhenCast.Name);
@ -548,70 +555,6 @@ 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.
//
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
//
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.
**
@ -692,7 +635,96 @@ local void SaveSpellAction(CLFile *file,SpellActionType* action)
}
}
/**
/*
** 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.
//
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
//
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 autocast info to a CCL file
**
** @param file The file to save to.
** @param autocast Auocastinfo to save.
*/
void SaveSpellAutoCast(CLFile *file,AutoCastInfo* autocast)
{
char condstrings [3][10] = {
"true", /// CONDITION_TRUE
"false", /// CONDITION_FALSE
"only" /// CONDITION_ONLY
};
CLprintf(file,"( range %d",autocast->Range);
if (autocast->Combat!=CONDITION_TRUE) {
CLprintf(file,"undead %s ",condstrings[(int)autocast->Combat]);
}
if (autocast->Condition) {
CLprintf(file," condition ");
SaveSpellCondition(file,autocast->Condition);
}
CLprintf(file," )\n");
}
/*
** Save spells to a CCL file.
**
** @param file The file to save to.
@ -746,20 +778,28 @@ global void SaveSpells(CLFile *file)
SaveSpellAction(file,spell->Action);
CLprintf(file,"\n");
//
// FIXME: Save conditions
// Save conditions
//
if (spell->Conditions) {
if (spell->Condition) {
CLprintf(file," 'condition '");
SaveSpellCondition(file,spell->Conditions);
SaveSpellCondition(file,spell->Condition);
CLprintf(file,"\n");
}
//
// FIXME: Save autocast and AI info
// Save own unit autocast
//
if (spell->AutoCast) {
CLprintf(file," 'autocast '(range %d condition ",spell->AutoCast->Range);
SaveSpellCondition(file,spell->Conditions);
CLprintf(file,")\n");
CLprintf(file," 'autocast '");
SaveSpellAutoCast(file,spell->AutoCast);
CLprintf(file,"\n");
}
//
// Save AI autocast.
//
if (spell->AICast) {
CLprintf(file," 'ai-cast '");
SaveSpellAutoCast(file,spell->AICast);
CLprintf(file,"\n");
}
CLprintf(file,")\n");
}

View file

@ -1255,11 +1255,23 @@ local Target *SelectTargetUnitsOfAutoCast(const Unit *caster, const SpellType *s
int i;
int j;
int combat;
AutoCastInfo* autocast;
DebugCheck(!spell);
DebugCheck(!spell->AutoCast);
DebugCheck(!caster);
//
// Ai cast should be a lot better. Use autocast if not found.
//
if (caster->Player->Ai&&spell->AICast) {
DebugLevel3Fn("The borg uses AI autocast XP.\n");
autocast=spell->AICast;
} else {
DebugLevel3Fn("You puny mortal, join the colective!\n");
autocast=spell->AutoCast;
}
x=caster->X;
y=caster->Y;
range=spell->AutoCast->Range;
@ -1282,8 +1294,8 @@ local Target *SelectTargetUnitsOfAutoCast(const Unit *caster, const SpellType *s
//
// Check generic conditions. FIXME: a better way to do this?
//
if (spell->AutoCast->Combat!=CONDITION_TRUE) {
if ((spell->AutoCast->Combat==CONDITION_ONLY)^(combat)) {
if (autocast->Combat!=CONDITION_TRUE) {
if ((autocast->Combat==CONDITION_ONLY)^(combat)) {
return 0;
}
}
@ -1293,8 +1305,8 @@ local Target *SelectTargetUnitsOfAutoCast(const Unit *caster, const SpellType *s
// TargetNone?
return NewTargetNone();
case TargetSelf :
if (PassCondition(caster, spell, caster, x, y, spell->Conditions) &&
PassCondition(caster, spell, caster, x, y, spell->AutoCast->Condition)) {
if (PassCondition(caster, spell, caster, x, y, spell->Condition) &&
PassCondition(caster, spell, caster, x, y, autocast->Condition)) {
return NewTargetUnit(caster);
}
return 0;
@ -1314,8 +1326,8 @@ local Target *SelectTargetUnitsOfAutoCast(const Unit *caster, const SpellType *s
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)) {
if (PassCondition(caster, spell, table[i], x, y, spell->Condition) &&
PassCondition(caster, spell, table[i], x, y, autocast->Condition)) {
table[j++] = table[i];
}
}
@ -1364,17 +1376,6 @@ global void InitSpells(void)
{
}
/**
** Spells destructor (currently does nothing)
*/
global void DoneSpells()
{
// FIXME
free(SpellTypeTable);
// nothing yet
}
// ****************************************************************************
// Get Spell.
// ****************************************************************************
@ -1509,7 +1510,7 @@ global int CanCastSpell(const Unit *caster, const SpellType *spell,
return 0;
}
return PassCondition(caster,spell,target,x,y,spell->Conditions);
return PassCondition(caster,spell,target,x,y,spell->Condition);
}
/**
@ -1580,6 +1581,45 @@ global int SpellCast(Unit *caster, const SpellType *spell, Unit *target,
return CanCastSpell(caster, spell, target, x, y) && spell->Action->CastFunction(caster, spell, target, x, y);
}
/*
** Cleanup the spell subsystem.
**
** @note: everything regarding spells is gone now.
** FIXME: not complete
*/
void CleanSpells(void)
{
SpellType* spell;
DebugLevel0("Cleaning spells.\n");
for (spell = SpellTypeTable; spell < SpellTypeTable + SpellTypeCount; ++spell) {
free(spell->IdentName);
free(spell->Name);
free(spell->Action);
if (spell->Condition) {
free(spell->Condition);
}
//
// Free Autocast.
//
if (spell->AutoCast) {
if (spell->AutoCast->Condition) {
free(spell->AutoCast->Condition);
}
free(spell->AutoCast);
}
if (spell->AICast) {
if (spell->AICast->Condition) {
free(spell->AICast->Condition);
}
free(spell->AICast);
}
// FIXME: missile free somewhere else, right?
}
free(SpellTypeTable);
SpellTypeTable=0;
SpellTypeCount=0;
}
#if 0
@ -1606,11 +1646,6 @@ global int SpellCast(Unit *caster, const SpellType *spell, Unit *target,
different range, cost and time to live (possibly and other
parameters as extensions)
FIXME: this should be configurable by CCL.
FIXME: 0x7F as unlimited range is too less for big maps.
*/
#endif