1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Update docs/developers/ai-description.md

Co-authored-by: Alexander Wilms <Alexander-Wilms@users.noreply.github.com>
This commit is contained in:
krs 2023-10-25 22:17:21 +03:00 committed by krs
parent 90f20b20d5
commit d0cdd06383

View File

@ -1,21 +1,21 @@
< [Documentation](../Readme.md) / AI Description - WIP
... excrept from Slack chat with Danylchenko
There are two types of AI: adventure and battle.
**Adventure AIs** are responsible on moving heroes on map and developing towns
**Battle AIs** are responsible on actually fighting: moving stack on battlefield
**Adventure AIs** are responsible for moving heroes across the map and developing towns
**Battle AIs** are responsible for fighting, i.e. moving stacks on the battlefield
We have 3 battle AIs so far: BattleAI - strongest, StupidAI - for neutrals, should be simple so that expirienced players can abuse it. And Empty AI - should do nothing at all. If needed another battle AI can be introduced.
We have 3 battle AIs so far:
* BattleAI - strongest
* StupidAI - for neutrals, should be simple so that experienced players can abuse it
* Empty AI - should do nothing at all. If needed another battle AI can be introduced.
Each battle AI consist of a few classes, but the main class, kind of entry point usually has the same name as the package itself. In BattleAI it is the BattleAI class. It implements some battle specific interface, do not remember. Main method there is activeStack(battle::Unit* stack). It is invoked by the system when it's time to move your stack. The thing you use to interact with the game and receive the gamestate is usually referenced in the code as cb. CPlayerSpecificCallback it should be. It has a lot of methods and can do anything. For instance it has battleGetUnitsIf(), which returns all units on the battlefield matching some lambda condition.
Each side in a battle is represented by an CArmedInstance object. CHeroInstance and CGDwelling, CGMonster and more are subclasses of CArmedInstance. CArmedInstance contains a set of stacks. When the battle starts, these stacks are converted to battle stacks. Usually Battle AIs reference them using the interface battle::Unit *.
Units have bonuses. Nearly everything aspect of a unit is configured in the form of bonuses. Attack, defense, health, retalitation, shooter or not, initial count of shots and so on.
When you call unit->getAttack() it summarizes all these bonuses and returns the resulting value.
Each battle AI consist of a few classes, but the main class, kind of entry point usually has same name as package itself. In BattleAI it is BattleAI class. It implements some battle specific interface, do not remember. Main method there is activeStack(battle::Unit* stack). It is invoked by system when it is time to move your stack. The thing you use to interact with game and recieve gamestate is usually referencesi n code as cb. CPlayerSpecificCallback it should be. It has a lot of methods and can do anything. For instance it has battleGetUnitsIf() can retrieve all units on battlefield matching some lambda condition.
sides in battle are represented by two CArmedInstance objects. CHeroInstance is subclass of CArmedInstance. Same can be said abot CGDwelling, CGMonster and so on. CArmedInstance contains a set of stacks. When battle starts these stacks are converted in battle stacks. Usually Battle AIs reference them using interface battle::Unit *.
Units have bonuses. Mostly everything about unit is configured in form of bonuses. Attack, defense, health, retalitation, shooter or not, initial count of shots and so on.
So when you call unit->getAttack() it summarize all these bonuses and return resulting value.
Now important part is HypotheticBattle. It is used to evaluate some effect, action without changing real gamestate. First of all it is a wrapper around CPlayerSpecificCallback or anther HypotheticBattle so it can provide you data, Internally it has a set of modified unit states and intercepts some calls to underlying callback and returns these internal states instead. These states in turn are wrappers around original units and contain modified bonuses (CStackWithBonuses). So if you need to emulate attack you can ask hypotheticbattle.getforupdate() and it wil lreturn you this CStackWithBonuses which you can safely change.
One important class is HypotheticBattle. It is used to evaluate the effects of an action without changing the actual gamestate. It is a wrapper around CPlayerSpecificCallback or another HypotheticBattle so it can provide you data, Internally it has a set of modified unit states and intercepts some calls to underlying callback and returns these internal states instead. These states in turn are wrappers around original units and contain modified bonuses (CStackWithBonuses). So if you need to emulate an attack you can call hypotheticbattle.getforupdate() and it will return the CStackWithBonuses which you can safely change.
Now about BattleAI. All possible attacks are measured using value I called damage reduce. It is how much damage enemy will loose after our attack. Also for negative effects we have our damage reduce. We get a difference and this value is used as attack score.