From 65b9398100bdd25855b8226735b398cd3f63b20f Mon Sep 17 00:00:00 2001 From: johns <> Date: Tue, 19 Mar 2002 22:44:00 +0000 Subject: [PATCH] AI uses the transporters better, code cleanups. --- src/ai/ai_force.cpp | 52 ++++++++++--- src/ai/ai_magic.cpp | 174 +++++++++++++++++++++++++++++-------------- src/ai/ai_plan.cpp | 2 + src/ai/script_ai.cpp | 2 +- 4 files changed, 164 insertions(+), 66 deletions(-) diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp index c566d28f2..873d2b651 100644 --- a/src/ai/ai_force.cpp +++ b/src/ai/ai_force.cpp @@ -356,10 +356,19 @@ global void AiAttackWithForce(int force) } } +//---------------------------------------------------------------------------- +// Handle attack of force with transporter. +//---------------------------------------------------------------------------- + /** +** Step 1) ** Load force on transporters. ** ** @param force Force pointer. +** +** @todo If an unit can't reach the transporter the code hangs. +** We must the transporter land on a new position. +** Or the board action will be better written. */ local void AiLoadForce(AiForce* force) { @@ -427,9 +436,14 @@ local void AiLoadForce(AiForce* force) } /** -** Send force off transporters. +** Step 2) +** Send force awaay in transporters, to unload at target position. ** ** @param force Force pointer. +** +** @todo The transporter should avoid enemy contact and should land +** at an unfortified coast. If we send more transporters they +** should land on different positions. */ local void AiSendTransporter(AiForce* force) { @@ -440,8 +454,13 @@ local void AiSendTransporter(AiForce* force) // aiunit=force->Units; while( aiunit ) { + // Transporter to unload units if( aiunit->Unit->Type->Transporter ) { - CommandMove(aiunit->Unit, force->GoalX, force->GoalY, + CommandUnload(aiunit->Unit, force->GoalX, force->GoalY, NoUnitP, + FlushCommands); + // Ships to defend transporter + } else if( aiunit->Unit->Type->UnitType==UnitTypeNaval ) { + CommandAttack(aiunit->Unit, force->GoalX, force->GoalY, NoUnitP, FlushCommands); } aiunit=aiunit->Next; @@ -450,14 +469,19 @@ local void AiSendTransporter(AiForce* force) } /** +** Step 3) ** Wait for transporters landed. ** ** @param force Force pointer. +** +** @todo If units blocks the unload process we should move them away. +** FIXME: hangs if the unit can't unloaded. */ local void AiWaitLanded(AiForce* force) { AiUnit* aiunit; int i; + int j; DebugLevel0Fn("Waiting\n"); // @@ -466,13 +490,20 @@ local void AiWaitLanded(AiForce* force) i=1; aiunit=force->Units; while( aiunit ) { - if( aiunit->Unit->Type->Transporter - && aiunit->Unit->Orders[0].Action==UnitActionStill ) { - DebugLevel0Fn("Unloading\n"); - CommandUnload(aiunit->Unit,aiunit->Unit->X,aiunit->Unit->Y, - NoUnitP,FlushCommands); - } else { - i=0; + if( aiunit->Unit->Type->Transporter ) { + if( aiunit->Unit->Orders[0].Action==UnitActionStill ) { + DebugLevel0Fn("Unloading\n"); + for( j=0; j<MAX_UNITS_ONBOARD; ++j ) { + if( aiunit->Unit->OnBoard[j] ) { + CommandUnload(aiunit->Unit,force->GoalX,force->GoalY, + NoUnitP,FlushCommands); + i=0; + break; + } + } + } else { + i=0; + } } aiunit=aiunit->Next; } @@ -482,7 +513,8 @@ local void AiWaitLanded(AiForce* force) } /** -** Force on attack ride. +** Step 4) +** Force on attack ride. We attack until there is no unit or enemy left. ** ** @param force Force pointer. */ diff --git a/src/ai/ai_magic.cpp b/src/ai/ai_magic.cpp index 9230c5ff9..23fc3c1f6 100644 --- a/src/ai/ai_magic.cpp +++ b/src/ai/ai_magic.cpp @@ -93,69 +93,96 @@ local void AiInitMagic(void) } /** -** Do magic for ogre-mage. +** Check if the unit should cast the "bloodlust" spell. +** +** If the spell is available and the unit has enough mana, the surrounding +** of the unit is checked if any enemy units are in sight. If enemy units +** are in sight the spell is casted on own units in range. +** +** @param unit Magic unit. +** +** @return True, if a spell is casted. +** +** @note This function can also be used for auto bloodlust. */ -local void AiDoOgreMage(Unit* unit) +local int AiBloodlustSpell(Unit* unit) { + Unit* best; + Unit* table[UnitMax]; int r; + int i; + int n; - if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-bloodlust") ) { - if( unit->Mana>AiBloodlust->ManaCost ) { - Unit* table[UnitMax]; - int n; - int i; + if (UpgradeIdentAvailable(AiPlayer->Player, "upgrade-bloodlust") + && unit->Mana > AiBloodlust->ManaCost) { - r=unit->Type->ReactRangeComputer; - n=SelectUnits(unit->X-r,unit->Y-r,unit->X+r+1,unit->Y+r+1,table); - if( n ) { - for( i=0; i<n; ++i ) { - Unit* best; + r = unit->Type->ReactRangeComputer; + n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1, + unit->Y + r + 1, table); - // a friend or neutral - if( !IsEnemy(unit->Player,table[i]) ) { - continue; - } - if( !table[i]->Type->CanAttack ) { - continue; - } - // - // We have an enemy in range. - // - best=NoUnitP; - for( i=0; i<n; ++i ) { - if( table[i]==unit - || table[i]->Bloodlust - || !table[i]->Type->CanAttack ) { - continue; - } - // Allied unit - // FIXME: should ally to self - if( unit->Player!=table[i]->Player && - !IsAllied(unit->Player,table[i]) ) { - continue; - } - r=MapDistanceBetweenUnits(unit,table[i]); - DebugLevel0Fn("Distance %d\n",r); - if( r<=1 ) { - DebugLevel0Fn("`%s' cast bloodlust\n" - _C_ unit->Type->Ident); - CommandSpellCast(unit,0,0,table[i], - AiBloodlust,FlushCommands); - break; - } - if( r==2 ) { - best=table[i]; - } - } - if( best ) { - CommandSpellCast(unit,0,0,best, - AiBloodlust,FlushCommands); - } - break; + for (i = 0; i < n; ++i) { + + // an enemy which can attack + if (!IsEnemy(unit->Player, table[i]) + || (!table[i]->Type->CanAttack)) { + continue; + } + // + // We have an enemy in range. + // + best = NoUnitP; + for (i = 0; i < n; ++i) { + // not self, not already bloodlust and can attack + if (table[i] == unit || table[i]->Bloodlust + || !table[i]->Type->CanAttack) { + continue; + } + // Allied unit + // FIXME: should ally to self + if (unit->Player != table[i]->Player + && !IsAllied(unit->Player, table[i])) { + continue; + } + r = MapDistanceBetweenUnits(unit, table[i]); + DebugLevel0Fn("Distance %d\n", r); + if (r <= 1) { + DebugLevel0Fn("`%s' cast bloodlust\n" _C_ unit->Type-> + Ident); + CommandSpellCast(unit, 0, 0, table[i], AiBloodlust, + FlushCommands); + return 1; + } + if (r == 2) { + best = table[i]; } } + if (best) { + CommandSpellCast(unit, 0, 0, best, AiBloodlust, + FlushCommands); + return 1; + } + break; } } + return 0; +} + +/** +** Check if the unit should cast the "eye of vision" spell. +** +** If the unit has nothing to do and the spell is available and the unit +** has full mana cast with a change of 1/32 the spell. The spells does +** nothing, because the AI cheats and already knows the surroundings. +** +** @param unit Magic unit. +** +** @return True, if a spell is casted. +** +** @note This function can also be used for auto eye of vision. +*/ +local int AiEyeOfVisionSpell(Unit* unit) +{ + int r; if( unit->Orders[0].Action==UnitActionStill ) { if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-eye-of-kilrogg") @@ -169,16 +196,41 @@ local void AiDoOgreMage(Unit* unit) CommandSpellCast(unit,unit->X,unit->Y,NoUnitP, AiEyeOfVision,FlushCommands); + return 1; } } } } + return 0; } /** -** Do magic for paladin. +** Do magic for ogre-mage. */ -local void AiDoPaladin(Unit* unit) +local void AiDoOgreMage(Unit* unit) +{ + if( AiBloodlustSpell(unit) ) { + return; + } + if( AiEyeOfVisionSpell(unit) ) { + return; + } +} + +/** +** Check if the unit should cast the "holy vision" spell. +** +** If the unit has nothing to do and the spell is available and the unit +** has full mana cast with a change of 1/32 the spell. The spells does +** nothing, because the AI cheats and already knows the surroundings. +** +** @param unit Magic unit. +** +** @return True, if a spell is casted. +** +** @note This function can also be used for auto holy vision. +*/ +local int AiHolyVisionSpell(Unit* unit) { int r; @@ -200,10 +252,22 @@ local void AiDoPaladin(Unit* unit) y=SyncRand()%TheMap.Height; CommandSpellCast(unit,x,y,NoUnitP, AiHolyVision,FlushCommands); + return 1; } } } } + return 0; +} + +/** +** Do magic for paladin. +*/ +local void AiDoPaladin(Unit* unit) +{ + if( AiHolyVisionSpell(unit) ) { + return; + } } /** diff --git a/src/ai/ai_plan.cpp b/src/ai/ai_plan.cpp index 64422a46d..88f437afc 100644 --- a/src/ai/ai_plan.cpp +++ b/src/ai/ai_plan.cpp @@ -288,6 +288,8 @@ local int AiFindTarget(const Unit* unit,unsigned char* matrix, } // Check targets on tile? + // FIXME: the move code didn't likes a shore building as + // target if( EnemyOnMapTile(unit,x,y) ) { DebugLevel0Fn("Target found %d,%d-%d\n" _C_ x _C_ y _C_ state); diff --git a/src/ai/script_ai.cpp b/src/ai/script_ai.cpp index 77965a526..8863e57a2 100644 --- a/src/ai/script_ai.cpp +++ b/src/ai/script_ai.cpp @@ -776,7 +776,7 @@ local SCM CclAiSleep(SCM value) { int i; - DebugLevel0Fn("%d %d\n",FrameCounter,AiPlayer->SleepFrames); + DebugLevel3Fn("%d %d\n",FrameCounter,AiPlayer->SleepFrames); if( AiPlayer->SleepFrames ) { if( AiPlayer->SleepFrames<FrameCounter ) { AiPlayer->SleepFrames=0;