bool Battle::AIApplySpell(const Spell & spell, const Unit* b, const HeroBase & hero, Actions & a) { u8 mass = Spell::NONE; switch(spell()) { case Spell::CURE: mass = Spell::MASSCURE; break; case Spell::HASTE: mass = Spell::MASSHASTE; break; case Spell::SLOW: mass = Spell::MASSSLOW; break; case Spell::BLESS: mass = Spell::MASSBLESS; break; case Spell::CURSE: mass = Spell::MASSCURSE; break; case Spell::DISPEL: mass = Spell::MASSDISPEL; break; case Spell::SHIELD: mass = Spell::MASSSHIELD; break; default: break; } if(mass != Spell::NONE && AIApplySpell(mass, b, hero, a)) return true; if(hero.CanCastSpell(spell) && (!b || b->AllowApplySpell(spell, &hero))) { a.push_back(Battle::Command(MSG_BATTLE_CAST, spell(), (b ? b->GetHeadIndex() : -1))); return true; } return false; }
void UnitAttackAbility::DetermineAvailableActions( const Unit* unit, const Path& movementPath, Actions& result ) const { // Get the UnitType of the Unit. UnitType* unitType = unit->GetUnitType(); if( unitType->HasWeapons() ) { // If this Unit has weapons, determine whether the Unit can wait in the destination square. Map* map = unit->GetMap(); Map::Iterator destinationTile = map->GetTile( movementPath.GetDestination() ); if( unit->CanOccupyTile( destinationTile ) ) { // If the Unit can stop here, get the list of Units in attack range from this location. Map::Units unitsInRange; map->FindUnitsInRange( destinationTile.GetPosition(), unitType->GetAttackRange(), unitsInRange ); for( auto it = unitsInRange.begin(); it != unitsInRange.end(); ++it ) { Unit* target = *it; if( unit->CanAttack( target ) ) { // Add an attack action to the list of actions. UnitAttackAbility::Action* attackAction = new UnitAttackAbility::Action(); attackAction->UnitID = unit->GetID(); attackAction->TargetID = target->GetID(); attackAction->MovementPath = movementPath; result.push_back( attackAction ); } } } } }
void queue(ActionItem *item) { mutex.wait(); actions.push_back(item); mutex.post(); }
bool AI::BattleMagicTurn(Arena & arena, const Unit & b, Actions & a, const Unit* enemy) { const HeroBase* hero = b.GetCommander(); if(b.Modes(SP_BERSERKER) || !hero || hero->Modes(Heroes::SPELLCASTED) || !hero->HaveSpellBook() || arena.isDisableCastSpell(Spell(), NULL) || a.HaveCommand(Battle::MSG_BATTLE_CAST)) return false; const Force & my_army = arena.GetForce(b.GetArmyColor(), false); const Force & enemy_army = arena.GetForce(b.GetArmyColor(), true); Units friends(my_army, true); Units enemies(enemy_army, true); // sort strongest friends.SortStrongest(); // troop bad spell - clean { // sort strongest Units::iterator it = std::find_if(friends.begin(), friends.end(), std::bind2nd(std::mem_fun(&Unit::Modes), IS_BAD_MAGIC)); if(it != friends.end()) { if(AIApplySpell(Spell::DISPEL, *it, *hero, a)) return true; if(AIApplySpell(Spell::CURE, *it, *hero, a)) return true; } } // area damage spell { const u8 areasp[] = { Spell::METEORSHOWER, Spell::FIREBLAST, Spell::CHAINLIGHTNING, Spell::FIREBALL, Spell::COLDRING }; s16 dst = AIAreaSpellDst(*hero); if(Board::isValidIndex(dst)) for(u8 ii = 0; ii < ARRAY_COUNT(areasp); ++ii) { if(hero->CanCastSpell(areasp[ii])) { a.push_back(Battle::Command(MSG_BATTLE_CAST, areasp[ii], dst)); return true; } } } // if handfighting if(enemy) { // kill dragons if(enemy->isDragons() && !b.Modes(SP_DRAGONSLAYER) && AIApplySpell(Spell::DRAGONSLAYER, &b, *hero, a)) return true; // curse if(!enemy->Modes(SP_CURSE) && AIApplySpell(Spell::CURSE, enemy, *hero, a)) return true; // enemy good spell - clean if(enemy->Modes(IS_GOOD_MAGIC) && AIApplySpell(Spell::DISPEL, enemy, *hero, a)) return true; // up defense if(!b.Modes(SP_STEELSKIN) && !b.Modes(SP_STONESKIN) && AIApplySpell(Spell::STEELSKIN, &b, *hero, a)) return true; if(!b.Modes(SP_STONESKIN) && !b.Modes(SP_STEELSKIN) && AIApplySpell(Spell::STONESKIN, &b, *hero, a)) return true; } // my army blessing if(b.isArchers()) { if(!b.Modes(SP_BLESS) && AIApplySpell(Spell::BLESS, &b, *hero, a)) return true; if(!b.Modes(SP_BLOODLUST) && AIApplySpell(Spell::BLOODLUST, &b, *hero, a)) return true; } // up speed if(hero->HaveSpell(Spell::HASTE) && !enemy) { // sort strongest Units::iterator it = std::find_if(friends.begin(), friends.end(), std::not1(std::bind2nd(std::mem_fun(&Unit::Modes), SP_HASTE))); if(it != friends.end() && AIApplySpell(Spell::HASTE, *it, *hero, a)) return true; } // shield spell conditions { Units::iterator it = std::find_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isArchers)); const Castle* castle = Arena::GetCastle(); // find enemy archers if(it != enemies.end() || // or archers tower (castle && castle->GetColor() != b.GetColor() && castle->isCastle())) { // find strongest archers for(it = friends.begin(); it != friends.end(); ++it) if((*it)->isArchers() && ! (*it)->Modes(SP_SHIELD)) break; // or other strongest friends if(it == friends.end()) it = std::find_if(friends.begin(), friends.end(), std::not1(std::bind2nd(std::mem_fun(&Unit::Modes), SP_SHIELD))); if(it != friends.end() && AIApplySpell(Spell::SHIELD, *it, *hero, a)) return true; } } // enemy army spell { // find mirror image or summon elem Units::iterator it = std::find_if(enemies.begin(), enemies.end(), std::bind2nd(std::mem_fun(&Unit::Modes), CAP_MIRRORIMAGE | CAP_SUMMONELEM)); if(it != enemies.end()) { if(AIApplySpell(Spell::ARROW, *it, *hero, a)) return true; if(AIApplySpell(Spell::LIGHTNINGBOLT, *it, *hero, a)) return true; } // find good magic it = std::find_if(enemies.begin(), enemies.end(), std::bind2nd(std::mem_fun(&Unit::Modes), IS_GOOD_MAGIC)); if(it != enemies.end()) { // slow if((*it)->Modes(SP_HASTE) && AIApplySpell(Spell::SLOW, *it, *hero, a)) return true; // curse if((*it)->Modes(SP_CURSE) && AIApplySpell(Spell::CURSE, *it, *hero, a)) return true; // if(AIApplySpell(Spell::DISPEL, *it, *hero, a)) return true; } // check undead if(std::count_if(friends.begin(), friends.end(), std::mem_fun(&Unit::isUndead)) < std::count_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isUndead))) { if(AIApplySpell(Spell::HOLYSHOUT, NULL, *hero, a)) return true; if(AIApplySpell(Spell::HOLYWORD, NULL, *hero, a)) return true; } // check alife if(std::count_if(friends.begin(), friends.end(), std::mem_fun(&Unit::isAlive)) < std::count_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isAlive))) { if(AIApplySpell(Spell::DEATHRIPPLE, NULL, *hero, a)) return true; if(AIApplySpell(Spell::DEATHWAVE, NULL, *hero, a)) return true; } Unit* stats = *Rand::Get(enemies); if(AIApplySpell(Spell::LIGHTNINGBOLT, stats, *hero, a)) return true; if(AIApplySpell(Spell::ARROW, stats, *hero, a)) return true; } /* FIX: Damage Spell: */ if(AIApplySpell(Spell::ARMAGEDDON, NULL, *hero, a)) return true; if(AIApplySpell(Spell::ELEMENTALSTORM, NULL, *hero, a)) return true; return false; }
void AI::BattleTurn(Arena & arena, const Unit & b, Actions & a) { Board* board = Arena::GetBoard(); // reset quality param for board board->Reset(); // set quality for enemy troop board->SetEnemyQuality(b); const Unit* enemy = NULL; bool attack = false; if(b.isArchers() && !b.isHandFighting()) { enemy = arena.GetEnemyMaxQuality(b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else if(b.isHandFighting()) { enemy = AIGetEnemyAbroadMaxQuality(b); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else { s16 move = -1; if(b.Modes(SP_BERSERKER)) { const Indexes positions = board->GetNearestTroopIndexes(b.GetHeadIndex(), NULL); if(positions.size()) move = *Rand::Get(positions); } else { if(BattleMagicTurn(arena, b, a, NULL)) return; /* repeat turn: correct spell ability */ // set quality position from enemy board->SetPositionQuality(b); // get passable quality positions const Indexes positions = board->GetPassableQualityPositions(b); attack = true; if(positions.size()) move = AIAttackPosition(arena, b, positions); } if(Board::isValidIndex(move)) { if(b.isFly()) { enemy = AIGetEnemyAbroadMaxQuality(move, b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), move)); attack = true; } else { Position dst = Position::GetCorrect(b, move); Indexes path = arena.GetPath(b, dst); if(path.empty()) { const u8 direction = b.GetPosition().GetHead()->GetPos().x > dst.GetHead()->GetPos().x ? RIGHT : LEFT; // find near position while(path.empty() && Board::isValidDirection(dst.GetHead()->GetIndex(), direction)) { const s16 & pos = Board::GetIndexDirection(dst.GetHead()->GetIndex(), direction); if(b.GetHeadIndex() == pos) break; dst.Set(pos, b.isWide(), direction == RIGHT); path = arena.GetPath(b, dst); } } if(path.size()) { if(b.isWide()) { const s16 & head = dst.GetHead()->GetIndex(); const s16 & tail = dst.GetTail()->GetIndex(); if(path.back() == head || path.back() == tail) { enemy = AIGetEnemyAbroadMaxQuality(head, b.GetColor()); if(!enemy) enemy = AIGetEnemyAbroadMaxQuality(tail, b.GetColor()); } } if(! enemy) enemy = AIGetEnemyAbroadMaxQuality(path.back(), b.GetColor()); a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), path.back())); // archers move and short attack only attack = b.isArchers() ? false : true; } } } else enemy = AIGetEnemyAbroadMaxQuality(b); } if(enemy) { if(attack) a.push_back(Battle::Command(MSG_BATTLE_ATTACK, b.GetUID(), enemy->GetUID(), enemy->GetHeadIndex(), 0)); } else { DEBUG(DBG_BATTLE, DBG_TRACE, "enemy: " << "is NULL" << ", board: " << board->AllUnitsInfo()); } // end action a.push_back(Battle::Command(MSG_BATTLE_END_TURN, b.GetUID())); }