示例#1
0
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 );
				}
			}
		}
	}
}
示例#3
0
 void queue(ActionItem *item)
 {
     mutex.wait();
     actions.push_back(item);
     mutex.post();
 }
示例#4
0
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;
}
示例#5
0
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()));
}