Ai uses it's own autocast. Added spell cleanup code.
This commit is contained in:
parent
9d42c9b96e
commit
d52d89898a
6 changed files with 193 additions and 109 deletions
src
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -104,6 +104,7 @@ global void CleanModules(void)
|
|||
CleanMap();
|
||||
CleanReplayLog();
|
||||
CleanCclCredits();
|
||||
CleanSpells();
|
||||
FreeVisionTable();
|
||||
#ifdef HIERARCHIC_PATHFINDER
|
||||
PfHierClean ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue