From d52d89898ac9b6195a2c83996517e019eccea490 Mon Sep 17 00:00:00 2001
From: n0body <>
Date: Fri, 3 Oct 2003 09:37:08 +0000
Subject: [PATCH] Ai uses it's own autocast. Added spell cleanup code.

---
 src/action/actions.cpp         |   1 +
 src/ai/ai_magic.cpp            |   2 +-
 src/game/loadgame.cpp          |   1 +
 src/include/spells.h           |  25 +++--
 src/stratagus/script_spell.cpp | 192 ++++++++++++++++++++-------------
 src/stratagus/spells.cpp       |  81 ++++++++++----
 6 files changed, 193 insertions(+), 109 deletions(-)

diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 7df15109b..683a0a1d5 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -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.
diff --git a/src/ai/ai_magic.cpp b/src/ai/ai_magic.cpp
index d7a266ed3..f4081e999 100644
--- a/src/ai/ai_magic.cpp
+++ b/src/ai/ai_magic.cpp
@@ -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
diff --git a/src/game/loadgame.cpp b/src/game/loadgame.cpp
index 1438a9cec..984bdfe36 100644
--- a/src/game/loadgame.cpp
+++ b/src/game/loadgame.cpp
@@ -104,6 +104,7 @@ global void CleanModules(void)
     CleanMap();
     CleanReplayLog();
     CleanCclCredits();
+    CleanSpells();
     FreeVisionTable();
 #ifdef HIERARCHIC_PATHFINDER
     PfHierClean ();
diff --git a/src/include/spells.h b/src/include/spells.h
index 74b5773a3..dbfae2cc5 100644
--- a/src/include/spells.h
+++ b/src/include/spells.h
@@ -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);
diff --git a/src/stratagus/script_spell.cpp b/src/stratagus/script_spell.cpp
index 0b203cabf..ed86e5497 100644
--- a/src/stratagus/script_spell.cpp
+++ b/src/stratagus/script_spell.cpp
@@ -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");
     }
diff --git a/src/stratagus/spells.cpp b/src/stratagus/spells.cpp
index 1a45fd3b4..ce6994129 100644
--- a/src/stratagus/spells.cpp
+++ b/src/stratagus/spells.cpp
@@ -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