AI uses the transporters better, code cleanups.
This commit is contained in:
parent
750654a3a6
commit
65b9398100
4 changed files with 164 additions and 66 deletions
|
@ -356,10 +356,19 @@ global void AiAttackWithForce(int force)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Handle attack of force with transporter.
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
** Step 1)
|
||||||
** Load force on transporters.
|
** Load force on transporters.
|
||||||
**
|
**
|
||||||
** @param force Force pointer.
|
** @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)
|
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.
|
** @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)
|
local void AiSendTransporter(AiForce* force)
|
||||||
{
|
{
|
||||||
|
@ -440,8 +454,13 @@ local void AiSendTransporter(AiForce* force)
|
||||||
//
|
//
|
||||||
aiunit=force->Units;
|
aiunit=force->Units;
|
||||||
while( aiunit ) {
|
while( aiunit ) {
|
||||||
|
// Transporter to unload units
|
||||||
if( aiunit->Unit->Type->Transporter ) {
|
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);
|
FlushCommands);
|
||||||
}
|
}
|
||||||
aiunit=aiunit->Next;
|
aiunit=aiunit->Next;
|
||||||
|
@ -450,14 +469,19 @@ local void AiSendTransporter(AiForce* force)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
** Step 3)
|
||||||
** Wait for transporters landed.
|
** Wait for transporters landed.
|
||||||
**
|
**
|
||||||
** @param force Force pointer.
|
** @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)
|
local void AiWaitLanded(AiForce* force)
|
||||||
{
|
{
|
||||||
AiUnit* aiunit;
|
AiUnit* aiunit;
|
||||||
int i;
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
DebugLevel0Fn("Waiting\n");
|
DebugLevel0Fn("Waiting\n");
|
||||||
//
|
//
|
||||||
|
@ -466,13 +490,20 @@ local void AiWaitLanded(AiForce* force)
|
||||||
i=1;
|
i=1;
|
||||||
aiunit=force->Units;
|
aiunit=force->Units;
|
||||||
while( aiunit ) {
|
while( aiunit ) {
|
||||||
if( aiunit->Unit->Type->Transporter
|
if( aiunit->Unit->Type->Transporter ) {
|
||||||
&& aiunit->Unit->Orders[0].Action==UnitActionStill ) {
|
if( aiunit->Unit->Orders[0].Action==UnitActionStill ) {
|
||||||
DebugLevel0Fn("Unloading\n");
|
DebugLevel0Fn("Unloading\n");
|
||||||
CommandUnload(aiunit->Unit,aiunit->Unit->X,aiunit->Unit->Y,
|
for( j=0; j<MAX_UNITS_ONBOARD; ++j ) {
|
||||||
NoUnitP,FlushCommands);
|
if( aiunit->Unit->OnBoard[j] ) {
|
||||||
} else {
|
CommandUnload(aiunit->Unit,force->GoalX,force->GoalY,
|
||||||
i=0;
|
NoUnitP,FlushCommands);
|
||||||
|
i=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
aiunit=aiunit->Next;
|
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.
|
** @param force Force pointer.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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 r;
|
||||||
|
int i;
|
||||||
|
int n;
|
||||||
|
|
||||||
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-bloodlust") ) {
|
if (UpgradeIdentAvailable(AiPlayer->Player, "upgrade-bloodlust")
|
||||||
if( unit->Mana>AiBloodlust->ManaCost ) {
|
&& unit->Mana > AiBloodlust->ManaCost) {
|
||||||
Unit* table[UnitMax];
|
|
||||||
int n;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
r=unit->Type->ReactRangeComputer;
|
r = unit->Type->ReactRangeComputer;
|
||||||
n=SelectUnits(unit->X-r,unit->Y-r,unit->X+r+1,unit->Y+r+1,table);
|
n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
|
||||||
if( n ) {
|
unit->Y + r + 1, table);
|
||||||
for( i=0; i<n; ++i ) {
|
|
||||||
Unit* best;
|
|
||||||
|
|
||||||
// a friend or neutral
|
for (i = 0; i < n; ++i) {
|
||||||
if( !IsEnemy(unit->Player,table[i]) ) {
|
|
||||||
continue;
|
// an enemy which can attack
|
||||||
}
|
if (!IsEnemy(unit->Player, table[i])
|
||||||
if( !table[i]->Type->CanAttack ) {
|
|| (!table[i]->Type->CanAttack)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// We have an enemy in range.
|
// We have an enemy in range.
|
||||||
//
|
//
|
||||||
best=NoUnitP;
|
best = NoUnitP;
|
||||||
for( i=0; i<n; ++i ) {
|
for (i = 0; i < n; ++i) {
|
||||||
if( table[i]==unit
|
// not self, not already bloodlust and can attack
|
||||||
|| table[i]->Bloodlust
|
if (table[i] == unit || table[i]->Bloodlust
|
||||||
|| !table[i]->Type->CanAttack ) {
|
|| !table[i]->Type->CanAttack) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Allied unit
|
// Allied unit
|
||||||
// FIXME: should ally to self
|
// FIXME: should ally to self
|
||||||
if( unit->Player!=table[i]->Player &&
|
if (unit->Player != table[i]->Player
|
||||||
!IsAllied(unit->Player,table[i]) ) {
|
&& !IsAllied(unit->Player, table[i])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r=MapDistanceBetweenUnits(unit,table[i]);
|
r = MapDistanceBetweenUnits(unit, table[i]);
|
||||||
DebugLevel0Fn("Distance %d\n",r);
|
DebugLevel0Fn("Distance %d\n", r);
|
||||||
if( r<=1 ) {
|
if (r <= 1) {
|
||||||
DebugLevel0Fn("`%s' cast bloodlust\n"
|
DebugLevel0Fn("`%s' cast bloodlust\n" _C_ unit->Type->
|
||||||
_C_ unit->Type->Ident);
|
Ident);
|
||||||
CommandSpellCast(unit,0,0,table[i],
|
CommandSpellCast(unit, 0, 0, table[i], AiBloodlust,
|
||||||
AiBloodlust,FlushCommands);
|
FlushCommands);
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
if( r==2 ) {
|
if (r == 2) {
|
||||||
best=table[i];
|
best = table[i];
|
||||||
}
|
|
||||||
}
|
|
||||||
if( best ) {
|
|
||||||
CommandSpellCast(unit,0,0,best,
|
|
||||||
AiBloodlust,FlushCommands);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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( unit->Orders[0].Action==UnitActionStill ) {
|
||||||
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-eye-of-kilrogg")
|
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-eye-of-kilrogg")
|
||||||
|
@ -169,16 +196,41 @@ local void AiDoOgreMage(Unit* unit)
|
||||||
|
|
||||||
CommandSpellCast(unit,unit->X,unit->Y,NoUnitP,
|
CommandSpellCast(unit,unit->X,unit->Y,NoUnitP,
|
||||||
AiEyeOfVision,FlushCommands);
|
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;
|
int r;
|
||||||
|
|
||||||
|
@ -200,10 +252,22 @@ local void AiDoPaladin(Unit* unit)
|
||||||
y=SyncRand()%TheMap.Height;
|
y=SyncRand()%TheMap.Height;
|
||||||
CommandSpellCast(unit,x,y,NoUnitP,
|
CommandSpellCast(unit,x,y,NoUnitP,
|
||||||
AiHolyVision,FlushCommands);
|
AiHolyVision,FlushCommands);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Do magic for paladin.
|
||||||
|
*/
|
||||||
|
local void AiDoPaladin(Unit* unit)
|
||||||
|
{
|
||||||
|
if( AiHolyVisionSpell(unit) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -288,6 +288,8 @@ local int AiFindTarget(const Unit* unit,unsigned char* matrix,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check targets on tile?
|
// Check targets on tile?
|
||||||
|
// FIXME: the move code didn't likes a shore building as
|
||||||
|
// target
|
||||||
if( EnemyOnMapTile(unit,x,y) ) {
|
if( EnemyOnMapTile(unit,x,y) ) {
|
||||||
DebugLevel0Fn("Target found %d,%d-%d\n"
|
DebugLevel0Fn("Target found %d,%d-%d\n"
|
||||||
_C_ x _C_ y _C_ state);
|
_C_ x _C_ y _C_ state);
|
||||||
|
|
|
@ -776,7 +776,7 @@ local SCM CclAiSleep(SCM value)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DebugLevel0Fn("%d %d\n",FrameCounter,AiPlayer->SleepFrames);
|
DebugLevel3Fn("%d %d\n",FrameCounter,AiPlayer->SleepFrames);
|
||||||
if( AiPlayer->SleepFrames ) {
|
if( AiPlayer->SleepFrames ) {
|
||||||
if( AiPlayer->SleepFrames<FrameCounter ) {
|
if( AiPlayer->SleepFrames<FrameCounter ) {
|
||||||
AiPlayer->SleepFrames=0;
|
AiPlayer->SleepFrames=0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue