1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Some very early work towards autofight feature.

Added EmptyAI to the solution.
Passing callbacks by shared_ptr.
This commit is contained in:
Michał W. Urbańczyk 2013-06-22 14:47:20 +00:00
parent 06dbdd234f
commit 254f194220
18 changed files with 175 additions and 78 deletions

View File

@ -8,7 +8,7 @@
#include "../../lib/VCMI_Lib.h" #include "../../lib/VCMI_Lib.h"
using boost::optional; using boost::optional;
CBattleCallback * cbc; shared_ptr<CBattleCallback> cbc;
#define LOGL(text) print(text) #define LOGL(text) print(text)
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl)) #define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
@ -85,7 +85,7 @@ CBattleAI::~CBattleAI(void)
} }
} }
void CBattleAI::init( CBattleCallback * CB ) void CBattleAI::init(shared_ptr<CBattleCallback> CB)
{ {
print("init called, saving ptr to IBattleCallback"); print("init called, saving ptr to IBattleCallback");
cbc = cb = CB; cbc = cb = CB;

View File

@ -109,7 +109,7 @@ struct PotentialTargets
class CBattleAI : public CBattleGameInterface class CBattleAI : public CBattleGameInterface
{ {
int side; int side;
CBattleCallback *cb; shared_ptr<CBattleCallback> cb;
//Previous setting of cb //Previous setting of cb
bool wasWaitingForRealize, wasUnlockingGs; bool wasWaitingForRealize, wasUnlockingGs;
@ -119,7 +119,7 @@ public:
CBattleAI(void); CBattleAI(void);
~CBattleAI(void); ~CBattleAI(void);
void init(CBattleCallback * CB) OVERRIDE; void init(shared_ptr<CBattleCallback> CB) OVERRIDE;
void actionFinished(const BattleAction &action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero void actionFinished(const BattleAction &action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero void actionStarted(const BattleAction &action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack

View File

@ -1,7 +1,7 @@
#include "StdInc.h" #include "StdInc.h"
#include "CEmptyAI.h" #include "CEmptyAI.h"
void CEmptyAI::init(CCallback * CB) void CEmptyAI::init(shared_ptr<CCallback> CB)
{ {
cb = CB; cb = CB;
human=false; human=false;

View File

@ -7,10 +7,10 @@ struct HeroMoveDetails;
class CEmptyAI : public CGlobalAI class CEmptyAI : public CGlobalAI
{ {
CCallback *cb; shared_ptr<CCallback> cb;
public: public:
void init(CCallback * CB) override; void init(shared_ptr<CCallback> CB) override;
void yourTurn() override; void yourTurn() override;
void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override; void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override;
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override; void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override;

View File

@ -41,23 +41,27 @@
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110_xp</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110_xp</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -106,7 +110,8 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/Zm130 %(AdditionalOptions)</AdditionalOptions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -122,7 +127,7 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>VCMI_DLL;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -140,7 +145,7 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>VCMI_DLL;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -160,7 +165,7 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>VCMI_DLL;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -5,7 +5,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
CPlayerBattleCallback * cbc; shared_ptr<CBattleCallback> cbc;
CStupidAI::CStupidAI(void) CStupidAI::CStupidAI(void)
: side(-1), cb(NULL) : side(-1), cb(NULL)
@ -19,7 +19,7 @@ CStupidAI::~CStupidAI(void)
print("destroyed"); print("destroyed");
} }
void CStupidAI::init( CBattleCallback * CB ) void CStupidAI::init(shared_ptr<CBattleCallback> CB)
{ {
print("init called, saving ptr to IBattleCallback"); print("init called, saving ptr to IBattleCallback");
cbc = cb = CB; cbc = cb = CB;

View File

@ -5,14 +5,14 @@
class CStupidAI : public CBattleGameInterface class CStupidAI : public CBattleGameInterface
{ {
int side; int side;
CBattleCallback *cb; shared_ptr<CBattleCallback> cb;
void print(const std::string &text) const; void print(const std::string &text) const;
public: public:
CStupidAI(void); CStupidAI(void);
~CStupidAI(void); ~CStupidAI(void);
void init(CBattleCallback * CB) OVERRIDE; void init(shared_ptr<CBattleCallback> CB) OVERRIDE;
void actionFinished(const BattleAction &action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero void actionFinished(const BattleAction &action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero void actionStarted(const BattleAction &action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack

View File

@ -34,7 +34,7 @@ struct SetGlobalState
assert(!cb.get()); assert(!cb.get());
ai.reset(AI); ai.reset(AI);
cb.reset(AI->myCb); cb.reset(AI->myCb.get());
} }
~SetGlobalState() ~SetGlobalState()
{ {
@ -823,7 +823,7 @@ void VCAI::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
} }
void VCAI::init(CCallback * CB) void VCAI::init(shared_ptr<CCallback> CB)
{ {
LOG_TRACE(logAi); LOG_TRACE(logAi);
myCb = CB; myCb = CB;

View File

@ -291,7 +291,7 @@ public:
AIStatus status; AIStatus status;
std::string battlename; std::string battlename;
CCallback *myCb; shared_ptr<CCallback> myCb;
unique_ptr<boost::thread> makingTurn; unique_ptr<boost::thread> makingTurn;
@ -306,7 +306,7 @@ public:
virtual std::string getBattleAIName() const OVERRIDE; virtual std::string getBattleAIName() const OVERRIDE;
virtual void init(CCallback * CB) OVERRIDE; virtual void init(shared_ptr<CCallback> CB) OVERRIDE;
virtual void yourTurn() OVERRIDE; virtual void yourTurn() OVERRIDE;
virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id

View File

@ -35,6 +35,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Editor", "editor\Editor.vcx
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyAI", "AI\EmptyAI\EmptyAI.vcxproj", "{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}"
ProjectSection(ProjectDependencies) = postProject
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F}
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -146,6 +151,18 @@ Global
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32 {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32 {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|Win32 {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.ActiveCfg = Debug|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.Build.0 = Debug|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|x64.ActiveCfg = Debug|x64
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|x64.Build.0 = Debug|x64
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|Win32.ActiveCfg = RD|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|Win32.Build.0 = RD|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|x64.ActiveCfg = RD|x64
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|x64.Build.0 = RD|x64
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Release|Win32.ActiveCfg = RD|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Release|Win32.Build.0 = RD|Win32
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Release|x64.ActiveCfg = RD|x64
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Release|x64.Build.0 = RD|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -135,9 +135,9 @@ CPlayerInterface::~CPlayerInterface()
LOCPLINT = NULL; LOCPLINT = NULL;
} }
void CPlayerInterface::init(CCallback * CB) void CPlayerInterface::init(shared_ptr<CCallback> CB)
{ {
cb = dynamic_cast<CCallback*>(CB); cb = CB;
if(observerInDuelMode) if(observerInDuelMode)
return; return;

View File

@ -101,7 +101,7 @@ public:
static CBattleInterface * battleInt; //NULL if no battle static CBattleInterface * battleInt; //NULL if no battle
CInGameConsole * cingconsole; CInGameConsole * cingconsole;
CCallback * cb; //to communicate with engine shared_ptr<CCallback> cb; //to communicate with engine
const BattleAction *curAction; //during the battle - action currently performed by active stack (or NULL) const BattleAction *curAction; //during the battle - action currently performed by active stack (or NULL)
std::list<CInfoWindow *> dialogs; //queue of dialogs awaiting to be shown (not currently shown!) std::list<CInfoWindow *> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
@ -221,7 +221,7 @@ public:
void openTownWindow(const CGTownInstance * town); //shows townscreen void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
void updateInfo(const CGObjectInstance * specific); void updateInfo(const CGObjectInstance * specific);
void init(CCallback * CB); void init(shared_ptr<CCallback> CB);
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
void showInfoDialog(const std::string &text, CComponent * component); void showInfoDialog(const std::string &text, CComponent * component);
void showInfoDialog(const std::string &text, const std::vector<CComponent*> & components = std::vector<CComponent*>(), int soundID = 0, bool delComps = false); void showInfoDialog(const std::string &text, const std::vector<CComponent*> & components = std::vector<CComponent*>(), int soundID = 0, bool delComps = false);

View File

@ -91,7 +91,6 @@ void CClient::init()
IObjectInterface::cb = this; IObjectInterface::cb = this;
serv = nullptr; serv = nullptr;
gs = nullptr; gs = nullptr;
cb = nullptr;
erm = nullptr; erm = nullptr;
terminate = false; terminate = false;
} }
@ -216,6 +215,7 @@ void CClient::endGame( bool closeConnection /*= true*/ )
} }
callbacks.clear(); callbacks.clear();
battleCallbacks.clear();
logNetwork->infoStream() << "Deleted playerInts."; logNetwork->infoStream() << "Deleted playerInts.";
logNetwork->infoStream() << "Client stopped."; logNetwork->infoStream() << "Client stopped.";
@ -372,7 +372,6 @@ void CClient::newGame( CConnection *con, StartInfo *si )
} }
int humanPlayers = 0; int humanPlayers = 0;
int sensibleAILimit = settings["session"]["oneGoodAI"].Bool() ? 1 : PlayerColor::PLAYER_LIMIT_I;
for(auto it = gs->scenarioOps->playerInfos.begin(); for(auto it = gs->scenarioOps->playerInfos.begin();
it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players
{ {
@ -384,45 +383,22 @@ void CClient::newGame( CConnection *con, StartInfo *si )
logNetwork->traceStream() << "Preparing interface for player " << color; logNetwork->traceStream() << "Preparing interface for player " << color;
if(si->mode != StartInfo::DUEL) if(si->mode != StartInfo::DUEL)
{ {
auto cb = make_shared<CCallback>(gs,color,this);
if(it->second.playerID == PlayerSettings::PLAYER_AI) if(it->second.playerID == PlayerSettings::PLAYER_AI)
{ {
std::string AItoGive = settings["server"]["playerAI"].String(); auto AiToGive = aiNameForPlayer(it->second, false);
if(!sensibleAILimit) logNetwork->infoStream() << boost::format("Player %s will be lead by %s") % color % AiToGive;
AItoGive = "EmptyAI"; installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
else
sensibleAILimit--;
playerint[color] = static_cast<CGameInterface*>(CDynLibHandler::getNewAI(AItoGive));
logNetwork->infoStream() << "Player " << static_cast<int>(color.getNum()) << " will be lead by " << AItoGive;
} }
else else
{ {
playerint[color] = new CPlayerInterface(color); installNewPlayerInterface(new CPlayerInterface(color), color);
humanPlayers++; humanPlayers++;
} }
battleints[color] = playerint[color];
logNetwork->traceStream() << "\tInitializing the interface";
playerint[color]->init(cb.get());
battleCallbacks[color] = callbacks[color] = cb;
} }
else else
{ {
auto cbc = make_shared<CBattleCallback>(gs, color, this); std::string AItoGive = aiNameForPlayer(it->second, true);
battleCallbacks[color] = cbc; installNewBattleInterface(CDynLibHandler::getNewBattleAI(AItoGive), color);
std::string AItoGive = it->second.name;
if(AItoGive.empty())
{
if(color == PlayerColor(0))
battleints[color] = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
else
battleints[color] = CDynLibHandler::getNewBattleAI("StupidAI");
}
battleints[color] = CDynLibHandler::getNewBattleAI(AItoGive);
battleints[color]->init(cbc.get());
} }
} }
@ -433,12 +409,8 @@ void CClient::newGame( CConnection *con, StartInfo *si )
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL); CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL);
p->observerInDuelMode = true; p->observerInDuelMode = true;
battleints[PlayerColor::UNFLAGGABLE] = playerint[PlayerColor::UNFLAGGABLE] = p; installNewPlayerInterface(p, boost::none);
privilagedBattleEventReceivers.push_back(p);
GH.curInt = p; GH.curInt = p;
auto cb = make_shared<CCallback>(gs, boost::optional<PlayerColor>(), this);
battleCallbacks[PlayerColor::NEUTRAL] = callbacks[PlayerColor::NEUTRAL] = cb;
p->init(cb.get());
} }
battleStarted(gs->curB); battleStarted(gs->curB);
} }
@ -502,10 +474,7 @@ void CClient::serialize( Handler &h, const int version )
{ {
if(pid == PlayerColor::NEUTRAL) if(pid == PlayerColor::NEUTRAL)
{ {
//CBattleCallback * cbc = new CBattleCallback(gs, pid, this);//FIXME: unused? installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
CBattleGameInterface *cbgi = CDynLibHandler::getNewBattleAI(dllname);
battleints[pid] = cbgi;
cbgi->init(cb);
//TODO? consider serialization //TODO? consider serialization
continue; continue;
} }
@ -525,9 +494,7 @@ void CClient::serialize( Handler &h, const int version )
nInt->human = isHuman; nInt->human = isHuman;
nInt->playerID = pid; nInt->playerID = pid;
battleCallbacks[pid] = callbacks[pid] = make_shared<CCallback>(gs,pid,this); installNewPlayerInterface(nInt, pid);
battleints[pid] = playerint[pid] = nInt;
nInt->init(callbacks[pid].get());
nInt->loadGame(dynamic_cast<CISer<CLoadFile>&>(h), version); //another evil cast, check above nInt->loadGame(dynamic_cast<CISer<CLoadFile>&>(h), version); //another evil cast, check above
} }
@ -658,10 +625,7 @@ void CClient::battleFinished()
void CClient::loadNeutralBattleAI() void CClient::loadNeutralBattleAI()
{ {
battleints[PlayerColor::NEUTRAL] = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()); installNewBattleInterface(CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()), PlayerColor::NEUTRAL);
auto cbc = make_shared<CBattleCallback>(gs, PlayerColor::NEUTRAL, this);
battleCallbacks[PlayerColor::NEUTRAL] = cbc;
battleints[PlayerColor::NEUTRAL]->init(cbc.get());
} }
void CClient::commitPackage( CPackForClient *pack ) void CClient::commitPackage( CPackForClient *pack )
@ -746,6 +710,65 @@ void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
} }
} }
void CClient::installNewPlayerInterface(CGameInterface *gameInterface, boost::optional<PlayerColor> color)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color)
privilagedGameEventReceivers.push_back(gameInterface);
playerint[colorUsed] = gameInterface;
logGlobal->traceStream() << boost::format("\tInitializing the interface for player %s") % colorUsed;
auto cb = make_shared<CCallback>(gs, color, this);
callbacks[colorUsed] = cb;
battleCallbacks[colorUsed] = cb;
gameInterface->init(cb);
installNewBattleInterface(gameInterface, color, false);
}
void CClient::installNewBattleInterface(CBattleGameInterface* battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color)
privilagedBattleEventReceivers.push_back(battleInterface);
battleints[colorUsed] = battleInterface;
if(needCallback)
{
logGlobal->traceStream() << boost::format("\tInitializing the battle interface for player %s") % *color;
auto cbc = make_shared<CBattleCallback>(gs, color, this);
battleCallbacks[colorUsed] = cbc;
battleInterface->init(cbc);
}
}
std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
{
if(ps.name.size())
{
std::string filename = VCMIDirs::get().libraryPath() + "/AI/" + VCMIDirs::get().libraryName(ps.name);
if(boost::filesystem::exists(filename))
return ps.name;
}
const int sensibleAILimit = settings["session"]["oneGoodAI"].Bool() ? 1 : PlayerColor::PLAYER_LIMIT_I;
std::string goodAI = battleAI ? settings["server"]["neutralAI"].String() : settings["server"]["playerAI"].String();
std::string badAI = battleAI ? "StupidAI" : "EmptyAI";
//TODO what about human players
if(battleints.size() >= sensibleAILimit)
return badAI;
return goodAI;
}
template void CClient::serialize( CISer<CLoadFile> &h, const int version ); template void CClient::serialize( CISer<CLoadFile> &h, const int version );
template void CClient::serialize( COSer<CSaveFile> &h, const int version ); template void CClient::serialize( COSer<CSaveFile> &h, const int version );

View File

@ -112,7 +112,6 @@ public:
class CClient : public IGameCallback class CClient : public IGameCallback
{ {
public: public:
CCallback *cb;
std::map<PlayerColor,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces std::map<PlayerColor,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
std::map<PlayerColor,shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces std::map<PlayerColor,shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
@ -141,6 +140,10 @@ public:
void newGame(CConnection *con, StartInfo *si); //con - connection to server void newGame(CConnection *con, StartInfo *si); //con - connection to server
void loadNeutralBattleAI(); void loadNeutralBattleAI();
void installNewPlayerInterface(CGameInterface *gameInterface, boost::optional<PlayerColor> color);
void installNewBattleInterface(CBattleGameInterface* battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
std::string aiNameForPlayer(const PlayerSettings &ps, bool battleAI); //empty means no AI -> human
void endGame(bool closeConnection = true); void endGame(bool closeConnection = true);
void stopConnection(); void stopConnection();
void save(const std::string & fname); void save(const std::string & fname);

View File

@ -93,8 +93,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
activeStack(NULL), stackToActivate(NULL), selectedStack(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1), activeStack(NULL), stackToActivate(NULL), selectedStack(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1),
currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL), currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0), siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0),
givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL) givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL),
autofightingAI(nullptr), background(nullptr)
{ {
OBJ_CONSTRUCTION; OBJ_CONSTRUCTION;
@ -172,8 +172,16 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
} }
else else
{ {
std::vector< std::string > & backref = graphics->battleBacks[ curInt->cb->battleGetBattlefieldType() ]; auto bfieldType = (int)curInt->cb->battleGetBattlefieldType();
background = BitmapHandler::loadBitmap(backref[ rand() % backref.size()], false ); if(graphics->battleBacks.size() <= bfieldType || bfieldType < 0)
logGlobal->errorStream() << bfieldType << " is not valid battlefield type index!";
else if(graphics->battleBacks[bfieldType].empty())
logGlobal->errorStream() << bfieldType << " battlefield type does not have any backgrounds!";
else
{
const std::string bgName = vstd::pickRandomElementOf(graphics->battleBacks[bfieldType], rand);
background = BitmapHandler::loadBitmap(bgName, false);
}
} }
//preparing menu background //preparing menu background
@ -446,6 +454,8 @@ CBattleInterface::~CBattleInterface()
delete siegeH; delete siegeH;
delete autofightingAI;
//TODO: play AI tracks if battle was during AI turn //TODO: play AI tracks if battle was during AI turn
//if (!curInt->makingTurn) //if (!curInt->makingTurn)
//CCS->musich->playMusicFromSet(CCS->musich->aiMusics, -1); //CCS->musich->playMusicFromSet(CCS->musich->aiMusics, -1);
@ -1254,6 +1264,39 @@ void CBattleInterface::bAutofightf()
{ {
if(spellDestSelectMode) //we are casting a spell if(spellDestSelectMode) //we are casting a spell
return; return;
static bool isAutoFightOn = false;
static unique_ptr<boost::thread> aiThread = nullptr;
if(isAutoFightOn)
{
assert(autofightingAI);
isAutoFightOn = false;
aiThread->join();
vstd::clear_pointer(autofightingAI);
aiThread = nullptr;
}
else
{
isAutoFightOn = true;
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
autofightingAI->init(curInt->cb);
autofightingAI->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
//Deactivate everything
deactivate();
bAutofight->activate(); //only autofight button is to remain active
aiThread = make_unique<boost::thread>([&]
{
auto ba = new BattleAction(autofightingAI->activeStack(activeStack));
if(isAutoFightOn)
{
givenCommand->setn(ba);
}
});
}
} }
void CBattleInterface::bSpellf() void CBattleInterface::bSpellf()

View File

@ -48,6 +48,7 @@ class CClickableHex;
struct BattleHex; struct BattleHex;
struct InfoAboutHero; struct InfoAboutHero;
struct BattleAction; struct BattleAction;
class CBattleGameInterface;
/// Class which manages the locked hex fields that are blocked e.g. by obstacles /// Class which manages the locked hex fields that are blocked e.g. by obstacles
class CBattleObstacle class CBattleObstacle
@ -155,6 +156,8 @@ private:
PossibleActions selectedAction; //last action chosen (and saved) by player PossibleActions selectedAction; //last action chosen (and saved) by player
PossibleActions illegalAction; //most likely action that can't be performed here PossibleActions illegalAction; //most likely action that can't be performed here
CBattleGameInterface *autofightingAI;
void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled) void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)

View File

@ -61,7 +61,7 @@ public:
std::string dllName; std::string dllName;
virtual ~CBattleGameInterface() {}; virtual ~CBattleGameInterface() {};
virtual void init(CBattleCallback * CB){}; virtual void init(shared_ptr<CBattleCallback> CB){};
//battle call-ins //battle call-ins
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
@ -76,7 +76,7 @@ public:
class CGameInterface : public CBattleGameInterface, public IGameEventsReceiver class CGameInterface : public CBattleGameInterface, public IGameEventsReceiver
{ {
public: public:
virtual void init(CCallback * CB){}; virtual void init(shared_ptr<CCallback> CB){};
virtual void yourTurn(){}; //called AFTER playerStartsTurn(player) virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
@ -115,7 +115,7 @@ public:
CAdventureAI() : battleAI(NULL), cbc(NULL) {}; CAdventureAI() : battleAI(NULL), cbc(NULL) {};
CBattleGameInterface *battleAI; CBattleGameInterface *battleAI;
CBattleCallback *cbc; shared_ptr<CBattleCallback> cbc;
virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used

View File

@ -4384,6 +4384,9 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
{ {
case Battle::HERO_SPELL: case Battle::HERO_SPELL:
{ {
COMPLAIN_RET_FALSE_IF(ba.side > 1, "Side must be 0 or 1!");
const CGHeroInstance *h = gs->curB->heroes[ba.side]; const CGHeroInstance *h = gs->curB->heroes[ba.side];
const CGHeroInstance *secondHero = gs->curB->heroes[!ba.side]; const CGHeroInstance *secondHero = gs->curB->heroes[!ba.side];
if(!h) if(!h)