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