Opis zadania — bitewne AI dla VCMI
Przebieg bitwy - jak to wygląda od strony AI
Contents
Informacje ogólne
Zarys przebiegu bitwy
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, przy czym pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z hexów (pól heksgonalnych) mogą być blokowane przeszkodami i jednostki nie mogą na nich stawać. Każda jednostka zajmuje jednego hexa lub dwa sąsiadujące w poziomie hexy. Bitwa jest podzielona na tury, w których każda jednostki ruszają się sekwencyjnie w kolejności zależnej od ich inicjatywy (w przypadku zwykłych jednostek jest ona równa prędkości jednostki). Ponadto AI, zależnie od rodzaju bohatera i posiadanych punktów many, raz na turę może rzucić wybrany czar z księgi zaklęć.
Jak AI komunikuje się z grą
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:
-
void GetAiName(char* name);
— powinno wypisać nazwę AI -
CGlobalAI* GetNewAI();
— zwrca obiekt klasy wydziedziczonej z abstrakcyjnej klasy CGlobalAI. Wywoływanie metod na zwróconym obiekcie stanowi podstawę komunikacji silnik -> AI
Komunikacja AI -> silnik odbywa się albo poprzez zwracanie odpowiednich wartości, albo, na żądanie AI, przez wywoływanie metod na obiekcie klasy CCallback, który jest dostarczany przez wskaźnik w wywołaniu metody init() AI.
Informacje szczegółowe
Początek bitwy
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side); w której przekazywane są następujące informacje:
- jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)
- jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)
- lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)
- informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.
- (nadmiarową) informację, po której stronie AI ma walczyć.
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.
Przebieg tury
Każda tura zaczyna się od dwóch wywołań: void battleNewRoundFirst(int round){}; void battleNewRound(int round){}; z których najpierw wykonywane jest pierwsze, a potem drugie (obydwa dostają jako parametr numer tury). Różnią się tym, że pierwsze jest robione przed, a drugie po naniesieniu na stan gry zmian wynikających z rozpoczęcia się nowej rudny (np. zakończenie działania pewnych efektów czarów).
Następnie, dla każdej jednostki w kolejności wyliczonej inicjatywy, może nastąpić następująca sytuacja:
- Jednostka traci turę z powodu złego morale - szansa zależna od wartości morale danej jednostki. AI dostaje wywołania o początku i końcu akcji BAD_MORALE.
- Jednostka jest pod wpływem berserku i automatycznie atakuje najbliższą jednostkę pozostającą w zasięgu (AI otrzymuje informację o początku i końcu akcji ataku na najbliższą jednostkę - WALK_AND_ATTACK). W przypadku braku jednostek w zasięgu jednostka nic nie robi (AI dostaje informację o początku i końcu akcji DO_NOTHING).
- Jeżeli jednostka jest balistą, a bohater AI nie posiada umiejętności "artyleria", to AI otrzymuje informację o początku i końcu akcji strzału balisty.
- Jeśli jednostka jest namiotem medyka, a bohater AI nie posiada umiejętności "pierwsza pomoc", to AI otrzymuje informację o początku i końcu akcji STACK_HEAL (jeśli jakaś jednostka jest ranna) lub DO_NOTHING (jeśli żadna nie jest ranna).
- Jeśli nie zaszła żadna z poprzednich możliwości, AI będące posiadaczem jednostki (lub wrogie, jeśli jednostka jest zahipnotyzowana) jest proszone o wykonanie akcji dla niej. Zapytanie to może zostać powtórzone, jeśli jednostka ma wysokie morale (szansa zależna od wartości premii). Zapytanie o akcję realizowane jest za pomocą funkcji BattleAction activeStack(int stackID) gdzie jako parametr występuje unikalny identyfikator jednostki. Funkcja ma zwrócić obiekt opisujący ruch jednostki lub rzucany czar. Możliwe akcje są następujące:
- rzucenie czaru przez bohatera (nie powoduje utraty tury przez jednostkę, można rzucać czar tylko raz na turę - o ile bohater AI ma taką możliwość w ogóle)
- przejście jednostki na inne pole
- polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony
- ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów
- poddanie się AI
- zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego
- strzał do dowolnej jednostki (może być niemożliwy, nie każda jednostka strzela, stojąca koło jednostki wroga jednostka z reguły blokuje możliwość strzelania)
- czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)
- rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)
- leczenie innej jednostki (dla namiotu medyka)
Informacja o początku / końcu akcji
TBD
Wywołania AI -> silnik
Obecnie zaimplementowane są następujące wywołania a callbacku:
TBD
Czary bohaterów
W grze na obecną chwilę zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Wśród nich są czary zadające jednostkom wroga bezpośrednie obrażenia, zwiększające parametry jednostek AI, obniżające parametry wrogich jednostek lub specyficzne czary pozwalające np. przejąć kontrolę nad wrogą jednostką na pewien czas. Pełną lista jest dostępna w Internecie.
Koniec bitwy
Jeżeli jedna ze stron się podda, ucieknie, lub wszystkie jej jednostki poza maszynami bojowymi zostaną zabite, bitwa się kończy. Oba walczące AI dostają wywołanie void battleEnd(const BattleResult *br); Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.