Spells cleanup. Ai uses auto cast, ai can use more spells, added check for enemy units in range, renamed Kilrogg to Vision

This commit is contained in:
jsalmon3 2003-02-05 06:22:55 +00:00
parent a26b5da183
commit 64838d3a3d
3 changed files with 258 additions and 202 deletions

View file

@ -50,10 +50,16 @@
local UnitType* AiPaladin;
local SpellType* AiHolyVision;
local SpellType* AiHealing;
local UnitType* AiMage;
local SpellType* AiSlow;
local SpellType* AiInvisibility;
local UnitType* AiOgreMage;
local SpellType* AiEyeOfVision;
local SpellType* AiBloodlust;
local UnitType* AiUnitTypeEyeOfVision;
local UnitType* AiDeathKnight;
local SpellType* AiHaste;
local SpellType* AiUnholyArmor;
/*----------------------------------------------------------------------------
-- Functions
@ -69,25 +75,27 @@ local void AiInitMagic(void)
AiPaladin=UnitTypeByIdent("unit-paladin");
AiHolyVision=SpellTypeByIdent("spell-holy-vision");
AiHealing=SpellTypeByIdent("spell-healing");
AiMage=UnitTypeByIdent("unit-mage");
AiSlow=SpellTypeByIdent("spell-slow");
AiInvisibility=SpellTypeByIdent("spell-invisibility");
AiOgreMage=UnitTypeByIdent("unit-ogre-mage");
AiEyeOfVision=SpellTypeByIdent("spell-eye-of-vision");
AiBloodlust=SpellTypeByIdent("spell-bloodlust");
AiUnitTypeEyeOfVision=UnitTypeByIdent("unit-eye-of-vision");
AiDeathKnight=UnitTypeByIdent("unit-death-knight");
AiHaste=SpellTypeByIdent("spell-haste");
AiUnholyArmor=SpellTypeByIdent("spell-unholy-armor");
/*
"spell-exorcism"
"spell-fireball"
"spell-slow"
"spell-flame-shield"
"spell-invisibility"
"spell-polymorph"
"spell-blizzard"
"spell-runes"
"spell-death-coil"
"spell-haste"
"spell-raise-dead"
"spell-whirlwind"
"spell-unholy-armor"
"spell-death-and-decay"
*/
}
@ -102,67 +110,12 @@ local void AiInitMagic(void)
** @param unit Magic unit.
**
** @return True, if a spell is casted.
**
** @note This function can also be used for auto bloodlust.
*/
local int AiBloodlustSpell(Unit* unit)
{
Unit* best;
Unit* table[UnitMax];
int r;
int i;
int n;
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);
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) {
// FIXME: Spell castable checks must be done global by spells.
// 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" _C_ 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;
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-bloodlust") ) {
if( AutoCastSpell(unit,AiBloodlust) ) {
return 1;
}
}
return 0;
@ -178,29 +131,18 @@ local int AiBloodlustSpell(Unit* unit)
** @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")
&& UpgradeIdentAvailable(AiPlayer->Player,
"upgrade-ogre-mage") ) {
r=SyncRand();
/* s0m3body: each unit can have different MaxMana, the original condition is testing MaxMana-10,
* so let's take unit's maxmana * 245/255 as a new treshold */
if( unit->Mana>((unit->Type->_MaxMana * 245 ) / 255) && !(r%32) ) {
if( unit->Mana>AiEyeOfVision->ManaCost ) {
DebugLevel0Fn("`%s' cast eye of vision\n"
_C_ unit->Type->Ident);
CommandSpellCast(unit,unit->X,unit->Y,NoUnitP,
AiEyeOfVision,FlushCommands);
return 1;
}
if( unit->Orders[0].Action==UnitActionStill
&& UpgradeIdentAvailable(AiPlayer->Player,"upgrade-eye-of-kilrogg")
&& UpgradeIdentAvailable(AiPlayer->Player,"upgrade-ogre-mage") ) {
// s0m3body: each unit can have different MaxMana, the original
// condition is testing MaxMana-10, so let's take unit's
// maxmana * 245/255 as a new threshold
if( unit->Mana>(unit->Type->_MaxMana*245)/255 && !SyncRand()%32 ) {
if( AutoCastSpell(unit,AiEyeOfVision) ) {
return 1;
}
}
}
@ -220,6 +162,82 @@ local void AiDoOgreMage(Unit* unit)
}
}
/**
** Check if the unit should cast the "slow" 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 the units in range.
**
** @param unit Magic unit.
**
** @return True, if a spell is casted.
*/
local int AiSlowSpell(Unit* unit)
{
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-slow") ) {
if( !SyncRand()%4 && AutoCastSpell(unit,AiSlow) ) {
return 1;
}
}
return 0;
}
/**
** Check if the unit should cast the "invisibility" 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.
*/
local int AiInvisibilitySpell(Unit* unit)
{
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-invisibility") ) {
if( !SyncRand()%4 && AutoCastSpell(unit,AiInvisibility) ) {
return 1;
}
}
return 0;
}
/**
** Do magic for mage.
*/
local void AiDoMage(Unit* unit)
{
if (AiSlowSpell(unit)) {
return;
}
if (AiInvisibilitySpell(unit)) {
return;
}
}
/**
** Check if the unit should cast the "healing" spell.
**
** If the spell is available and the unit has enough mana, the surrounding
** of the unit is checked if any ally damaged units are in sight. If ally
** damaged units are in sight the spell is casted on own units in range.
**
** @param unit Magic unit.
**
** @return True, if a spell is casted.
*/
local int AiHealingSpell(Unit* unit)
{
if (UpgradeIdentAvailable(AiPlayer->Player, "upgrade-healing") ) {
if( AutoCastSpell(unit,AiHealing) ) {
return 1;
}
}
return 0;
}
/**
** Check if the unit should cast the "holy vision" spell.
**
@ -230,115 +248,19 @@ local void AiDoOgreMage(Unit* unit)
** @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;
if( unit->Orders[0].Action==UnitActionStill ) {
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-holy-vision")
&& UpgradeIdentAvailable(AiPlayer->Player,
"upgrade-paladin") ) {
r=SyncRand();
// s0m3body: each unit can have different MaxMana, the original
// condition is testing MaxMana-10, so let's take unit's
// maxmana * 245/255 as a new treshold
if( unit->Mana>((unit->Type->_MaxMana * 245)/255) && !(r%32) ) {
if( unit->Mana>AiHolyVision->ManaCost ) {
int x;
int y;
DebugLevel0Fn("`%s' cast holy vision\n"
_C_ unit->Type->Ident);
// Look around randomly
r>>=5;
x=r%TheMap.Width;
y=SyncRand()%TheMap.Height;
CommandSpellCast(unit,x,y,NoUnitP,
AiHolyVision,FlushCommands);
return 1;
}
}
}
}
return 0;
}
/**
** Check if the unit should cast the "heal" spell.
**
** If the spell is available and the unit has enough mana, the surrounding
** of the unit is checked if any ally damaged units are in sight. If ally
** damaged 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 heal.
*/
local int AiHealingSpell(Unit* unit)
{
Unit* best;
Unit* table[UnitMax];
int r;
int i;
int n;
// FIXME : minimum Mana for Ai Healing should be configurable.
if (UpgradeIdentAvailable(AiPlayer->Player, "upgrade-healing")
&& unit->Mana > AiHealing->ManaCost+20) {
r = unit->Type->ReactRangeComputer;
n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
unit->Y + r + 1, table);
for (i = 0; i < n; ++i) {
// an ally
if (IsEnemy(unit->Player, table[i])) {
continue;
}
//
// We have an ally in range...
//
best = NoUnitP;
for (i = 0; i < n; ++i) {
// not self, organic and somewhat in need with healing
// (HP<8/10*max), ...
// FIXME: Spell castable checks must be done global by spells.
if (table[i] == unit || !table[i]->Type->Organic
|| table[i]->HP>=((table[i]->Type->_HitPoints*9)/10)) {
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" _C_ r);
if (r <= 1) {
DebugLevel0Fn("`%s' cast healing\n" _C_ unit->Type->
Ident);
CommandSpellCast(unit, 0, 0, table[i], AiHealing,
FlushCommands);
return 1;
}
if (r == 2) {
best = table[i];
}
}
if (best) {
CommandSpellCast(unit, 0, 0, best, AiHealing,
FlushCommands);
if( unit->Orders[0].Action==UnitActionStill
&& UpgradeIdentAvailable(AiPlayer->Player,"upgrade-holy-vision")
&& UpgradeIdentAvailable(AiPlayer->Player,"upgrade-paladin") ) {
// s0m3body: each unit can have different MaxMana, the original
// condition is testing MaxMana-10, so let's take unit's
// maxmana * 245/255 as a new threshold
if( unit->Mana>(unit->Type->_MaxMana*245)/255 && !SyncRand()%32 ) {
if( AutoCastSpell(unit,AiHolyVision) ) {
return 1;
}
break;
}
}
return 0;
@ -357,6 +279,61 @@ local void AiDoPaladin(Unit* unit)
}
}
/**
** Check if the unit should cast the "haste" spell.
**
** If the spell is available and the unit has enough mana, the surrounding
** of the unit is checked if any ally units are in sight. If ally units
** are in sight the spell is casted on the units in range.
**
** @param unit Magic unit.
**
** @return True, if a spell is casted.
*/
local int AiHasteSpell(Unit* unit)
{
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-haste") ) {
if( !SyncRand()%4 && AutoCastSpell(unit,AiHaste) ) {
return 1;
}
}
return 0;
}
/**
** Check if the unit should cast the "unholy armor" 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.
*/
local int AiUnholyArmorSpell(Unit* unit)
{
if( UpgradeIdentAvailable(AiPlayer->Player,"upgrade-unholy-armor") ) {
if( !SyncRand()%4 && AutoCastSpell(unit,AiUnholyArmor) ) {
return 1;
}
}
return 0;
}
/**
** Do magic for death knight.
*/
local void AiDoDeathKnight(Unit* unit)
{
if (AiHasteSpell(unit)) {
return;
}
if (AiUnholyArmorSpell(unit)) {
return;
}
}
/**
** Check what computer units can do with magic.
*/
@ -378,8 +355,12 @@ global void AiCheckMagic(void)
// FIXME: I hardcode the reactions now
if( unit->Type==AiOgreMage ) {
AiDoOgreMage(unit);
} else if( unit->Type==AiMage ) {
AiDoMage(unit);
} else if( unit->Type==AiPaladin ) {
AiDoPaladin(unit);
} else if( unit->Type==AiDeathKnight ) {
AiDoDeathKnight(unit);
}
}
//

View file

@ -62,7 +62,7 @@ typedef enum _spell_action_type_ {
SpellActionPolymorph, /// Polymorph
SpellActionBlizzard, /// Blizzard
// ---orc ogres---
SpellActionEyeOfKilrogg, /// Eye
SpellActionEyeOfVision, /// Eye
SpellActionBloodlust, /// Blood lust
SpellActionRunes, /// Runes
// ---orc death knights---

View file

@ -107,7 +107,7 @@ global SpellType SpellTypeTable[]
{ "spell-polymorph", "polymorph", 10, 200, -1, SpellActionPolymorph , { "polymorph", NULL } , { NULL, NULL} },
{ "spell-blizzard", "blizzard", 12, 25, -1, SpellActionBlizzard , { "blizzard", NULL } , { NULL, NULL} },
// ---orc ogres--- ---orc ogres---
{ "spell-eye-of-vision", "eye of vision", 6, 70, -1, SpellActionEyeOfKilrogg , { "eye of vision", NULL } , { NULL, NULL} },
{ "spell-eye-of-vision", "eye of vision", 6, 70, -1, SpellActionEyeOfVision , { "eye of vision", NULL } , { NULL, NULL} },
{ "spell-bloodlust", "bloodlust", 6, 50,1000, SpellActionBloodlust , { "bloodlust", NULL } , { NULL, NULL} },
{ "spell-runes", "runes", 10, 200,2000, SpellActionRunes , { "runes", NULL } , { NULL, NULL} },
// ---orc death knights--- ---orc death knights-
@ -819,7 +819,7 @@ global int CanCastSpell(const Unit* unit, const SpellType* spell,
return 1;
// ---orc ogres---
case SpellActionEyeOfKilrogg:
case SpellActionEyeOfVision:
return 1;
case SpellActionBloodlust:
@ -858,6 +858,25 @@ global int CanCastSpell(const Unit* unit, const SpellType* spell,
return 1;
}
/**
** Auto cast holy vision if possible.
**
** @param unit Unit that casts the spell
** @param spell Spell-type pointer
**
** @return =!0 if spell can be cast, 0 if not
*/
local int AutoCastHolyVision(Unit* unit, SpellType* spell)
{
int x;
int y;
x = SyncRand() % TheMap.Width;
y = SyncRand() % TheMap.Height;
CommandSpellCast(unit, x, y, NoUnitP, spell, FlushCommands);
return 1;
}
/**
** Auto cast healing if possible.
**
@ -874,7 +893,11 @@ local int AutoCastHealing(Unit* unit, SpellType* spell)
int j;
int n;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
@ -919,7 +942,11 @@ local int AutoCastSlow(Unit* unit, SpellType* spell)
int j;
int n;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
@ -968,15 +995,25 @@ local int AutoCastInvisibility(Unit* unit, SpellType* spell)
int i;
int j;
int n;
int enemy;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
unit->Y + r + 1, table);
enemy = 0;
for (i = 0, j = 0; i < n; ++i) {
if (!enemy && IsEnemy(unit->Player, table[i])) {
enemy = 1;
}
// Only cast on ourselves or an ally
if (table[i] == unit || (unit->Player != table[i]->Player
&& !IsAllied(unit->Player, table[i]))) {
@ -996,7 +1033,7 @@ local int AutoCastInvisibility(Unit* unit, SpellType* spell)
table[j++] = table[i];
}
if (j) {
if (enemy && j) {
j = SyncRand() % j;
CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
return 1;
@ -1004,6 +1041,20 @@ local int AutoCastInvisibility(Unit* unit, SpellType* spell)
return 0;
}
/**
** Auto cast eye of vision if possible.
**
** @param unit Unit that casts the spell
** @param spell Spell-type pointer
**
** @return =!0 if spell can be cast, 0 if not
*/
local int AutoCastEyeOfVision(Unit* unit, SpellType* spell)
{
CommandSpellCast(unit, unit->X, unit->Y, NoUnitP, spell, FlushCommands);
return 1;
}
/**
** Auto cast bloodlust if possible.
**
@ -1019,15 +1070,25 @@ local int AutoCastBloodlust(Unit* unit, SpellType* spell)
int i;
int j;
int n;
int enemy;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
unit->Y + r + 1, table);
enemy = 0;
for (i = 0, j = 0; i < n; ++i) {
if (!enemy && IsEnemy(unit->Player, table[i])) {
enemy = 1;
}
// Only cast on ourselves or an ally
if (table[i] == unit || (unit->Player != table[i]->Player
&& !IsAllied(unit->Player, table[i]))) {
@ -1047,7 +1108,7 @@ local int AutoCastBloodlust(Unit* unit, SpellType* spell)
table[j++] = table[i];
}
if (j) {
if (enemy && j) {
j = SyncRand() % j;
CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
return 1;
@ -1071,7 +1132,11 @@ local int AutoCastHaste(Unit* unit, SpellType* spell)
int j;
int n;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
@ -1121,15 +1186,25 @@ local int AutoCastUnholyArmor(Unit* unit, SpellType* spell)
int i;
int j;
int n;
int enemy;
r = unit->Type->ReactRangePerson;
if (unit->Player->Type == PlayerPerson) {
r = unit->Type->ReactRangePerson;
} else {
r = unit->Type->ReactRangeComputer;
}
if (spell->Range < r) {
r = spell->Range;
}
n = SelectUnits(unit->X - r, unit->Y - r, unit->X + r + 1,
unit->Y + r + 1, table);
enemy = 0;
for (i = 0, j = 0; i < n; ++i) {
if (!enemy && IsEnemy(unit->Player, table[i])) {
enemy = 1;
}
// Only cast on ourselves or an ally
if (table[i] == unit || (unit->Player != table[i]->Player
&& !IsAllied(unit->Player, table[i]))) {
@ -1149,7 +1224,7 @@ local int AutoCastUnholyArmor(Unit* unit, SpellType* spell)
table[j++] = table[i];
}
if (j) {
if (enemy && j) {
j = SyncRand() % j;
CommandSpellCast(unit, 0, 0, table[j], spell, FlushCommands);
return 1;
@ -1181,7 +1256,7 @@ global int AutoCastSpell(Unit* unit, SpellType* spell)
// ---human paladins---
case SpellActionHolyVision:
return 0;
return AutoCastHolyVision(unit, spell);
case SpellActionHealing:
return AutoCastHealing(unit, spell);
@ -1209,8 +1284,8 @@ global int AutoCastSpell(Unit* unit, SpellType* spell)
return 0;
// ---orc ogres---
case SpellActionEyeOfKilrogg:
return 0;
case SpellActionEyeOfVision:
return AutoCastEyeOfVision(unit, spell);
case SpellActionBloodlust:
return AutoCastBloodlust(unit, spell);
@ -1557,7 +1632,7 @@ global int SpellCast(Unit * unit, const SpellType * spell, Unit * target,
break;
// ---orc ogres---
case SpellActionEyeOfKilrogg:
case SpellActionEyeOfVision:
unit->Mana -= spell->ManaCost;
// FIXME: johns: the unit is placed on the wrong position