https://wiki.vcmi.eu/api.php?action=feedcontributions&user=Tow&feedformat=atomVCMI Project Wiki - User contributions [en]2024-03-28T21:22:23ZUser contributionsMediaWiki 1.28.2https://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1518How to build VCMI (Windows)2014-04-19T22:21:02Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* Git client: <br />
** Visual Studio 2013 has built-in Git support. It isn't complete, but having most important Git commands integrated in IDE is very convienent. Update 2 brings a few handy features (blame).<br />
** Visual Studio 2012 [which you shouldn't use anyway] offers similar (though more limited) feature set through official plugin. [http://visualstudiogallery.msdn.microsoft.com/abafc7d6-dcaa-40f4-8a5e-d6724bdb980c microsoft.com]<br />
** Because Visual Studio support fir Git is limited, I recommend having installed some else Git client, like TortoiseGit [http://code.google.com/p/tortoisegit/ code.google.com]<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/]. Depending on the version of Visual Studio you use, you'll need:<br />
** Boost 1.51 or (preferably) newer for Visual Studio 2012,<br />
** Post-1.55 (you'll need to grab sources from Git) build for Visual Studio 2013.<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== Obtaining VCMI sources ==<br />
=== Using Visual Studio===<br />
* Start Visual Studio. Don't load any project.<br />
* Open Team Explorer panel.<br />
* Click the "Connect to Team Projects" icon at the Team Explorer's top bar. <br />
* Make sure that the "Local Git Repositories" node is expanded and click the "Clone" below it. <br />
* Enter the <br />
** repo address (first field): https://github.com/vcmi/vcmi )<br />
** the desired path for the repo to be placed. In our example this'll be: C:\VCMI\trunk<br />
* Click clone. Done.<br />
<br />
Now you have the local copy of the repository on the disk. It should appear in the Team Explorer under the "Local Git Repositories" section. Double click it and then select a solution to open.<br />
<br />
<br />
=== Using TortoiseGit client ===<br />
(The screenshots are not updated for the Git, however the process is pretty much the same.)<br />
<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select "Git Clone…" from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://github.com/vcmi/vcmi/ as URL of repository. You should not need to alter other options.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-12.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-12.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1517How to build VCMI (Windows)2014-04-19T22:19:39Z<p>Tow: /* VCMI sources */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* Git client: <br />
** Visual Studio 2013 has built-in Git support. It isn't complete, but having most important Git commands integrated in IDE is very convienent. Update 2 brings a few handy features (blame).<br />
** Visual Studio 2012 [which you shouldn't use anyway] offers similar (though more limited) feature set through official plugin. [http://visualstudiogallery.msdn.microsoft.com/abafc7d6-dcaa-40f4-8a5e-d6724bdb980c microsoft.com]<br />
** Because Visual Studio support is limited, I recommend having installed some else Git client, like TortoiseGit [http://code.google.com/p/tortoisegit/ code.google.com]<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/]. Depending on the version of Visual Studio you use, you'll need:<br />
** Boost 1.51 or (preferably) newer for Visual Studio 2012,<br />
** Post-1.55 (you'll need to grab sources from Git) build for Visual Studio 2013.<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== Obtaining VCMI sources ==<br />
=== Using Visual Studio===<br />
* Start Visual Studio. Don't load any project.<br />
* Open Team Explorer panel.<br />
* Click the "Connect to Team Projects" icon at the Team Explorer's top bar. <br />
* Make sure that the "Local Git Repositories" node is expanded and click the "Clone" below it. <br />
* Enter the <br />
** repo address (first field): https://github.com/vcmi/vcmi )<br />
** the desired path for the repo to be placed. In our example this'll be: C:\VCMI\trunk<br />
* Click clone. Done.<br />
<br />
Now you have the local copy of the repository on the disk. It should appear in the Team Explorer under the "Local Git Repositories" section. Double click it and then select a solution to open.<br />
<br />
<br />
=== Using TortoiseGit client ===<br />
(The screenshots are not updated for the Git, however the process is pretty much the same.)<br />
<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select "Git Clone…" from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://github.com/vcmi/vcmi/ as URL of repository. You should not need to alter other options.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-12.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-12.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1516How to build VCMI (Windows)2014-04-19T22:11:12Z<p>Tow: /* Building from sources */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* Git client: <br />
** Visual Studio 2013 has built-in Git support. It isn't complete, but having most important Git commands integrated in IDE is very convienent. Update 2 brings a few handy features (blame).<br />
** Visual Studio 2012 [which you shouldn't use anyway] offers similar (though more limited) feature set through official plugin. [http://visualstudiogallery.msdn.microsoft.com/abafc7d6-dcaa-40f4-8a5e-d6724bdb980c microsoft.com]<br />
** Because Visual Studio support is limited, I recommend having installed some else Git client, like TortoiseGit [http://code.google.com/p/tortoisegit/ code.google.com]<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/]. Depending on the version of Visual Studio you use, you'll need:<br />
** Boost 1.51 or (preferably) newer for Visual Studio 2012,<br />
** Post-1.55 (you'll need to grab sources from Git) build for Visual Studio 2013.<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-12.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-12.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1515How to build VCMI (Windows)2014-04-19T22:10:33Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* Git client: <br />
** Visual Studio 2013 has built-in Git support. It isn't complete, but having most important Git commands integrated in IDE is very convienent. Update 2 brings a few handy features (blame).<br />
** Visual Studio 2012 [which you shouldn't use anyway] offers similar (though more limited) feature set through official plugin. [http://visualstudiogallery.msdn.microsoft.com/abafc7d6-dcaa-40f4-8a5e-d6724bdb980c microsoft.com]<br />
** Because Visual Studio support is limited, I recommend having installed some else Git client, like TortoiseGit [http://code.google.com/p/tortoisegit/ code.google.com]<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/]. Depending on the version of Visual Studio you use, you'll need:<br />
** Boost 1.51 or (preferably) newer for Visual Studio 2012,<br />
** Post-1.55 (you'll need to grab sources from Git) build for Visual Studio 2013.<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=Main_Page&diff=1493Main Page2014-04-06T21:54:58Z<p>Tow: /* Documentation and guidelines for developers */</p>
<hr />
<div>__NOTOC__<br />
= Welcome to VCMI Project Wiki =<br />
<br />
[[VCMI]] is an open-source project aiming to reimplement HMM3:WoG game engine, giving it new and extended possibilities.<br />
<br />
== Latest release ==<br />
Latest released version is <strong>0.95</strong>.<br />
* [http://forum.vcmi.eu/viewtopic.php?t=854 Information about build]<br />
<br />
== Documentation and guidelines for users ==<br />
* [[VCMI | General information about VCMI Project]]<br />
* [[Frequently asked questions]]<br />
* [[Engine features]]<br />
* [[Game mechanics]]<br />
* [[Bug reporting guidelines]]<br />
* [[Installation on Linux]]<br />
* [http://www.4shared.com/file/135714811/d0214227/vcmimanual.html Manual]<br />
* [http://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA List of implemented game items]<br />
* [[Mod list]]<br />
* [[Modding guidelines]]<br />
<br />
== Documentation and guidelines for developers ==<br />
* [[How to build VCMI (Windows)]]<br />
* [[How to build VCMI (Linux)]]<br />
* [[How to build VCMI (OS X)]]<br />
* [[Code structure]]<br />
* [[Logging API]]<br />
* [[Coding guidelines]]<br />
* [[TODO list]]<br />
<br />
Links for developers:<br />
* [https://github.com/vcmi/vcmi Git repository]<br />
* [http://svn.code.sf.net/p/vcmi/code/trunk/ The old SVN repository (not used anymore)]<br />
<br />
== VCMI Places ==<br />
* [http://forum.vcmi.eu/portal.php Portal]<br />
* [http://forum.vcmi.eu/ Forum]<br />
* [http://bugs.vcmi.eu/ Bugtracker]</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1404How to build VCMI (Windows)2014-02-08T22:12:07Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/]. Depending on the version of Visual Studio you use, you'll need:<br />
** Boost 1.51 or (preferably) newer for Visual Studio 2012,<br />
** Post-1.55 (you'll need to grab sources from Git) build for Visual Studio 2013.<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=Serialization&diff=1359Serialization2013-12-29T17:06:56Z<p>Tow: /* Polymorphic serialization */</p>
<hr />
<div>=Introduction =<br />
The serializer translates between objects living in our code (like int or CGameState*) and stream of bytes. Having objects represented as a stream of bytes is useful. Such bytes can send through the network connection (so client and server can communicate) or written to the disk (savegames).<br />
<br />
VCMI uses binary format. The primitive types are simply copied from memory, more complex structures are represented as a sequence of primitives.<br />
<br />
==Typical tasks==<br />
===Bumping a version number===<br />
Different major version of VCMI likely change the format of the save game. Every save game needs a version identifier, that loading can work properly. Backward compatibility isn't supported for now. The version identifier is a constant named version in Connection.h and should be updated every major VCMI version or development version if the format has been changed. Do not change this constant if it's not required as it leads to full rebuilds. Why should the version be updated? If VCMI cannot detect "invalid" save games the program behaviour is random and undefined. It mostly results in a crash. The reason can be anything from null pointer exceptions, index out of bounds exceptions(ok, they aren't available in c++, but you know what I mean:) or invalid objects loading(too much elements in a vector, etc...) This should be avoided at least for public VCMI releases.<br />
<br />
===Adding a new class===<br />
If you want your class to be serializable (eg. being storable in a savegame) you need to define a serialize method template, as described in [[#User types]]<br />
<br />
Additionally, if your class is part of one of registered object hierarchies (basically: if it derives from CGObjectInstance, IPropagator, ILimiter, CBonusSystemNode, CPack) it needs to be registered. Just add an appropriate entry in the <code class="inline">RegisterTypes.h</code> file. See [[#Polymorphic serialization]] for more information.<br />
<br />
=How does it work=<br />
==Primitive types==<br />
They are simply stored in a binary form, as in memory. Compatibility is ensued through the following means:<br />
* VCMI uses internally types that have constant, defined size (like si32 - has 32 bits on all platforms)<br />
* serializer stores information about its endianess<br />
<br />
It's not "really" portable, yet it works properly across all platforms we currently support.<br />
<br />
==Dependant types==<br />
===Pointers===<br />
Storing pointers mechanics can be and almost always is customized. See [[#Additional features]].<br />
<br />
In the most basic form storing pointer simply sends the object state and loading pointer allocates an object (using "new" operator) and fills its state with the stored data.<br />
<br />
===Arrays===<br />
Serializing array is simply serializing all its elements.<br />
<br />
==Standard library types==<br />
===STL Containers===<br />
First the container size is stored, then every single contained element.<br />
<br />
Supported STL types include:<br />
vector<br />
array<br />
set<br />
unordered_set<br />
list<br />
string<br />
pair<br />
map<br />
<br />
===Smart pointers===<br />
Smart pointers at the moment are treated as the raw C-style pointers. <br />
This is very bad and dangerous for shared_ptr and is expected to be fixed somewhen in the future.<br />
<br />
The list of supported data types from standard library:<br />
shared_ptr (partial!!!)<br />
unique_ptr<br />
<br />
===Boost===<br />
Additionally, a few types for Boost are supported as well:<br />
variant<br />
optional<br />
<br />
==User types==<br />
To make the user-defined type serializable, it has to provide a template method serialize. The first argument (typed as template parameter) is a reference to serializer. The second one is version number.<br />
<br />
Serializer provides an operator& that is internally expanded to << when serialziing or >> when deserializing. <br />
<br />
Serializer provides a public bool field <code class="inline">saving</code>that set to true during serialziation and to false for deserialziation.<br />
<br />
Typically, serializing class involves serializing all its members (given that they are serializable). Sample:<br />
<syntaxhighlight lang="cpp"><br />
/// The rumor struct consists of a rumor name and text.<br />
struct DLL_LINKAGE Rumor<br />
{<br />
std::string name;<br />
std::string text;<br />
<br />
template <typename Handler><br />
void serialize(Handler & h, const int version)<br />
{<br />
h & name & text;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
==Backwards compatibility==<br />
Serializer, before sending any data, stores its version number. It is passed as the parameter to the serialize method, so conditional code ensuring backwards compatibility can be added.<br />
<br />
Yet, because of numerous changes to our game data structure, providing means of backwards compatibility is not feasible. The versioning feature is rarely used.<br />
<br />
Sample:<br />
<syntaxhighlight lang="cpp"><br />
/// The rumor struct consists of a rumor name and text.<br />
struct DLL_LINKAGE Rumor<br />
{<br />
std::string name; //introduced in version 1065<br />
std::string text;<br />
<br />
template <typename Handler><br />
void serialize(Handler & h, const int version)<br />
{<br />
if(version >= 1065)<br />
h & name;<br />
else if(!h.saving) //when loading old savegame<br />
name = "no name"; //set name to some default value [could be done in class constructor as well]<br />
<br />
h & text;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
==Serializer classes==<br />
===Common information===<br />
Serializer classes provide iostream-like interface with operator<< for serialization and operator>> for deserialization.<br />
Serializer upon creation will retrieve/store some metadata (version number, endianess), so even if no object is actually serialized, some data will be passed.<br />
<br />
===Serialization to file===<br />
CLoadFile/CSaveFile classes allow to read data to file and store data to file. They take filename as the first parameter in constructor and, optionally, the minimum supported version number (default to the current version). If the construction fails (no file or wrong file) the exception is thrown.<br />
<br />
===Networking===<br />
CConnection class provides support for sending data structures over TCP/IP protocol. It provides 3 constructors:<br />
1) connect to given hostname at given port (host must be accepting connection)<br />
2) accept connection (takes boost.asio acceptor and io_service)<br />
3) adapt boost.asio socket with already established connection<br />
<br />
All three constructors take as the last parameter the name that will be used to identify the peer.<br />
<br />
==Additional features==<br />
Here is the list of additional custom features serialzier provides. Most of them can be turned on and off.<br />
* [[#Polymorphic serialization]] — no flag to control it, turned on by calls to registerType.<br />
* [[#Vectorized list member serialization]] — enabled by smartVectorMembersSerialization flag.<br />
* [[#Stack instance serialization]] — enabled by sendStackInstanceByIds flag.<br />
* [[#Smart pointer serialization]] — enabled by smartPointerSerialization flag.<br />
<br />
===Polymorphic serialization===<br />
Serializer is to recognize the true type of object under the pointer if classes of that hierarchy were previously registered.<br />
<br />
This means that following will work<br />
<syntaxhighlight lang="cpp"><br />
Derived *d = new Derived();<br />
Base *basePtr = d;<br />
CSaveFile output("test.dat");<br />
output << b;<br />
//<br />
Base *basePtr = nullptr;<br />
CLoadFile input("test.dat");<br />
input >> basePtr; //a new Derived object will be put under the pointer<br />
</syntaxhighlight><br />
<br />
Class hierarchies that are now registered to benefit from this feature are mostly adventure map object (CGObjectInstance) and network packs (CPack). See the RegisterTypes.h file for the full list.<br />
<br />
It is crucial that classes are registered in the same order in the both serializers (storing and loading).<br />
<br />
===Vectorized list member serialization===<br />
Both client and server store their own copies of game state and VLC (handlers with data from config). Many game logic objects are stored in the vectors and possess a unique id number that represent also their position in such vector.<br />
<br />
The vectorised game objects are:<br />
CGObjectInstance<br />
CGHeroInstance<br />
CCreature<br />
CArtifact<br />
CArtifactInstance<br />
CQuest<br />
<br />
For this to work, serializer needs an access to gamestate library classes. This is done by calling a method <code class="inline">CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)</code>. <br />
<br />
When the game ends (or gamestate pointer is invaldiated for another reason) this feature needs to be turned off by toggling its flag.<br />
<br />
When vectorized member serialization is turned on, serializing pointer to such object denotes not sending an object itself but rather its identity. For example:<br />
<syntaxhighlight lang="cpp"><br />
//Server code<br />
CCreature *someCreature = ...;<br />
connection << someCreature;<br />
</syntaxhighlight><br />
<br />
the last line is equivalent to <syntaxhighlight lang="cpp">connection << someCreature->idNumber;</syntaxhighlight><br />
<br />
//Client code<br />
<syntaxhighlight lang="cpp"><br />
CCreature *someCreature = nullptr;<br />
connection >> someCreature;<br />
</syntaxhighlight><br />
<br />
the last line is equivalent to<br />
<syntaxhighlight lang="cpp"><br />
CreatureID id;<br />
connection >> id;<br />
someCreature = VLC->creh->creatures[id.getNum()];<br />
</syntaxhighlight><br />
<br />
Important: this means that the object state is not serialized. <br />
<br />
This feature makes sense only for server-client network communication.<br />
<br />
<br />
===Stack instance serialization===<br />
This feature works very much like the vectorised object serialization. It is like its special case for stack instances that are not vectorised (each hero owns its map). When this option is turned on, sending CStackInstance* will actually send an owning object (town, hero, garrison, etc) id and the stack slot position.<br />
<br />
For this to work, obviously, both sides of the connection need to have exactly the same copies of an armed object and its stacks.<br />
<br />
This feature depends on vectorised member serialization being turned on. (Sending owning object by id.)<br />
<br />
<br />
===Smart pointer serialization===<br />
Note: name is unfortunate, this feature is not about smart pointers (like shared-ptr and unique_ptr). It is for raw C-style pointers, that happen to point to the same object.<br />
<br />
This feature makes it that multiple pointers pointing to the same object are not stored twice.<br />
<br />
Each time a pointer is stored, a unique id is given to it. If the same pointer is stored a second time, its contents is not serialized — serializer just stores a reference to the id.<br />
<br />
For example:<br />
<syntaxhighlight lang="cpp"><br />
Foo * a = new Foo();<br />
Foo * b = b;<br />
<br />
{<br />
CSaveFile test("test.txt");<br />
test << a << b;<br />
}<br />
<br />
Foo *loadedA, *loadedB;<br />
{<br />
CLoadFile test("test.txt");<br />
test >> loadedA >> loadedB;<br />
//now both pointers point to the same object<br />
assert(loadedA == loadedB);<br />
}<br />
</syntaxhighlight><br />
<br />
The feature recognizes pointers by addresses. Therefore it allows mixing pointers to base and derived classes. However, it does not allow serializing classes with multiple inheritance using a "non-first" base (other bases have a certain address offset from the actual object). <br />
<br />
Pointer cycles are properly handled/<br />
<br />
This feature makes sense for savegames and is turned on for them.</div>Towhttps://wiki.vcmi.eu/index.php?title=Serialization&diff=1350Serialization2013-12-29T13:33:42Z<p>Tow: Created page with "=Introduction = The serializer translates between objects living in our code (like int or CGameState*) and stream of bytes. Having objects represented as a stream of bytes is ..."</p>
<hr />
<div>=Introduction =<br />
The serializer translates between objects living in our code (like int or CGameState*) and stream of bytes. Having objects represented as a stream of bytes is useful. Such bytes can send through the network connection (so client and server can communicate) or written to the disk (savegames).<br />
<br />
VCMI uses binary format. The primitive types are simply copied from memory, more complex structures are represented as a sequence of primitives.<br />
<br />
==Typical tasks==<br />
===Bumping a version number===<br />
Different major version of VCMI likely change the format of the save game. Every save game needs a version identifier, that loading can work properly. Backward compatibility isn't supported for now. The version identifier is a constant named version in Connection.h and should be updated every major VCMI version or development version if the format has been changed. Do not change this constant if it's not required as it leads to full rebuilds. Why should the version be updated? If VCMI cannot detect "invalid" save games the program behaviour is random and undefined. It mostly results in a crash. The reason can be anything from null pointer exceptions, index out of bounds exceptions(ok, they aren't available in c++, but you know what I mean:) or invalid objects loading(too much elements in a vector, etc...) This should be avoided at least for public VCMI releases.<br />
<br />
===Adding a new class===<br />
If you want your class to be serializable (eg. being storable in a savegame) you need to define a serialize method template, as described in [[#User types]]<br />
<br />
Additionally, if your class is part of one of registered object hierarchies (basically: if it derives from CGObjectInstance, IPropagator, ILimiter, CBonusSystemNode, CPack) it needs to be registered. Just add an appropriate entry in the <code class="inline">RegisterTypes.h</code> file. See [[#Polymorphic serialization]] for more information.<br />
<br />
=How does it work=<br />
==Primitive types==<br />
They are simply stored in a binary form, as in memory. Compatibility is ensued through the following means:<br />
* VCMI uses internally types that have constant, defined size (like si32 - has 32 bits on all platforms)<br />
* serializer stores information about its endianess<br />
<br />
It's not "really" portable, yet it works properly across all platforms we currently support.<br />
<br />
==Dependant types==<br />
===Pointers===<br />
Storing pointers mechanics can be and almost always is customized. See [[#Additional features]].<br />
<br />
In the most basic form storing pointer simply sends the object state and loading pointer allocates an object (using "new" operator) and fills its state with the stored data.<br />
<br />
===Arrays===<br />
Serializing array is simply serializing all its elements.<br />
<br />
==Standard library types==<br />
===STL Containers===<br />
First the container size is stored, then every single contained element.<br />
<br />
Supported STL types include:<br />
vector<br />
array<br />
set<br />
unordered_set<br />
list<br />
string<br />
pair<br />
map<br />
<br />
===Smart pointers===<br />
Smart pointers at the moment are treated as the raw C-style pointers. <br />
This is very bad and dangerous for shared_ptr and is expected to be fixed somewhen in the future.<br />
<br />
The list of supported data types from standard library:<br />
shared_ptr (partial!!!)<br />
unique_ptr<br />
<br />
===Boost===<br />
Additionally, a few types for Boost are supported as well:<br />
variant<br />
optional<br />
<br />
==User types==<br />
To make the user-defined type serializable, it has to provide a template method serialize. The first argument (typed as template parameter) is a reference to serializer. The second one is version number.<br />
<br />
Serializer provides an operator& that is internally expanded to << when serialziing or >> when deserializing. <br />
<br />
Serializer provides a public bool field <code class="inline">saving</code>that set to true during serialziation and to false for deserialziation.<br />
<br />
Typically, serializing class involves serializing all its members (given that they are serializable). Sample:<br />
<syntaxhighlight lang="cpp"><br />
/// The rumor struct consists of a rumor name and text.<br />
struct DLL_LINKAGE Rumor<br />
{<br />
std::string name;<br />
std::string text;<br />
<br />
template <typename Handler><br />
void serialize(Handler & h, const int version)<br />
{<br />
h & name & text;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
==Backwards compatibility==<br />
Serializer, before sending any data, stores its version number. It is passed as the parameter to the serialize method, so conditional code ensuring backwards compatibility can be added.<br />
<br />
Yet, because of numerous changes to our game data structure, providing means of backwards compatibility is not feasible. The versioning feature is rarely used.<br />
<br />
Sample:<br />
<syntaxhighlight lang="cpp"><br />
/// The rumor struct consists of a rumor name and text.<br />
struct DLL_LINKAGE Rumor<br />
{<br />
std::string name; //introduced in version 1065<br />
std::string text;<br />
<br />
template <typename Handler><br />
void serialize(Handler & h, const int version)<br />
{<br />
if(version >= 1065)<br />
h & name;<br />
else if(!h.saving) //when loading old savegame<br />
name = "no name"; //set name to some default value [could be done in class constructor as well]<br />
<br />
h & text;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
==Serializer classes==<br />
===Common information===<br />
Serializer classes provide iostream-like interface with operator<< for serialization and operator>> for deserialization.<br />
Serializer upon creation will retrieve/store some metadata (version number, endianess), so even if no object is actually serialized, some data will be passed.<br />
<br />
===Serialization to file===<br />
CLoadFile/CSaveFile classes allow to read data to file and store data to file. They take filename as the first parameter in constructor and, optionally, the minimum supported version number (default to the current version). If the construction fails (no file or wrong file) the exception is thrown.<br />
<br />
===Networking===<br />
CConnection class provides support for sending data structures over TCP/IP protocol. It provides 3 constructors:<br />
1) connect to given hostname at given port (host must be accepting connection)<br />
2) accept connection (takes boost.asio acceptor and io_service)<br />
3) adapt boost.asio socket with already established connection<br />
<br />
All three constructors take as the last parameter the name that will be used to identify the peer.<br />
<br />
==Additional features==<br />
Here is the list of additional custom features serialzier provides. Most of them can be turned on and off.<br />
* [[#Polymorphic serialization]] — no flag to control it, turned on by calls to registerType.<br />
* [[#Vectorized list member serialization]] — enabled by smartVectorMembersSerialization flag.<br />
* [[#Stack instance serialization]] — enabled by sendStackInstanceByIds flag.<br />
* [[#Smart pointer serialization]] — enabled by smartPointerSerialization flag.<br />
<br />
===Polymorphic serialization===<br />
Serializer is to recognize the true type of object under the pointer if classes of that hierarchy were previously registered.<br />
<br />
This means that following will work<br />
<syntaxhighlight lang="cpp"><br />
Derived *d = new Derived();<br />
Base *basePtr = d;<br />
CSaveFile output("test.dat");<br />
output << d;<br />
//<br />
Base *basePtr = nullptr;<br />
CLoadFile input("test.dat");<br />
input >> basePtr; //a new Derived object will be put under the pointer<br />
</syntaxhighlight><br />
<br />
Class hierarchies that are now registered to benefit from this feature are mostly adventure map object (CGObjectInstance) and network packs (CPack). See the RegisterTypes.h file for the full list.<br />
<br />
It is crucial that classes are registered in the same order in the both serializers (storing and loading).<br />
<br />
===Vectorized list member serialization===<br />
Both client and server store their own copies of game state and VLC (handlers with data from config). Many game logic objects are stored in the vectors and possess a unique id number that represent also their position in such vector.<br />
<br />
The vectorised game objects are:<br />
CGObjectInstance<br />
CGHeroInstance<br />
CCreature<br />
CArtifact<br />
CArtifactInstance<br />
CQuest<br />
<br />
For this to work, serializer needs an access to gamestate library classes. This is done by calling a method <code class="inline">CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)</code>. <br />
<br />
When the game ends (or gamestate pointer is invaldiated for another reason) this feature needs to be turned off by toggling its flag.<br />
<br />
When vectorized member serialization is turned on, serializing pointer to such object denotes not sending an object itself but rather its identity. For example:<br />
<syntaxhighlight lang="cpp"><br />
//Server code<br />
CCreature *someCreature = ...;<br />
connection << someCreature;<br />
</syntaxhighlight><br />
<br />
the last line is equivalent to <syntaxhighlight lang="cpp">connection << someCreature->idNumber;</syntaxhighlight><br />
<br />
//Client code<br />
<syntaxhighlight lang="cpp"><br />
CCreature *someCreature = nullptr;<br />
connection >> someCreature;<br />
</syntaxhighlight><br />
<br />
the last line is equivalent to<br />
<syntaxhighlight lang="cpp"><br />
CreatureID id;<br />
connection >> id;<br />
someCreature = VLC->creh->creatures[id.getNum()];<br />
</syntaxhighlight><br />
<br />
Important: this means that the object state is not serialized. <br />
<br />
This feature makes sense only for server-client network communication.<br />
<br />
<br />
===Stack instance serialization===<br />
This feature works very much like the vectorised object serialization. It is like its special case for stack instances that are not vectorised (each hero owns its map). When this option is turned on, sending CStackInstance* will actually send an owning object (town, hero, garrison, etc) id and the stack slot position.<br />
<br />
For this to work, obviously, both sides of the connection need to have exactly the same copies of an armed object and its stacks.<br />
<br />
This feature depends on vectorised member serialization being turned on. (Sending owning object by id.)<br />
<br />
<br />
===Smart pointer serialization===<br />
Note: name is unfortunate, this feature is not about smart pointers (like shared-ptr and unique_ptr). It is for raw C-style pointers, that happen to point to the same object.<br />
<br />
This feature makes it that multiple pointers pointing to the same object are not stored twice.<br />
<br />
Each time a pointer is stored, a unique id is given to it. If the same pointer is stored a second time, its contents is not serialized — serializer just stores a reference to the id.<br />
<br />
For example:<br />
<syntaxhighlight lang="cpp"><br />
Foo * a = new Foo();<br />
Foo * b = b;<br />
<br />
{<br />
CSaveFile test("test.txt");<br />
test << a << b;<br />
}<br />
<br />
Foo *loadedA, *loadedB;<br />
{<br />
CLoadFile test("test.txt");<br />
test >> loadedA >> loadedB;<br />
//now both pointers point to the same object<br />
assert(loadedA == loadedB);<br />
}<br />
</syntaxhighlight><br />
<br />
The feature recognizes pointers by addresses. Therefore it allows mixing pointers to base and derived classes. However, it does not allow serializing classes with multiple inheritance using a "non-first" base (other bases have a certain address offset from the actual object). <br />
<br />
Pointer cycles are properly handled/<br />
<br />
This feature makes sense for savegames and is turned on for them.</div>Towhttps://wiki.vcmi.eu/index.php?title=Code_structure&diff=1349Code structure2013-12-29T12:56:48Z<p>Tow: /* Lib */</p>
<hr />
<div>The code of VCMI is divided into several main parts: client, server, lib and AIs, each one in a separate binary file.<br />
<br />
= The big picture =<br />
<br />
[[File:Architektura.png|center]]<br />
<br />
VCMI contains three core projects: VCMI_lib (dll / so), VCMI_client (executable) and VCMI_server (executable). <br />
[[Server]] handles all [[game mechanics]] and events. [[Client]] presents [[game state]] and events to player and collects input from him.<br />
<br />
During the game, we have one (and only one) server and one or more (one for each player computer) clients. <br />
<br />
Important: State of the game and its mechanics are synchronized between clients and server. All changes to the game state or mechanics must be done by server which will send appropriate notices to clients.<br />
<br />
== Game state ==<br />
It's basically CGameState class object and everything that's accessible from it: map (with objects), player statuses, game options, etc.<br />
<br />
== Bonus system ==<br />
One of the more important pieces of VCMI is the [[bonus system]]. It's described in a separate article.<br />
<br />
== Configuration ==<br />
<br />
Most of VCMI configuration files uses Json format and located in "config" directory<br />
<br />
=== [[Json parser and writer]] ===<br />
<br />
= Client =<br />
<br />
== Main purposes of client ==<br />
<br />
[[Client]] is responsible for:<br />
* displaying state of game to human player<br />
* capturing player's actions and sending requests to server<br />
* displaying changes in state of game indicated by server<br />
<br />
== Rendering of graphics ==<br />
<br />
Rendering of graphics relies heavily on SDL. Currently we do not have any wrapper for SDL internal structures and most of rendering is about blitting surfaces using SDL_BlitSurface. We have a few function that make rendering easier or make specific parts of rendering (like printing text). They are places in client/SDL_Extensions and client/SDL_Framerate (the second one contains code responsible for keeping appropriate framerate, it should work more smart than just SDL_Delay(miliseconds)). In rendering, Interface object system is quite helpful. Its base is CIntObject class that is basically a base class for our library of GUI components and other objects.<br />
<br />
=== Video player ===<br />
<br />
Located in client/VideoHandler.cpp/.h, have several platform-specific versions:<br />
* For 32-bit Windows - using original 32-bit libraries (binkw32.dll, smackw32.dll)<br />
* For *nix systems - using ffmpeg libraries.<br />
* Empty player for 64-bit Windows<br />
<br />
=== [[Primitive controls]] ===<br />
<br />
== [[Adventure map interface]] ==<br />
<br />
TBD<br />
<br />
== [[Town interface]] ==<br />
<br />
TBD<br />
<br />
== [[Battle interface]] ==<br />
<br />
= Server =<br />
<br />
== Main purposes of server ==<br />
<br />
[[Server]] is responsible for:<br />
* maintaining state of the game<br />
* handling requests from all clients participating in game<br />
* informing all clients about changes in state of the game that are visible to them<br />
<br />
= Lib =<br />
<br />
== Main purposes of lib ==<br />
VCMI_Lib is a library that contains code common to server and client, so we avoid it's duplication.<br />
Important: the library code is common for client and server and used by them, but the library instance (in opposition to the library as file) is not shared by them! Both client and server create their own "copies" of lib with all its class instances.<br />
<br />
[[Lib]] contains code responsible for:<br />
* handling most of Heroes III files (.lod, .txt setting files)<br />
* storing information common to server and client like state of the game<br />
* managing armies, buildings, artifacts, spells, bonuses and other game objects<br />
* handling general game mechanics and related actions (only adventure map objects; it's an unwanted remnant of past development - all game mechanics should be handled by the server)<br />
* networking and serialization<br />
<br />
=== [[Serialization]] ===<br />
The serialization framework can serialize basic types, several standard containers among smart pointers and custom objects. Its design is based on the [http://www.boost.org/doc/libs/1_52_0/libs/serialization/doc/index.html boost serialization libraries]. In addition to the basic functionality it provides light-weight transfer of CGObjectInstance objects by sending only the index/id. <br />
<br />
See the [[Serialization]] page for all the details.<br />
<br />
= [[Artificial Intelligence]] (AI)=<br />
<br />
== [[GeniusAI]] ==<br />
<br />
Genius AI is first and obsolete battle AI.<br />
It was removed from trunk, yet it contains some potentially useful utilities like neural network.<br />
<br />
== [[StupidAI]] ==<br />
<br />
Stupid AI is recent and used battle AI.<br />
<br />
== [[Adventure AI]] ==<br />
<br />
VCAI module is currently developed agent-based system driven by goals and heroes.<br />
<br />
== [[Programming challenge]] ==<br />
<br />
== [[Neural network]] ==<br />
<br />
Neural network is an unused and abandoned part of [[GeniusAI]].<br />
<br />
== [[Fuzzy logic]] ==<br />
<br />
VCMI includes [http://code.google.com/p/fuzzy-lite/ FuzzyLite] library to make use of fuzzy rule-based algorithms. They are useful to handle uncertanity and resemble human behaviour who takes decisions based on rough observations.<br />
FuzzyLite is linked as separate static library in AI/FuzzyLite.lib file.<br />
<br />
= [[Modding tools]] =<br />
<br />
Modding engine and tools are not yet finished nor avaliable to end user.<br />
<br />
[[Mod system proposal]]<br />
<br />
== [[ERM parser]] ==</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1317How to build VCMI (Windows)2013-11-23T19:34:44Z<p>Tow: /* Global */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.55 or newer (1.51+ if you're using Visual Studuo 2012). You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/].<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_55_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1316How to build VCMI (Windows)2013-11-23T19:33:08Z<p>Tow: /* Boost libraries */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.55 or newer (1.51+ if you're using Visual Studuo 2012). You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/].<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
VCMI depends on the Boost libraries. You can either build them on your own or download the installer.<br />
<br />
=== Using precompiled binaries ===<br />
Go to http://sourceforge.net/projects/boost/files/boost-binaries/ and enter the latest stable (not beta) build directory. Then download the appropriate version. If you are following the suggested workflow (Visual 2013, 32-bit VCMI build) this would be "boost_1_55_0-msvc-12.0-32.exe" (sic! msvc-12.0 means Visual 2013)<br />
<br />
Run the installer. If you chose the default install location, your paths to library are:<br />
* Include path: C:\local\boost_1_55_0<br />
* Library path: C:\local\boost_1_55_0\lib32-msvc-12.0<br />
<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_55_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.55.0 version it's as simple as typing in the '''VS2013 x86 Native Tools Command Prompt''' (look for it in your Start menu; the usual Command Prompt might work as well) the following:<br />
<pre>cd "C:\C++\boost_1_55_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_55_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_55_0.<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1315How to build VCMI (Windows)2013-11-23T19:17:48Z<p>Tow: /* Initial directory structure and libraries pack */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.55 or newer (1.51+ if you're using Visual Studuo 2012). You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/].<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
It is recommended to avoid non-ascii characters in the path to your VCMI development folder. The folder should not be write-protected by system. <br />
Good location:<br />
* C:\VCMI<br />
Bad locations:<br />
* C:\Users\Michał\VCMI (non-ascii character)<br />
* C:\Program Files (x86)\VCMI (write protection)<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1301How to build VCMI (Windows)2013-11-16T16:08:24Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2013 Express for Desktop. It can be downloaded for free from [http://go.microsoft.com/?linkid=9832280&clcid=0x409 microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2012 is support is deprecated but still present.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them separately, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.55 or newer (1.51+ if you're using Visual Studuo 2012). You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/].<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=Installation_on_Linux&diff=1269Installation on Linux2013-10-02T22:50:00Z<p>Tow: /* Fedora */</p>
<hr />
<div>VCMI requires data from original Heroes 3: Shadow of Death or Complete editions. Data from native Linux version made by LOKI will not work.<br />
= Binaries installation =<br />
== Ubuntu ==<br />
VCMI can be installed from PPA:<br />
<br />
* stable version (recommended): https://launchpad.net/~saven-ivan/+archive/vcmi<br />
* daily builds (for testing only): https://launchpad.net/~vcmi/+archive/ppa<br />
<br />
To use it type in Terminal:<br />
<pre><br />
sudo apt-add-repository ppa:saven-ivan/vcmi<br />
sudo apt-get update<br />
sudo apt-get install vcmi<br />
</pre><br />
<br />
== Debian ==<br />
Download and install package for your distribution. Install can be done using any GUI managers or using command line:<br />
<pre><br />
sudo dpkg -i downloaded_package.deb<br />
sudo apt-get -f install<br />
</pre><br />
Note: First command most probably will result in errors - this is normal behavior, all of them should be fixed by second one.<br />
<br />
{|<br />
|'''Debian Wheezy'''<br />
|[http://download.vcmi.eu/vcmi_0.94~wheezy1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.94~wheezy1_amd64.deb 64 bit]<br />
|}<br />
<br />
== Fedora ==<br />
Download and install package for your distribution. There are two ways to install package along with all dependencies: <br />
<br />
Option A) Double-click the package. A package management window should appear with instructions to guide you through the process.<br />
<br />
Option B) Open a terminal window, and type <br />
<pre><br />
sudo rpm -i package_location_and_name(e.g. vcmi-0.9.4-1.fc16.x86_64.rpm)<br />
</pre><br />
<br />
{|<br />
|'''Fedora 19'''<br />
|[http://download.vcmi.eu/vcmi-0.9.4-1.fc19.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.4-1.fc19.x86_64.rpm 64 bit]<br />
|}<br />
<br />
== Other distributions ==<br />
* Gentoo https://github.com/qdii/qdiilay/tree/master/games-strategy/vcmi<br />
* Archlinux [https://aur.archlinux.org/packages/vcmi/ vcmi] [https://aur.archlinux.org/packages/vcmi-svn/ vcmi-svn]<br />
<br />
== Compiling from source ==<br />
* [http://download.vcmi.eu/vcmi-0.94.tar.gz Packaged source]<br />
* [http://svn.code.sf.net/p/vcmi/code/trunk/README.linux Readme] (available as README.linux in source package)<br />
<br />
= Installing Heroes III data files =<br />
To install VCMI you will need:<br />
* Heroes III: Shadow of Death or Complete edition<br />
* Unnoficial WoG addon: http://download.vcmi.eu/WoG/wog.zip<br />
* VCMI data files: http://download.vcmi.eu/core.zip<br />
== Automated install ==<br />
To install Heroes 3 data using automated script you need any of:<br />
* One or two CD's or CD images<br />
* gog.com installer<br />
* Directory with installed game<br />
<br />
Run the script using options appropriate to your input files:<br />
<pre><br />
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd --download<br />
vcmibuilder --gog /path/to/gog.com/installer --download<br />
vcmibuilder --data /path/to/h3/data --download<br />
</pre><br />
You should use only one of these commands.<br />
<br />
=== Offline install ===<br />
Normally vcmibuilder script will autodownload WoG and VCMI data packages. For offline install you need to download this packages manually and replace download switch with this:<br />
<pre><br />
vcmibuilder <h3 data commands> --wog /path/to/wog/archive --vcmi /path/to/vcmi/package<br />
</pre><br />
Where '''h3 data commands''' stands for described earlier option(s) needed to install H3 data (path to data, Install CD or gog.com installer)<br />
<br />
=== Fedora music support ===<br />
To have Music support on Fedora it is required to perform a additional step. Fedora doesn't provide Mp3 playback support natively due to patents applied on the Mp3 technique. The SDL_mixer package from the official Fedora repo is compiled without Mp3 support.<br />
<br />
To make music work it must be converted into ogg format. This can be done either manually or using vcmibuilder:<br />
<pre><br />
vcmibuilder --convertMP3<br />
</pre><br />
This command can be run separately after install or as additional switch during initial vcmibuilder launch<br />
<br />
== Manual install ==<br />
<br />
* Install Heroes III<br />
* Extract WoG addon http://download.vcmi.eu/WoG/wog.zip<br />
* Extract VCMI data files: http://download.vcmi.eu/core.zip<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/games<br />
</pre><br />
Copy your data to data directory. This should result in directory structure similar to this:<br />
<pre><br />
/usr/share/vcmi/config/<br />
/usr/share/vcmi/Data/<br />
/usr/share/vcmi/Maps/<br />
/usr/share/vcmi/Mods/WoG/<br />
/usr/share/vcmi/Mods/vcmi/<br />
/usr/share/vcmi/Mp3/<br />
</pre><br />
<br />
= Launching game =<br />
To start the game type in console:<br />
<pre><br />
vcmiclient<br />
</pre><br />
VCMI should be also available via desktop environment menu or launcher (Games/Strategy/VCMI)<br />
= Reporting bugs =<br />
Report any issues with packages on our [http://bugs.vcmi.eu bugtracker] or post a message on [http://forum.vcmi.eu/index.php VCMI forums]<br />
In report please post:<br />
* used distributive, version and architecture (for example "Ubuntu 11.10 32 bit"). For distributives that use rolling releases please post versions of all used libraries (boost, ffmpeg, SDL)<br />
* console log as well as log files from ~/.vcmi<br />
* steps to reproduce bug</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Linux)&diff=1187How to build VCMI (Linux)2013-07-03T20:21:07Z<p>Tow: /* Compiling VCMI */</p>
<hr />
<div>= Compiling VCMI =<br />
Supported C++ compilers for UNIX-like systems: GCC 4.6+, Clang 3.1+<br />
<br />
There is a guide for compiling and running VCMI located in the SVN trunk root directory: [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/README.linux README.linux]<br />
<br />
'''Set automatically soft-links bash script'''<br />
<br />
The last step in the above-mentioned compiling guide requires to create soft-links for convenient debugging and development in general. There is a bash script which does this step automatically for you. You have to enter the build path, specify the source path and select the usual library folder of the operating system. Then the script takes the work to create all those symbolic links. This is comfortable if you're working on different source folders(trunk, tag, branch) or build types(debug, release) and you want to switch from one build to the other. The link to the script is here: http://download.vcmi.eu/setBuildLinks<br />
<br />
= Setting up a development environment using QtCreator =<br />
<br />
QtCreator is the recommended IDE for VCMI development on linux distros. (It may be used on other operating systems as well) It has the following advantages compared to other IDEs:<br />
* Almost no manual configuration when used with CMake (Project configuration is read from CMake text files)<br />
* Fast parser/indexer, stable<br />
* Can use several compiler toolchains: GCC, Visual Studio, Clang<br />
* Doesn't pollute SVN with project files<br />
<br />
You can download QtCreator from here: http://qt-project.org/downloads#qt-creator<br />
<br />
== Configuration ==<br />
To open the project you have to click File -> Open file or project... -> Select /trunk/src/CMakeLists.txt.<br />
<br />
<br />
For the first time and for every CMake project configuration change you have to execute CMake. This step can be done when opening the project for the first time or alternatively via the left bar -> Projects -> Build Settings -> Execute CMake. You have to specify CMake arguments and the build dir. CMake arguments can be the following:<br />
<pre>-DDISABLE_ERM=ON -DCMAKE_BUILD_TYPE=Debug</pre><br />
The build dir should be set to sth. like /trunk/build for the debug build and /trunk/buildrel for the release build.<br />
For cleaning the build dir a command like "make clean" may be not enough. Better way is to delete the build dir, re-create it and re-execute CMake. Steps for cleaning can be configured in the Projects tab as well.<br />
<br />
== Debugging ==<br />
There is a problem with QtCreator when debugging both vcmiclient and vcmiserver. If you debug the vcmiclient, start a game, attach the vcmiserver process to the gdb debugger(Debug > Start Debugging > Attach to Running External Application...) then breakpoints which are set for vcmiserver will be ignored. This looks like a bug, in any case it's not intuitively. Two workarounds are available luckily:<br />
<br />
1) Run vcmiclient (no debug mode), then attach server process to the debugger<br />
<br />
2) Open two instances of QtCreator and debug vcmiserver and vcmiclient separately(it works!)<br />
<br />
= Package building =<br />
<br />
== RPM package ==<br />
<br />
The first step is to prepare a RPM build environment. On Fedora systems you can follow this guide: http://fedoraproject.org/wiki/How_to_create_an_RPM_package#SPEC_file_overview<br />
<br />
1. Download the file rpm/vcmi.spec from any tagged VCMI release for which you wish to build a RPM package via the SVN Browser trac at this URL for example(which is for VCMI 0.9): http://sourceforge.net/apps/trac/vcmi/browser/tags/0.9/rpm/vcmi.spec<br />
<br />
2. Copy the file to ~/rpmbuild/SPECS<br />
<br />
3. Follow instructions in the vcmi.spec. You have to export the corresponding SVN tag, compress it to a g-zipped archive and copy it to ~/rpmbuild/SOURCES. Instructions are written as comments and you can copy/paste commands into terminal.<br />
<br />
4. Go to ~/rpmbuild/SPECS and open terminal in this folder and type: <pre>rpmbuild -ba vcmi.spec (this will build rpm and source rpm)</pre><br />
<br />
5. Generated RPM is in folder ~/rpmbuild/RPMS<br />
<br />
If you want to package the generated RPM above for different processor architectures and operating systems you can use the tool mock. Moreover, it is necessary to install mock-rpmfusion_free due to the packages ffmpeg-devel and ffmpeg-libs which aren't available in the standard RPM repositories(at least for Fedora). Go to ~/rpmbuild/SRPMS in terminal and type:<br />
<pre>mock -r fedora-17-i386-rpmfusion_free path_to_source_RPM<br />
mock -r fedora-17-x86_64-rpmfusion_free path_to_source_RPM</pre><br />
<br />
Available root environments and their names are listed in /etc/mock.</div>Towhttps://wiki.vcmi.eu/index.php?title=Coding_guidelines&diff=1186Coding guidelines2013-06-29T15:54:03Z<p>Tow: /* C++ Standard */</p>
<hr />
<div>= Coding Guidelines =<br />
<br />
<br />
== C++ Standard ==<br />
<br />
VCMI implementation bases on C++03 standard with several extensions available in compilers we target (GCC 4.6+, MSVC 2012+, Clang 3.1+), i.e.:<br />
* auto keyword,<br />
* decltype,<br />
* lambda expressions and closures,<br />
* local and unnamed types as template arguments,<br />
* new function declaration syntax for deduced return types (returned type after argument list),<br />
* right angle brackets,<br />
* r-value references and std::move,<br />
* static assert.<br />
* nullptr keyword<br />
* range-based for loops<br />
* forward enum declarations<br />
* strongly-typed enums<br />
<br />
In future VCMI may require installation of MSVC 2013. This would allow to use following C++11 constructs:<br />
* explicit conversion operators<br />
* initializer lists<br />
* raw string literals<br />
* variadic templates<br />
* defaulted and deleted functions (except for defaulted move functions)<br />
<br />
<br />
<br />
Further information about these extensions and compiler support for them is available at [http://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport].<br />
<br />
== Style Guidelines ==<br />
<br />
<br />
In order to keep the code consistent, please use the following conventions. From here on `good' and `bad' are used to attribute things that would make the coding style match, or not match. It is not a judgment call on your coding abilities, but more of a style and look call. Please try to follow these guidelines to ensure prettiness.<br />
<br />
<br />
=== Indentation ===<br />
<br />
Use 4 space tabs for writing your code (hopefully we can keep this consistent). If you are modifying someone else's code, try to keep the coding style similar. Switch statements have the case at the same indentation as the switch.<br />
<br />
=== Switch statement ===<br />
<br />
<syntaxhighlight lang="cpp"><br />
switch(alignment)<br />
{<br />
case EAlignment::EVIL:<br />
do_that();<br />
break;<br />
case EAlignment::GOOD:<br />
do_that();<br />
break;<br />
}<br />
</syntaxhighlight><br />
<br />
=== Where to put spaces ===<br />
<br />
Use a space before and after the address or pointer character in a pointer declaration.<br />
<br />
Good:<br />
<syntaxhighlight lang="cpp">CIntObject * images[100];</syntaxhighlight><br />
<br />
Bad:<br />
<syntaxhighlight lang="cpp">CIntObject* images[100]; or<br />
CIntObject *images[100];</syntaxhighlight><br />
<br />
<br />
=== Use whitespace for clarity ===<br />
<br />
Use white space in expressions liberally, except in the presence of parenthesis.<br />
<br />
'''Good:'''<br />
<syntaxhighlight lang="cpp">if(a + 5 > method (blah ('a') + 4))<br />
foo += 24;</syntaxhighlight><br />
<br />
'''Bad:'''<br />
<syntaxhighlight lang="cpp">if(a+5>method(blah('a')+4))<br />
foo+=24;</syntaxhighlight><br />
<br />
Between if, for, while,.. and the opening brace there shouldn't be a whitespace. The keywords are highlighted, so they don't need further separation.<br />
<br />
=== Where to put braces ===<br />
<br />
Inside a code block put the opening brace on the next line after the current statement:<br />
<br />
Good:<br />
<syntaxhighlight lang="cpp">if(a) <br />
{<br />
code ();<br />
code ();<br />
}</syntaxhighlight><br />
<br />
Bad:<br />
<syntaxhighlight lang="cpp">if(a) {<br />
code ();<br />
code ();<br />
}</syntaxhighlight><br />
<br />
Avoid using unnecessary open/close braces, vertical space is usually limited: <br />
<br />
Good:<br />
<syntaxhighlight lang="cpp">if(a)<br />
code ();</syntaxhighlight><br />
<br />
Better:<br />
<syntaxhighlight lang="cpp">if(a) code ();</syntaxhighlight><br />
<br />
Bad: <br />
<syntaxhighlight lang="cpp">if(a) {<br />
code ();<br />
}</syntaxhighlight><br />
<br />
When defining a method, use a new line for the brace, like this: <br />
<br />
Good: <br />
<syntaxhighlight lang="cpp">void method()<br />
{<br />
}</syntaxhighlight><br />
<br />
Bad: <br />
<syntaxhighlight lang="cpp">void Method() {<br />
}</syntaxhighlight><br />
<br />
When allocating objects, don't use parentheses for creating stack-based objects by zero param c-tors to avoid c++ most vexing parse and use parentheses for creating heap-based objects.<br />
<br />
Good:<br />
<syntaxhighlight lang="cpp">std::vector<int> v; <br />
CGBoat btn = new CGBoat();</syntaxhighlight><br />
<br />
Bad:<br />
<syntaxhighlight lang="cpp">std::vector<int> v(); // shouldn't compile anyway <br />
CGBoat btn = new CGBoat;</syntaxhighlight><br />
<br />
=== File headers ===<br />
<br />
For any new files, please use a descriptive introduction, like this:<br />
<syntaxhighlight lang="cpp">/*<br />
* Name_of_File.h, part of VCMI engine<br />
*<br />
* Authors: listed in file AUTHORS in main folder<br />
*<br />
* License: GNU General Public License v2.0 or later<br />
* Full text of license available in license.txt file, in main folder<br />
*<br />
*/</syntaxhighlight><br />
The above notice have to be included only in header files (.h), except there is a cpp file with no corresponding header file.<br />
<br />
=== Where and how to comment ===<br />
<br />
You should write a comment before the class definition which describes shortly the class. 1-2 sentences are enough. Methods and class data members should be commented if they aren't self-describing only. Getters/Setters, simple methods where the purpose is clear or similar methods shouldn't be commented, because vertical space is usually limited. The style of documentation comments should be the three slashes-style: ///. <br />
<br />
<syntaxhighlight lang="cpp">/// Returns true if a debug/trace log message will be logged, false if not.<br />
/// Useful if performance is important and concatenating the log message is a expensive task.<br />
bool isDebugEnabled() const;<br />
bool isTraceEnabled() const;</syntaxhighlight><br />
<br />
The above example doesn't follow a strict scheme on how to comment a method. It describes two methods in one go. Comments should be kept short.<br />
<br />
A good essay about writing comments: [http://ardalis.com/when-to-comment-your-code]<br />
<br />
=== Casing ===<br />
<br />
<br />
Local variables and methods start with a lowercase letter and use the camel casing. Classes/Structs start with an uppercase letter and use the camel casing as well. Macros and constants are written uppercase. <br />
<br />
<br />
=== Line length ===<br />
<br />
The line length for c++ source code is 120 columns. If your function declaration arguments go beyond this point, please align your arguments to match the opening brace. For best results use the same number of tabs used on the first line followed by enough spaces to align the arguments. <br />
<br />
<br />
=== Warnings ===<br />
<br />
Avoid use of #pragma to disable warnings. Compile at warning level 3.<br />
Avoid commiting code with new warnings.<br />
<br />
=== Type naming ===<br />
<br />
Classes are prefixed with an upper C, interfaces with an upper I, enumerations with an upper E, structs without an prefix and typedefs with an upper T<br />
<br />
=== File/directory naming ===<br />
<br />
Compilation units(.cpp,.h files) start with a uppercase letter and are named like the name of a class which resides in that file if possible. Header only files start with a uppercase letter. JSON files start with a lowercase letter and use the camel casing.<br />
<br />
Directories start with a lowercase letter and use the camel casing where necessary.<br />
<br />
== Best practices ==<br />
<br />
<br />
=== Avoid code duplication ===<br />
<br />
Avoid code duplication or don't repeat yourself(DRY) is the most important aspect in programming. Code duplication of any kind can lead to inconsistency and is much harder to maintain. If one part of the system gets changed you have to change the code in several places. This process is error-prone and leads often to problems. Here you can read more about the DRY principle: [http://en.wikipedia.org/wiki/Don%27t_repeat_yourself http://en.wikipedia.org/wiki/Don%27t_repeat_yourself]<br />
<br />
=== Loop handling ===<br />
<br />
Use BOOST_FOREACH for iterating through every item of a container. It should be used in any case except if Visual Studio debug performance is important, then you may use a simple for loop to avoid use of STL Iterator checks. <br />
<br />
The loop counter should be of type int, unless you are sure you won't need negative indices -- then use size_t.<br />
<br />
=== Include guards ===<br />
<br />
Use #pragma once instead of the traditional #ifndef/#define/#endif include guards.<br />
<br />
<br />
=== Pre compiled header file ===<br />
<br />
The header StdInc.h should be included in every compilation unit. It has to be included before any C macro and before any c++ statements. Pre compiled header should not be changed, except any important thing is missing.<br />
The StdInc includes most Boost libraries and nearly all standard STL and C libraries, so you don’t have to include them by yourself. <br />
<br />
<br />
=== Enumeration handling ===<br />
<br />
Do not declare enumerations in global namespace. It is better to wrap them in class or namespace to avoid polluting global namespace:<br />
<syntaxhighlight lang="cpp"><br />
namespace EAlignment<br />
{<br />
enum EAlignment { GOOD, EVIL, NEUTRAL };<br />
}<br />
</syntaxhighlight><br />
<br />
=== Avoid senseless comments ===<br />
<br />
If the comment duplicates the name of commented member, it's better if it wouldn't exist at all. It just increases maintenance cost.<br />
Bad:<br />
<syntaxhighlight lang="cpp">size_t getHeroesCount(); //gets count of heroes (surprise?)</syntaxhighlight><br />
<br />
<br />
=== Class handling ===<br />
<br />
There is no definitive rule which has to be followed strictly. You can freely decide if you want to pack your own classes, where you are programming on, all in one file or each in one file. It's more important that you feel comfortable with the code, than consistency overall the project. VCMI has several container class files, so if you got one additional class to them than just add it to them instead of adding new files.<br />
<br />
=== Functions and interfaces ===<br />
<br />
Don't return const objects or primitive types from functions -- it's pointless. Also, don't return pointers to non-const game data objects from callbacks to player interfaces.<br />
<br />
Bad:<br />
<syntaxhighlight lang="cpp"><br />
const std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;<br />
</syntaxhighlight><br />
<br />
Good:<br />
<syntaxhighlight lang="cpp"><br />
std::vector<const CGObjectInstance*> guardingCreatures (int3 pos) const;<br />
</syntaxhighlight><br />
<br />
== Sources ==<br />
[http://www.mono-project.com/Coding_Guidelines Mono project coding guidelines]</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1185How to build VCMI (Windows)2013-06-29T15:44:04Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Optionally, you can have also WoG or ERA installed.<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.6+ (using MinGW environment), however it's not covered in this tutorial. We strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
** Visual Studio 2013 Preview is supported as well.<br />
** Visual Studio 2010 is *not* supported and won't work.<br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.51 or newer. You can either build them using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below) or download the binaries from [http://sourceforge.net/projects/boost/files/boost-binaries/].<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1177How to build VCMI (Windows)2013-06-03T21:52:08Z<p>Tow: /* VCMI sources */ SVN address</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.51 or newer. You need to build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below).<br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Mid 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) http://svn.code.sf.net/p/vcmi/code/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=Main_Page&diff=1166Main Page2013-06-01T23:34:54Z<p>Tow: /* Latest release */ 0.93</p>
<hr />
<div>__NOTOC__<br />
= Welcome to VCMI Project Wiki =<br />
<br />
[[VCMI]] is an open-source project aiming to reimplement HMM3:WoG game engine, giving it new and extended possibilities.<br />
<br />
== Latest release ==<br />
Latest released version is <strong>0.93</strong>.<br />
* [http://forum.vcmi.eu/viewtopic.php?t=696 Information about build]<br />
* [http://forum.vcmi.eu/dload.php?action=download&id=26 Download link]<br />
<br />
== Documentation and guidelines for users ==<br />
* [[VCMI | General information about VCMI Project]]<br />
* [[Frequently asked questions]]<br />
* [[Engine features]]<br />
* [[Game mechanics]]<br />
* [[Bug reporting guidelines]]<br />
* [[Installation on Linux]]<br />
* [http://www.4shared.com/file/135714811/d0214227/vcmimanual.html Manual]<br />
* [http://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA List of implemented game items]<br />
* [[Mod list]]<br />
* [[Modding guidelines]]<br />
<br />
== Documentation and guidelines for developers ==<br />
* [[How to build VCMI (Windows)]]<br />
* [[How to build VCMI (Linux)]]<br />
* [[How to build VCMI (OS X)]]<br />
* [[Code structure]]<br />
* [[Logging API]]<br />
* [[Coding guidelines]]<br />
* [[TODO list]]<br />
<br />
Links for developers:<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ SVN]<br />
* [http://vcmi.svn.sourceforge.net/ SVN web browser]<br />
<br />
== VCMI Places ==<br />
* [http://forum.vcmi.eu/portal.php Portal]<br />
* [http://forum.vcmi.eu/ Forum]<br />
* [http://bugs.vcmi.eu/ Bugtracker]</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1162How to build VCMI (Windows)2013-05-30T19:24:32Z<p>Tow: Boostpro has shut down and we don't want people to use VC10 anyway.</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.51 or newer. You need to build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple, check the instruction below).<br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Mid 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=1161How to build VCMI (Windows)2013-05-30T19:21:03Z<p>Tow: /* Building from sources */ Boost, minor update.</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.51 or newer. You can build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple) or download precompiled binaries with installer from [http://www.boostpro.com/download boostpro.com]. <br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Feb 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_53_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.53.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_53_0"<br />
bootstrap<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_53_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_53_0.<br />
<br />
=== Obtaining precompiled binaries from Boostpro (only for VC10 users) === <br />
At the moment (December 2012) Boostpro doesn't provide binaries for Visual Studio 2012. <br />
<br />
If you use Visual Studio 2010 then you can use Boostpro Boost distribution. When installing make sure that following options are checked in the "Select Default Variants" screen:<br />
* Visual C++ 10.0<br />
* Multithreaded<br />
* Multithreaded debug<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=Installation_on_Linux&diff=1009Installation on Linux2013-02-03T00:16:36Z<p>Tow: /* Manual install */</p>
<hr />
<div>VCMI requires data from original Heroes 3: Shadow of Death or Complete editions and from the WoG expansion pack. Data from native Linux version made by LOKI will not work.<br />
= Binaries installation =<br />
== Debian-based distributions ==<br />
Download and install package for your distribution. Install can be done using any GUI managers or using command line:<br />
<pre><br />
sudo dpkg -i downloaded_package.deb<br />
sudo apt-get -f install<br />
</pre><br />
Note: First command most probably will result in errors - this is normal behavior, all of them should be fixed by second one.<br />
=== Packages ===<br />
<br />
{|<br />
|'''Ubuntu 12.10 quantal'''<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_amd64.deb 64 bit]<br />
|-<br />
|'''Ubuntu 12.04 precise'''<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Wheezy'''<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Sid'''<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_amd64.deb 64 bit]<br />
|}<br />
<br />
=== Other Debian-based distributions ===<br />
VCMI requires g++-4.5 and boost-1.46 which are unavailable on Debian Squeeze and Ubuntu 11.04 or lower.<br />
In order for VCMI to work on this system you'll need to install them first.<br />
== RPM-based distributions ==<br />
Download and install package for your distribution. There are two ways to install package along with all dependencies: <br />
<br />
Option A) Double-click the package. A package management window should appear with instructions to guide you through the process.<br />
<br />
Option B) Open a terminal window, and type <br />
<pre><br />
sudo rpm -i package_location_and_name(e.g. vcmi-0.89-1.fc16.x86_64.rpm)<br />
</pre><br />
=== Packages ===<br />
<br />
{|<br />
|'''Fedora 18'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.x86_64.rpm 64 bit]<br />
|}<br />
<br />
{|<br />
|'''Fedora 17'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.x86_64.rpm 64 bit]<br />
|}<br />
<br />
== Compiling from source ==<br />
* [http://download.vcmi.eu/vcmi-0.91.tar.gz Packaged source]<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/README.linux Readme] (available in README.linux file in source package)<br />
<br />
= Installing Heroes III data files =<br />
To install VCMI you will need:<br />
* Heroes III: Shadow of Death or Complete edition<br />
* Unnoficial WoG addon: http://download.vcmi.eu/WoG/wog.zip<br />
* VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
== Automated install ==<br />
To install Heroes 3 data using automated script you need any of:<br />
* One or two CD's or CD images<br />
* gog.com installer<br />
* Directory with installed game<br />
<br />
Create temporary directory that will be used by script and go into it:<br />
<pre><br />
mkdir temp<br />
cd temp<br />
</pre><br />
Run the script using options appropriate to your input files:<br />
<pre><br />
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd --download<br />
vcmibuilder --gog /path/to/gog.com/installer --download<br />
vcmibuilder --data /path/to/h3/data --download<br />
</pre><br />
You should use only one of these commands.<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/bin/vcmi<br />
</pre><br />
<br />
Copy resulting files into your vcmi data directory:<br />
<pre><br />
cp -RTu vcmi /path/to/vcmi/data/directory<br />
</pre><br />
<br />
=== Offline install ===<br />
Normally vcmibuilder script will autodownload WoG and VCMI data packages. For offline install you need to download this packages manually and replace download switch with this:<br />
<pre><br />
vcmibuilder <h3 data commands> --wog /path/to/wog/archive --vcmi /path/to/vcmi/package<br />
</pre><br />
<br />
=== Fedora music support ===<br />
To have Music support on Fedora it is required to perform a additional step. Fedora doesn't provide Mp3 playback support natively due to patents applied on the Mp3 technique. The SDL_mixer package from the official Fedora repo is compiled without Mp3 support. Luckily this isn't a huge problem due to the filesystem API of VCMI. If you place ogg files in the Mp3 folder it'll use those files. So all you have to do is to convert the original Mp3 to OGG by yourself. Then copy them to the /Mp3 folder and remove the old .mp3 files with e.g. rm -rf *.mp3. You may use those tools for converting MP3 to OGG e.g.: Dirogg Bash Script http://freecode.com/projects/dirogg or the graphical program SoundConverter(sudo yum install soundconverter).<br />
<br />
== Manual install ==<br />
<br />
* Install Heroes III<br />
* Extract WoG addon http://download.vcmi.eu/WoG/wog.zip<br />
* Extract VCMI data files: http://download.vcmi.eu/core.zip<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/games<br />
</pre><br />
Copy your data to data directory. This should result in directory structure similar to this:<br />
<pre><br />
/usr/share/vcmi/config/<br />
/usr/share/vcmi/Data/<br />
/usr/share/vcmi/Maps/<br />
/usr/share/vcmi/Mods/WoG/<br />
/usr/share/vcmi/Mods/vcmi/<br />
/usr/share/vcmi/Mp3/<br />
</pre><br />
<br />
= Launching game =<br />
To start the game type in console:<br />
<pre><br />
vcmiclient<br />
</pre><br />
VCMI should be also available via desktop environment menu or launcher (Games/Strategy/VCMI)<br />
= Reporting bugs =<br />
Report any issues with packages on our [http://bugs.vcmi.eu bugtracker] or post a message on [http://forum.vcmi.eu/index.php VCMI forums]<br />
In report please post:<br />
* used distributive, version and architecture (for example "Ubuntu 11.10 32 bit"). For distributives that use rolling releases please post versions of all used libraries (boost, ffmpeg, SDL)<br />
* console log as well as log files from ~/.vcmi<br />
* steps to reproduce bug</div>Towhttps://wiki.vcmi.eu/index.php?title=Installation_on_Linux&diff=1008Installation on Linux2013-02-03T00:15:49Z<p>Tow: /* Compiling from source */</p>
<hr />
<div>VCMI requires data from original Heroes 3: Shadow of Death or Complete editions and from the WoG expansion pack. Data from native Linux version made by LOKI will not work.<br />
= Binaries installation =<br />
== Debian-based distributions ==<br />
Download and install package for your distribution. Install can be done using any GUI managers or using command line:<br />
<pre><br />
sudo dpkg -i downloaded_package.deb<br />
sudo apt-get -f install<br />
</pre><br />
Note: First command most probably will result in errors - this is normal behavior, all of them should be fixed by second one.<br />
=== Packages ===<br />
<br />
{|<br />
|'''Ubuntu 12.10 quantal'''<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_amd64.deb 64 bit]<br />
|-<br />
|'''Ubuntu 12.04 precise'''<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Wheezy'''<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Sid'''<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_amd64.deb 64 bit]<br />
|}<br />
<br />
=== Other Debian-based distributions ===<br />
VCMI requires g++-4.5 and boost-1.46 which are unavailable on Debian Squeeze and Ubuntu 11.04 or lower.<br />
In order for VCMI to work on this system you'll need to install them first.<br />
== RPM-based distributions ==<br />
Download and install package for your distribution. There are two ways to install package along with all dependencies: <br />
<br />
Option A) Double-click the package. A package management window should appear with instructions to guide you through the process.<br />
<br />
Option B) Open a terminal window, and type <br />
<pre><br />
sudo rpm -i package_location_and_name(e.g. vcmi-0.89-1.fc16.x86_64.rpm)<br />
</pre><br />
=== Packages ===<br />
<br />
{|<br />
|'''Fedora 18'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.x86_64.rpm 64 bit]<br />
|}<br />
<br />
{|<br />
|'''Fedora 17'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.x86_64.rpm 64 bit]<br />
|}<br />
<br />
== Compiling from source ==<br />
* [http://download.vcmi.eu/vcmi-0.91.tar.gz Packaged source]<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/README.linux Readme] (available in README.linux file in source package)<br />
<br />
= Installing Heroes III data files =<br />
To install VCMI you will need:<br />
* Heroes III: Shadow of Death or Complete edition<br />
* Unnoficial WoG addon: http://download.vcmi.eu/WoG/wog.zip<br />
* VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
== Automated install ==<br />
To install Heroes 3 data using automated script you need any of:<br />
* One or two CD's or CD images<br />
* gog.com installer<br />
* Directory with installed game<br />
<br />
Create temporary directory that will be used by script and go into it:<br />
<pre><br />
mkdir temp<br />
cd temp<br />
</pre><br />
Run the script using options appropriate to your input files:<br />
<pre><br />
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd --download<br />
vcmibuilder --gog /path/to/gog.com/installer --download<br />
vcmibuilder --data /path/to/h3/data --download<br />
</pre><br />
You should use only one of these commands.<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/bin/vcmi<br />
</pre><br />
<br />
Copy resulting files into your vcmi data directory:<br />
<pre><br />
cp -RTu vcmi /path/to/vcmi/data/directory<br />
</pre><br />
<br />
=== Offline install ===<br />
Normally vcmibuilder script will autodownload WoG and VCMI data packages. For offline install you need to download this packages manually and replace download switch with this:<br />
<pre><br />
vcmibuilder <h3 data commands> --wog /path/to/wog/archive --vcmi /path/to/vcmi/package<br />
</pre><br />
<br />
=== Fedora music support ===<br />
To have Music support on Fedora it is required to perform a additional step. Fedora doesn't provide Mp3 playback support natively due to patents applied on the Mp3 technique. The SDL_mixer package from the official Fedora repo is compiled without Mp3 support. Luckily this isn't a huge problem due to the filesystem API of VCMI. If you place ogg files in the Mp3 folder it'll use those files. So all you have to do is to convert the original Mp3 to OGG by yourself. Then copy them to the /Mp3 folder and remove the old .mp3 files with e.g. rm -rf *.mp3. You may use those tools for converting MP3 to OGG e.g.: Dirogg Bash Script http://freecode.com/projects/dirogg or the graphical program SoundConverter(sudo yum install soundconverter).<br />
<br />
== Manual install ==<br />
<br />
* Install Heroes III<br />
* Extract WoG addon http://download.vcmi.eu/WoG/wog.zip<br />
* Extract VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/games<br />
</pre><br />
Copy your data to data directory. This should result in directory structure similar to this:<br />
<pre><br />
/usr/share/vcmi/config/<br />
/usr/share/vcmi/Data/<br />
/usr/share/vcmi/Maps/<br />
/usr/share/vcmi/Mods/WoG/<br />
/usr/share/vcmi/Mods/vcmi/<br />
/usr/share/vcmi/Mp3/<br />
</pre><br />
<br />
= Launching game =<br />
To start the game type in console:<br />
<pre><br />
vcmiclient<br />
</pre><br />
VCMI should be also available via desktop environment menu or launcher (Games/Strategy/VCMI)<br />
= Reporting bugs =<br />
Report any issues with packages on our [http://bugs.vcmi.eu bugtracker] or post a message on [http://forum.vcmi.eu/index.php VCMI forums]<br />
In report please post:<br />
* used distributive, version and architecture (for example "Ubuntu 11.10 32 bit"). For distributives that use rolling releases please post versions of all used libraries (boost, ffmpeg, SDL)<br />
* console log as well as log files from ~/.vcmi<br />
* steps to reproduce bug</div>Towhttps://wiki.vcmi.eu/index.php?title=Installation_on_Linux&diff=1007Installation on Linux2013-02-03T00:15:27Z<p>Tow: /* Packages */</p>
<hr />
<div>VCMI requires data from original Heroes 3: Shadow of Death or Complete editions and from the WoG expansion pack. Data from native Linux version made by LOKI will not work.<br />
= Binaries installation =<br />
== Debian-based distributions ==<br />
Download and install package for your distribution. Install can be done using any GUI managers or using command line:<br />
<pre><br />
sudo dpkg -i downloaded_package.deb<br />
sudo apt-get -f install<br />
</pre><br />
Note: First command most probably will result in errors - this is normal behavior, all of them should be fixed by second one.<br />
=== Packages ===<br />
<br />
{|<br />
|'''Ubuntu 12.10 quantal'''<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~quantal1_amd64.deb 64 bit]<br />
|-<br />
|'''Ubuntu 12.04 precise'''<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~precise1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Wheezy'''<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~wheezy1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Sid'''<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_i386.deb 32 bit]<br />
|[http://download.vcmi.eu/vcmi_0.91~sid1_amd64.deb 64 bit]<br />
|}<br />
<br />
=== Other Debian-based distributions ===<br />
VCMI requires g++-4.5 and boost-1.46 which are unavailable on Debian Squeeze and Ubuntu 11.04 or lower.<br />
In order for VCMI to work on this system you'll need to install them first.<br />
== RPM-based distributions ==<br />
Download and install package for your distribution. There are two ways to install package along with all dependencies: <br />
<br />
Option A) Double-click the package. A package management window should appear with instructions to guide you through the process.<br />
<br />
Option B) Open a terminal window, and type <br />
<pre><br />
sudo rpm -i package_location_and_name(e.g. vcmi-0.89-1.fc16.x86_64.rpm)<br />
</pre><br />
=== Packages ===<br />
<br />
{|<br />
|'''Fedora 18'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.x86_64.rpm 64 bit]<br />
|}<br />
<br />
{|<br />
|'''Fedora 17'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.x86_64.rpm 64 bit]<br />
|}<br />
<br />
== Compiling from source ==<br />
* [https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi-0.91.tar.gz Packaged source]<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/README.linux Readme] (available in README.linux file in source package)<br />
<br />
= Installing Heroes III data files =<br />
To install VCMI you will need:<br />
* Heroes III: Shadow of Death or Complete edition<br />
* Unnoficial WoG addon: http://download.vcmi.eu/WoG/wog.zip<br />
* VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
== Automated install ==<br />
To install Heroes 3 data using automated script you need any of:<br />
* One or two CD's or CD images<br />
* gog.com installer<br />
* Directory with installed game<br />
<br />
Create temporary directory that will be used by script and go into it:<br />
<pre><br />
mkdir temp<br />
cd temp<br />
</pre><br />
Run the script using options appropriate to your input files:<br />
<pre><br />
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd --download<br />
vcmibuilder --gog /path/to/gog.com/installer --download<br />
vcmibuilder --data /path/to/h3/data --download<br />
</pre><br />
You should use only one of these commands.<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/bin/vcmi<br />
</pre><br />
<br />
Copy resulting files into your vcmi data directory:<br />
<pre><br />
cp -RTu vcmi /path/to/vcmi/data/directory<br />
</pre><br />
<br />
=== Offline install ===<br />
Normally vcmibuilder script will autodownload WoG and VCMI data packages. For offline install you need to download this packages manually and replace download switch with this:<br />
<pre><br />
vcmibuilder <h3 data commands> --wog /path/to/wog/archive --vcmi /path/to/vcmi/package<br />
</pre><br />
<br />
=== Fedora music support ===<br />
To have Music support on Fedora it is required to perform a additional step. Fedora doesn't provide Mp3 playback support natively due to patents applied on the Mp3 technique. The SDL_mixer package from the official Fedora repo is compiled without Mp3 support. Luckily this isn't a huge problem due to the filesystem API of VCMI. If you place ogg files in the Mp3 folder it'll use those files. So all you have to do is to convert the original Mp3 to OGG by yourself. Then copy them to the /Mp3 folder and remove the old .mp3 files with e.g. rm -rf *.mp3. You may use those tools for converting MP3 to OGG e.g.: Dirogg Bash Script http://freecode.com/projects/dirogg or the graphical program SoundConverter(sudo yum install soundconverter).<br />
<br />
== Manual install ==<br />
<br />
* Install Heroes III<br />
* Extract WoG addon http://download.vcmi.eu/WoG/wog.zip<br />
* Extract VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/games<br />
</pre><br />
Copy your data to data directory. This should result in directory structure similar to this:<br />
<pre><br />
/usr/share/vcmi/config/<br />
/usr/share/vcmi/Data/<br />
/usr/share/vcmi/Maps/<br />
/usr/share/vcmi/Mods/WoG/<br />
/usr/share/vcmi/Mods/vcmi/<br />
/usr/share/vcmi/Mp3/<br />
</pre><br />
<br />
= Launching game =<br />
To start the game type in console:<br />
<pre><br />
vcmiclient<br />
</pre><br />
VCMI should be also available via desktop environment menu or launcher (Games/Strategy/VCMI)<br />
= Reporting bugs =<br />
Report any issues with packages on our [http://bugs.vcmi.eu bugtracker] or post a message on [http://forum.vcmi.eu/index.php VCMI forums]<br />
In report please post:<br />
* used distributive, version and architecture (for example "Ubuntu 11.10 32 bit"). For distributives that use rolling releases please post versions of all used libraries (boost, ffmpeg, SDL)<br />
* console log as well as log files from ~/.vcmi<br />
* steps to reproduce bug</div>Towhttps://wiki.vcmi.eu/index.php?title=Installation_on_Linux&diff=1006Installation on Linux2013-02-03T00:10:24Z<p>Tow: /* Packages */</p>
<hr />
<div>VCMI requires data from original Heroes 3: Shadow of Death or Complete editions and from the WoG expansion pack. Data from native Linux version made by LOKI will not work.<br />
= Binaries installation =<br />
== Debian-based distributions ==<br />
Download and install package for your distribution. Install can be done using any GUI managers or using command line:<br />
<pre><br />
sudo dpkg -i downloaded_package.deb<br />
sudo apt-get -f install<br />
</pre><br />
Note: First command most probably will result in errors - this is normal behavior, all of them should be fixed by second one.<br />
=== Packages ===<br />
<br />
{|<br />
|'''Ubuntu 12.10 quantal'''<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~quantal1_i386.deb 32 bit]<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~quantal1_amd64.deb 64 bit]<br />
|-<br />
|'''Ubuntu 12.04 precise'''<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~precise1_i386.deb 32 bit]<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~precise1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Wheezy'''<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~wheezy1_i386.deb 32 bit]<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~wheezy1_amd64.deb 64 bit]<br />
|-<br />
|'''Debian Sid'''<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~sid1_i386.deb 32 bit]<br />
|[https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi_0.91~sid1_amd64.deb 64 bit]<br />
|}<br />
<br />
=== Other Debian-based distributions ===<br />
VCMI requires g++-4.5 and boost-1.46 which are unavailable on Debian Squeeze and Ubuntu 11.04 or lower.<br />
In order for VCMI to work on this system you'll need to install them first.<br />
== RPM-based distributions ==<br />
Download and install package for your distribution. There are two ways to install package along with all dependencies: <br />
<br />
Option A) Double-click the package. A package management window should appear with instructions to guide you through the process.<br />
<br />
Option B) Open a terminal window, and type <br />
<pre><br />
sudo rpm -i package_location_and_name(e.g. vcmi-0.89-1.fc16.x86_64.rpm)<br />
</pre><br />
=== Packages ===<br />
<br />
{|<br />
|'''Fedora 18'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc18.x86_64.rpm 64 bit]<br />
|}<br />
<br />
{|<br />
|'''Fedora 17'''<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.i686.rpm 32 bit]<br />
|[http://download.vcmi.eu/vcmi-0.9.1-2.fc17.x86_64.rpm 64 bit]<br />
|}<br />
<br />
== Compiling from source ==<br />
* [https://dl.dropbox.com/u/22372764/vcmi/packages/vcmi-0.91.tar.gz Packaged source]<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/README.linux Readme] (available in README.linux file in source package)<br />
<br />
= Installing Heroes III data files =<br />
To install VCMI you will need:<br />
* Heroes III: Shadow of Death or Complete edition<br />
* Unnoficial WoG addon: http://download.vcmi.eu/WoG/wog.zip<br />
* VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
== Automated install ==<br />
To install Heroes 3 data using automated script you need any of:<br />
* One or two CD's or CD images<br />
* gog.com installer<br />
* Directory with installed game<br />
<br />
Create temporary directory that will be used by script and go into it:<br />
<pre><br />
mkdir temp<br />
cd temp<br />
</pre><br />
Run the script using options appropriate to your input files:<br />
<pre><br />
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd --download<br />
vcmibuilder --gog /path/to/gog.com/installer --download<br />
vcmibuilder --data /path/to/h3/data --download<br />
</pre><br />
You should use only one of these commands.<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/bin/vcmi<br />
</pre><br />
<br />
Copy resulting files into your vcmi data directory:<br />
<pre><br />
cp -RTu vcmi /path/to/vcmi/data/directory<br />
</pre><br />
<br />
=== Offline install ===<br />
Normally vcmibuilder script will autodownload WoG and VCMI data packages. For offline install you need to download this packages manually and replace download switch with this:<br />
<pre><br />
vcmibuilder <h3 data commands> --wog /path/to/wog/archive --vcmi /path/to/vcmi/package<br />
</pre><br />
<br />
=== Fedora music support ===<br />
To have Music support on Fedora it is required to perform a additional step. Fedora doesn't provide Mp3 playback support natively due to patents applied on the Mp3 technique. The SDL_mixer package from the official Fedora repo is compiled without Mp3 support. Luckily this isn't a huge problem due to the filesystem API of VCMI. If you place ogg files in the Mp3 folder it'll use those files. So all you have to do is to convert the original Mp3 to OGG by yourself. Then copy them to the /Mp3 folder and remove the old .mp3 files with e.g. rm -rf *.mp3. You may use those tools for converting MP3 to OGG e.g.: Dirogg Bash Script http://freecode.com/projects/dirogg or the graphical program SoundConverter(sudo yum install soundconverter).<br />
<br />
== Manual install ==<br />
<br />
* Install Heroes III<br />
* Extract WoG addon http://download.vcmi.eu/WoG/wog.zip<br />
* Extract VCMI data files: https://dl.dropbox.com/u/22372764/vcmi/mods/core.zip<br />
<br />
Launch vcmiclient to determine data directory (output may differ)<br />
<pre><br />
$vcmiclient -v<br />
Starting... <br />
VCMI 0.91<br />
data directory: /usr/share/vcmi<br />
library directory: /usr/lib/vcmi<br />
binary directory: /usr/games<br />
</pre><br />
Copy your data to data directory. This should result in directory structure similar to this:<br />
<pre><br />
/usr/share/vcmi/config/<br />
/usr/share/vcmi/Data/<br />
/usr/share/vcmi/Maps/<br />
/usr/share/vcmi/Mods/WoG/<br />
/usr/share/vcmi/Mods/vcmi/<br />
/usr/share/vcmi/Mp3/<br />
</pre><br />
<br />
= Launching game =<br />
To start the game type in console:<br />
<pre><br />
vcmiclient<br />
</pre><br />
VCMI should be also available via desktop environment menu or launcher (Games/Strategy/VCMI)<br />
= Reporting bugs =<br />
Report any issues with packages on our [http://bugs.vcmi.eu bugtracker] or post a message on [http://forum.vcmi.eu/index.php VCMI forums]<br />
In report please post:<br />
* used distributive, version and architecture (for example "Ubuntu 11.10 32 bit"). For distributives that use rolling releases please post versions of all used libraries (boost, ffmpeg, SDL)<br />
* console log as well as log files from ~/.vcmi<br />
* steps to reproduce bug</div>Towhttps://wiki.vcmi.eu/index.php?title=Modding_guidelines&diff=981Modding guidelines2013-02-01T13:07:13Z<p>Tow: Uploaded mods to download.vcmi.eu</p>
<hr />
<div>= For players =<br />
== Installing mod ==<br />
To install mod unpack archive in <data directory>/Mods. This should result in such directory structure:<br />
<pre><br />
<data directory>/Mods/<name of mod>/mod.json<br />
</pre><br />
<br />
There is no need to activate newly installed mods.<br />
== List of currently available mods ==<br />
{|<br />
! Name !! Download URL !! Author<br />
|-<br />
! Cove town || [http://download.vcmi.eu/mods/cove.zip URL] || HotA Crew<br />
|-<br />
! New artifacts pack || [http://download.vcmi.eu/mods/witchking-arts.rar URL] || Witchking<br />
|-<br />
! High resolution main menu || [http://download.vcmi.eu/mods/new-menu.zip URL] || Dru<br />
|}<br />
<br />
== Managing mods ==<br />
To activate or deactivate mod open file '''<data dir>/config/modSettings.json'''. Set mod state to "false" for disabling it or to "true" for enabling.<br />
<br />
Note that removing mod from this list will not deactivate or remove mod from the game - any mods not present in this file will be considered by game as newly installed and will be (re-)inserted in this file on startup.<br />
<br />
To remove mod delete its folder (<data dir>/Mods/modname).<br />
== Notes ==<br />
* Data directory location is system-specific:<br />
** Windows : Same as your Heroes III directory<br />
** Unix-like : Inside home directory: '''~/.vcmi'''<br />
<br />
= For modders =<br />
== Creating mod ==<br />
To make your own mod you need to create subdirectory in '''<data dir>/Mods/''' with name that will be used as identifier for your mod.<br />
<br />
Main mod is file called '''mod.json''' and should be placed into main folder of your mod, e.g. '''Mods/myMod/mod.json'''<br />
<br />
All content of your mod should go into '''Content''' directory, e.g. '''Mods/myMod/Content/'''. In future it will be possible to replace this directory with single .zip archive.<br />
<br />
Example of how directory structure of your mod may look like:<br />
<pre><br />
Mods/<br />
myMod/<br />
mod.json<br />
Content/<br />
data/ - unorganized files, mostly bitmap images (.bmp, .png, .pcx)<br />
config/ - json configuration files<br />
maps/ - h3m maps added or modified by mod<br />
music/ - music files. Mp3 is fully supported, ogg may be added if needed<br />
sounds/ - sound files, in wav format.<br />
sprites/ - animation, image sets (H3 .def files or VCMI .json files)<br />
video/ - video files, .bik or .smk<br />
</pre><br />
<br />
== Creating mod file ==<br />
All VCMI configuration files use [http://en.wikipedia.org/wiki/Json JSON format] so you may want to familiarize yourself with it first.<br />
<br />
Mod.json is main file in your mod and must be present in any mod. This file contains basic description of your mod, dependencies or conflicting mods (if present), list of new content and so on.<br />
<br />
Minimalistic version of this file:<br />
<syntaxhighlight lang="javascript"><br />
{<br />
"name" : "My test mod",<br />
"description" : "My test mod that add a lot of useless stuff into the game"<br />
}<br />
</syntaxhighlight><br />
See [[Mod file Format]] for its full description.<br />
<br />
== Overriding graphical files from Heroes III ==<br />
<br />
Any graphical replacer mods fall under this category. In VCMI directory '''<mod name>/Content''' acts as mod-specific game root directory.<br />
So for example file '''<mod name>/Content/Data/AISHIELD.PNG''' will replace file with same name from '''H3Bitmap.lod''' game archive.<br />
<br />
Any other files can be replaced in exactly same way.<br />
<br />
Note that replacing files from archives requires placing them into specific location:<br />
<pre><br />
H3Bitmap.lod -> Data<br />
H3Sprite.lod -> Sprites<br />
Heroes3.snd -> Sounds<br />
Video.vid -> Video<br />
</pre><br />
This includes archives added by expansions (e.g. '''H3ab_bmp.lod''' uses same rules as '''H3Bitmap.lod''')<br />
<br />
=== Replacing .def animation files ===<br />
Heroes III uses custom format for storing animation: def files. These files are used to store all in-game animations as well as for some GUI elements like buttons and for icon sets.<br />
<br />
These files can be replaced by another def file but in some cases original format can't be used. This includes but not limited to:<br />
* Replacing one (or several) icons in set<br />
* Replacing animation with fully-colored 32-bit images<br />
<br />
In VCMI these animation files can also be replaced by json description of their content. See [[Animation Format]] for full description of this format.<br />
<br />
Example: replacing single icon<br />
<syntaxhighlight lang="javascript"><br />
{<br />
// List of replaced images<br />
"images" : <br />
[ // Index of replaced frame<br />
{ "frame" : 0, "file" : "HPS000KN.bmp"} <br />
//name of file that will be used as replacement<br />
]<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
"High resolution main menu" mod can be used as example of file replacer mod.<br />
== Mod with new content: Artifact ==<br />
TODO<br />
== Mod with new content: Creature ==<br />
TODO<br />
== Custom filesystem format. Porting Era Mod to VCMI ==<br />
TODO<br />
<br />
<br />
{{Modding}}</div>Towhttps://wiki.vcmi.eu/index.php?title=Main_Page&diff=980Main Page2013-02-01T13:06:16Z<p>Tow: /* Latest release */</p>
<hr />
<div>__NOTOC__<br />
= Welcome to VCMI Project Wiki =<br />
<br />
[[VCMI]] is an open-source project aiming to reimplement HMM3:WoG game engine, giving it new and extended possibilities.<br />
<br />
== Latest release ==<br />
Latest released version is <strong>0.91</strong>.<br />
* [http://forum.vcmi.eu/viewtopic.php?p=8314#8314 Information about build]<br />
* [http://forum.vcmi.eu/dload.php?action=download&id=27 Download link]<br />
<br />
== Documentation and guidelines for users ==<br />
* [[VCMI | General information about VCMI Project]]<br />
* [[Engine features | Engine features]]<br />
* [[Game mechanics]]<br />
* [[Bug reporting guidelines]]<br />
* [[Installation on Linux]]<br />
* [http://www.4shared.com/file/135714811/d0214227/vcmimanual.html Manual]<br />
* [http://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA List of implemented game items]<br />
* [[Modding guidelines]]<br />
<br />
== Documentation and guidelines for developers ==<br />
* [[How to build VCMI (Windows)]]<br />
* [[How to build VCMI (Linux)]]<br />
* [[How to build VCMI (OS X)]]<br />
* [[Code structure]]<br />
* [[Coding guidelines]]<br />
* [[TODO list]]<br />
<br />
Links for developers:<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ SVN]<br />
* [http://vcmi.svn.sourceforge.net/ SVN web browser]<br />
<br />
== VCMI Places ==<br />
* [http://forum.vcmi.eu/portal.php Portal]<br />
* [http://forum.vcmi.eu/ Forum]<br />
* [http://bugs.vcmi.eu/ Bugtracker]</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=915How to build VCMI (Windows)2013-01-24T20:29:44Z<p>Tow: /* Prerequisites */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries in version 1.51 or newer. You can build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple) or download precompiled binaries with installer from [http://www.boostpro.com/download boostpro.com]. <br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Feb 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_52_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.52.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_52_0"<br />
bootstrap<br />
.\b2<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_52_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_52_0.<br />
<br />
=== Obtaining precompiled binaries from Boostpro (only for VC10 users) === <br />
At the moment (December 2012) Boostpro doesn't provide binaries for Visual Studio 2012. <br />
<br />
If you use Visual Studio 2010 then you can use Boostpro Boost distribution. When installing make sure that following options are checked in the "Select Default Variants" screen:<br />
* Visual C++ 10.0<br />
* Multithreaded<br />
* Multithreaded debug<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=805How to build VCMI (Windows)2012-12-19T18:50:48Z<p>Tow: /* Obtaining precompiled binaries from Boostpro */</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries. You can build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple) or download precompiled binaries with installer from [http://www.boostpro.com/download boostpro.com]. Warning: Boost has to be in 1.46 version or newer!<br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Feb 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_52_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.52.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_52_0"<br />
bootstrap<br />
.\b2<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_52_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_52_0.<br />
<br />
=== Obtaining precompiled binaries from Boostpro (only for VC10 users) === <br />
At the moment (December 2012) Boostpro doesn't provide binaries for Visual Studio 2012. <br />
<br />
If you use Visual Studio 2010 then you can use Boostpro Boost distribution. When installing make sure that following options are checked in the "Select Default Variants" screen:<br />
* Visual C++ 10.0<br />
* Multithreaded<br />
* Multithreaded debug<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Windows)&diff=804How to build VCMI (Windows)2012-12-19T18:38:03Z<p>Tow: Update for new project files.</p>
<hr />
<div>= Prerequisites =<br />
* Installed Heroes3 (can be bought for $10 at [http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/ gog.com])<br />
* Installed WoG or ERA add-on over H3 ([http://download.vcmi.eu/WoG/WoG_Install.7z WoG Installer]).<br />
* IDE: Microsoft Visual C++ 2012 Express for Desktop. It can be downloaded for free from [http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop microsoft.com]. Higher editions of Visual Studio (Professional, Premium and Ultimate) are also supported. VCMI can be also built with GCC 4.5+, however since it's not covered in this tutorial, we strongly suggest using MSVC on Windows, unless you're an advanced developer (but then you wouldn't need this tutorial :]). <br />
* SVN Client: TortoiseSVN. Available (for free) at [http://tortoisesvn.net/downloads tortoisesvn.net].<br />
* Libraries pack: [http://download.vcmi.eu/msvc-pack.7z download.vcmi.eu]. It contains includes and pre-built binaries of several libraries VCMI uses. You DO NOT need to download them, they're in the pack. The libraries included are:<br />
** [http://www.libsdl.org/ SDL]<br />
** [http://www.libsdl.org/projects/SDL_image/ SDL_image]<br />
** [http://www.libsdl.org/projects/SDL_mixer SDL_mixer]<br />
** [http://www.libsdl.org/projects/SDL_ttf/ SDL_TTF]<br />
** [http://www.zlib.net/ zlib]<br />
* Boost libraries. You can build them on your own using sources from [http://www.boost.org/users/download/ boost.org] (it's very simple) or download precompiled binaries with installer from [http://www.boostpro.com/download boostpro.com]. Warning: Boost has to be in 1.46 version or newer!<br />
<br />
== For Visual Studio 2010 users ==<br />
Note: Visual Studio 2010 support is still present though deprecated (and expected to be dropped in Feb 2013). To use Visual Studio 2010 with project files from repository follow this tutorial with the following exceptions:<br />
* use VCMI_VS10.sln solution (not VCMI_VS11)<br />
* in the properties of all projects change Platform Toolset to Visual Studio 2010 (v100). <br />
* when building Boost replace msvc-11.0 with msvc-10.0<br />
<br />
= Preparing place =<br />
== Initial directory structure and libraries pack ==<br />
Create a directory for VCMI development, eg. C:\VCMI. Extract there libraries pack. It contains initial directory structure.<br />
<br />
== VCMI sources ==<br />
Libraries pack contains default subfolder for VCMI sources named trunk. Right click it and select SVN Checkout from context menu.<br />
<br />
[[File:trunk-menu.png|250px]]<br />
<br />
<br />
In the dialog type (or paste :]) https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ as URL of repository.<br />
<br />
[[File:Checkout.png|250px]]<br />
<br />
<br />
Hit OK and latest VCMI sources will be downloaded from the repository. Double click VCMI_VS11.sln file to open VCMI projects in Visual Studio.<br />
<br />
== Boost libraries ==<br />
<br />
=== Building from sources ===<br />
Boost libraries sources are distributed as an archive file containing single folder named like "boost_1_52_0". Let's assume that you've extracted the archive into C:\C++ folder.<br />
<br />
Instructions on how to build Boost are available in the [http://www.boost.org/doc/libs/release/more/getting_started/ libraries documentation]. As for 1.52.0 version it's as simple as typing in the '''Visual Studio Command Prompt''' (look for it in your Start menu) the following:<br />
<pre>cd "C:\C++\boost_1_52_0"<br />
bootstrap<br />
.\b2<br />
b2 address-model=32 --toolset=msvc-11.0 --stagedir=./stage32</pre><br />
<br />
If you want to build 64-bit version of VCMI issue also<br />
<pre>b2 address-model=64 --toolset=msvc-11.0 --stagedir=./stage64</pre><br />
<br />
When build is complete (it may take some time), there should exist folder C:\C++\boost_1_52_0\stage32\lib containing numerous *.lib files. It's your Boost '''library directory'''. Your Boost '''include directory''' will be C:\C++\boost_1_52_0.<br />
<br />
=== Obtaining precompiled binaries from Boostpro === <br />
At the moment (December 2012) Boostpro doesn't provide binaries for Visual Studio 2012. <br />
<br />
If you use Visual Studio 2010 then you can use Boostpro Boost distribution. When installing make sure that following options are checked in the "Select Default Variants" screen:<br />
* Visual C++ 10.0<br />
* Multithreaded<br />
* Multithreaded debug<br />
<br />
= Adjusting project files =<br />
== Adding Boost library folders ==<br />
All projects are aware of includes/ and libs/ directories in the main VCMI folder. Because libraries package uses them, the only remaining issue is giving IDE information where you have Boost library (the only library not included in the package).<br />
<br />
<br />
There are several alternative ways to do that:<br />
=== Global ===<br />
By following these steps, you'll enable Boost for all your projects in Visual Studio. If you wish to use Boost in your other projects without repeating this setup, this scenario is recommended. <br />
<br />
# Select "expert settings" mode (Tools -> Settings -> Expert Settings). This step may not be needed for Visual Studio editions other then Express.<br />
# Open Property Pages (View -> Property Pages).<br />
# In the property manager panel (that just showed up) expand any project and then expand any Win32 configuration within it (Debug or RD). It doesn't make any difference which project and configuration you'll pick, since they all share the one property sheet we're interested in.<br />
# Double click on Microsoft.Cpp.Win32.user (or r-click it -> Properties). Property window opens.<br />
# Select "VC++ Directories".<br />
# Click on "Include Directories" row. <br />
## A small button on the right appears. Click it and click on <Edit...>. <br />
## Click on "New Line" icon.<br />
## Click on "..." batton on the right of textbox that appeared.<br />
## Select your Boost '''include directory''' (eg. C:\C++\boost_1_47_0). Confirm with OK.<br />
## Check if your folder path correrctly appeared on the list. Click OK to save changes and dismiss window.<br />
# Click on "Library Directories" row. Repeat the steps described for "Include directories", just this time select Boost '''library directory''' (eg. C:\C++\boost_1_47_0\stage\lib). <br />
# Close the property page with OK.<br />
<br />
[[File:vc_dirs.png|250px]] [[File:include.png|250px]]<br />
<br />
=== For all VCMI projects ===<br />
Follow the instructions from previous section with one exception — in step 4. select VCMI_global property sheet.<br />
<br />
=== Individually per project ===<br />
Add Boost individually for each of the VCMI projects. This is not recommended, since it's most tiresome way.<br />
<br />
Open solution explorer. Right click on the project and select "Properties". Follow steps 5 — 8 from "Global" section. Repeat for each project.<br />
<br />
=== Put along with other libs ===<br />
Project files are pre-configured to use includes/ and libs/ subfolders (that are meant to be next to the trunk folder) during lookup for headers and libs. <br />
To make Boost visible to compiler, you can simply copy<br />
* all the boost .lib's (by default from boostfolder/boost_1_x_y/stage/lib) to the libs/ subfolder in your main VCMI directory <br />
* folder "boostfolder/boost_1_x_y/boost" to the includes/ subfolder. Be careful, you need to copy "boost" folder, not its contents!<br />
<br />
= Compiling =<br />
Now you should be able to successfully build VCMI. Select "Build solution" from "Build" menu or press F7. Wait until the compilation finishes.<br />
<br />
You should finally see <code class="inline">========== Build: 8 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========</code> message in the IDE output. Built VCMI binaries will be put in the solution folder (C:\VCMI\trunk in our example). If you want to run VCMI somewhere else, open each project properties and adjust "Output Directory" in "General Properties" tab.<br />
<br />
Remember that VCMI_client.exe, VCMI_client.dll and VCMI_server.exe need to be in the same directory and AI (GeniusAI.dll) must be in AI/ subfolder.<br />
<br />
= Running and debugging VCMI =<br />
After compilation you should have received new VCMI binaries in your trunk/ folder:<br />
* VCMI_client.exe<br />
* VCMI_server.exe<br />
* VCMI_lib.dll <br />
* GeniusAI.dll (in trunk/AI/ subfolder)<br />
* StupidAI.dll (in trunk/AI/ subfolder)<br />
<br />
== Running VCMI in a build place (recommended) ==<br />
=== VCMI files ===<br />
Extract package with latest VCMI release to the trunk folder. It contains some content (fonts, graphics, etc) that are not part of SVN repository.<br />
<strong>Do NOT overwrite</strong> anything. Files from repository are always most up-to-date and have priority over the ones released some time ago.<br />
If you overwrite any file from SVN you can always use Revert command from TortoiseSVN.<br />
<br />
=== H3 files ===<br />
VCMI needs files with content from H3.<br />
Copy:<br />
* From the game folder:<br />
** MP3 folder with its contents<br />
** binkw32.dll<br />
** smackw32.dll<br />
* From Data subfolder:<br />
** VIDEO.VID<br />
** Heroes3.snd<br />
** h3sprite.lod<br />
** h3bitmap.lod<br />
** H3ab_bmp.lod<br />
** H3ab_ahd.snd<br />
** H3ab_ahd.vid<br />
<br />
You'll also may want to copy some (or all) maps.<br />
<br />
VCMI should be smart enough to give meaningful error message when one of content files is missing. Check the console output or VCMI_client_log.txt if something goes wrong.<br />
<br />
=== Libraries ===<br />
Additionally, you need to copy all *.dll files from libraries pack (libs/x86) to the trunk folder (or your destination folder of choice).<br />
<br />
== Running VCMI in external folder ==<br />
Alternatively, you can simply replace binaries in existing VCMI installation with the ones you've built. <br />
In such case you should also replace .txt files in config/ directory with the ones from trunk (and any other relevant files that have changed in SVN).<br />
<br />
It's not very convenient because you need to copy files each time after build. To avoid that necessity you can change Output Directory in properties of all projects. Then binaries you built will be automatically put in the right place.<br />
However you would still need to remember about changes in config files. (Some script for copying them used as post-built event may be a good idea here)<br />
<br />
<br />
== Running / debugging VCMI from IDE ==<br />
Visual Studio offers several convenient commands to run / debug project. Before you can use them, you need to set Working Directory to <code class="inline">$(OutDir)</code> in project properties for VCMI_client.<br />
<br />
[[File:workingDir.png|250px]]<br />
<br />
Now you can start debugging by:<br />
* Using Start Debugging (F5) command - starts game with debugger attached<br />
* Using Step Over/Into (F10 or F11) command - starts game and stops at the beginning of main function, allowing line-by-line execution<br />
* Running VCMI normally and attaching debugger to its process<br />
<br />
To debug server, you need to attach to its process before it crashes; otherwise you will just see an information that server has crashed. No breakpoints in its code will be hit. However, in Visual Studio Professional or higher there is possibility to attach to server after is crashes.<br />
<br />
= Further help =<br />
If you need any further help, ask at [http://forum.vcmi.eu our forums].</div>Towhttps://wiki.vcmi.eu/index.php?title=MediaWiki:Geshi.css&diff=762MediaWiki:Geshi.css2012-12-14T00:14:10Z<p>Tow: </p>
<hr />
<div>/* CSS placed here will be applied to GeSHi syntax highlighting */<br />
<br />
div.mw-geshi {<br />
font-family: Monaco, Consolas, Courier, 'Courier New', sans-serif;<br />
padding: 1em;<br />
border: 1px dashed #2f6fab;<br />
color: #E0E0E0;<br />
background-color: black;<br />
line-height: 1.1em;<br />
}<br />
<br />
.cpp.source-cpp .de1, .cpp.source-cpp .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}<br />
.cpp.source-cpp {font-family:monospace;}<br />
.cpp.source-cpp .imp {font-weight: bold; color: red;}<br />
.cpp.source-cpp li, .cpp.source-cpp .li1 {font-weight: normal; vertical-align:top;}<br />
.cpp.source-cpp .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}<br />
.cpp.source-cpp .li2 {font-weight: bold; vertical-align:top;}<br />
.cpp.source-cpp .kw1 {color: #8080C0;}<br />
.cpp.source-cpp .kw2 {color: #8080C0;}<br />
.cpp.source-cpp .kw3 {color: #8080C0;}<br />
.cpp.source-cpp .kw4 {color: #8080C0;}<br />
.cpp.source-cpp .co1 {color: #666666;}<br />
.cpp.source-cpp .co2 {color: #339900;}<br />
.cpp.source-cpp .coMULTI {color: #ff0000; font-style: italic;}<br />
.cpp.source-cpp .es0 {color: #000099; font-weight: bold;}<br />
.cpp.source-cpp .es1 {color: #000099; font-weight: bold;}<br />
.cpp.source-cpp .es2 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es3 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es4 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es5 {color: #006699; font-weight: bold;}<br />
.cpp.source-cpp .br0 {color: #E0E0E0;}<br />
.cpp.source-cpp .sy0 {color: #E0E0E0;}<br />
.cpp.source-cpp .sy1 {color: #E0E0E0;}<br />
.cpp.source-cpp .sy2 {color: #E0E0E0;}<br />
.cpp.source-cpp .sy3 {color: #E0E0E0;}<br />
.cpp.source-cpp .sy4 {color: #E0E0E0;}<br />
.cpp.source-cpp .st0 {color: #60FF60;}<br />
.cpp.source-cpp .nu0 {color: #0000dd;}<br />
.cpp.source-cpp .nu6 {color: #208080;}<br />
.cpp.source-cpp .nu8 {color: #208080;}<br />
.cpp.source-cpp .nu12 {color: #208080;}<br />
.cpp.source-cpp .nu16 {color:#800080;}<br />
.cpp.source-cpp .nu17 {color:#800080;}<br />
.cpp.source-cpp .nu18 {color:#800080;}<br />
.cpp.source-cpp .nu19 {color:#800080;}<br />
.cpp.source-cpp .me1 {color: #E0E0E0;}<br />
.cpp.source-cpp .me2 {color: #E0E0E0;}<br />
.cpp.source-cpp .ln-xtra, .cpp.source-cpp li.ln-xtra, .cpp.source-cpp div.ln-xtra {background-color: #ffc;}<br />
.cpp.source-cpp span.xtra { display:block; }</div>Towhttps://wiki.vcmi.eu/index.php?title=MediaWiki:Geshi.css&diff=761MediaWiki:Geshi.css2012-12-14T00:11:51Z<p>Tow: </p>
<hr />
<div>/* CSS placed here will be applied to GeSHi syntax highlighting */<br />
<br />
div.mw-geshi {<br />
font-family: Monaco, Consolas, Courier, 'Courier New', sans-serif;<br />
padding: 1em;<br />
border: 1px dashed #2f6fab;<br />
color: white;<br />
background-color: black;<br />
line-height: 1.1em;<br />
}<br />
<br />
.cpp.source-cpp .de1, .cpp.source-cpp .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}<br />
.cpp.source-cpp {font-family:monospace;}<br />
.cpp.source-cpp .imp {font-weight: bold; color: red;}<br />
.cpp.source-cpp li, .cpp.source-cpp .li1 {font-weight: normal; vertical-align:top;}<br />
.cpp.source-cpp .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}<br />
.cpp.source-cpp .li2 {font-weight: bold; vertical-align:top;}<br />
.cpp.source-cpp .kw1 {color: #8080C0;}<br />
.cpp.source-cpp .kw2 {color: #8080C0;}<br />
.cpp.source-cpp .kw3 {color: #8080C0;}<br />
.cpp.source-cpp .kw4 {color: #8080C0;}<br />
.cpp.source-cpp .co1 {color: #666666;}<br />
.cpp.source-cpp .co2 {color: #339900;}<br />
.cpp.source-cpp .coMULTI {color: #ff0000; font-style: italic;}<br />
.cpp.source-cpp .es0 {color: #000099; font-weight: bold;}<br />
.cpp.source-cpp .es1 {color: #000099; font-weight: bold;}<br />
.cpp.source-cpp .es2 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es3 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es4 {color: #660099; font-weight: bold;}<br />
.cpp.source-cpp .es5 {color: #006699; font-weight: bold;}<br />
.cpp.source-cpp .br0 {color: #008000;}<br />
.cpp.source-cpp .sy0 {color: #008000;}<br />
.cpp.source-cpp .sy1 {color: #000080;}<br />
.cpp.source-cpp .sy2 {color: #000040;}<br />
.cpp.source-cpp .sy3 {color: #000040;}<br />
.cpp.source-cpp .sy4 {color: #008080;}<br />
.cpp.source-cpp .st0 {color: #60FF60;}<br />
.cpp.source-cpp .nu0 {color: #0000dd;}<br />
.cpp.source-cpp .nu6 {color: #208080;}<br />
.cpp.source-cpp .nu8 {color: #208080;}<br />
.cpp.source-cpp .nu12 {color: #208080;}<br />
.cpp.source-cpp .nu16 {color:#800080;}<br />
.cpp.source-cpp .nu17 {color:#800080;}<br />
.cpp.source-cpp .nu18 {color:#800080;}<br />
.cpp.source-cpp .nu19 {color:#800080;}<br />
.cpp.source-cpp .me1 {color: #007788;}<br />
.cpp.source-cpp .me2 {color: #007788;}<br />
.cpp.source-cpp .ln-xtra, .cpp.source-cpp li.ln-xtra, .cpp.source-cpp div.ln-xtra {background-color: #ffc;}<br />
.cpp.source-cpp span.xtra { display:block; }</div>Towhttps://wiki.vcmi.eu/index.php?title=MediaWiki:Geshi.css&diff=760MediaWiki:Geshi.css2012-12-14T00:07:36Z<p>Tow: </p>
<hr />
<div>/* CSS placed here will be applied to GeSHi syntax highlighting */<br />
<br />
div.mw-geshi {<br />
font-family: Monaco, Consolas, Courier, 'Courier New', sans-serif;<br />
padding: 1em;<br />
border: 1px dashed #2f6fab;<br />
color: white;<br />
background-color: black;<br />
line-height: 1.1em;<br />
}</div>Towhttps://wiki.vcmi.eu/index.php?title=MediaWiki:Geshi.css&diff=759MediaWiki:Geshi.css2012-12-14T00:07:07Z<p>Tow: </p>
<hr />
<div>/* CSS placed here will be applied to GeSHi syntax highlighting */<br />
<br />
div.mw-geshi {<br />
font-family: Monaco, Consolas, Courier, 'Courier New', sans-serif;<br />
padding: 1em;<br />
border: 1px dashed #2f6fab;<br />
/*color: black;*/<br />
background-color: black;<br />
line-height: 1.1em;<br />
}</div>Towhttps://wiki.vcmi.eu/index.php?title=MediaWiki:Geshi.css&diff=758MediaWiki:Geshi.css2012-12-14T00:02:49Z<p>Tow: Created page with "/* CSS placed here will be applied to GeSHi syntax highlighting */ div.mw-geshi { padding: 1em; margin: 1em 0; border: 1px dashed #2f6fab; background-color: #f9f9f9; }"</p>
<hr />
<div>/* CSS placed here will be applied to GeSHi syntax highlighting */<br />
<br />
div.mw-geshi {<br />
padding: 1em; <br />
margin: 1em 0; <br />
border: 1px dashed #2f6fab;<br />
background-color: #f9f9f9;<br />
}</div>Towhttps://wiki.vcmi.eu/index.php?title=Main_Page&diff=598Main Page2012-03-06T22:24:18Z<p>Tow: /* Latest release */</p>
<hr />
<div>__NOTOC__<br />
= Welcome to VCMI Project Wiki =<br />
<br />
[[VCMI]] is an open-source project aiming to reimplement HMM3:WoG game engine, giving it new and extended possibilities.<br />
<br />
== Latest release ==<br />
Latest released version is <strong>0.88</strong>.<br />
* [http://forum.vcmi.eu/viewtopic.php?p=6567 Information about build]<br />
* [http://forum.vcmi.eu/dload.php?action=download&id=24 Download link]<br />
<br />
== Documentation and guidelines for users ==<br />
* [[VCMI | General information about VCMI Project]]<br />
* [[Engine features | Engine features]]<br />
* [[Game mechanics]]<br />
* [[Bug reporting guidelines]]<br />
* [[Installation on Linux]]<br />
* [http://www.4shared.com/file/135714811/d0214227/vcmimanual.html Manual]<br />
* [http://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA List of implemented game items]<br />
<br />
== Documentation and guidelines for developers ==<br />
* [[How to build VCMI (Windows)]]<br />
* [[How to build VCMI (Linux)]]<br />
* [[Code structure]]<br />
* [[Coding guidelines]]<br />
* [[TODO list]]<br />
<br />
Links for developers:<br />
* [https://vcmi.svn.sourceforge.net/svnroot/vcmi/trunk/ SVN]<br />
* [http://vcmi.svn.sourceforge.net/ SVN web browser]<br />
<br />
== VCMI Places ==<br />
* [http://forum.vcmi.eu/portal.php Portal]<br />
* [http://forum.vcmi.eu/ Forum]<br />
* [http://bugs.vcmi.eu/ Bugtracker]</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=522Opis zadania — bitewne AI dla VCMI2011-12-23T14:45:00Z<p>Tow: /* Szarża na strzelców ("Kill bloody elves!") */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ("Pojedynek samurajów") ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ("Elf - kill the Dwarf!") ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ("Kill bloody elves!") ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 1000 ms (jedna sekunda) na przeprowadzenie fazy taktycznej.<br />
* 150 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
Jednocześnie zwracam uwagę, że przesunięcie jednostki w fazie taktycznej na studencie trwa ok. 80 ms, zaś rzucenie czaru ok 40 ms. Pozostałe wywołania powinny być wyraźnie szybsze. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
"Zerowy" termin: do końca 23 grudnia 2011. <br />
Pierwszy termin: do końca 30 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* '''Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?'''<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* '''Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej?''' <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* '''Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów?''' <br />
Tak, wizualizację bitwy można uruchomić dodając do parametrów odpalarki -v. Będzie działać pod warunkiem wgrania archiwów z grafikami. Rozegraną już bitwę także można zwizualizować, czemu służy plik duel_log.vdat. Umieśćcie go (pod jakąkolwiek nazwą) w folderze z odpalarką i wydajcie polecenie<br />
VCMI_client.exe -rbduel_log.vdat<br />
<br />
<br />
* '''Czy jednostki są rozstawiane na pozycjach początkowych automatycznie?''' <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* '''Jakie jednostki są dostępne dla każdego przypadku?''' <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
<br />
* '''Czy można korzystać ze specjalnych umiejętności jednostek?''' <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
<br />
* '''Co w przypadku, gdy wszyscy zginą?''' <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
<br />
* '''Czy są brane pod uwagę artefakty?''' <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
<br />
* '''Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI?''' <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
<br />
* '''Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami?''' <br />
Dostępne są przykładowe bitwy, którymi warto się zainteresować: http://vcmi.eu/pc/battles/<br />
Nie są to jednak bitwy identyczne z właściwymi testami — może się pojawić więcej jednostek (np. dwaj wrodzy strzelcy, z czego jeden słabowity i dla zmyłki) lub nieco innych typów.<br />
<br />
<br />
* '''Czy jest gdzieś dostępny opis tworzenia pliku bitwy?''' <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
<br />
* '''Jakie czary będą dostępne?''' <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
<br />
* '''Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony?''' <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
<br />
* '''Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie?''' <br />
Nie będzie posiadał.<br />
<br />
<br />
* '''Walka samurajów (kto pierwszy zada cios): wysterczy przecież poczekać aż podejdzie rywal i zadać mu cios?'''<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.<br />
<br />
<br />
* '''Czy jest możliwość sprawdzenia czy wróg jest już pod wpływem zaklęcia (np. przed rzuceniem następnego) ?'''<br />
Tak.<br />
Generalnie interesują nas dwie klasy:<br />
CSpell opisuje zaklęcie z punktu widzenia mechaniki. Jest globalnie dostępny wektor VLC->spellh->spells indeksowany po ID zaklęcia (p. namespace Spells) i można z jego pomocą sprawdzać parametry czaru o danym ID.<br />
Bonus to klasa... bardzo uniwersalna. W szczególności realizuje „bycie pod wpływem czaru”.<br />
<br />
Pobieranie czarów, pod których wpływem jest jednostka można zrobic na dwa sposoby.<br />
Prostszy — same ID:<br />
tlog0 << "Active spell IDs: ";<br />
BOOST_FOREACH(si32 spellID, firstEnemy->activeSpells())<br />
tlog0 << spellID << " ";<br />
tlog0 << std::endl;<br />
<br />
Sprytniejszy — ID oraz informacje dodatkowe:<br />
tlog0 << "Active spells:\n";<br />
BOOST_FOREACH(const Bonus *b, *firstEnemy->getSpellBonuses())<br />
{<br />
const CSpell *spellInfo = VLC->spellh->spells[b->sid];<br />
tlog0 << "Name=" << spellInfo->name << "\tID=" << b->sid <<"\tTurns remaining: " << b->turnsRemain << "\tPositive=" << (int)spellInfo->positiveness << std::endl;<br />
}<br />
tlog0 << std::endl;<br />
<br />
<br />
* '''battleGetAvailableHexes (const CStack *stack, bool addOccupiable, std::vector< THex > *attackable=NULL) - czym jest drugi i trzeci argument'''<br />
a) stack — oddział, dla którego dostępność pól jest liczona<br />
b) addOccupiable — czy dodać pola „zajmowalne”. Twój oddział może mieć dwa heksy szerokości. Jego pozycją jest pole „ku centrum” (prawe dla atakującego, lewe dla obrońcy). To drugie pole, na którym stoi tył jednostki, nazywane jest polem zajętym (zwraca je metoda occupiedHex). Jeżeli parametr addOccupiable jest ustawiony, to funkcja zwróci nie tylko pola, na których może stanąć przód jednostki, ale też pola, na których może się znaleźć jej tył. Jeżeli stack zajmuje jeden hex, wartość tego argumentu jest bez znaczenia. Aby sprawdzić, czy jednostka zajmuje dwa heksy można użyć wywołania stack->doubleWide() (zwraca prawdę dla dwuheksowców).<br />
c) wskaźnik na wektor pól. Jeżeli jest ustawiony (wołający musi taki wektor zapewnić), to funkcja wypełni go polami, które mogą być celami ataku. Są to pola, na których stoją wrogie jednostki (lub przynajmniej ich tyły), które przy tym znajdują się w zasięgu ruchu lub przylegają do niego (tak, że poprawna jest akcja WALK_AND_ATTACK). Jeżeli stack potrafi strzelać, to w tym wektorze umieszczone zostaną wszystkie pozycje wrogich jednostek (strzelać można na dowolną odległość).<br />
<br />
<br />
* '''battleGetDistances (const CStack *stack, THex hex=THex::INVALID, THex *predecessors=NULL) - co zwraca?'''<br />
Funkcja wykonuje BFS na polu bitwy — celem jest określenie odległości poszczególnych pól od naszego oddziału. Zwraca wektor liczący tyle elementów, ile jest pól. Tak więc battleGetDistances(stack)[70] to liczba pól, jakie oddział musi przejść, by dojść do heksa nr 70. Jeżeli odległość wynosi -1 to znaczy, że się obecnie nie da dojść na dane pole. Dwa opcjonalne parametry to heks, z którego nalezy rozpocząć poszukiwania (jesli inny od pozycji stacku) oraz wskaźnik na tablicę heksów (predecessors). Jeśli ten wskaźnik jest ustawiony, to musi pokazywć na tablicę obiektów THex liczącą przynajmniej BFIELD_SIZE elementów. Zostanie ona wypełniona poprzednikami, tj. predecessors[70] zawierać będzie nr poprzedniego heksa, który był odwiedzony przez BFS. W funkcji jest błąd — jej drugi parametr jest w istocie ignorowany! Jeśli chcecie liczyć odległości z heksa innego niż pozycja jednostki wykorzystajcie funkcję battleGetDistancesFromHex, która zachowuje się zgodnie z opisem wyżej (to takie battleGetDistances bez buga)!<br />
<br />
<br />
* '''Jakie współczynniki bierze pod uwagę battleEstimateDamage? Czy tylko obrażenia, czy również obronę, atak (w tym ich różnicę z odpowiednim do jej wartości współczynnikiem), coś jeszcze?'''<br />
Wszystkie wymienione współczynniki są uwzględnione. Funkcja w ogóle bierze pod uwagę wszystko za wyjątkiem efektów losowych lub zależnych od komendy. NIE uwzględnia:<br />
- premii za szarżę (5% za każde pole przejechane w drodze do ataku dla staków z hasBonusOfType(Bonus::JOUSTING) ),<br />
- szczęścia — i tak wyłączone w wyzwaniu,<br />
- losowo działających zdolności jednostek, jak np. death blow rycerza śmierci (szansa na podwójne obrażenia) — i tak wyłączone w wyzwaniu,<br />
- szansy na podwójne obrażenia balisty — nie dość, że wyłączone, to i tak nie dostaniecie balisty.<br />
<br />
<br />
* '''Czy jest jakaś funkcja, dzięki której automatycznie możemy się dowiedzieć, którą z kolei turę walki rozgrywamy?'''<br />
Nie, ale na początku każdej tury walki AI otrzymuje jej numer w argumencie funkcji battleNewRound.<br />
<br />
<br />
* '''W jaki sposob sprawdzic, czy CStack moze czekac, czy musi sie ruszyc?'''<br />
CStack może czekać tylko raz w turze. Aby sprawdzić, czy już czekał, można użyć konstrukcji:<br />
if(vstd::contains(stack->state, WAITING))<br />
...; //juz czekal, nie moze ponownie<br />
else<br />
...; //moze zaczekac jeszcze raz<br />
<br />
<br />
* '''Jak najlepiej wyciagnac liste dostepnych czarow? Iteracja battleCanCastThisSpell() po wszystkich czarach?'''<br />
Można tak, to jest najpewniejsza metoda — battleCanCastThisSpell sprawdza szereg warunków okolicznościowych, mogących zablokwoać rzucanie czaru (np. specjalny teren pola bitwy, artefakty blokujące magię lub jej część, itp.) lub umożliwiających rzucanie mimo braku znajomości czaru. Jeśli komuś bardzo zależy na szybkości, to można sprawdzać tylko czary o ID ze zbioru hero->spells (to „własna” księga czarów bohatera), choć w pewnych specyficznych przypadkach bohater może rzucać czary spoza tej listy (np. gdy ma artefakt typu Tome of Air).<br />
<br />
<br />
* '''Czy da sie estymowac obrazenia zadawane przez czary?'''<br />
Dodałem do callbacku metodę battleEstimateSpellDamage. Oprócz czarujacego bohatera i czaru, może przyjąć jako trzeci argument (opcjonalny) oddział, w który czarem chcemy rąbnąć (sprawdzi wtedy jego odporności). Można jej używać wg wzorca:<br />
int dmg = cb->battleEstimateSpellDamage(cb->battleGetFightingHero(side), VLC->spellh->spells[Spells::MAGIC_ARROW]);<br />
Metoda zwraca liczbę punktów obrażeń, jakie czar zapewne by wyrządził. Nie sprawdza jednak, czy bohater może rzucić ten czar.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=521Opis zadania — bitewne AI dla VCMI2011-12-23T01:01:23Z<p>Tow: /* Ogólne wymogi */ Limit czasowu -> 150 ms; rzucanie czaru na studencie trwa</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ("Pojedynek samurajów") ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ("Elf - kill the Dwarf!") ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ("Kill bloody elves!") ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 1000 ms (jedna sekunda) na przeprowadzenie fazy taktycznej.<br />
* 150 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
Jednocześnie zwracam uwagę, że przesunięcie jednostki w fazie taktycznej na studencie trwa ok. 80 ms, zaś rzucenie czaru ok 40 ms. Pozostałe wywołania powinny być wyraźnie szybsze. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
"Zerowy" termin: do końca 23 grudnia 2011. <br />
Pierwszy termin: do końca 30 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* '''Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?'''<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* '''Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej?''' <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* '''Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów?''' <br />
Tak, wizualizację bitwy można uruchomić dodając do parametrów odpalarki -v. Będzie działać pod warunkiem wgrania archiwów z grafikami. Rozegraną już bitwę także można zwizualizować, czemu służy plik duel_log.vdat. Umieśćcie go (pod jakąkolwiek nazwą) w folderze z odpalarką i wydajcie polecenie<br />
VCMI_client.exe -rbduel_log.vdat<br />
<br />
<br />
* '''Czy jednostki są rozstawiane na pozycjach początkowych automatycznie?''' <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* '''Jakie jednostki są dostępne dla każdego przypadku?''' <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
<br />
* '''Czy można korzystać ze specjalnych umiejętności jednostek?''' <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
<br />
* '''Co w przypadku, gdy wszyscy zginą?''' <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
<br />
* '''Czy są brane pod uwagę artefakty?''' <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
<br />
* '''Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI?''' <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
<br />
* '''Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami?''' <br />
Dostępne są przykładowe bitwy, którymi warto się zainteresować: http://vcmi.eu/pc/battles/<br />
Nie są to jednak bitwy identyczne z właściwymi testami — może się pojawić więcej jednostek (np. dwaj wrodzy strzelcy, z czego jeden słabowity i dla zmyłki) lub nieco innych typów.<br />
<br />
<br />
* '''Czy jest gdzieś dostępny opis tworzenia pliku bitwy?''' <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
<br />
* '''Jakie czary będą dostępne?''' <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
<br />
* '''Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony?''' <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
<br />
* '''Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie?''' <br />
Nie będzie posiadał.<br />
<br />
<br />
* '''Walka samurajów (kto pierwszy zada cios): wysterczy przecież poczekać aż podejdzie rywal i zadać mu cios?'''<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.<br />
<br />
<br />
* '''Czy jest możliwość sprawdzenia czy wróg jest już pod wpływem zaklęcia (np. przed rzuceniem następnego) ?'''<br />
Tak.<br />
Generalnie interesują nas dwie klasy:<br />
CSpell opisuje zaklęcie z punktu widzenia mechaniki. Jest globalnie dostępny wektor VLC->spellh->spells indeksowany po ID zaklęcia (p. namespace Spells) i można z jego pomocą sprawdzać parametry czaru o danym ID.<br />
Bonus to klasa... bardzo uniwersalna. W szczególności realizuje „bycie pod wpływem czaru”.<br />
<br />
Pobieranie czarów, pod których wpływem jest jednostka można zrobic na dwa sposoby.<br />
Prostszy — same ID:<br />
tlog0 << "Active spell IDs: ";<br />
BOOST_FOREACH(si32 spellID, firstEnemy->activeSpells())<br />
tlog0 << spellID << " ";<br />
tlog0 << std::endl;<br />
<br />
Sprytniejszy — ID oraz informacje dodatkowe:<br />
tlog0 << "Active spells:\n";<br />
BOOST_FOREACH(const Bonus *b, *firstEnemy->getSpellBonuses())<br />
{<br />
const CSpell *spellInfo = VLC->spellh->spells[b->sid];<br />
tlog0 << "Name=" << spellInfo->name << "\tID=" << b->sid <<"\tTurns remaining: " << b->turnsRemain << "\tPositive=" << (int)spellInfo->positiveness << std::endl;<br />
}<br />
tlog0 << std::endl;<br />
<br />
<br />
* '''battleGetAvailableHexes (const CStack *stack, bool addOccupiable, std::vector< THex > *attackable=NULL) - czym jest drugi i trzeci argument'''<br />
a) stack — oddział, dla którego dostępność pól jest liczona<br />
b) addOccupiable — czy dodać pola „zajmowalne”. Twój oddział może mieć dwa heksy szerokości. Jego pozycją jest pole „ku centrum” (prawe dla atakującego, lewe dla obrońcy). To drugie pole, na którym stoi tył jednostki, nazywane jest polem zajętym (zwraca je metoda occupiedHex). Jeżeli parametr addOccupiable jest ustawiony, to funkcja zwróci nie tylko pola, na których może stanąć przód jednostki, ale też pola, na których może się znaleźć jej tył. Jeżeli stack zajmuje jeden hex, wartość tego argumentu jest bez znaczenia. Aby sprawdzić, czy jednostka zajmuje dwa heksy można użyć wywołania stack->doubleWide() (zwraca prawdę dla dwuheksowców).<br />
c) wskaźnik na wektor pól. Jeżeli jest ustawiony (wołający musi taki wektor zapewnić), to funkcja wypełni go polami, które mogą być celami ataku. Są to pola, na których stoją wrogie jednostki (lub przynajmniej ich tyły), które przy tym znajdują się w zasięgu ruchu lub przylegają do niego (tak, że poprawna jest akcja WALK_AND_ATTACK). Jeżeli stack potrafi strzelać, to w tym wektorze umieszczone zostaną wszystkie pozycje wrogich jednostek (strzelać można na dowolną odległość).<br />
<br />
<br />
* '''battleGetDistances (const CStack *stack, THex hex=THex::INVALID, THex *predecessors=NULL) - co zwraca?'''<br />
Funkcja wykonuje BFS na polu bitwy — celem jest określenie odległości poszczególnych pól od naszego oddziału. Zwraca wektor liczący tyle elementów, ile jest pól. Tak więc battleGetDistances(stack)[70] to liczba pól, jakie oddział musi przejść, by dojść do heksa nr 70. Jeżeli odległość wynosi -1 to znaczy, że się obecnie nie da dojść na dane pole. Dwa opcjonalne parametry to heks, z którego nalezy rozpocząć poszukiwania (jesli inny od pozycji stacku) oraz wskaźnik na tablicę heksów (predecessors). Jeśli ten wskaźnik jest ustawiony, to musi pokazywć na tablicę obiektów THex liczącą przynajmniej BFIELD_SIZE elementów. Zostanie ona wypełniona poprzednikami, tj. predecessors[70] zawierać będzie nr poprzedniego heksa, który był odwiedzony przez BFS. W funkcji jest błąd — jej drugi parametr jest w istocie ignorowany! Jeśli chcecie liczyć odległości z heksa innego niż pozycja jednostki wykorzystajcie funkcję battleGetDistancesFromHex, która zachowuje się zgodnie z opisem wyżej (to takie battleGetDistances bez buga)!<br />
<br />
<br />
* '''Jakie współczynniki bierze pod uwagę battleEstimateDamage? Czy tylko obrażenia, czy również obronę, atak (w tym ich różnicę z odpowiednim do jej wartości współczynnikiem), coś jeszcze?'''<br />
Wszystkie wymienione współczynniki są uwzględnione. Funkcja w ogóle bierze pod uwagę wszystko za wyjątkiem efektów losowych lub zależnych od komendy. NIE uwzględnia:<br />
- premii za szarżę (5% za każde pole przejechane w drodze do ataku dla staków z hasBonusOfType(Bonus::JOUSTING) ),<br />
- szczęścia — i tak wyłączone w wyzwaniu,<br />
- losowo działających zdolności jednostek, jak np. death blow rycerza śmierci (szansa na podwójne obrażenia) — i tak wyłączone w wyzwaniu,<br />
- szansy na podwójne obrażenia balisty — nie dość, że wyłączone, to i tak nie dostaniecie balisty.<br />
<br />
<br />
* '''Czy jest jakaś funkcja, dzięki której automatycznie możemy się dowiedzieć, którą z kolei turę walki rozgrywamy?'''<br />
Nie, ale na początku każdej tury walki AI otrzymuje jej numer w argumencie funkcji battleNewRound.<br />
<br />
<br />
* '''W jaki sposob sprawdzic, czy CStack moze czekac, czy musi sie ruszyc?'''<br />
CStack może czekać tylko raz w turze. Aby sprawdzić, czy już czekał, można użyć konstrukcji:<br />
if(vstd::contains(stack->state, WAITING))<br />
...; //juz czekal, nie moze ponownie<br />
else<br />
...; //moze zaczekac jeszcze raz<br />
<br />
<br />
* '''Jak najlepiej wyciagnac liste dostepnych czarow? Iteracja battleCanCastThisSpell() po wszystkich czarach?'''<br />
Można tak, to jest najpewniejsza metoda — battleCanCastThisSpell sprawdza szereg warunków okolicznościowych, mogących zablokwoać rzucanie czaru (np. specjalny teren pola bitwy, artefakty blokujące magię lub jej część, itp.) lub umożliwiających rzucanie mimo braku znajomości czaru. Jeśli komuś bardzo zależy na szybkości, to można sprawdzać tylko czary o ID ze zbioru hero->spells (to „własna” księga czarów bohatera), choć w pewnych specyficznych przypadkach bohater może rzucać czary spoza tej listy (np. gdy ma artefakt typu Tome of Air).<br />
<br />
<br />
* '''Czy da sie estymowac obrazenia zadawane przez czary?'''<br />
Dodałem do callbacku metodę battleEstimateSpellDamage. Oprócz czarujacego bohatera i czaru, może przyjąć jako trzeci argument (opcjonalny) oddział, w który czarem chcemy rąbnąć (sprawdzi wtedy jego odporności). Można jej używać wg wzorca:<br />
int dmg = cb->battleEstimateSpellDamage(cb->battleGetFightingHero(side), VLC->spellh->spells[Spells::MAGIC_ARROW]);<br />
Metoda zwraca liczbę punktów obrażeń, jakie czar zapewne by wyrządził. Nie sprawdza jednak, czy bohater może rzucić ten czar.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=520Opis zadania — bitewne AI dla VCMI2011-12-23T00:57:48Z<p>Tow: /* FAQ */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ("Pojedynek samurajów") ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ("Elf - kill the Dwarf!") ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ("Kill bloody elves!") ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
"Zerowy" termin: do końca 23 grudnia 2011. <br />
Pierwszy termin: do końca 30 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* '''Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?'''<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* '''Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej?''' <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* '''Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów?''' <br />
Tak, wizualizację bitwy można uruchomić dodając do parametrów odpalarki -v. Będzie działać pod warunkiem wgrania archiwów z grafikami. Rozegraną już bitwę także można zwizualizować, czemu służy plik duel_log.vdat. Umieśćcie go (pod jakąkolwiek nazwą) w folderze z odpalarką i wydajcie polecenie<br />
VCMI_client.exe -rbduel_log.vdat<br />
<br />
<br />
* '''Czy jednostki są rozstawiane na pozycjach początkowych automatycznie?''' <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* '''Jakie jednostki są dostępne dla każdego przypadku?''' <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
<br />
* '''Czy można korzystać ze specjalnych umiejętności jednostek?''' <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
<br />
* '''Co w przypadku, gdy wszyscy zginą?''' <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
<br />
* '''Czy są brane pod uwagę artefakty?''' <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
<br />
* '''Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI?''' <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
<br />
* '''Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami?''' <br />
Dostępne są przykładowe bitwy, którymi warto się zainteresować: http://vcmi.eu/pc/battles/<br />
Nie są to jednak bitwy identyczne z właściwymi testami — może się pojawić więcej jednostek (np. dwaj wrodzy strzelcy, z czego jeden słabowity i dla zmyłki) lub nieco innych typów.<br />
<br />
<br />
* '''Czy jest gdzieś dostępny opis tworzenia pliku bitwy?''' <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
<br />
* '''Jakie czary będą dostępne?''' <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
<br />
* '''Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony?''' <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
<br />
* '''Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie?''' <br />
Nie będzie posiadał.<br />
<br />
<br />
* '''Walka samurajów (kto pierwszy zada cios): wysterczy przecież poczekać aż podejdzie rywal i zadać mu cios?'''<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.<br />
<br />
<br />
* '''Czy jest możliwość sprawdzenia czy wróg jest już pod wpływem zaklęcia (np. przed rzuceniem następnego) ?'''<br />
Tak.<br />
Generalnie interesują nas dwie klasy:<br />
CSpell opisuje zaklęcie z punktu widzenia mechaniki. Jest globalnie dostępny wektor VLC->spellh->spells indeksowany po ID zaklęcia (p. namespace Spells) i można z jego pomocą sprawdzać parametry czaru o danym ID.<br />
Bonus to klasa... bardzo uniwersalna. W szczególności realizuje „bycie pod wpływem czaru”.<br />
<br />
Pobieranie czarów, pod których wpływem jest jednostka można zrobic na dwa sposoby.<br />
Prostszy — same ID:<br />
tlog0 << "Active spell IDs: ";<br />
BOOST_FOREACH(si32 spellID, firstEnemy->activeSpells())<br />
tlog0 << spellID << " ";<br />
tlog0 << std::endl;<br />
<br />
Sprytniejszy — ID oraz informacje dodatkowe:<br />
tlog0 << "Active spells:\n";<br />
BOOST_FOREACH(const Bonus *b, *firstEnemy->getSpellBonuses())<br />
{<br />
const CSpell *spellInfo = VLC->spellh->spells[b->sid];<br />
tlog0 << "Name=" << spellInfo->name << "\tID=" << b->sid <<"\tTurns remaining: " << b->turnsRemain << "\tPositive=" << (int)spellInfo->positiveness << std::endl;<br />
}<br />
tlog0 << std::endl;<br />
<br />
<br />
* '''battleGetAvailableHexes (const CStack *stack, bool addOccupiable, std::vector< THex > *attackable=NULL) - czym jest drugi i trzeci argument'''<br />
a) stack — oddział, dla którego dostępność pól jest liczona<br />
b) addOccupiable — czy dodać pola „zajmowalne”. Twój oddział może mieć dwa heksy szerokości. Jego pozycją jest pole „ku centrum” (prawe dla atakującego, lewe dla obrońcy). To drugie pole, na którym stoi tył jednostki, nazywane jest polem zajętym (zwraca je metoda occupiedHex). Jeżeli parametr addOccupiable jest ustawiony, to funkcja zwróci nie tylko pola, na których może stanąć przód jednostki, ale też pola, na których może się znaleźć jej tył. Jeżeli stack zajmuje jeden hex, wartość tego argumentu jest bez znaczenia. Aby sprawdzić, czy jednostka zajmuje dwa heksy można użyć wywołania stack->doubleWide() (zwraca prawdę dla dwuheksowców).<br />
c) wskaźnik na wektor pól. Jeżeli jest ustawiony (wołający musi taki wektor zapewnić), to funkcja wypełni go polami, które mogą być celami ataku. Są to pola, na których stoją wrogie jednostki (lub przynajmniej ich tyły), które przy tym znajdują się w zasięgu ruchu lub przylegają do niego (tak, że poprawna jest akcja WALK_AND_ATTACK). Jeżeli stack potrafi strzelać, to w tym wektorze umieszczone zostaną wszystkie pozycje wrogich jednostek (strzelać można na dowolną odległość).<br />
<br />
<br />
* '''battleGetDistances (const CStack *stack, THex hex=THex::INVALID, THex *predecessors=NULL) - co zwraca?'''<br />
Funkcja wykonuje BFS na polu bitwy — celem jest określenie odległości poszczególnych pól od naszego oddziału. Zwraca wektor liczący tyle elementów, ile jest pól. Tak więc battleGetDistances(stack)[70] to liczba pól, jakie oddział musi przejść, by dojść do heksa nr 70. Jeżeli odległość wynosi -1 to znaczy, że się obecnie nie da dojść na dane pole. Dwa opcjonalne parametry to heks, z którego nalezy rozpocząć poszukiwania (jesli inny od pozycji stacku) oraz wskaźnik na tablicę heksów (predecessors). Jeśli ten wskaźnik jest ustawiony, to musi pokazywć na tablicę obiektów THex liczącą przynajmniej BFIELD_SIZE elementów. Zostanie ona wypełniona poprzednikami, tj. predecessors[70] zawierać będzie nr poprzedniego heksa, który był odwiedzony przez BFS. W funkcji jest błąd — jej drugi parametr jest w istocie ignorowany! Jeśli chcecie liczyć odległości z heksa innego niż pozycja jednostki wykorzystajcie funkcję battleGetDistancesFromHex, która zachowuje się zgodnie z opisem wyżej (to takie battleGetDistances bez buga)!<br />
<br />
<br />
* '''Jakie współczynniki bierze pod uwagę battleEstimateDamage? Czy tylko obrażenia, czy również obronę, atak (w tym ich różnicę z odpowiednim do jej wartości współczynnikiem), coś jeszcze?'''<br />
Wszystkie wymienione współczynniki są uwzględnione. Funkcja w ogóle bierze pod uwagę wszystko za wyjątkiem efektów losowych lub zależnych od komendy. NIE uwzględnia:<br />
- premii za szarżę (5% za każde pole przejechane w drodze do ataku dla staków z hasBonusOfType(Bonus::JOUSTING) ),<br />
- szczęścia — i tak wyłączone w wyzwaniu,<br />
- losowo działających zdolności jednostek, jak np. death blow rycerza śmierci (szansa na podwójne obrażenia) — i tak wyłączone w wyzwaniu,<br />
- szansy na podwójne obrażenia balisty — nie dość, że wyłączone, to i tak nie dostaniecie balisty.<br />
<br />
<br />
* '''Czy jest jakaś funkcja, dzięki której automatycznie możemy się dowiedzieć, którą z kolei turę walki rozgrywamy?'''<br />
Nie, ale na początku każdej tury walki AI otrzymuje jej numer w argumencie funkcji battleNewRound.<br />
<br />
<br />
* '''W jaki sposob sprawdzic, czy CStack moze czekac, czy musi sie ruszyc?'''<br />
CStack może czekać tylko raz w turze. Aby sprawdzić, czy już czekał, można użyć konstrukcji:<br />
if(vstd::contains(stack->state, WAITING))<br />
...; //juz czekal, nie moze ponownie<br />
else<br />
...; //moze zaczekac jeszcze raz<br />
<br />
<br />
* '''Jak najlepiej wyciagnac liste dostepnych czarow? Iteracja battleCanCastThisSpell() po wszystkich czarach?'''<br />
Można tak, to jest najpewniejsza metoda — battleCanCastThisSpell sprawdza szereg warunków okolicznościowych, mogących zablokwoać rzucanie czaru (np. specjalny teren pola bitwy, artefakty blokujące magię lub jej część, itp.) lub umożliwiających rzucanie mimo braku znajomości czaru. Jeśli komuś bardzo zależy na szybkości, to można sprawdzać tylko czary o ID ze zbioru hero->spells (to „własna” księga czarów bohatera), choć w pewnych specyficznych przypadkach bohater może rzucać czary spoza tej listy (np. gdy ma artefakt typu Tome of Air).<br />
<br />
<br />
* '''Czy da sie estymowac obrazenia zadawane przez czary?'''<br />
Dodałem do callbacku metodę battleEstimateSpellDamage. Oprócz czarujacego bohatera i czaru, może przyjąć jako trzeci argument (opcjonalny) oddział, w który czarem chcemy rąbnąć (sprawdzi wtedy jego odporności). Można jej używać wg wzorca:<br />
int dmg = cb->battleEstimateSpellDamage(cb->battleGetFightingHero(side), VLC->spellh->spells[Spells::MAGIC_ARROW]);<br />
Metoda zwraca liczbę punktów obrażeń, jakie czar zapewne by wyrządził. Nie sprawdza jednak, czy bohater może rzucić ten czar.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=487Opis zadania — bitewne AI dla VCMI2011-12-12T00:26:04Z<p>Tow: /* FAQ */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej? <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów? <br />
Tak, wizualizację bitwy można uruchomić dodając do parametrów odpalarki -v. Będzie działać pod warunkiem wgrania archiwów z grafikami. Rozegraną już bitwę także można zwizualizować, czemu służy plik duel_log.vdat. Umieśćcie go (pod jakąkolwiek nazwą) w folderze z odpalarką i wydajcie polecenie<br />
VCMI_client.exe -rbduel_log.vdat<br />
<br />
<br />
* Czy jednostki są rozstawiane na pozycjach początkowych automatycznie? <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* Jakie jednostki są dostępne dla każdego przypadku? <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
<br />
* Czy można korzystać ze specjalnych umiejętności jednostek? <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
<br />
* Co w przypadku, gdy wszyscy zginą? <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
<br />
* Czy są brane pod uwagę artefakty? <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
<br />
* Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI? <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
<br />
* Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami? <br />
Dostępne są przykładowe bitwy, którymi warto się zainteresować: http://vcmi.eu/pc/battles/<br />
Nie są to jednak bitwy identyczne z właściwymi testami — może się pojawić więcej jednostek (np. dwaj wrodzy strzelcy, z czego jeden słabowity i dla zmyłki) lub nieco innych typów.<br />
<br />
<br />
* Czy jest gdzieś dostępny opis tworzenia pliku bitwy? <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
<br />
* Jakie czary będą dostępne? <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
<br />
* Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony? <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
<br />
* Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie? <br />
Nie będzie posiadał.<br />
<br />
<br />
* Walka kto pierwszy zada cios: czy można wymusić, że jednostka MUSI się ruszyć lub zaatakować? (w przeciwnym razie wygrywająca jest strategia: czekam bez ruchu, aż podejdzie do mnie rywal, wtedy zadaję cios).<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=486Opis zadania — bitewne AI dla VCMI2011-12-11T15:26:56Z<p>Tow: /* FAQ */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej? <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów? <br />
TBD<br />
<br />
<br />
* Czy jednostki są rozstawiane na pozycjach początkowych automatycznie? <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* Jakie jednostki są dostępne dla każdego przypadku? <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
<br />
* Czy można korzystać ze specjalnych umiejętności jednostek? <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
<br />
* Co w przypadku, gdy wszyscy zginą? <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
<br />
* Czy są brane pod uwagę artefakty? <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
<br />
* Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI? <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
<br />
* Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami? <br />
Dostępne są przykładowe bitwy, którymi warto się zainteresować: http://vcmi.eu/pc/battles/<br />
Nie są to jednak bitwy identyczne z właściwymi testami — może się pojawić więcej jednostek (np. dwaj wrodzy strzelcy, z czego jeden słabowity i dla zmyłki) lub nieco innych typów.<br />
<br />
<br />
* Czy jest gdzieś dostępny opis tworzenia pliku bitwy? <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
<br />
* Jakie czary będą dostępne? <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
<br />
* Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony? <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
<br />
* Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie? <br />
Nie będzie posiadał.<br />
<br />
<br />
* Walka kto pierwszy zada cios: czy można wymusić, że jednostka MUSI się ruszyć lub zaatakować? (w przeciwnym razie wygrywająca jest strategia: czekam bez ruchu, aż podejdzie do mnie rywal, wtedy zadaję cios).<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=485Opis zadania — bitewne AI dla VCMI2011-12-11T15:24:26Z<p>Tow: /* FAQ */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* Co to są te fazy? I czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?<br />
Faza to tylko pomocniczy termin opisujący część procesu oceniania (testowania). AI będzie musiało stoczyć sześć lub siedem bitew. Są one kompletnie niezależne od siebie.<br />
<br />
Pierwsze pięć bitew to będą dość proste układy, dla których istnieje wyraźna strategia wygrywająca (jedna lub więcej). Naiwna strategia prowadzi do porażki, sprytna do łatwego zwycięstwa. Strategie [[#Strategie_wymagane_w_pierwszej_fazie|są opisane na wiki]], AI musi „znać” je wszystkie i potrafić ocenić, którą należy stosować (przy czym generalnie one są w znacznej mierze niewykluczające wzajemnie). Za zwycięstwo w każdej z tych pięciu bitew AI otrzymuje po punkcie. Za porażkę — nic. Rozegranie tych pięciu bitew to pierwsza faza testów.<br />
<br />
Druga faza zawiera tylko jedną, szóstą z kolei bitwę. Składa się na nią duży, skomplikowany układ. Dwie liczne armie stają naprzeciw siebie. Oceniany jest tutaj nie tylko sam fakt zwycięstwa, ale także poniesione straty. Jeśli AI rozgromi wroga, otrzyma trzy punkty. Jeśli wygra ledwo-ledwo — jeden punkt.<br />
<br />
Trzecia faza to turniej między najlepszymi AI. Przebieg tych rozgrywek zostanie określony, gdy już będzie wiadomo, ile tych AI. Odbędzie się po ocenie pozostałych bitew, a możliwe, że nawet po drugim terminie wyzwania.<br />
<br />
<br />
* Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej? <br />
Czary możemy generalnie podzielić na efekty natychmiastowe oraz długotrwałe uroki. Czar natychmiastowy, to np. błyskawica — we wroga uderza grom z jasnego nieba, niosący obrażenia. Nie ma tu mowy o trwaniu.<br />
Natomiast jeśli idzie o uroki (czary typu spowolnienie, błogosławieństwo, itp.) to trwają one tyle tur, ile wynosi siła czarów bohatera.<br />
Wartość siły czarów bohatera można sprawdzić instrukcją:<br />
if(const CGHeroInstance *h = cb->battleGetFightingHero(side)) //mamy bohatera<br />
h->getPrimSkillLevel(PrimarySkill::SPELL_POWER) //pytamy o jego siłę czarów<br />
<br />
<br />
* Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów? <br />
TBD<br />
<br />
* Czy jednostki są rozstawiane na pozycjach początkowych automatycznie? <br />
Tak. Gdy AI otrzymuje wywołanie battleStart, każdy z oddziałów stoi już na swoim początkowym polu (p. CStack::position).<br />
<br />
<br />
* Jakie jednostki są dostępne dla każdego przypadku? <br />
Nie jest to określone. AI nie powinna się nastawiać na żadne konkretne jednostki, a raczej samodzielnie je klasyfikować. <br />
<br />
* Czy można korzystać ze specjalnych umiejętności jednostek? <br />
Tak. O ile działają. :P<br />
Inna sprawa, że akurat nieszczególnie warto sobie tym zaprzątać głowę, raczej za dużo tych umiejętności się nie pojawi. Wiele z nich zresztą funkcjonuje bez żadnej ingerencji ze strony AI (podwójny atak np. sam się wykonuje podwójnie, AI nie ma zlecać drugiej akcji).<br />
<br />
* Co w przypadku, gdy wszyscy zginą? <br />
Zupełnie wszyscy na polu bitwy? Wtedy jest remis, AI nie otrzymuje punktów (wymagane jest zwycięstwo). Zresztą, gdy wszyscy już zginą, to co taka sytuacja obchodzi AI? Po wszystkim przecież.<br />
Inna sprawa, że taka sytuacja raczej się nie zdarzy, może być jedynie skutkiem masowych czarów ofensywnych, które raczej nie pojawią się w zestawach testowych.<br />
<br />
* Czy są brane pod uwagę artefakty? <br />
Są, ale AI to w ogóle nie powinno się tym interesować. Wszystkie premie pochodzące z artefaktów są widoczne u bohatera i jego oddziałów.<br />
<br />
Przykładowo, jeśli bohater ma czarodziejski łuk, który sprawia że strzelcy nie ponoszą kary za odległość strzału, to AI nie musi sprawdzać listy artefaktów bohatera. Premia ta przechodzi na bohatera i wszystkie jego oddziały. Tak więc wywołanie CBattleInfoCallback::battleHasDistancePenalty da zawsze poprawną odpowiedź, uwzględniającą artefakty. Podobnie jest z innymi efektami artefaktów.<br />
<br />
* Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI? <br />
Nie wykluczam jakichś drobnych poprawek, ale zasadniczo tak. Wróg będzie głupi, jego siła będzie tkwić... w sile.<br />
<br />
* Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami? <br />
Nie w pierwszym terminie.<br />
<br />
* Czy jest gdzieś dostępny opis tworzenia pliku bitwy? <br />
[[#Plik_JSON_z_bitw.C4.85|Opis został dodany.]]<br />
<br />
* Jakie czary będą dostępne? <br />
Wystarczające do zdobycia punktów będzie wykorzystanie czarów wymienionych w opisie strategii. Nie znaczy to, że pojawią się wszystkie te czary, ani że pojawią się tylko te czary.<br />
<br />
* Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony? <br />
Nie można. Bohater jest określony w pliku z bitwą.<br />
<br />
* Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie? <br />
Nie będzie posiadał.<br />
<br />
* Walka kto pierwszy zada cios: czy można wymusić, że jednostka MUSI się ruszyć lub zaatakować? (w przeciwnym razie wygrywająca jest strategia: czekam bez ruchu, aż podejdzie do mnie rywal, wtedy zadaję cios).<br />
Jednostka może odłożyć ruch na później (wait, raz w turze) lub zrezygnować z ruchu (defend). Strategia właśnie na tym polega — trzeba zaczekać aż wróg podejdzie i wtedy zadać cios.</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=484Opis zadania — bitewne AI dla VCMI2011-12-11T15:14:59Z<p>Tow: </p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread<br />
<br />
= FAQ =<br />
* Co to są te fazy? <br />
* Czy te strategie jakie zastosuję (którą) to wybieram ja w AI czy gra?<br />
* Czy działanie czaru jednostka odczuwa w trakcie jednej tury, czy może on trwać dłużej? <br />
* Czy istnieje łatwa metoda na wizualizację bitwy na żywo, lub na podstawie logów? <br />
* Czy jednostki są rozstawiane na pozycjach początkowych automatycznie? <br />
* Jakie jednostki są dostępne dla każdego przypadku? Czy można korzystać ze specjalnych umiejętności jednostek? <br />
* Co w przypadku, gdy wszyscy zginą? <br />
* Czy są brane pod uwagę artefakty? <br />
* Czy walczyć będziemy z przeciwnikiem sterowanym StupidAI? <br />
* Czy dostaniemy pliki *.json bitew, które są naszymi zadaniami? <br />
* Czy jest gdzieś dostępny opis tworzenia pliku bitwy? <br />
* Jakie czary będą dostępne? <br />
* Czy można wybrać bohatera (specjalność, umiejętności) czy jest z góry określony? <br />
* Czy bohater będzie posiadał machiny wojenne, a jeśli tak, to jakie? <br />
* Walka kto pierwszy zada cios: czy można wymusić, że jednostka MUSI się ruszyć lub zaatakować? (w przeciwnym razie wygrywająca jest strategia: czekam bez ruchu, aż podejdzie do mnie rywal, wtedy zadaję cios).</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=483Opis zadania — bitewne AI dla VCMI2011-12-11T12:45:18Z<p>Tow: /* Mistrz taktyki */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze. Strzelec zaś, gdy przyjdzie jego czas, powinien uderzyć najgroźniejszego wroga.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=482Opis zadania — bitewne AI dla VCMI2011-12-11T12:44:40Z<p>Tow: /* Czarodziej */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
Do przejścia tego testu wystarczy wspomaganie swoich oddziałów czarami i osłabianie nimi wrogów. Przydadzą się także zasady sterowania oddziałami z pozostałych scenariuszy taktycznych.<br />
Poza czarami wymienionymi w pozostałych taktykach, warto wesprzeć:<br />
* Bless/Curse — jednostka zadaje maksymalne/minimalne obrażenia. Efektywne względem jednostek o dużym „rozrzucie” zadawanych obrażeń.<br />
* czary ofensywne: magic arrow, ice bolt, lightening bolt, implosion — działają dość identycznie: zadają wrogowi obrażenia.<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=481Opis zadania — bitewne AI dla VCMI2011-12-11T12:36:10Z<p>Tow: /* Jak AI komunikuje się z grą */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|fazy taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
TBA<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=480Opis zadania — bitewne AI dla VCMI2011-12-11T12:35:43Z<p>Tow: /* Jak AI komunikuje się z grą */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie [[#Faza_taktyczna fazy|taktycznej]]. P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
TBA<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=479Opis zadania — bitewne AI dla VCMI2011-12-11T12:34:26Z<p>Tow: /* Faza taktyczna */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie fazy taktycznej (niestosowanej w ramach Wyzwania). P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
TBA<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=478Opis zadania — bitewne AI dla VCMI2011-12-11T12:34:17Z<p>Tow: /* Informacje szczegółowe */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie fazy taktycznej (niestosowanej w ramach Wyzwania). P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Faza taktyczna ==<br />
Jeżeli jeden z bohaterów ma lepiej rozwiniętą zdolność drugorzędna „taktyka” od rywala, ma możliwość ustawienia swoich oddziałów przed rozpoczęciem bitwy.<br />
<br />
AI otrzymuje wywołanie metody yourTacticPhase. Wewnątrz tej funkcji może robić wywołania cb->battleMakeTacticAction. Dozwolone akcje to zakończenie taktyki oraz przesunięcie jednostki. Parametrem yourTacticPhase jest int distance — określa szerokość pasu dostępnych pól (liczone od skrajnej kolumny heksów po stronie gracza z taktyką).<br />
<br />
Po wykonaniu wszystkich przesunięć jednostek, należy zgłosić zakończenie fazy taktycznej — wywołać battleMakeTacticAction z akcją typu END_TACTIC_PHASE (warto wykorzystać pomocniczą funkcjęBattleAction::makeEndOFTacticPhase).<br />
<br />
<br />
<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
TBA<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Towhttps://wiki.vcmi.eu/index.php?title=Opis_zadania_%E2%80%94_bitewne_AI_dla_VCMI&diff=477Opis zadania — bitewne AI dla VCMI2011-12-11T11:29:31Z<p>Tow: /* Zwinny strzelec */</p>
<hr />
<div>Przebieg bitwy - jak to wygląda od strony AI<br />
<br />
<blockquote><font size="tiny" color="black">Lasciate ogni speranza, voi ch'entrate.</font></blockquote><br />
<br />
= Informacje ogólne =<br />
== Zadanie ==<br />
Przedmiotem zadania jest napisanie programu, który będzie sterował graczem w czasie bitwy w otwartej reimplementacji Heroesa 3 — [[VCMI]]. Sprowadza się to do napisania w języku C++ dynamicznie ładowanej biblioteki (zależnie od platformy .dll bądź .so), zawierającej klasę implementującą interfejs dla AI.<br />
<br />
== Skrótowy opis bitwy ==<br />
Uwaga: opis w tej sekcji jest mocno uproszczony. Ma za zadanie wprowadzić do zadania i wyrobić podstawowe intuicje, uszczegółowiony jest przez reguły zawarte dalej. W razie rozbieżności, to one są decydujące.<br />
<br />
=== Podstawy ===<br />
Bitwa toczona jest pomiędzy dwiema armiami, które zaczynają rozstawione po przeciwległych krańcach planszy. Armia może (choć nie musi) być dowodzona przez bohatera. Gracza „lewego” nazywamy „atakującym”, „prawego” zaś „broniącym się”. Armia składa się z oddziałów (jednostek) — każdy oddział jest charakteryzowany przez typ (np. pikinier albo czerwony smok) oraz liczebność. Dodatkowo każda jednostka posiada szereg zmiennych współczynników opisujących jej parametry bojowe, do najważniejszych zaliczają się:<br />
* Atak<br />
* Obrona<br />
* Zakres zadawanych obrażeń<br />
* Wytrzymałość (punkty życia — HP)<br />
* Szybkość <br />
<br />
Oddział ginie, gdy jego liczebność spadnie do zera. Gracz, który straci wszystkie oddziały, przegrywa bitwę.<br />
<br />
=== Ruch ===<br />
Bitwa podzielona jest na tury. Każda jednostka rusza się raz na turę. Oddziały wykonują ruchy po kolei, w porządku malejącej szybkości. Za każdym razem, gdy wypada kolej ruchu jednostki sterowanej przez AI, następuje wywołanie metody activeStack. Zadaniem AI jest zwrócenie struktury opisującej, co dana jednostka ma uczynić. Podstawowe akcje to:<br />
* Atak — jednostka może zaatakować sąsiadującą jednostkę w zwarciu, bądź — jeśli umie strzelać — dowolną jednostkę na mapie.<br />
* Ruch — jednostka może przesunąć się o tyle pól na mapie, ile wynosi jej szybkość. Ruch może zostać zakończony atakiem na osiągnięty oddział wroga.<br />
* Czekanie — jednostka spróbuje się ruszyć później w tej turze (najwyżej raz na turę).<br />
* Obrona — jednostka rezygnuje z akcji, aby czasowo poprawić swój współczynnik obrony.<br />
<br />
=== Pole bitwy ===<br />
Pole bitwy składa się z heksagonalnych pól ułożonych w 11 linii po 17 pól, ponumerowanych jak pokazano na rysunku.<br />
<br />
[[File:Bfield_grid.gif]]<br />
<br />
Pola w dwóch skrajnych kolumnach nie są dostępne dla zwykłych jednostek. Ponadto niektóre z heksów (tj. pól) mogą być zablokowane ze względu na umieszczone na nich przeszkody. Heksy na których stoi już inne jednostka także traktowane są jak zablokowane. Na takim polu żadna z jednostek nie może zakończyć ruchu, przekraczać zaś to pole mogą wyłącznie jednostki latające. <br />
<br />
Pozycją jednostki jest numer heksa, na którym stoi. Każda jednostka zajmuje jednego lub dwa sąsiadujące w poziomie heksy. W przypadku jednostki dwuheksowej jej pozycją jest pozycja PRZODU jednostki (wojska atakującego są zawsze zwrócone w prawo, broniącego się zaś w lewo).<br />
<br />
=== Bohater ===<br />
Jak wskazano wcześniej armia może być dowodzona przez bohatera. Wiąże się to paroma korzyściami:<br />
* Bohater może posługiwać się magią (p. niżej)<br />
* Bohater może posiadać specjalne machiny wojenne<br />
* Jednostki otrzymują premie do atrybutów, zależne od parametrów bohatera<br />
<br />
=== Czary ===<br />
Bohater, jeżeli jest obecny na polu bitwy, może raz na turę, przed przesunięciem oddziału (w czasie, gdy ten jest aktywny) rzucić zaklęcie. Każdy bohater może posiadać księgę zaklęć, określającą, jakie czary są dostępne (bohater nie posiadający księgi nie może czarować). Rzucenie czaru wymaga poświęcenia pewnej liczby punktów many. Bohater, który wyczerpie swoją manę, traci możliwość rzucania czarów.<br />
<br />
== Jak AI komunikuje się z grą ==<br />
Do komunikacji służą dwa interfejsy:<br />
* CBattleGameInterface — główna klasa AI musi dziedziczyć po tej klasie. Silnik gry wywołuje jej metody, by informować AI o wydarzeniach w grze bądź by zapytać, jaką akcję chce podjąć.<br />
** Poprzez interfejs IBattleEventsReceiver odziedziczono szereg metod pozwalających otrzymywać informacje o wydarzeniach w bitwie [http://vcmi.eu/pc/class_i_battle_events_receiver.html].<br />
** Zaimplementowanie wirtualnej i abstrakcyjnej metody activeStack (wołanej, ilekroć otrzymuje się kolejkę) jest kluczowym aspektem implementacji AI. P. [[#Co_AI_.2Amusi.2A_robić|dalej]].<br />
<br />
* CBattleCallback — interfejs zaimplementowany w silniku, udostępniany AI. AI może wywoływac jego metody, by pobierać informacje o stanie bitwy oraz by podejmować niektóre specjalne akcje. Dziedziczy on po dwu interfejsach:<br />
** CBattleInfoCallback — zbiór metod pozwalających odpytywać silnik o stan bitwy. P. [http://vcmi.eu/pc/class_c_battle_info_callback.html]<br />
** IBattleCallback — zbiór (a właściwie) para metod. Pierwsza, battleMakeAction jest stosowana do rzucania czarów przez bohatera. Druga, battleMakeTacticAction, w czasie fazy taktycznej (niestosowanej w ramach Wyzwania). P. [http://vcmi.eu/pc/class_i_battle_callback.html]<br />
<br />
Każde AI jest kompilowane do dynamicznie ładowanej biblioteki, która musi eksportować następujące funkcje:<br />
* <code class="inline">void GetAiName(char* name);</code> — powinno wypełnić pamięć pod zadanym wskaźnikiem ciągiem znaków z nazwą AI.<br />
* <code class="inline">CBattleGameInterface* GetNewBattleAI();</code> — powinno stworzyć nowy obiekt głównej klasy AI (dziedziczącej po CBattleGameInterface), które pokieruje nadchodzącą bitwą. Obiekt powinien być stworzony operatorem new, tak aby po zakończeniu bitwy poprawna na nim była operacja delete. Silnik na otrzymanym obiekcie będzie wywoływał stosowne metody. Stanowić one będą podstawę komunikacji silnik -> AI. Pierwszym wywołaniem będzie metoda init, poprzez którą AI otrzyma wskaźnik na implementację interfejsu CBattleCallback, poprzez który AI może „odpytywać silnik”.<br />
<br />
== Co AI *musi* robić? ==<br />
Choć interfejs dla AI jest bogaty i zawiera wiele metod, tak naprawdę koniecznie wymagane jest zaimplementowanie tylko jednej. Jest to:<br />
virtual BattleAction activeStack(const CStack * stack)=0;<br />
Metoda ta jest wołana, ilekroć AI musi podjąć akcję dla jakiejś jednostki. Należy zwrócić poprawnie wypełnioną strukturę BattleAction, opisującą przedsiębraną akcję [[#Akcje_jednostek_i_ich_wydawanie|akcję]].<br />
<br />
Implementacja wszystkich innych metod jest opcjonalna — służą one informowaniu AI o wydarzeniach w bitwie, niemniej AI może te informacje samodzielnie (acz żmudnie) pozyskiwać odpytując interfejs ICallback. Do tego jednak konieczne jest zapamiętanie jego adresu — drugą funkcją, którą należy więc przeciążyć jest:<br />
virtual void init(CBattleCallback * CB);<br />
Nie jest to „konieczne” w sensie ścisłym, niemniej bez tego AI nie będzie w stanie sensownie działać.<br />
<br />
= Ważne klasy i ich ważne atrybuty =<br />
== Węzeł systemu bonusów — CBonusSystemNode ==<br />
Wszystkie opisane niżej klasy (i wiele innych) dziedziczą po CBonusSystemNode. Oznacza to, że są zarządzane przez [[Bonus_system|system bonusów]]. Najkrócej ujmując, system bonusów pozwala określić dla każdego z węzłów wartość szeregu atrybutów (np. liczba punktów ataku), obecność flag i efektów.<br />
<br />
== Oddział — CStack ==<br />
Podstawowa klasa opisująca oddział na polu bitwy. Żaden z oddziałów nie zostanie skasowany w trakcie bitwy — obiekty tej klasy trwać będą nawet po śmierci oddziału. Natomiast w czasie bitwy mogą pojawić się nowe oddziały, wtedy AI otrzyma wywołanie battleNewStackAppeared.<br />
<br />
<br />
=== Ważne pola ===<br />
* TQuantity count — liczebność oddziału<br />
* THex position — numer heksa na którym stoi oddział (lub jego przód, jeśli zajmuje dwa heksy)<br />
* ui32 firstHPleft — ile punktów zdrowia potrzeba odebrać, by ubić pierwszego stwora w oddziale.<br />
<br />
=== Ważne metody ===<br />
* ui32 Speed(int turn = 0) — oblicza szybkość stwora (opcjonalnie — za ileś tur)<br />
<br />
== Obiekt z armią — CArmedInstace ==<br />
Obie armie uczestniczące w bitwie nie biorą się znikąd. Silnik gry musi je skojarzyć z jakimś uzbrojonym obiektem. CArmedInstance stanowi bazową klasę dla bohatera, miasta (opisanych niżej) oraz szeregu mniej znaczących klas reprezentujących rozmaite obiekty z armią.<br />
<br />
== Bohater — CGHeroInstance ==<br />
CGHeroInstance to podstawowa klasa reprezentująca bohatera - obiekt posiadający w sensie systemu bonusów wszystkie jednostki AI. W trakcie rozgrywki każde AI ma dokładnie jednego bohatera, żyjącego przez cały czas bitwy. Jest to węzeł pośredniczący w przekazywaniu pewnych bonusów jednostkom, jednak sam również generuje pewne premie. Jego obecność umożliwia AI rzucanie czarów zapisanych w księdze zaklęć bohatera.<br />
<br />
=== Ważne pola ===<br />
* si32 mana — liczba punktów many (za te punkty rzuca się czary).<br />
* std::set<ui32> spells — identyfikatory znanych czarów.<br />
<br />
=== Ważne metody ===<br />
* int getPrimSkillLevel(int id) — pozwala sprawdzić wartość umiejętności drugorzędnej. Przykład: h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)<br />
* ui8 getSecSkillLevel(SecondarySkill skill) — pozwala sprawdzić wartość umiejętności drugorzędnej (wyniki: 0 — brak; ...; 3 — ekspert)<br />
<br />
== Miasto — CGTownInstance ==<br />
<br />
Niektóre bitwy są oblężeniami miast. W takim przypadku broniące się AI (to po prawej stronie pola bitwy) dostaje dodatkowe premie z tego powodu. Przede wszystkim miasto może być wyposażone w fort/cytadelę/zamek, które powodują, że obrońca jest otoczony murem z opcjonalną fosą i wieżyczkami strażniczymi (zależne od poziomu ulepszenia). Ponadto niektóre miasta dodają inne premie broniącej się armii - patrz np. [http://h3.heroes.net.pl/budynki/zamek.html tutaj]. AI atakujące miasto z murami otrzymuje katapultę mogącą niszczyć mury i wieżyczki strażnicze.<br />
<br />
= Informacje szczegółowe =<br />
== Początek bitwy ==<br />
<br />
Na początku bitwy AI otrzymuje od silnika wywołanie funkcji<br />
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);<br />
w której przekazywane są następujące informacje:<br />
* jednostki należące do atakującego (znajduje się po lewej stronie pola bitwy)<br />
* jednostki należące do broniącego się (znajduje się po prawej stronie pola bitwy)<br />
* lokalizację pola bitwy na mapie przygody (mogą od tego parametru zależeć premie lub kary)<br />
* informacje o bohaterze atakującym i broniącym się, takie jak czary, które może rzucać, bonusy dla jednostek itp.<br />
* (nadmiarową) informację, po której stronie AI ma walczyć.<br />
<br />
Opcjonalnie, zależnie od artefaktów posiadanych przez bohatera, zaraz po tym wywołaniu możliwe są wywołania takie jak przy rzucaniu czaru.<br />
<br />
== Przebieg tury ==<br />
<br />
Każda tura zaczyna się od dwu wywołań:<br />
void battleNewRoundFirst(int round)<br />
void battleNewRound(int round)<br />
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).<br />
<br />
Następnie po kolei dla każdej jednostki następuje jedna z poniższych sytuacji:<br />
* 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.<br />
* 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).<br />
* 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.<br />
* 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).<br />
* 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 podanie akcji, którą oddział winien podjąć. <br />
* Po wykonaniu akcji, jeżeli jednostka jest żywa i ma dodatnie morale, istnieje szansa na uzyskanie przez nią powtórnego ruchu — AI wtedy ponownie jest pytane o akcję (jak wyżej).<br />
<br />
Jeżeli po przejściu tej sekwencji bitwa ciągle nie jest skończona (obie strony posiadają żywe oddziały, następuje kolejna tura.<br />
<br />
== Akcje jednostek i ich wydawanie ==<br />
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:<br />
* 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) <br />
* przejście jednostki na inne pole<br />
* polecenie przejścia jednostki do obrony - jednostka traci turę, ale zwiększa się jej współczynnik obrony<br />
* ucieczka AI z pola bitwy (może być niemożliwa, zależnie od posiadanych artefaktów<br />
* poddanie się AI<br />
* zaatakowanie pieszo (ang. melee) jednostki wroga znajdującej się w zasięgu, z wybranego pola sąsiadującego<br />
* 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; każdy strzał zmniejsza liczbę pocisków jednostki, chyba, że na polu bitwy jest wóz z amunicją (Ammo Cart). Jednostka z liczbą pocisków równą zero nie może strzelać)<br />
* czekanie (jednostka będzie się ruszała na końcu tury, po wszystkich jednostkach z niższą inicjatywą)<br />
* rzucenie czaru przez jednostkę (nieliczne jednostki to potrafią, jest to jeszcze nieobsługiwane, ale powinno w końcu się pojawić)<br />
* leczenie innej jednostki (dla namiotu medyka)<br />
<br />
== Informacja o początku / końcu akcji ==<br />
<br />
Każde polecenie wysłane przez AI do silnika jest analizowane pod kątem możliwości jego wykonania. Jeśli uzna, że polecenie jest wykonalne (czyli np. nie jest poleceniem rzucenia nieposiadanego czaru lub próbą ataku własną jednostką na inną własną jednostkę), przystępuje do jego wykonania. Wykonanie akcji zawsze zaczyna się od poinformowania o jej początku przez wywołanie <code class="inline">void actionStarted(const BattleAction *action){}</code>, następnie, jeśli jest taka potrzeba, następują wywołania o efektach akcji (np. jednostka ruszyła się na inne pole / zaatakowała jakąś inną / czar został rzucony), całość zaś kończy wywołanie <code class="inline">void actionFinished(const BattleAction *action){}</code> oznaczające, że wszystkie efekty związane z daną akcją zostały obsłużone.<br />
<br />
== Wywołania AI -> silnik ==<br />
<br />
Obecnie zaimplementowane są następujące wywołania w callbacku:<br />
<br />
[http://sourceforge.net/apps/trac/vcmi/browser/branches/programmingChallenge/lib/IGameCallback.h Plik nagłówkowy]<br />
<br />
[http://vcmi.eu/pc/class_c_battle_info_callback.html Dokumentacja wygenerowana Doxygenem]<br />
<br />
Umożliwiają one dostęp do każdej mechanicznie istotnej informacji o stanie gry, do jakiej dostęp ma AI. Część informacji zdobywana jest jednak w sposób pośredni, przez wywoływanie odpowiednich metod na obiektach dostarczanych przez wymienione metody. Pewne niezmienne w czasie elementy mechaniki sa także dostępne przez specjalny obiekt klasy VLC (dostępne dla AI po zainclude'owaniu pliku /lib/VCMI_Lib.h).<br />
<br />
== Czary bohaterów ==<br />
<br />
Bohaterowie mogą rzucać w trakcie bitwy czarować. Aby rzucić zaklęcie konieczne jest jednak spełnienie następujących warunków:<br />
* Bohater musi posiadać księgę zaklęć oraz nie rzucił jeszcze w tej turze czaru. Aby sprawdzić, czy nasz bohater w danym momencie bitwy jest zdolny do czarowania, można posłużyć się metody <code class="inline">bool CCallback::battleCanCastSpell()</code>. <br />
* Zaklęcie jest dostępne dla bohatera: ma je zapisane w księdze zaklęć bądź uzyskał w drodze bonusu (np. dzięki artefaktowi). Aby sprawdzić, czy konkretny czar jest dostępny dla bohatera, należy na nim wywołać metodę <code class="inline">bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const</code>. Wektor wszystkich czarów w grze jest dostępny np. jako <code class="inline">VLC->spellh->spells</code><br />
* Bohater ma nie mniej punktów many niż wynosi koszt zaklęcia. Aby sprawdzić koszt rzucenia czaru, należy użyć metody <code class="inline">int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const</code>, podając jako argumenty wybrany czar i naszego bohatera-dowódcę. Liczba punktów many bohatera jest publicznie dostępnym polem klasy <code class="inline">CGHeroInstance</code> o nazwie <code class="inline">mana</code><br />
* Czar można rzucić tylko, gdy nasza jednostka oczekuje na wykonanie akcji: musi się to odbyć po wywołaniu metody activeStack, a przed jej zwróceniem. Rzucenie czaru nie zwalnia od obowiązku zwrócenia akcji dla obecnego oddziału. [TODO: opisać synchronizację oraz przypadek utraty akcji, jeśli oddział zginie w efekcie rzuconego czaru.<br />
<br />
Aby rzucić czar, należy wywołać metodę <code class="inline">int CCallback::battleMakeAction(BattleAction* action)</code>, gdzie struktura BattleAction opisuje rzucony czar: typ akcji wynosi <code class="inline">BattleAction::HERO_SPELL</code>, pole <code class="inline">additionalInfo</code> zawiera ID czaru, pole <code class="inline">destinationTile</code> docelowy heks na który ma być rzucony czar (jeśli dotyczy). Pamiętać również trzeba o polu <code class="inline">side</code> — musi być ustawione zgodnie z naszą stroną (0 — atakujący, 1 — obrońca).<br />
<br />
W grze obecnie zaimplementowane jest 48 z 59 czarów bitewnych dostępnych w oryginalnej grze. Listę zaimplementowanych czarów można znaleźć [https://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA#gid=1 tutaj], a opisy działania czarów np. [http://www.heroesofmightandmagic.com/heroes3/spellsair.shtml tutaj] (wyświetla tylko czary magii powietrza; aby obejrzeć inne, trzeba wybrać inną opcję z menu na górze!) 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.<br />
<br />
== Koniec bitwy ==<br />
<br />
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<br />
void battleEnd(const BattleResult *br);<br />
Zawierające informacje o typie zwycięstwa, wygranej stronie, ofiarach, doświadczeniu zdobytym przez bohatera oraz przejętych artefaktach.<br />
<br />
= Uruchamianie bitwy =<br />
== Uczestniczące programy ==<br />
Bitwa rozgrywa się między dwoma AI. AI jest jednak biblioteką dynamiczną, jej samej nie da się uruchomić. Konieczna jest do tego aplikacja, która ją załaduje. Do przeprowadzenia bitwy potrzebna jest współpraca kilku aplikacji:<br />
* VCMI_server — serwer rozgrywki sterujący jej przebiegiem i logiką. Łączy się z runnerami, odbiera od nich żądania akcji i informuje je o ich skutkach.<br />
* VCMI_runner — aplikacja pośrednicząca między serwerem oraz AI. Runner przechowuje stan bitwy i aktualizuje go w oparciu o informacje otrzymywane z serwera. Jeden runner ładuje jedną bibliotekę AI, którą obsługuje (wywołuje jej call-iny oraz dostarcza interfejsu zwrotnego).<br />
* odpalarka — pomocniczy program, który odpala wszystkie powyższe aplikacje w odpowiedniej liczbie i z odpowiednimi argumentami.<br />
<br />
== Odpalarka ==<br />
=== Parametry odpalarki ===<br />
Aby uruchomić bitwę trzeba skorzystać z odpalarki. Przyjmuje ona argumenty określające:<br />
* plik JSON z parametrami bitwy. Domyślnie wykorzystywany jest plik b1.json z folderu z VCMI.<br />
* nazwy AI (lub pełne ścieżki do nich) uczestniczących w bitwie. Domyślnie dostępne jest StupidAI będące równoważne udostępnionej przykładowej implementacji AI.<br />
* folder, w którym maja być umieszczone logi<br />
* plik, do którego ma być dopisany rezultat bitwy<br />
<br />
Składnia argumentów:<br />
-h [ --help ] Display help and exit<br />
-l [ --aiLeft ] arg (=StupidAI) Left AI path<br />
-r [ --aiRight ] arg (=StupidAI) Right AI path<br />
-b [ --battle ] arg (=b1.json) Duel file path<br />
-o [ --resultsOut ] arg (=./results.txt)<br />
Output file when results will be <br />
appended<br />
-d [ --logsDir ] arg (=.) Directory where log files will be <br />
created<br />
-v [ --visualization ] Runs a client to display a <br />
visualization of battle<br />
<br />
Przykładowa komenda (wydana w folderze VCMI):<br />
odpalarka.exe -l"C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll" -d../logs -o../logs/results_list.txt<br />
Uruchomi bitwę, gdzie lewe AI będzie wczytane z podanej ścieżki, zaś logi trafią do fodleru nadrzędnego „logs”.<br />
<br />
<br />
=== Plik JSON z bitwą ===<br />
Plik opisujący bitwę zapisany jest w tekstowym formacie [http://pl.wikipedia.org/wiki/JSON JSON] ([http://www.json.org/ strona oficjalna]). Ogólnie format JSON obsługuje:<br />
* obiekty — są to pary "nazwa" : wartość wewnątrz klamer {}.<br />
* tablice (wektory) — są to ciągi wartości w klamrach []<br />
* literały — liczby i stringi w cudzysłowach ""<br />
<br />
Plik zawiera jeden obiekt o następujących polach:<br />
* "terType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_tr.htm identyfikator terenu], na którym odbywa się bitwa. Jednostki znajdujące się na swoim [http://heroes.thelazy.net/wiki/Native_Terrain ojczystym terenie] otrzymują niewielkie premie.<br />
* "bfieldType" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_bi.htm typ pola bitwy]. Nie ma znaczenia mechanicznego, określa grafikę w tle.<br />
* "obstacles" — wektor zawierający liczby lub dwuelementowe wektory liczb. Opisuje rozmieszczenie przeszkód. Pojedyncza liczba oznacza umieszczenie na danym polu pniaka (będzie on zablokowany). Pary mają postać [id_przeszkody, nr_pola] — przeszkoda danego typu zostanie umieszczona na wskazanej pozycji. Spis identyfikatorów przeszkód jest dostępny [http://bbs.wakeofgods.com/erm_help/receivers/receiver_bf.htm np. tu].<br />
* "sides" — dwuelementowy wektor zawierający struktury z opisem stron uczestniczących w bitwie.<br />
* "creatures" — wektor struktur pozwalających zmienić parametry danej jednostki na czas bitwy.<br />
<br />
Struktura opisująca stronę walki zawiera następujące pola:<br />
* "side" — liczba, określa, która to jest strona (0 — lewa, 1 — prawa)<br />
* "army" — wektor par liczb postaci [[http://bbs.wakeofgods.com/erm_help/format/format_c.htm id_stwora], liczebność]. Każda para opisuje jeden oddział. Liczba oddziałów musi być w przedziale [1—7].<br />
* "heroid" — liczba, [http://bbs.wakeofgods.com/erm_help/format/format_h.htm identyfikator bohatera]. Jeśli brak tego parametru, strona nie będzie miała bohatera.<br />
* "heroPrimSkills" — czteroelementowy wektor liczb, określających wartości kolejnych umiejętności pierwszorzędnych boahtera (atak, obrona, siła czarów, wiedza).<br />
* "spells" — wektor zawierający [http://bbs.wakeofgods.com/erm_help/format/format_sp.htm identyfikatory czarów] znanych przez bohatera.<br />
<br />
Struktura opisująca zmianę parametrów jednostki:<br />
* "id" — liczba określająca identyfikator jednostki, która otrzyma nowe parametry<br />
* "attack" — liczba, wartość punktów ataku stwora. Analogicznie: "defense" (obrona), "HP" (punkty wytrzymałości), "dmg" (zadawane obrażenia), "shoots" (strzały), "speed" (szybkość).<br />
<br />
<br />
== Wynik bitwy i logi ==<br />
=== Logi ===<br />
W wyniku przeprowadznia bitwy w folderze z logami pojawią się następujące pliki:<br />
* VCMI_Server_log.txt — log serwera. Można w nim m.in. sprawdzić, jakie PID dostały runnery obsługujące poszczególne AI (ctrl+f za „PID=”).<br />
* VCMI_runner_log_N.txt — dwa lub trzy takie pliki powstają, gdzie za N podstawiony jest PID programu. Odpowiadają runnerom obsługującym AI. Jeśli AI spowoduje błąd, logu należy szukać właśnie w zapisie runnera, który je wczytał.<br />
* first_runner.txt, second_runner.txt, third_runner.txt — zapisy standardowego wyjścia runnerów. Zwykle zawierają podzbiór ich logów, ale przy niektórych błędach mogą zawierać wskazówkę.<br />
* result.vdrst — binarny plik (nie do odczytu ludzkiego) z informacjami o rezultacie bitwy. Zawiera zserializowany obiekt BattleResult.<br />
* duel_log.vdat — binarny plik z zapisem przebiegu bitwy. Klient VCMI może go wykorzystać do wizualizacji bitwy.<br />
<br />
=== Wyniki ===<br />
Podany w argumencie odpalarki plik z wynikami po przeprowadzeniu bitwy otrzyma dodatkową linię. Będzie wyglądała podobnie do poniższej:<br />
b1.json C:\Documents and Settings\Administrator\Pulpit\Programming challenge\YourAI\YourAI_Standalone.dll StupidAI 0 13622 SIDE_DEFEATED Sat Dec 10 00:06:16 2011<br />
<br />
Kolejne pola wyniku (oddzielone tabulacją) to:<br />
* nazwa pliku z bitwą<br />
* nazwa lewego (atakującego) AI<br />
* nazwa prawego (broniącego się) AI<br />
* kto wygrał: 0 oznacza lewego, 1 prawego<br />
* z jakimi stratami wygrał (im większa liczba, tym gorsze zwycięstwo)<br />
* przyczyna zakończenia bitwy. SIDE_DEFEATED oznacza normalne zwycięstwo (możliwa jest również dyskwalifikacja którejś ze stron)<br />
* czas bitwy<br />
<br />
= Przebieg rozgrywek i punktacja =<br />
Punkty będą przyznawane w trzech fazach. Max. do zdobycia: 8 pkt, przy czym:<br />
# 0—5 pkt — za implementację konkretnych (wskazanych) strategii. AI będzie musiało stoczyć ciąg bitew, za każde zwycięstwo otrzymuje punkt.<br />
# 0—3 pkt — za ogólną skuteczność AI. Moduł będzie musiał pokierować znaczną armią w bitwie, otrzyma punkty zależne od strat poniesionych przy zwycięstwie.<br />
# 0—? pkt — po zakończeniu i ocenie zasadniczej części „Wyzwania” przeprowadzony zostanie turniej między najlepszymi AI. Te, które się wyróżnią (zakładając satysfakcjonujący ogólny poziom projektów) otrzymają dodatkowe punkty.<br />
<br />
Spełnienie wymogów formalnych ([[#Wymogi_techniczne_i_formalne]]) jest niezbędne, aby program był wzięty pod uwagę w ocenianiu.<br />
<br />
<br />
== Strategie wymagane w pierwszej fazie ==<br />
=== Zaatakuj pierwszy ===<br />
Często w bitwie przewagę zyskuje ten, kto zada pierwszy cios. Osłabiony atakiem przeciwnik kontratakuje mniej groźnie.<br />
AI powinno więc tak manewrować swoimi oddziałami, by te nie wchodziły w zasięg wrogich oddziałów i były zdolne do zadania uderzenia jako pierwsze.<br />
Pomocne może być użycie akcji WAIT, by wróg zdradził się ze swoimi zamiarami.<br />
<br />
=== Zwinny strzelec ===<br />
Nawet pojedynczy strzelec może pokonać wielekroć silniejszy oddział, jeżeli ma odpowiednią przewagę szybkości. Wystarczy biegać naokoło i strzelać, samemu pozostając w bezpiecznej odległości. <br />
Uwaga! Część pól może być zablokowana przez przeszkody, trzeba uważać, by się nie zapędzić w ślepy zaułek.<br />
<br />
Przydatne czary:<br />
* Precision — zwiększa atak jednostki strzelającej w walce dystansowej.<br />
* Haste — zwiększa szybkość jednostki.<br />
* Slow — zmniejsza szybkość wroga.<br />
<br />
=== Szarża na strzelców ===<br />
Jeżeli wróg dysponuje grupą strzelców, należy działać roztropnie. Nie wolno przedwcześnie zanadto się zbliżyć, gdyż przy znacznej odległości strzały tracą połowę efektywności (p. funkcja callbacku battleHasDistancePenalty). Tu przydatny jest WAIT — niech wróg najpierw strzeli.<br />
<br />
Gdy już się dotrze do wroga, należy możliwie efektywnie go „zablokować” (oddział strzelający traci tę zdolność, gdy stoi obok niego wróg, zaś walcząc wręcz zadaje połowę obrażeń i traci niektóre zdolności, takie jak wielokrotny atak). Jeśli jest kilka wrogich oddziałów, możliwe, że będziemy w stanie zablokować więcej niż jeden na raz. (Tylko czasem warto zablokować jeden silny zamiast dwu słabych...)<br />
<br />
Pomocne też mogą być czary:<br />
* Air Shield — zmniejsza obrażenia otrzymywane w wyniku ostrzału<br />
* Forgetfulness — przeklęty oddział traci zdolność strzelania i musi walczyć wręcz (połowa efektywności)<br />
* Earth Shield — zmniejsza obrażenia w walce wręcz. Do stosowania, gdy już się do wroga i zaangażuje w bezpośrednią walkę.<br />
<br />
=== Czarodziej ===<br />
TBA<br />
<br />
=== Mistrz taktyki ===<br />
Najlepsi dowódcy potrafią tak ustawić swoje armie przed bitwą, aby wykorzystać nawet najsłabsze z nich. Zadaniem gracza jest chronienie mało wytrzymałego (ale silnego w ataku) strzelca przed atakiem w pierwszej turze.<br />
<br />
== Wskazówki odnośnie drugiej fazy ==<br />
Ogłoszone zostaną czary i umiejętności jednostek, którymi warto się zainteresować.<br />
<br />
== Trzecia faza — turniej ==<br />
Po zakończeniu obu poprzednich faz, pojawią się tu szczegóły.<br />
<br />
= Wymogi techniczne i formalne =<br />
Celem zadania jest implementacja modułu bitewnego AI. Całość musi być napisana w języku C++. Wolno korzystać wyłącznie ze standardowej biblioteki języka, biblioteki silnika VCMI oraz dostępnego na serwerze student zbioru bibliotek Boost. Nie wolno wykorzystywać innych bibliotek, w tym systemowych. <br />
<br />
== Budowa ==<br />
Folder ze źródłami powinien być zatytułowany NazwiskoImie.<br />
Do kodu źródłowego biblioteki musi być dołączony plik Makefile. Wydanie polecenia make w folderze z nazwiskiem ma stworzyć wewnątrz tego folderu plik NazwiskoImie.so. Budowanie musi odbywać się wewnątrz folderu (tzn. nie można tworzyć ani pisać do plików poza nim). Kod musi się kompilować bez żadnych dodatkowych zależności na serwerze student (GCC 4.3).<br />
<br />
== Ogólne wymogi ==<br />
Modułowi AI nie wolno tworzyć procesów potomnych, tworzyć ani pisać do żadnych plików ani komunikować się z jakimikolwiek procesami. (Wyjąwszy, oczywiście, interfejsy udostępnianie przez silnik VCMI.) Modułowi AI nie wolno w żaden sposób zakłócać działania serwera rozgrywki ani procesu go hostującego. W szczególności nie wolno zakłócać pomiarów czasu i uzycia pamięci.<br />
<br />
Limity czasowe nałożone na moduł:<br />
* 50 ms na stworzenie (konstruktor i metoda init ŁĄCZNIE)<br />
* 100 ms na inicjalizację (wykonanie metody battleStart)<br />
* 100 ms na podjęcie decyzji o ruchu (wykonanie metody activeStack)<br />
* 5 ms na odnotowanie wydarzenia w bitwie (wszystkie pozostałe metody interfejsu IBattleEventsReceiver)<br />
<br />
Czas jest mierzony od wywołania procedury do jej „zwrócenia się”. Pomiar będzie dokonany na serwerze Student, tak więc trzeba się liczyć z jego szybkością. Na waszych komputerach AI może działać szybciej lub wolniej. <br />
<br />
Limit dostępnej pamięci dla modułu wynosi 16 MB.<br />
<br />
Postać wysyłanych projektów:<br />
Projekt musi być spakowany do postaci NazwiskoImie.tar.gz. W jego wnętrzu musi się znajdować jeden folder o nazwie NazwiskoImie zawierający źródła AI oraz plik Makefile. Aby program mógł zostać poprawnie oceniony, niezbędne jest spełnienie tych wymagań! Archiwum musi zostać wgrane przed upływem [[#Terminy|terminu]] na platformę Moodle.<br />
<br />
= Terminy =<br />
Czas na zadawanie pytań: 11 grudnia 2011. <br />
Pierwszy termin: 18 grudnia 2011. <br />
<br />
Planowany jest także drugi termin, w którym jednak liczba punktów do zdobycia będzie wyraźnie mniejsza. Ogłoszony zostanie po sprawdzeniu i ocenieniu programów z pierwszego terminu. Na drugi termin można ponownie przysłać poprawiony program z pierwszego, bez żadnego ryzyka utraty zdobytych punktów (będzie się liczył lepszy z wyników).<br />
<br />
= Materiały =<br />
== Serwer Student ==<br />
Po zalogowaniu się na serwer i przejściu do '''katalogu domowego''', proszę wydać następujące polecenia:<br />
<br />
wget http://vcmi.eu/pc/YourAI.zip<br />
mkdir ~/challenge_out <br />
unzip YourAI.zip<br />
cd YourAI/<br />
make<br />
chmod 700 run.sh<br />
./run.sh<br />
cat ~/challenge_out/results_1.txt | tail -1<br />
<br />
Uwaga — można też całość postawić w podfolderze (nie w katalogu domowym), trzeba wtedy dostosować też skrypt run.sh.<br />
<br />
Folder YourAI będzie zawierał źródła i plik Makefile rozwijanego AI. Komenda make buduje plik libYourAI.so. Aby go wypróbować, użyty jest skrypt run.sh, który uruchamia odpalarkę, podając w argumencie ścieżkę do pliku .so oraz do folderu z logami. Ostatnie poelcenie wypisuje ostatnią linię pliku z wynikami bitwy. Ma ona postać:<br />
b1.json StupidAI /home/infsgrp/mwutow/YourAI/libYourAI.so 0 13622 SIDE_DEFEATED Sun Dec 4 16:04:59 2011<br />
<br />
por. [[#Wyniki|opis pliku z wynikami]].<br />
<br />
== Windows ==<br />
=== Budowa ===<br />
Aby zbudować AI na Windowsie z użyciem środowiska Visual studio należy:<br />
* pobrać poniższe archiwa<br />
** [http://vcmi.eu/pc/challenge_lib_pack.7z Paczka z bibliotekami] — 33 MB, 7zip<br />
** [http://vcmi.eu/pc/YourAI.zip Paczka z przykładowym AI] — 8 kB, zip<br />
** [http://vcmi.eu/pc/zasoby.7z Paczka z zasobami tekstowymi (reguły gry)] — 600 kB, 7zip<br />
** [http://vcmi.eu/pc/grafiki.7z Paczka z zasobami graficznymi] — 144 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
** [http://vcmi.eu/pc/grafiki2.7z Paczka z zasobami graficznymi, part 2] — 80 MB, 7zip — opcjonalnie, jeżeli chcemy korzystać z wizualizacji bitwy.<br />
* wypakować do wspólnego folderu. Po tej operacji powinien zawierać podfoldery include, libs, VCMI, YourAI<br />
* w folderze VCMI tworzymy repozytorium SVN ustawione na adres<br />
https://vcmi.svn.sourceforge.net/svnroot/vcmi/branches/programmingChallenge/<br />
* otwieramy Visualem solucję VCMI_VS10.sln z podfolderu VCMI. Wybieramy konfigurację, jaką chcemy (Debug lub RD, czyli Release). Budujemy solucję. Czekamy chwilę — powinniśmy w końcu otrzymać informację o poprawnym zbudowaniu ośmiu projektów. <br />
* otwieramy Visualem solucję YourAI_Standalone.sln z podfolderu YourAI. Budujemy, powinno przejść poprawnie.<br />
* voila! Powinniśmy w podfolderze YourAI uzyskać plik YourAI_Standalone.dll. Jest to biblioteka z AI, którą można już uruchomić odpalarce.<br />
<br />
=== Uruchamianie ===<br />
Wykonanie komendy F5 (Start Debugging) uruchomi odpalarkę, a ta bitwę. We właściwościach projektu w karcie „Debugging” w polu „Command Arguments” znajdują się parametry, z jakimi zostanie odpalona. Domyślnie za lewe AI zostanie wzięty wasz projekt, zaś wyniki trafią do nadrzędnego folderu logs.<br />
<br />
Więcej o parametrach odpalarki i odczytywaniu wyników bitwy w sekcji [[#Uruchamianie_bitwy]].<br />
<br />
UWAGA! Żeby AI poprawnie działało, musi być zbudowane w tej samej konfiguracji (Debug lub RD) co solucja VCMI_VS10! Ich pomieszanie może powodować dziwnie wyglądające błędy, prowadzące najczęściej do dyskwalifikacji AI.<br />
<br />
== „Własny” Linux ==<br />
Nie polecam, bo na różnych dystrybucjach się może zachowywać nieprzewidywalnie. <br />
<br />
mkdir vcmi<br />
cd vcmi<br />
wget http://sourceforge.net/apps/trac/vcmi/export/2480/branches/programmingChallenge/vcmiinstall.sh<br />
chmod 700 vcmiinstall.sh<br />
./vcmiinstall.sh --install lean<br />
<br />
Dalej postępować jak w instrukcji dla studenta. Konieczne są tylko dostosowania w pliku Makefile i run.sh (poprawić ścieżki).<br />
<br />
Potrzebne pakiety:<br />
* libtool<br />
* automake<br />
* autoconf<br />
<br />
Biblioteki:<br />
* libstdc++ devel<br />
* SDL and SDL-devel<br />
* SDL_mixer and SDL_mixer-devel<br />
* SDL_image and SDL_image-devel<br />
* SDL_ttf and SDL_ttf-devel<br />
* zlib and zlib-devel<br />
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.<br />
* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):<br />
** program-options<br />
** filesystem<br />
** iostreams<br />
** system<br />
** thread</div>Tow