Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

T-800 mod для Free Heroes II

Не запускается игра? Проблемы со звуком? Где, в конце концов, взять игру, скачать патчи, приложения и карты? Как установить все это? Все проблемы обсуждаем в этом разделе
offlineАватара пользователя
t800  
Ветеран
Ветеран
 
Сообщения: 982
Зарегистрирован: 22 июл 2015, 11:36
Пол: Не указан
Награды: 4
Наградной знак (1) Деревянный Щит (1) Золотой Меч (1) Серебряные Сапоги (1)
Поблагодарили: 191 раз.

Re: Кампания во Free Heroes II

Сообщение t800 » 26 сен 2015, 11:19

Никак не могу придумать как считать рейтинги для каманий.

В файле game_highscores.cpp в разделе int Game::HighScores


Код: Выделить всё
int Game::HighScores(bool fill)
{
   Cursor & cursor = Cursor::Get();
   Display & display = Display::Get();
   const Settings & conf = Settings::Get();

   cursor.Hide();
   if(fill) display.Fill(ColorBlack);

#ifdef WITH_DEBUG
   if(IS_DEVEL() && world.CountDay())
   {
   std::string msg = std::string("Devepoper mode, not save! \n \n Your result: ") + GetString(GetGameOverScores());
   Dialog::Message("High Scores", msg, Font::BIG, Dialog::OK);
   return MAINMENU;
   }
#endif

   HGSData hgs;

   std::ostringstream stream;
   stream << System::ConcatePath(conf.GetSaveDir(), "fheroes2.hgs");

   cursor.SetThemes(cursor.POINTER);
   Mixer::Pause();
   AGG::PlayMusic(MUS::MAINMENU);
   hgs.Load(stream.str().c_str());

   const Sprite &back = AGG::GetICN(ICN::HSBKG, 0);

   cursor.Hide();
   const Point top((display.w() - back.w()) / 2, (display.h() - back.h()) / 2);

   hgs.RedrawList(top.x, top.y);

   LocalEvent & le = LocalEvent::Get();

   Button buttonCampain(top.x + (conf.QVGA() ? 0 : 9), top.y + (conf.QVGA() ? 100 : 315), ICN::HISCORE, 0, 1);
   Button buttonExit(top.x + back.w() - (conf.QVGA() ? 27 : 36), top.y + (conf.QVGA() ? 100 : 315), ICN::HISCORE, 4, 5);

   buttonCampain.Draw();
   buttonExit.Draw();

   cursor.Show();
   display.Flip();

   const u32 rating = GetGameOverScores();
   const u32 days = world.CountDay();
   GameOver::Result & gameResult = GameOver::Result::Get();

   std::cout  << days;
   std::cout  << " Дни \n";

   std::cout  << rating;
   std::cout  << " Рейтинг \n";

   
   if(rating && (gameResult.GetResult() & GameOver::WINS))
   {
   std::string player(_("Unknown Hero"));
   Dialog::InputString(_("Your Name"), player);
   cursor.Hide();
   if(player.empty()) player = _("Unknown Hero");
   hgs.ScoreRegistry(player, Settings::Get().CurrentFileInfo().name, days, rating);
   hgs.Save(stream.str().c_str());
   hgs.RedrawList(top.x, top.y);
   buttonCampain.Draw();
   buttonExit.Draw();
   cursor.Show();
   display.Flip();
   gameResult.Reset();
   }




Я нашел такие команды.

Код: Выделить всё
const u32 rating = GetGameOverScores();
const u32 days = world.CountDay();



Я проверил что они делают оказываются он считаю рейтинг игры и число дней.

Код: Выделить всё
   std::cout  << days;
   std::cout  << " Дни \n";

   std::cout  << rating;
std::cout  << " Рейтинг \n";


И подумал что можно наверно сделать так. Для каждой из кампаний сделать отдельный файлик куда игра будет записывать имя карты и число дней и рейтинг карты после выигрыша каржлдго из эпизодов. А потом если закончилась игра на последней карты. Их оттуда опять брать складывать все дни по всем картам и все рейтинг по всем картам и уже записывать с именем кампании в файл откуда она берет очки для все камапаний.
Но я подумал а может можно это проще сделать? Без файликов?
Вернуться к началу

offlineАватара пользователя
t800  
Ветеран
Ветеран
 
Сообщения: 982
Зарегистрирован: 22 июл 2015, 11:36
Пол: Не указан
Награды: 4
Наградной знак (1) Деревянный Щит (1) Золотой Меч (1) Серебряные Сапоги (1)
Поблагодарили: 191 раз.

Re: Кампания во Free Heroes II

Сообщение t800 » 15 окт 2015, 15:43

Решил в T-800 Mod поставить свою музыку в замок. Cыграл на фортепиано и записал на видео.

[youtube]http://youtu.be/tXZtYVsv_tA[/youtube]

Попробовал переделать в MIDI через через он лайн конвертор MIDI файл получился со страшным дребезжанием :smile7:
И что делать? Как мне сделать MIDI чтобы не дребезжал?
Вернуться к началу

offlineАватара пользователя
Orzie  
Ветеран
Ветеран
 
Сообщения: 698
Зарегистрирован: 12 сен 2013, 15:17
Откуда: Томск
Пол: Не указан
Награды: 3
Высшая медаль (1) 3 место 1 этапа по HMM1 (1) Бонусный шлем (1)
Поблагодарили: 457 раз.

Re: Кампания во Free Heroes II

Сообщение Orzie » 15 окт 2015, 16:38

Я же говорю, возьми нормальную программу для сочинения миди и напиши это в ней, нотами.

На самый крайний случай, если с муз образованием беда, можно взять Guitar Pro и натыкать по клавишам - там есть такая панель интерфейса. Потом экспортируешь в миди, дальше - как я сказал, искать конвертер миди в двоечный формат XMI.
Вернуться к началу

offlineАватара пользователя
VDV_forever  
имя: Дмитрий
Администратор
 
Сообщения: 3860
Зарегистрирован: 22 мар 2009, 12:36
Пол: Мужчина
Поблагодарили: 983 раз.

Re: Кампания во Free Heroes II

Сообщение VDV_forever » 16 окт 2015, 10:14

t800 писал(а):

Решил в T-800 Mod поставить свою музыку в замок. Cыграл на фортепиано и записал на видео.

[youtube]http://youtu.be/tXZtYVsv_tA[/youtube]

Попробовал переделать в MIDI через через он лайн конвертор MIDI файл получился со страшным дребезжанием :smile7:
И что делать? Как мне сделать MIDI чтобы не дребезжал?


Молодец парень! Мне нравится! :smile20: Отточи игру на фортепьяно и залей еще раз, с удовольствием послушаю и посмотрю. :smile10: :smile20:
Мне кажется слишком долгие паузы делаешь, попробуй без них. :smile2: Надо чтобы музыка как бы перетекала, плавно, а не шла с затыками. Надеюсь смысл понятен. :smile1:
Человек делом занят, хорошим делом. Удачи тебе во всех твоих начинаниях и в особенности в геройских проектах :smile4:
http://www.handbookhmm.ru- Познай все тонкости игры!
Вернуться к началу

offlineBruzon  
Новичок
Новичок
 
Сообщения: 24
Зарегистрирован: 30 окт 2015, 22:24
Пол: Не указан
Поблагодарили: 4 раз.

Re: Кампания во Free Heroes II

Сообщение Bruzon » 30 окт 2015, 22:32

Товарищ, друг!
Ты ковыряешь Free Heroes II и делаешь кампанию? Благодарность тебе огромная!
Я уже давно жду, что хоть кто-нибудь займется этой игрой. Уже год играю в нее на смартфоне, все нравится, но ИИ просто ужасен! Автор не обновляет игру, видать, забросил. И это очень печально. Есть один лучик надежды - это ты! Скажи, дружище, а ты сможешь поправить ИИ игры так, чтобы он адекватно играл? Нормально воевал, создавал армии, передвигался по карте и соблюдал баланс, составлял реальную угрозу игроку? Или это очень сложно?
Просто весь фан от игры пропадает, когда выставляешь сложность 160% и ИИ сливает тебе вчистую при любом раскладе! Его действия абсолютно непонятны, в этом беда.
Андрей Афлетдинов, разработчик игры молчит, никому ничего не отвечает. И это плохо. Написал хотя бы, что забросил проект.
Последнее обновление было месяцев 5 назад, я был удивлен этому. Но, к сожалению, оно ничего кардинально не поменяло. А только ухудшило. После него перестала убавляться громкость игры кнопкой смартфона.
А еще в игре не сохраняются настройки скорости перемещения по карте, скорость прокрутки карты и громкость музыки. Если это поправишь - вообще будет супер!
В общем, всячески желаю тебе успехов в этом нелегком деле!
Я уже потерял всякую надежду, но тут нашел вот этот форум...
Не пропадай, товарищ!
Вернуться к началу

offlineАватара пользователя
Владимир  
Эксперт
Эксперт
 
Сообщения: 1032
Зарегистрирован: 30 окт 2012, 18:37
Пол: Не указан
Награды: 3
Высшая медаль (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (1)
Поблагодарили: 615 раз.

Re: Кампания во Free Heroes II

Сообщение Владимир » 31 окт 2015, 08:21

Bruzon писал(а):

Скажи, дружище, а ты сможешь поправить ИИ игры так, чтобы он адекватно играл?
...
Или это очень сложно?

Это фантастически сложно (по сравнению с расположением сценариев в кампании).
Вернуться к началу

offlineBruzon  
Новичок
Новичок
 
Сообщения: 24
Зарегистрирован: 30 окт 2015, 22:24
Пол: Не указан
Поблагодарили: 4 раз.

Re: Кампания во Free Heroes II

Сообщение Bruzon » 31 окт 2015, 09:48

Ясно. Ну тогда остается либо надеяться на чудо, или просто смириться.
Вернуться к началу

offlineАватара пользователя
t800  
Ветеран
Ветеран
 
Сообщения: 982
Зарегистрирован: 22 июл 2015, 11:36
Пол: Не указан
Награды: 4
Наградной знак (1) Деревянный Щит (1) Золотой Меч (1) Серебряные Сапоги (1)
Поблагодарили: 191 раз.

Re: Кампания во Free Heroes II

Сообщение t800 » 31 окт 2015, 10:22

Bruzon писал(а):

Товарищ, друг!
Ты ковыряешь Free Heroes II и делаешь кампанию? Благодарность тебе огромная!
Я уже давно жду, что хоть кто-нибудь займется этой игрой. Уже год играю в нее на смартфоне, все нравится, но ИИ просто ужасен! Автор не обновляет игру, видать, забросил. И это очень печально. Есть один лучик надежды - это ты! Скажи, дружище, а ты сможешь поправить ИИ игры так, чтобы он адекватно играл? Нормально воевал, создавал армии, передвигался по карте и соблюдал баланс, составлял реальную угрозу игроку? Или это очень сложно?
Просто весь фан от игры пропадает, когда выставляешь сложность 160% и ИИ сливает тебе вчистую при любом раскладе! Его действия абсолютно непонятны, в этом беда.
Андрей Афлетдинов, разработчик игры молчит, никому ничего не отвечает. И это плохо. Написал хотя бы, что забросил проект.
Последнее обновление было месяцев 5 назад, я был удивлен этому. Но, к сожалению, оно ничего кардинально не поменяло. А только ухудшило. После него перестала убавляться громкость игры кнопкой смартфона.
А еще в игре не сохраняются настройки скорости перемещения по карте, скорость прокрутки карты и громкость музыки. Если это поправишь - вообще будет супер!
В общем, всячески желаю тебе успехов в этом нелегком деле!
Я уже потерял всякую надежду, но тут нашел вот этот форум...
Не пропадай, товарищ!


Я не пропадаю. Просто у меня сейчас контрольные за четверть. А с 3-го ноября у меня каникулярные дни, и я доделаю рейнтинги для кампаний. И тогда я попробую заняться ИИ :smile21:

Bruzon писал(а):

Ясно. Ну тогда остается либо надеяться на чудо, или просто смириться.


Мне скажите. что там не в порядке с ИИ и я попробую испраавить.
Последний раз редактировалось Владимир 31 окт 2015, 10:48, всего редактировалось 2 раз(а).
Причина: Не злоупотребляйте мультипостами
Вернуться к началу

offlineАватара пользователя
t800  
Ветеран
Ветеран
 
Сообщения: 982
Зарегистрирован: 22 июл 2015, 11:36
Пол: Не указан
Награды: 4
Наградной знак (1) Деревянный Щит (1) Золотой Меч (1) Серебряные Сапоги (1)
Поблагодарили: 191 раз.

Re: Кампания во Free Heroes II

Сообщение t800 » 31 окт 2015, 10:39

Я сейчас посмотрел ИИ он очень простой наверное потому компьютер и играет так глупо.

ai_kingdom.cpp

Код: Выделить всё
/********************************************************************************
* Copyright (C) 2010 by Andrey Afletdinov <fheroes2@gmail.com> *
* All rights reserved. *
* *
* Part of the Free Heroes2 Engine: *
* http://sourceforge.net/projects/fheroes2 *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* - Redistributions may not be sold, nor may they be used in a *
* commercial product or activity. *
* - Redistributions of source code and/or in binary form must reproduce *
* the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials *
* provided with the distribution. *
* *
* THIS SOFTWARE IS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, *
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE *
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, *
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*******************************************************************************/
#include <functional>
#include <algorithm>
#include "game.h"
#include "cursor.h"
#include "engine.h"
#include "game_interface.h"
#include "interface_gamearea.h"
#include "heroes.h"
#include "castle.h"
#include "world.h"
#include "settings.h"
#include "kingdom.h"
#include "agg.h"
#include "ai.h"
#include "ai_simple.h"
void AICastleTurn(Castle*);
void AIHeroesTurn(Heroes*);
void AIHeroesEnd(Heroes*);
void AIHeroesCaptureNearestTown(Heroes*);
void AIHeroesSetHunterWithTarget(Heroes*, s32);
AIKingdoms & AIKingdoms::Get(void)
{
static AIKingdoms ai_kingdoms;
return ai_kingdoms;
}
AIKingdom & AIKingdoms::Get(int color)
{
return AIKingdoms::Get().at(Color::GetIndex(color));
}
void AIKingdoms::Reset(void)
{
AIKingdoms & ai = AIKingdoms::Get();
std::for_each(ai.begin(), ai.end(), std::mem_fun_ref(&AIKingdom::Reset));
}
void AIKingdom::Reset(void)
{
capital = NULL;
scans.clear();
}
void IndexObjectMap::DumpObjects(const IndexDistance & id)
{
IndexObjectMap::const_iterator it = find(id.first);
if(it != end())
DEBUG(DBG_AI, DBG_TRACE, MP2::StringObject((*it).second) \
<< ", maps index: " << id.first << ", dist: " << id.second);
}
void WorldStoreObjects(int color, IndexObjectMap & store)
{
for(s32 it = 0; it < world.w() * world.h(); ++it)
{
const Maps::Tiles & tile = world.GetTiles(it);
if(tile.isFog(color)) continue;
if(MP2::isGroundObject(tile.GetObject()) ||
MP2::isWaterObject(tile.GetObject()) || MP2::OBJ_HEROES == tile.GetObject())
{
// if quantity object is empty
if(MP2::isQuantityObject(tile.GetObject()) &&
! MP2::isPickupObject(tile.GetObject()) && ! tile.QuantityIsValid()) continue;
// skip captured obj
if(MP2::isCaptureObject(tile.GetObject()) &&
Players::isFriends(color, tile.QuantityColor())) continue;
// skip for meeting heroes
if(MP2::OBJ_HEROES == tile.GetObject())
{
const Heroes* hero = tile.GetHeroes();
if(hero && color == hero->GetColor()) continue;
}
// check: is visited objects
switch(tile.GetObject())
{
case MP2::OBJ_MAGELLANMAPS:
case MP2::OBJ_OBSERVATIONTOWER:
if(world.GetKingdom(color).isVisited(tile)) continue;
break;
default: break;
}
store[it] = tile.GetObject();
}
}
}
void AI::KingdomTurn(Kingdom & kingdom)
{
KingdomHeroes & heroes = kingdom.GetHeroes();
KingdomCastles & castles = kingdom.GetCastles();
const int color = kingdom.GetColor();
if(kingdom.isLoss() || color == Color::NONE)
{
kingdom.LossPostActions();
return;
}
DEBUG(DBG_AI, DBG_INFO, Color::String(kingdom.GetColor()) << " funds: " << kingdom.GetFunds().String());
if(! Settings::Get().MusicMIDI()) AGG::PlayMusic(MUS::COMPUTER);
Interface::StatusWindow & status = Interface::Basic::Get().GetStatusWindow();
AIKingdom & ai = AIKingdoms::Get(color);
// turn indicator
status.RedrawTurnProgress(0);
// scan map
ai.scans.clear();
WorldStoreObjects(color, ai.scans);
DEBUG(DBG_AI, DBG_INFO, Color::String(color) << ", size cache objects: " << ai.scans.size());
// set capital
if(NULL == ai.capital && castles.size())
{
KingdomCastles::iterator it = std::find_if(castles.begin(), castles.end(), Castle::PredicateIsCastle);
if(castles.end() != it)
{
if(*it)
{
ai.capital = *it;
ai.capital->SetModes(Castle::CAPITAL);
}
}
else
// first town
{
ai.capital = castles.front();
ai.capital->SetModes(Castle::CAPITAL);
}
}
// turn indicator
status.RedrawTurnProgress(1);
// castles AI turn
std::for_each(castles.begin(), castles.end(), AICastleTurn);
// need capture town?
if(castles.empty())
std::for_each(heroes.begin(), heroes.end(), AIHeroesCaptureNearestTown);
// buy hero in capital
if(ai.capital && ai.capital->isCastle())
{
u32 modes = 0;
const u32 maxhero = Maps::XLARGE > world.w() ? (Maps::LARGE > world.w() ? 3 : 2) : 4;
if(heroes.empty())
modes = AI::HEROES_HUNTER|AI::HEROES_SCOUTER;
else
if(heroes.size() < maxhero ||
0 == std::count_if(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_SCOUTER)))
modes = AI::HEROES_SCOUTER;
if(modes &&
heroes.size() < Kingdom::GetMaxHeroes())
{
Recruits & rec = kingdom.GetRecruits();
Heroes* hero = ai.capital->GetHeroes().Guest();
if(!hero)
{
if(rec.GetHero1() && rec.GetHero2())
hero = ai.capital->RecruitHero(rec.GetHero1()->GetLevel() >= rec.GetHero2()->GetLevel() ? rec.GetHero1() : rec.GetHero2());
else
if(rec.GetHero1())
hero = ai.capital->RecruitHero(rec.GetHero1());
else
if(rec.GetHero2())
hero = ai.capital->RecruitHero(rec.GetHero2());
if(hero)
hero->SetModes(modes);
}
}
}
// set hunters
if(ai.capital)
{
const size_t hunters =
std::count_if(heroes.begin(), heroes.end(),
std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_HUNTER));
// every time
if(0 == hunters &&
heroes.size())
{
KingdomHeroes::iterator it = std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes), Heroes::PATROL)));
if(it != heroes.end() &&
! ai.capital->GetHeroes().Guest())
AIHeroesSetHunterWithTarget((*it), ai.capital->GetIndex());
}
else
// each month
if(world.BeginMonth() && 1 < world.CountDay())
{
KingdomHeroes::iterator it =
std::find_if(heroes.begin(), heroes.end(),
std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_HUNTER));
if(it != heroes.end() &&
! ai.capital->GetHeroes().Guest())
AIHeroesSetHunterWithTarget(*it, ai.capital->GetIndex());
}
}
// update roles
{
std::for_each(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::ResetModes), AI::HEROES_STUPID|AI::HEROES_WAITING));
// init roles
if(heroes.end() != std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_SCOUTER|AI::HEROES_HUNTER))))
{
KingdomHeroes::iterator ith, first = heroes.end();
while(heroes.end() != (ith = std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes),
// also skip patrol
AI::HEROES_HUNTER|AI::HEROES_SCOUTER|Heroes::PATROL)))))
{
if(first == heroes.end())
{
first = ith;
if(*ith) (*ith)->SetModes(AI::HEROES_HUNTER|AI::HEROES_SCOUTER);
}
else
if(*ith) (*ith)->SetModes(AI::HEROES_SCOUTER);
}
}
}
// turn indicator
status.RedrawTurnProgress(2);
// heroes turns
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesTurn));
//std::for_each(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::ResetModes), AI::HEROES_STUPID|AI::HEROES_WAITING));
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesTurn));
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesEnd));
// turn indicator
status.RedrawTurnProgress(9);
DEBUG(DBG_AI, DBG_INFO, Color::String(color) << " moved");
}


ai_battle.cpp

Код: Выделить всё
/********************************************************************************
* Copyright (C) 2010 by Andrey Afletdinov <fheroes2@gmail.com> *
* All rights reserved. *
* *
* Part of the Free Heroes2 Engine: *
* http://sourceforge.net/projects/fheroes2 *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* - Redistributions may not be sold, nor may they be used in a *
* commercial product or activity. *
* - Redistributions of source code and/or in binary form must reproduce *
* the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials *
* provided with the distribution. *
* *
* THIS SOFTWARE IS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, *
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE *
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, *
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*******************************************************************************/
#include <algorithm>
#include <functional>
#include "settings.h"
#include "heroes.h"
#include "castle.h"
#include "speed.h"
#include "battle_arena.h"
#include "battle_cell.h"
#include "battle_troop.h"
#include "battle_interface.h"
#include "battle_command.h"
#include "ai_simple.h"
namespace Battle
{
bool   AIApplySpell(const Spell &, const Unit*, const HeroBase &, Actions &);
s32   AIShortDistance(s32, const Indexes &);
s32   AIAttackPosition(Arena &, const Unit &, const Indexes &);
s32   AIMaxQualityPosition(const Indexes &);
const Unit* AIGetEnemyAbroadMaxQuality(s32, int color);
const Unit* AIGetEnemyAbroadMaxQuality(const Unit &);
s32   AIAreaSpellDst(const HeroBase &);
bool MaxDstCount(const std::pair<s32, u32> & p1, const std::pair<s32, u32> & p2) { return p1.second < p2.second; }
}
s32 Battle::AIAreaSpellDst(const HeroBase & hero)
{
std::map<s32, u32> dstcount;
Arena* arena = GetArena();
Units enemies(arena->GetForce(hero.GetColor(), true), true);
for(Units::const_iterator
it1 = enemies.begin(); it1 != enemies.end(); ++it1)
{
const Indexes around = Board::GetAroundIndexes(**it1);
for(Indexes::const_iterator
it2 = around.begin(); it2 != around.end(); ++it2)
dstcount[*it2] += 1;
}
// find max
std::map<s32, u32>::const_iterator max = std::max_element(dstcount.begin(), dstcount.end(), MaxDstCount);
return max != dstcount.end() ? (*max).first : -1;
}
s32 Battle::AIMaxQualityPosition(const Indexes & positions)
{
s32 res = -1;
for(Indexes::const_iterator
it = positions.begin(); it != positions.end(); ++it)
if(Board::isValidIndex(*it))
{
if(res < 0)
res = *it;
else
if(Board::GetCell(res)->GetQuality() < Board::GetCell(*it)->GetQuality())
res = *it;
}
return res;
}
const Battle::Unit* Battle::AIGetEnemyAbroadMaxQuality(s32 position, int color)
{
const Unit* res = NULL;
s32 quality = 0;
const Indexes around = Board::GetAroundIndexes(position);
for(Indexes::const_iterator
it = around.begin(); it != around.end(); ++it)
{
const Cell* cell = Board::GetCell(*it);
const Unit* enemy = cell ? cell->GetUnit() : NULL;
if(enemy && enemy->GetColor() != color &&
quality < cell->GetQuality())
{
res = enemy;
quality = cell->GetQuality();
}
}
return res;
}
const Battle::Unit* Battle::AIGetEnemyAbroadMaxQuality(const Unit & b)
{
const Unit* res1 = AIGetEnemyAbroadMaxQuality(b.GetHeadIndex(), b.GetColor());
if(b.isWide())
{
const Unit* res2 = AIGetEnemyAbroadMaxQuality(b.GetTailIndex(), b.GetColor());
if(!res1) return res2;
else
if(!res2) return res1;
else
{
const s32 & quality1 = res1->GetPosition().GetHead()->GetQuality();
const s32 & quality2 = res2->GetPosition().GetHead()->GetQuality();
return quality1 > quality2 ? res1 : res2;
}
}
return res1;
}
s32 Battle::AIShortDistance(s32 from, const Indexes & indexes)
{
u32 len = MAXU16;
s32 res = -1;
for(Indexes::const_iterator
it = indexes.begin(); it != indexes.end(); ++it)
{
const u32 length = Board::GetDistance(from, *it);
if(len > length)
{
len = length;
res = *it;
}
}
DEBUG(DBG_BATTLE, DBG_TRACE, res);
return res;
}
s32 Battle::AIAttackPosition(Arena & arena, const Unit & b, const Indexes & positions)
{
s32 res = -1;
if(b.isMultiCellAttack())
{
res = AIMaxQualityPosition(positions);
}
else
if(b.isDoubleCellAttack())
{
Indexes results;
results.reserve(12);
const Units enemies(arena.GetForce(b.GetColor(), true), true);
if(1 < enemies.size())
{
for(Units::const_iterator
it1 = enemies.begin(); it1 != enemies.end(); ++it1)
{
const Indexes around = Board::GetAroundIndexes(**it1);
for(Indexes::const_iterator
it2 = around.begin(); it2 != around.end(); ++it2)
{
const Unit* unit = Board::GetCell(*it2)->GetUnit();
if(unit && enemies.end() != std::find(enemies.begin(), enemies.end(), unit))
results.push_back(*it2);
}
}
if(results.size())
{
// find passable results
Indexes passable = Arena::GetBoard()->GetPassableQualityPositions(b);
Indexes::iterator it2 = results.begin();
for(Indexes::const_iterator
it = results.begin(); it != results.end(); ++it)
if(passable.end() != std::find(passable.begin(), passable.end(), *it))
*it2++ = *it;
if(it2 != results.end())
results.resize(std::distance(results.begin(), it2));
// get max quality
if(results.size())
res = AIMaxQualityPosition(results);
}
}
}
return 0 > res ? AIShortDistance(b.GetHeadIndex(), positions) : res;
}
using namespace Battle;
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
{
s32 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 u32 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 s32 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 s32 head = dst.GetHead()->GetIndex();
const s32 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()));
}
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 };
s32 dst = AIAreaSpellDst(*hero);
if(Board::isValidIndex(dst))
for(u32 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;
}
bool Battle::AIApplySpell(const Spell & spell, const Unit* b, const HeroBase & hero, Actions & a)
{
u32 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;
}


ai_heroes.cpp

Код: Выделить всё
/********************************************************************************
* Copyright (C) 2010 by Andrey Afletdinov <fheroes2@gmail.com> *
* All rights reserved. *
* *
* Part of the Free Heroes2 Engine: *
* http://sourceforge.net/projects/fheroes2 *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* - Redistributions may not be sold, nor may they be used in a *
* commercial product or activity. *
* - Redistributions of source code and/or in binary form must reproduce *
* the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials *
* provided with the distribution. *
* *
* THIS SOFTWARE IS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, *
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE *
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, *
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*******************************************************************************/
#include <functional>
#include <algorithm>
#include "settings.h"
#include "kingdom.h"
#include "castle.h"
#include "army.h"
#include "battle.h"
#include "luck.h"
#include "morale.h"
#include "race.h"
#include "difficulty.h"
#include "world.h"
#include "payment.h"
#include "heroes.h"
#include "cursor.h"
#include "game_interface.h"
#include "interface_gamearea.h"
#include "maps_tiles.h"
#include "ai_simple.h"
#define HERO_MAX_SHEDULED_TASK 7
AIHeroes & AIHeroes::Get(void)
{
static AIHeroes ai_heroes;
return ai_heroes;
}
AIHero & AIHeroes::Get(const Heroes & ht)
{
return AIHeroes::Get().at(ht.GetID());
}
void AIHeroes::Reset(void)
{
AIHeroes & ai = AIHeroes::Get();
std::for_each(ai.begin(), ai.end(), std::mem_fun_ref(&AIHero::Reset));
}
void AIHero::Reset(void)
{
primary_target = -1;
sheduled_visit.clear();
fix_loop = 0;
}
bool AI::HeroesSkipFog(void)
{
return false;
}
void AI::HeroesActionComplete(Heroes &, s32)
{
}
std::string AI::HeroesString(const Heroes & hero)
{
std::ostringstream os;
AIHero & ai_hero = AIHeroes::Get(hero);
Queue & task = ai_hero.sheduled_visit;
os << "flags : " <<
(hero.Modes(AI::HEROES_SCOUTER) ? "SCOUTER," : "") <<
(hero.Modes(AI::HEROES_HUNTER) ? "HUNTER," : "") <<
(hero.Modes(AI::HEROES_WAITING) ? "WAITING," : "") <<
(hero.Modes(AI::HEROES_STUPID) ? "STUPID" : "") << std::endl;
os << "ai primary target: " << ai_hero.primary_target << std::endl <<
"ai sheduled visit: ";
for(Queue::const_iterator
it = task.begin(); it != task.end(); ++it)
os << *it << "(" << MP2::StringObject(world.GetTiles(*it).GetObject()) << "), ";
os << std::endl;
return os.str();
}
void AI::HeroesPostLoad(Heroes & hero)
{
hero.SetModes(AI::HEROES_HUNTER);
}
void AI::HeroesLevelUp(Heroes & hero)
{
if(4 < hero.GetLevel() && !hero.Modes(AI::HEROES_HUNTER))
hero.SetModes(AI::HEROES_HUNTER);
if(9 < hero.GetLevel() && hero.Modes(AI::HEROES_SCOUTER))
hero.ResetModes(AI::HEROES_SCOUTER);
}
void AI::HeroesPreBattle(HeroBase & hero)
{
Castle* castle = world.GetCastle(hero.GetCenter());
if(castle && hero.GetType() != HeroBase::CAPTAIN)
hero.GetArmy().JoinTroops(castle->GetArmy());
}
void AI::HeroesAfterBattle(HeroBase & hero)
{
}
void AI::HeroesClearTask(const Heroes & hero)
{
AIHeroes::Get(hero).ClearTasks();
}
bool AIHeroesValidObject2(const Heroes* hero, s32 index)
{
const Heroes & hero2 = *hero;
return AI::HeroesValidObject(hero2, index);
}
// get priority object for AI independent of distance (1 day)
bool AIHeroesPriorityObject(const Heroes & hero, s32 index)
{
Maps::Tiles & tile = world.GetTiles(index);
if(MP2::OBJ_CASTLE == tile.GetObject())
{
const Castle* castle = world.GetCastle(Maps::GetPoint(index));
if(castle)
{
if(hero.GetColor() == castle->GetColor())
{
// maybe need join army
return hero.Modes(AI::HEROES_HUNTER) &&
castle->GetArmy().isValid() &&
! hero.isVisited(world.GetTiles(castle->GetIndex()));
}
else
if(! hero.isFriends(castle->GetColor()))
return AI::HeroesValidObject(hero, index);
}
}
else
if(MP2::OBJ_HEROES == tile.GetObject())
{
// kill enemy hero
const Heroes* hero2 = tile.GetHeroes();
return hero2 &&
! hero.isFriends(hero2->GetColor()) &&
AI::HeroesValidObject(hero, index);
}
switch(tile.GetObject())
{
case MP2::OBJ_MONSTER:
case MP2::OBJ_SAWMILL:
case MP2::OBJ_MINES:
case MP2::OBJ_ALCHEMYLAB:
case MP2::OBJ_ARTIFACT:
case MP2::OBJ_RESOURCE:
case MP2::OBJ_CAMPFIRE:
case MP2::OBJ_TREASURECHEST:
return AI::HeroesValidObject(hero, index);
default: break;
}
return false;
}
s32 FindUncharteredTerritory(Heroes & hero, u32 scoute)
{
Maps::Indexes v = Maps::GetAroundIndexes(hero.GetIndex(), scoute, true);
Maps::Indexes res;
v.resize(std::distance(v.begin(),
std::remove_if(v.begin(), v.end(), std::ptr_fun(&Maps::TileIsUnderProtection))));
#if defined(ANDROID)
const MapsIndexes::const_reverse_iterator crend = v.rend();
for(MapsIndexes::const_reverse_iterator
it = v.rbegin(); it != crend && res.size() < 4; ++it)
#else
for(MapsIndexes::const_reverse_iterator
it = v.rbegin(); it != v.rend() && res.size() < 4; ++it)
#endif
{
// find fogs
if(world.GetTiles(*it).isFog(hero.GetColor()) &&
world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) &&
hero.GetPath().Calculate(*it))
res.push_back(*it);
}
const s32 result = res.size() ? *Rand::Get(res) : -1;
if(0 <= result)
{
DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) <<
", hero: " << hero.GetName() << ", added task: " << result);
}
return result;
}
s32 GetRandomHeroesPosition(Heroes & hero, u32 scoute)
{
Maps::Indexes v = Maps::GetAroundIndexes(hero.GetIndex(), scoute, true);
Maps::Indexes res;
v.resize(std::distance(v.begin(),
std::remove_if(v.begin(), v.end(), std::ptr_fun(&Maps::TileIsUnderProtection))));
#if defined(ANDROID)
const MapsIndexes::const_reverse_iterator crend = v.rend();
for(MapsIndexes::const_reverse_iterator
it = v.rbegin(); it != crend && res.size() < 4; ++it)
#else
for(MapsIndexes::const_reverse_iterator
it = v.rbegin(); it != v.rend() && res.size() < 4; ++it)
#endif
{
if(world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) &&
hero.GetPath().Calculate(*it))
res.push_back(*it);
}
const s32 result = res.size() ? *Rand::Get(res) : -1;
if(0 <= result)
{
DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) <<
", hero: " << hero.GetName() << ", added task: " << result);
}
return result;
}
void AIHeroesAddedRescueTask(Heroes & hero)
{
AIHero & ai_hero = AIHeroes::Get(hero);
Queue & task = ai_hero.sheduled_visit;
DEBUG(DBG_AI, DBG_TRACE, hero.GetName());
u32 scoute = hero.GetScoute();
switch(Settings::Get().GameDifficulty())
{
case Difficulty::NORMAL: scoute += 2; break;
case Difficulty::HARD: scoute += 3; break;
case Difficulty::EXPERT: scoute += 4; break;
case Difficulty::IMPOSSIBLE:scoute += 6; break;
default: break;
}
// find unchartered territory
s32 index = FindUncharteredTerritory(hero, scoute);
const Maps::Tiles & tile = world.GetTiles(hero.GetIndex());
if(index < 0)
{
// check teleports
if(MP2::OBJ_STONELIGHTS == tile.GetObject(false) ||
MP2::OBJ_WHIRLPOOL == tile.GetObject(false))
{
AI::HeroesAction(hero, hero.GetIndex());
}
else
{
// random
index = GetRandomHeroesPosition(hero, scoute);
}
}
if(0 <= index) task.push_back(index);
}
void AIHeroesAddedTask(Heroes & hero)
{
AIHero & ai_hero = AIHeroes::Get(hero);
AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor());
Queue & task = ai_hero.sheduled_visit;
IndexObjectMap & ai_objects = ai_kingdom.scans;
// load minimal distance tasks
std::vector<IndexDistance> objs;
objs.reserve(ai_objects.size());
for(std::map<s32, int>::const_iterator
it = ai_objects.begin(); it != ai_objects.end(); ++it)
{
const Maps::Tiles & tile = world.GetTiles((*it).first);
if(hero.isShipMaster())
{
if(MP2::OBJ_COAST != tile.GetObject() &&
! tile.isWater()) continue;
// check previous positions
if(MP2::OBJ_COAST == (*it).second &&
hero.isVisited(world.GetTiles((*it).first))) continue;
}
else
{
if(tile.isWater() && MP2::OBJ_BOAT != tile.GetObject()) continue;
}
objs.push_back(IndexDistance((*it).first,
Maps::GetApproximateDistance(hero.GetIndex(), (*it).first)));
}
DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) <<
", hero: " << hero.GetName() << ", task prepare: " << objs.size());
std::sort(objs.begin(), objs.end(), IndexDistance::Shortest);
for(std::vector<IndexDistance>::const_iterator
it = objs.begin(); it != objs.end(); ++it)
{
if(task.size() >= HERO_MAX_SHEDULED_TASK) break;
const bool validobj = AI::HeroesValidObject(hero, (*it).first);
if(validobj &&
hero.GetPath().Calculate((*it).first))
{
DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) <<
", hero: " << hero.GetName() << ", added tasks: " <<
MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first <<
", distance: " << (*it).second);
task.push_back((*it).first);
ai_objects.erase((*it).first);
}
else
{
DEBUG(DBG_AI, DBG_TRACE, Color::String(hero.GetColor()) <<
", hero: " << hero.GetName() << (!validobj ? ", invalid: " : ", impossible: ") <<
MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first <<
", distance: " << (*it).second);
}
}
if(task.empty())
AIHeroesAddedRescueTask(hero);
}
void AI::HeroesActionNewPosition(Heroes & hero)
{
AIHero & ai_hero = AIHeroes::Get(hero);
//AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor());
Queue & task = ai_hero.sheduled_visit;
const u8 objs[] = { MP2::OBJ_ARTIFACT, MP2::OBJ_RESOURCE, MP2::OBJ_CAMPFIRE, MP2::OBJ_TREASURECHEST, 0 };
Maps::Indexes pickups = Maps::ScanAroundObjects(hero.GetIndex(), objs);
if(pickups.size() && hero.GetPath().isValid() &&
pickups.end() == std::find(pickups.begin(), pickups.end(), hero.GetPath().GetDestinationIndex()))
hero.GetPath().Reset();
for(MapsIndexes::const_iterator
it = pickups.begin(); it != pickups.end(); ++it)
if(*it != hero.GetPath().GetDestinationIndex())
task.push_front(*it);
}
bool AI::HeroesGetTask(Heroes & hero)
{
std::vector<s32> results;
results.reserve(5);
const Settings & conf = Settings::Get();
AIHero & ai_hero = AIHeroes::Get(hero);
AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor());
Queue & task = ai_hero.sheduled_visit;
IndexObjectMap & ai_objects = ai_kingdom.scans;
const u8 objs1[] = { MP2::OBJ_ARTIFACT, MP2::OBJ_RESOURCE, MP2::OBJ_CAMPFIRE, MP2::OBJ_TREASURECHEST, 0 };
const u8 objs2[] = { MP2::OBJ_SAWMILL, MP2::OBJ_MINES, MP2::OBJ_ALCHEMYLAB, 0 };
const u8 objs3[] = { MP2::OBJ_CASTLE, MP2::OBJ_HEROES, MP2::OBJ_MONSTER, 0 };
// rescan path
hero.RescanPath();
Castle* castle = hero.inCastle();
// if hero in castle
if(castle)
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", in castle");
castle->RecruitAllMonster();
hero.GetArmy().UpgradeTroops(*castle);
// recruit army
if(hero.Modes(AI::HEROES_HUNTER))
hero.GetArmy().JoinStrongestFromArmy(castle->GetArmy());
else
if(hero.Modes(AI::HEROES_SCOUTER))
hero.GetArmy().KeepOnlyWeakestTroops(castle->GetArmy());
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", " << hero.GetArmy().String());
}
// patrol task
if(hero.Modes(Heroes::PATROL))
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", is patrol mode");
// goto patrol center
if(hero.GetCenterPatrol() != hero.GetCenter() &&
hero.GetPath().Calculate(Maps::GetIndexFromAbsPoint(hero.GetCenterPatrol())))
return true;
// scan enemy hero
if(hero.GetSquarePatrol())
{
const Maps::Indexes & results = Maps::ScanAroundObject(Maps::GetIndexFromAbsPoint(hero.GetCenterPatrol()),
hero.GetSquarePatrol(), MP2::OBJ_HEROES);
for(MapsIndexes::const_iterator
it = results.begin(); it != results.end(); ++it)
{
const Heroes* enemy = world.GetTiles(*it).GetHeroes();
if(enemy && ! enemy->isFriends(hero.GetColor()))
{
if(hero.GetPath().Calculate(enemy->GetIndex()))
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", find enemy");
return true;
}
}
}
}
// can pickup objects
if(conf.ExtHeroPatrolAllowPickup())
{
const Maps::Indexes & results = Maps::ScanAroundObjects(hero.GetIndex(),
hero.GetSquarePatrol(), objs1);
for(MapsIndexes::const_iterator
it = results.begin(); it != results.end(); ++it)
if(AI::HeroesValidObject(hero, *it) &&
hero.GetPath().Calculate(*it))
{
ai_objects.erase(*it);
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ": find object: " <<
MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")");
return true;
}
}
// random move
/*
// disable move: https://sourceforge.net/tracker/?func=detail&aid=3157397&group_id=96859&atid=616180
{
Maps::ScanAroundObject(hero.GetIndex(), hero.GetSquarePatrol(), MP2::OBJ_ZERO);
if(results.size())
{
std::random_shuffle(results.begin(), results.end());
std::vector<s32>::const_iterator it = results.begin();
for(; it != results.end(); ++it)
if(world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) &&
hero.GetPath().Calculate(*it))
{
DEBUG(DBG_AI, Color::String(hero.GetColor()) <<
", Patrol " << hero.GetName() << ": move: " << *it);
return;
}
}
}
*/
hero.SetModes(AI::HEROES_STUPID);
return false;
}
if(ai_hero.fix_loop > 3)
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ": loop");
hero.SetModes(hero.Modes(AI::HEROES_WAITING) ? AI::HEROES_STUPID : AI::HEROES_WAITING);
return false;
}
// primary target
if(Maps::isValidAbsIndex(ai_hero.primary_target))
{
if(hero.GetIndex() == ai_hero.primary_target)
{
ai_hero.primary_target = -1;
hero.GetPath().Reset();
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", reset path");
}
else
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", primary target: " <<
ai_hero.primary_target << ", " << MP2::StringObject(world.GetTiles(ai_hero.primary_target).GetObject()));
const Castle* castle = NULL;
if(NULL != (castle = world.GetCastle(Maps::GetPoint(ai_hero.primary_target))) &&
NULL != castle->GetHeroes().Guest() && castle->isFriends(hero.GetColor()))
{
hero.SetModes(AI::HEROES_WAITING);
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", castle busy..");
}
// make path
if(ai_hero.primary_target != hero.GetPath().GetDestinationIndex() &&
!hero.GetPath().Calculate(ai_hero.primary_target))
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", path unknown, primary target reset");
ai_hero.primary_target = -1;
}
}
if(hero.GetPath().isValid()) return true;
}
// scan heroes and castle
const Maps::Indexes & enemies = Maps::ScanAroundObjects(hero.GetIndex(), hero.GetScoute(), objs3);
for(MapsIndexes::const_iterator
it = enemies.begin(); it != enemies.end(); ++it)
if(AIHeroesPriorityObject(hero, *it) &&
hero.GetPath().Calculate(*it))
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", set primary target: " <<
MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")");
ai_hero.primary_target = *it;
return true;
}
// check destination
if(hero.GetPath().isValid())
{
if(! AI::HeroesValidObject(hero, hero.GetPath().GetDestinationIndex()))
hero.GetPath().Reset();
else
if(hero.GetPath().size() < 5)
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", continue short");
ai_hero.fix_loop++;
return true;
}
}
// scan 2x2 pickup objects
Maps::Indexes pickups = Maps::ScanAroundObjects(hero.GetIndex(), 2, objs1);
// scan 3x3 capture objects
const Maps::Indexes & captures = Maps::ScanAroundObjects(hero.GetIndex(), 3, objs2);
if(captures.size()) pickups.insert(pickups.end(), captures.begin(), captures.end());
if(pickups.size())
{
hero.GetPath().Reset();
for(MapsIndexes::const_iterator
it = pickups.begin(); it != pickups.end(); ++it)
if(AI::HeroesValidObject(hero, *it))
{
task.push_front(*it);
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", find object: " <<
MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")");
}
}
if(hero.GetPath().isValid())
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", continue");
ai_hero.fix_loop++;
return true;
}
if(task.empty())
{
// get task from kingdom
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", empty task");
AIHeroesAddedTask(hero);
}
else
// remove invalid task
task.remove_if(std::not1(std::bind1st(std::ptr_fun(&AIHeroesValidObject2), &hero)));
// random shuffle
if(1 < task.size() && Rand::Get(1))
{
Queue::iterator it1, it2;
it2 = it1 = task.begin();
++it2;
std::swap(*it1, *it2);
}
// find passable index
while(task.size())
{
const s32 & index = task.front();
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", look for: " << MP2::StringObject(world.GetTiles(index).GetObject()) << "(" << index << ")");
if(hero.GetPath().Calculate(index)) break;
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: unable get object: " << index << ", remove task...");
task.pop_front();
}
// success
if(task.size())
{
const s32 & index = task.front();
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " go to: " << index);
ai_objects.erase(index);
task.pop_front();
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", route: " << hero.GetPath().String());
return true;
}
else
if(hero.Modes(AI::HEROES_WAITING))
{
hero.GetPath().Reset();
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: unknown task., help my please..");
hero.ResetModes(AI::HEROES_WAITING);
hero.SetModes(AI::HEROES_STUPID);
}
else
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: waiting...");
hero.SetModes(AI::HEROES_WAITING);
}
return false;
}
void AIHeroesTurn(Heroes* hero)
{
if(hero) AI::HeroesTurn(*hero);
}
void AI::HeroesTurn(Heroes & hero)
{
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", start: " <<
(hero.Modes(Heroes::SHIPMASTER) ? "SHIPMASTER," : "") <<
(hero.Modes(AI::HEROES_SCOUTER) ? "SCOUTER," : "") <<
(hero.Modes(AI::HEROES_HUNTER) ? "HUNTER," : "") <<
(hero.Modes(Heroes::PATROL) ? "PATROL," : "") <<
(hero.Modes(AI::HEROES_WAITING) ? "WAITING," : "") <<
(hero.Modes(AI::HEROES_STUPID) ? "STUPID" : ""));
Interface::StatusWindow & status = Interface::Basic::Get().GetStatusWindow();
while(hero.MayStillMove() &&
!hero.Modes(AI::HEROES_WAITING|AI::HEROES_STUPID))
{
// turn indicator
status.RedrawTurnProgress(3);
// get task for heroes
AI::HeroesGetTask(hero);
// turn indicator
status.RedrawTurnProgress(5);
// heroes AI turn
AI::HeroesMove(hero);
// turn indicator
status.RedrawTurnProgress(7);
}
DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", end");
}
bool AIHeroesScheduledVisit(const Kingdom & kingdom, s32 index)
{
for(KingdomHeroes::const_iterator
it = kingdom.GetHeroes().begin(); it != kingdom.GetHeroes().end(); ++it)
{
AIHero & ai_hero = AIHeroes::Get(**it);
Queue & task = ai_hero.sheduled_visit;
if(task.isPresent(index)) return true;
}
return false;
}
bool IsPriorityAndNotVisitAndNotPresent(const std::pair<s32, int> & indexObj, const Heroes* hero)
{
AIHero & ai_hero = AIHeroes::Get(*hero);
Queue & task = ai_hero.sheduled_visit;
return AIHeroesPriorityObject(*hero, indexObj.first) &&
! AIHeroesScheduledVisit(hero->GetKingdom(), indexObj.first) &&
! task.isPresent(indexObj.first);
}
void AIHeroesEnd(Heroes* hero)
{
if(hero)
{
AIHero & ai_hero = AIHeroes::Get(*hero);
AIKingdom & ai_kingdom = AIKingdoms::Get(hero->GetColor());
Queue & task = ai_hero.sheduled_visit;
IndexObjectMap & ai_objects = ai_kingdom.scans;
if(hero->Modes(AI::HEROES_WAITING|AI::HEROES_STUPID))
{
ai_hero.Reset();
hero->ResetModes(AI::HEROES_WAITING|AI::HEROES_STUPID);
}
IndexObjectMap::iterator it;
while(true)
{
for(it = ai_objects.begin(); it != ai_objects.end(); ++it)
if(IsPriorityAndNotVisitAndNotPresent(*it, hero)) break;
if(ai_objects.end() == it) break;
DEBUG(DBG_AI, DBG_TRACE, hero->GetName() << ", added priority object: " <<
MP2::StringObject((*it).second) << ", index: " << (*it).first);
task.push_front((*it).first);
ai_objects.erase((*it).first);
}
}
}
void AIHeroesSetHunterWithTarget(Heroes* hero, s32 dst)
{
if(hero)
{
AIHero & ai_hero = AIHeroes::Get(*hero);
hero->SetModes(AI::HEROES_HUNTER);
if(0 > ai_hero.primary_target)
{
ai_hero.primary_target = dst;
}
}
}
void AIHeroesCaptureNearestTown(Heroes* hero)
{
if(hero)
{
AIHero & ai_hero = AIHeroes::Get(*hero);
if(0 > ai_hero.primary_target)
{
const Maps::Indexes & castles = Maps::GetObjectPositions(hero->GetIndex(), MP2::OBJ_CASTLE, true);
for(MapsIndexes::const_iterator
it = castles.begin(); it != castles.end(); ++it)
{
const Castle* castle = world.GetCastle(Maps::GetPoint(*it));
if(castle)
DEBUG(DBG_AI, DBG_TRACE, hero->GetName() << ", to castle: " << castle->GetName());
if(castle &&
Army::TroopsStrongerEnemyTroops(hero->GetArmy(), castle->GetArmy()))
{
ai_hero.primary_target = *it;
DEBUG(DBG_AI, DBG_INFO, Color::String(hero->GetColor()) <<
", Hero " << hero->GetName() << " set primary target: " << *it);
break;
}
}
}
}
}


ai_kingdom.cpp
Код: Выделить всё
/********************************************************************************
* Copyright (C) 2010 by Andrey Afletdinov <fheroes2@gmail.com> *
* All rights reserved. *
* *
* Part of the Free Heroes2 Engine: *
* http://sourceforge.net/projects/fheroes2 *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* - Redistributions may not be sold, nor may they be used in a *
* commercial product or activity. *
* - Redistributions of source code and/or in binary form must reproduce *
* the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials *
* provided with the distribution. *
* *
* THIS SOFTWARE IS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, *
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE *
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, *
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*******************************************************************************/
#include <functional>
#include <algorithm>
#include "game.h"
#include "cursor.h"
#include "engine.h"
#include "game_interface.h"
#include "interface_gamearea.h"
#include "heroes.h"
#include "castle.h"
#include "world.h"
#include "settings.h"
#include "kingdom.h"
#include "agg.h"
#include "ai.h"
#include "ai_simple.h"
void AICastleTurn(Castle*);
void AIHeroesTurn(Heroes*);
void AIHeroesEnd(Heroes*);
void AIHeroesCaptureNearestTown(Heroes*);
void AIHeroesSetHunterWithTarget(Heroes*, s32);
AIKingdoms & AIKingdoms::Get(void)
{
static AIKingdoms ai_kingdoms;
return ai_kingdoms;
}
AIKingdom & AIKingdoms::Get(int color)
{
return AIKingdoms::Get().at(Color::GetIndex(color));
}
void AIKingdoms::Reset(void)
{
AIKingdoms & ai = AIKingdoms::Get();
std::for_each(ai.begin(), ai.end(), std::mem_fun_ref(&AIKingdom::Reset));
}
void AIKingdom::Reset(void)
{
capital = NULL;
scans.clear();
}
void IndexObjectMap::DumpObjects(const IndexDistance & id)
{
IndexObjectMap::const_iterator it = find(id.first);
if(it != end())
DEBUG(DBG_AI, DBG_TRACE, MP2::StringObject((*it).second) \
<< ", maps index: " << id.first << ", dist: " << id.second);
}
void WorldStoreObjects(int color, IndexObjectMap & store)
{
for(s32 it = 0; it < world.w() * world.h(); ++it)
{
const Maps::Tiles & tile = world.GetTiles(it);
if(tile.isFog(color)) continue;
if(MP2::isGroundObject(tile.GetObject()) ||
MP2::isWaterObject(tile.GetObject()) || MP2::OBJ_HEROES == tile.GetObject())
{
// if quantity object is empty
if(MP2::isQuantityObject(tile.GetObject()) &&
! MP2::isPickupObject(tile.GetObject()) && ! tile.QuantityIsValid()) continue;
// skip captured obj
if(MP2::isCaptureObject(tile.GetObject()) &&
Players::isFriends(color, tile.QuantityColor())) continue;
// skip for meeting heroes
if(MP2::OBJ_HEROES == tile.GetObject())
{
const Heroes* hero = tile.GetHeroes();
if(hero && color == hero->GetColor()) continue;
}
// check: is visited objects
switch(tile.GetObject())
{
case MP2::OBJ_MAGELLANMAPS:
case MP2::OBJ_OBSERVATIONTOWER:
if(world.GetKingdom(color).isVisited(tile)) continue;
break;
default: break;
}
store[it] = tile.GetObject();
}
}
}
void AI::KingdomTurn(Kingdom & kingdom)
{
KingdomHeroes & heroes = kingdom.GetHeroes();
KingdomCastles & castles = kingdom.GetCastles();
const int color = kingdom.GetColor();
if(kingdom.isLoss() || color == Color::NONE)
{
kingdom.LossPostActions();
return;
}
DEBUG(DBG_AI, DBG_INFO, Color::String(kingdom.GetColor()) << " funds: " << kingdom.GetFunds().String());
if(! Settings::Get().MusicMIDI()) AGG::PlayMusic(MUS::COMPUTER);
Interface::StatusWindow & status = Interface::Basic::Get().GetStatusWindow();
AIKingdom & ai = AIKingdoms::Get(color);
// turn indicator
status.RedrawTurnProgress(0);
// scan map
ai.scans.clear();
WorldStoreObjects(color, ai.scans);
DEBUG(DBG_AI, DBG_INFO, Color::String(color) << ", size cache objects: " << ai.scans.size());
// set capital
if(NULL == ai.capital && castles.size())
{
KingdomCastles::iterator it = std::find_if(castles.begin(), castles.end(), Castle::PredicateIsCastle);
if(castles.end() != it)
{
if(*it)
{
ai.capital = *it;
ai.capital->SetModes(Castle::CAPITAL);
}
}
else
// first town
{
ai.capital = castles.front();
ai.capital->SetModes(Castle::CAPITAL);
}
}
// turn indicator
status.RedrawTurnProgress(1);
// castles AI turn
std::for_each(castles.begin(), castles.end(), AICastleTurn);
// need capture town?
if(castles.empty())
std::for_each(heroes.begin(), heroes.end(), AIHeroesCaptureNearestTown);
// buy hero in capital
if(ai.capital && ai.capital->isCastle())
{
u32 modes = 0;
const u32 maxhero = Maps::XLARGE > world.w() ? (Maps::LARGE > world.w() ? 3 : 2) : 4;
if(heroes.empty())
modes = AI::HEROES_HUNTER|AI::HEROES_SCOUTER;
else
if(heroes.size() < maxhero ||
0 == std::count_if(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_SCOUTER)))
modes = AI::HEROES_SCOUTER;
if(modes &&
heroes.size() < Kingdom::GetMaxHeroes())
{
Recruits & rec = kingdom.GetRecruits();
Heroes* hero = ai.capital->GetHeroes().Guest();
if(!hero)
{
if(rec.GetHero1() && rec.GetHero2())
hero = ai.capital->RecruitHero(rec.GetHero1()->GetLevel() >= rec.GetHero2()->GetLevel() ? rec.GetHero1() : rec.GetHero2());
else
if(rec.GetHero1())
hero = ai.capital->RecruitHero(rec.GetHero1());
else
if(rec.GetHero2())
hero = ai.capital->RecruitHero(rec.GetHero2());
if(hero)
hero->SetModes(modes);
}
}
}
// set hunters
if(ai.capital)
{
const size_t hunters =
std::count_if(heroes.begin(), heroes.end(),
std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_HUNTER));
// every time
if(0 == hunters &&
heroes.size())
{
KingdomHeroes::iterator it = std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes), Heroes::PATROL)));
if(it != heroes.end() &&
! ai.capital->GetHeroes().Guest())
AIHeroesSetHunterWithTarget((*it), ai.capital->GetIndex());
}
else
// each month
if(world.BeginMonth() && 1 < world.CountDay())
{
KingdomHeroes::iterator it =
std::find_if(heroes.begin(), heroes.end(),
std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_HUNTER));
if(it != heroes.end() &&
! ai.capital->GetHeroes().Guest())
AIHeroesSetHunterWithTarget(*it, ai.capital->GetIndex());
}
}
// update roles
{
std::for_each(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::ResetModes), AI::HEROES_STUPID|AI::HEROES_WAITING));
// init roles
if(heroes.end() != std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes), AI::HEROES_SCOUTER|AI::HEROES_HUNTER))))
{
KingdomHeroes::iterator ith, first = heroes.end();
while(heroes.end() != (ith = std::find_if(heroes.begin(), heroes.end(),
std::not1(std::bind2nd(std::mem_fun(&Heroes::Modes),
// also skip patrol
AI::HEROES_HUNTER|AI::HEROES_SCOUTER|Heroes::PATROL)))))
{
if(first == heroes.end())
{
first = ith;
if(*ith) (*ith)->SetModes(AI::HEROES_HUNTER|AI::HEROES_SCOUTER);
}
else
if(*ith) (*ith)->SetModes(AI::HEROES_SCOUTER);
}
}
}
// turn indicator
status.RedrawTurnProgress(2);
// heroes turns
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesTurn));
//std::for_each(heroes.begin(), heroes.end(), std::bind2nd(std::mem_fun(&Heroes::ResetModes), AI::HEROES_STUPID|AI::HEROES_WAITING));
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesTurn));
std::for_each(heroes.begin(), heroes.end(), std::ptr_fun(&AIHeroesEnd));
// turn indicator
status.RedrawTurnProgress(9);
DEBUG(DBG_AI, DBG_INFO, Color::String(color) << " moved");
}


Надо наверное придумать и прописать ему какие-нибудь дополнительные правила чтобы компьютер их выполнял
и дейстовавал более умно.
Вернуться к началу

offlineАватара пользователя
t800  
Ветеран
Ветеран
 
Сообщения: 982
Зарегистрирован: 22 июл 2015, 11:36
Пол: Не указан
Награды: 4
Наградной знак (1) Деревянный Щит (1) Золотой Меч (1) Серебряные Сапоги (1)
Поблагодарили: 191 раз.

Re: Кампания во Free Heroes II

Сообщение t800 » 31 окт 2015, 10:44

Вы просто подскажите какие правила надо компьютеру прописать чтобы он не делал глупости. Я их попробую тогда прописать. Например, вы заметили что компьютер делает какую-то глупость, скажите что это за глупость и тогда попробую я прописать в код команды чтобы он так не делал, а делал так как вы скажите что он должен делать.
Вернуться к началу

Пред.След.

Вернуться в Техническая часть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2