1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

More work on auto-fight.

Dynamic libraries return smart-pointers to what they create.
This commit is contained in:
Michał W. Urbańczyk
2013-06-22 21:47:51 +00:00
parent 2be2143844
commit 4a0587d500
15 changed files with 130 additions and 136 deletions

View File

@@ -19,18 +19,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName); strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
} }
extern "C" DLL_EXPORT char* GetAiNameS() extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
{ {
// need to be defined out = make_shared<CBattleAI>();
return NULL; }
}
extern "C" DLL_EXPORT CBattleGameInterface* GetNewBattleAI()
{
return new CBattleAI();
}
extern "C" DLL_EXPORT void ReleaseBattleAI(CBattleGameInterface* i)
{
delete (CBattleAI*)i;
}

View File

@@ -12,19 +12,8 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
{ {
strcpy(name,NAME); strcpy(name,NAME);
} }
extern "C" DLL_EXPORT char * GetAiNameS()
extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
{ {
char * ret = new char[50]; out = make_shared<CEmptyAI>();
strcpy(ret,NAME); }
return ret;
}
extern "C" DLL_EXPORT CGlobalAI * GetNewAI()
{
return new CEmptyAI();
// return
}
extern "C" DLL_EXPORT void ReleaseAI(CGlobalAI * i)
{
delete (CEmptyAI*)i;
ais.erase(i);
}

View File

@@ -19,18 +19,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName); strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
} }
extern "C" DLL_EXPORT char* GetAiNameS() extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
{ {
// need to be defined out = make_shared<CStupidAI>();
return NULL; }
}
extern "C" DLL_EXPORT CBattleGameInterface* GetNewBattleAI()
{
return new CStupidAI();
}
extern "C" DLL_EXPORT void ReleaseBattleAI(CBattleGameInterface* i)
{
delete (CStupidAI*)i;
}

View File

@@ -17,7 +17,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName); strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
} }
extern "C" DLL_EXPORT CGlobalAI* GetNewAI() extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
{ {
return new VCAI(); out = make_shared<VCAI>();
} }

View File

@@ -361,7 +361,7 @@ void CCallback::validatePaths()
ASSERT_IF_CALLED_WITH_PLAYER ASSERT_IF_CALLED_WITH_PLAYER
const CGHeroInstance *h = cl->IGameCallback::getSelectedHero(*player); const CGHeroInstance *h = cl->IGameCallback::getSelectedHero(*player);
if(h && ( cl->pathInfo->hero != h //wrong hero if(h && ( cl->pathInfo->hero != h //wrong hero
|| cl->pathInfo->hpos != h->getPosition(false) //wrong hero positoin || cl->pathInfo->hpos != h->getPosition(false) //wrong hero position
|| !cl->pathInfo->isValid)) //paths invalidated by game event || !cl->pathInfo->isValid)) //paths invalidated by game event
{ {
recalculatePaths(); recalculatePaths();
@@ -376,25 +376,25 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
return swapCreatures(s1, s2, p1, p2); return swapCreatures(s1, s2, p1, p2);
} }
void CCallback::registerGameInterface(CGameInterface *cgi) void CCallback::registerGameInterface(shared_ptr<CGameInterface> cgi)
{ {
cl->additionalPlayerInts[*player].push_back(cgi); cl->additionalPlayerInts[*player].push_back(cgi);
registerBattleInterface(cgi); registerBattleInterface(cgi);
} }
void CCallback::registerBattleInterface(CBattleGameInterface *cbga) void CCallback::registerBattleInterface(shared_ptr<CBattleGameInterface> cbga)
{ {
cl->additionalBattleInts[*player].push_back(cbga); cl->additionalBattleInts[*player].push_back(cbga);
} }
void CCallback::unregisterGameInterface(CGameInterface *cgi) void CCallback::unregisterGameInterface(shared_ptr<CGameInterface> cgi)
{ {
cl->additionalPlayerInts[*player] -= cgi; cl->additionalPlayerInts[*player] -= cgi;
unregisterBattleInterface(cgi); unregisterBattleInterface(cgi);
} }
void CCallback::unregisterBattleInterface(CBattleGameInterface *cbga) void CCallback::unregisterBattleInterface(shared_ptr<CBattleGameInterface> cbga)
{ {
cl->additionalBattleInts[*player] -= cbga; cl->additionalBattleInts[*player] -= cbga;
} }

View File

@@ -114,10 +114,10 @@ public:
virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over) virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over)
//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins. //Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
void registerGameInterface(CGameInterface *cgi); void registerGameInterface(shared_ptr<CGameInterface> cgi);
void registerBattleInterface(CBattleGameInterface *cbga); void registerBattleInterface(shared_ptr<CBattleGameInterface> cbga);
void unregisterGameInterface(CGameInterface *cgi); void unregisterGameInterface(shared_ptr<CGameInterface> cgi);
void unregisterBattleInterface(CBattleGameInterface *cbga); void unregisterBattleInterface(shared_ptr<CBattleGameInterface> cbga);
void unregisterMyInterface(); //stops delivering information about game events to that player's interface -> can be called ONLY after victory/loss void unregisterMyInterface(); //stops delivering information about game events to that player's interface -> can be called ONLY after victory/loss

View File

@@ -706,7 +706,6 @@ void processCommand(const std::string &message)
{ {
if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
{ {
delete ai;
Settings neutralAI = settings.write["server"]["neutralAI"]; Settings neutralAI = settings.write["server"]["neutralAI"];
neutralAI->String() = fname; neutralAI->String() = fname;
std::cout << "Setting changed, from now the battle ai will be " << fname << "!\n"; std::cout << "Setting changed, from now the battle ai will be " << fname << "!\n";

View File

@@ -207,13 +207,8 @@ void CClient::endGame( bool closeConnection /*= true*/ )
logNetwork->infoStream() << "Deleted mapHandler and gameState."; logNetwork->infoStream() << "Deleted mapHandler and gameState.";
LOCPLINT = NULL; LOCPLINT = NULL;
} }
while (!playerint.empty())
{
CGameInterface *pint = playerint.begin()->second;
playerint.erase(playerint.begin());
delete pint;
}
playerint.clear();
callbacks.clear(); callbacks.clear();
battleCallbacks.clear(); battleCallbacks.clear();
logNetwork->infoStream() << "Deleted playerInts."; logNetwork->infoStream() << "Deleted playerInts.";
@@ -391,7 +386,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
} }
else else
{ {
installNewPlayerInterface(new CPlayerInterface(color), color); installNewPlayerInterface(make_shared<CPlayerInterface>(color), color);
humanPlayers++; humanPlayers++;
} }
} }
@@ -407,10 +402,10 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(!gNoGUI) if(!gNoGUI)
{ {
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL); auto p = make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
p->observerInDuelMode = true; p->observerInDuelMode = true;
installNewPlayerInterface(p, boost::none); installNewPlayerInterface(p, boost::none);
GH.curInt = p; GH.curInt = p.get();
} }
battleStarted(gs->curB); battleStarted(gs->curB);
} }
@@ -469,7 +464,7 @@ void CClient::serialize( Handler &h, const int version )
h & pid & dllname & isHuman; h & pid & dllname & isHuman;
LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid); LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid);
CGameInterface *nInt = nullptr; shared_ptr<CGameInterface> nInt = nullptr;
if(dllname.length()) if(dllname.length())
{ {
if(pid == PlayerColor::NEUTRAL) if(pid == PlayerColor::NEUTRAL)
@@ -487,7 +482,7 @@ void CClient::serialize( Handler &h, const int version )
else else
{ {
assert(isHuman); assert(isHuman);
nInt = new CPlayerInterface(pid); nInt = make_shared<CPlayerInterface>(pid);
} }
nInt->dllName = dllname; nInt->dllName = dllname;
@@ -584,18 +579,18 @@ void CClient::battleStarted(const BattleInfo * info)
// if(battleCallbacks.count(side)) // if(battleCallbacks.count(side))
// battleCallbacks[side]->setBattle(info); // battleCallbacks[side]->setBattle(info);
CPlayerInterface * att, * def; shared_ptr<CPlayerInterface> att, def;
if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human) if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
att = static_cast<CPlayerInterface*>( playerint[info->sides[0]] ); att = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[0]] );
else else
att = NULL; att = NULL;
if(vstd::contains(playerint, info->sides[1]) && playerint[info->sides[1]]->human) if(vstd::contains(playerint, info->sides[1]) && playerint[info->sides[1]]->human)
def = static_cast<CPlayerInterface*>( playerint[info->sides[1]] ); def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[1]] );
else else
def = NULL; def = NULL;
if(!gNoGUI && (att || def || gs->scenarioOps->mode == StartInfo::DUEL)) if(!gNoGUI && (!!att || !!def || gs->scenarioOps->mode == StartInfo::DUEL))
{ {
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1],
@@ -650,7 +645,7 @@ void CClient::calculatePaths(const CGHeroInstance *h)
gs->calculatePaths(h, *pathInfo); gs->calculatePaths(h, *pathInfo);
} }
void CClient::commenceTacticPhaseForInt(CBattleGameInterface *battleInt) void CClient::commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt)
{ {
setThreadName("CClient::commenceTacticPhaseForInt"); setThreadName("CClient::commenceTacticPhaseForInt");
try try
@@ -710,7 +705,7 @@ void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
} }
} }
void CClient::installNewPlayerInterface(CGameInterface *gameInterface, boost::optional<PlayerColor> color) void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color)
{ {
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE); PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
@@ -729,7 +724,7 @@ void CClient::installNewPlayerInterface(CGameInterface *gameInterface, boost::op
installNewBattleInterface(gameInterface, color, false); installNewBattleInterface(gameInterface, color, false);
} }
void CClient::installNewBattleInterface(CBattleGameInterface* battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/) void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
{ {
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE); PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);

View File

@@ -114,13 +114,13 @@ class CClient : public IGameCallback
public: public:
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<shared_ptr<IGameEventsReceiver>> privilagedGameEventReceivers; //scripting modules, spectator interfaces
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces std::vector<shared_ptr<IBattleEventsReceiver>> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
std::map<PlayerColor,CGameInterface *> playerint; std::map<PlayerColor, shared_ptr<CGameInterface>> playerint;
std::map<PlayerColor,CBattleGameInterface *> battleints; std::map<PlayerColor, shared_ptr<CBattleGameInterface>> battleints;
std::map<PlayerColor,std::vector<CGameInterface *>> additionalPlayerInts; std::map<PlayerColor,std::vector<shared_ptr<CGameInterface>>> additionalPlayerInts;
std::map<PlayerColor,std::vector<CBattleGameInterface *>> additionalBattleInts; std::map<PlayerColor,std::vector<shared_ptr<CBattleGameInterface>>> additionalBattleInts;
bool hotSeat; bool hotSeat;
CConnection *serv; CConnection *serv;
@@ -144,8 +144,8 @@ 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 installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color);
void installNewBattleInterface(CBattleGameInterface* battleInterface, boost::optional<PlayerColor> color, bool needCallback = true); void installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
std::string aiNameForPlayer(const PlayerSettings &ps, bool battleAI); //empty means no AI -> human std::string aiNameForPlayer(const PlayerSettings &ps, bool battleAI); //empty means no AI -> human
void endGame(bool closeConnection = true); void endGame(bool closeConnection = true);
@@ -229,7 +229,7 @@ public:
void handlePack( CPack * pack ); //applies the given pack and deletes it void handlePack( CPack * pack ); //applies the given pack and deletes it
void battleStarted(const BattleInfo * info); void battleStarted(const BattleInfo * info);
void commenceTacticPhaseForInt(CBattleGameInterface *battleInt); //will be called as separate thread void commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt); //will be called as separate thread
void commitPackage(CPackForClient *pack) OVERRIDE; void commitPackage(CPackForClient *pack) OVERRIDE;

View File

@@ -88,24 +88,31 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
animsAreDisplayed.setn(true); animsAreDisplayed.setn(true);
} }
CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen) CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2,
CGHeroInstance *hero1, CGHeroInstance *hero2,
const SDL_Rect & myRect,
shared_ptr<CPlayerInterface> att, shared_ptr<CPlayerInterface> defen)
: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), : queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
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) autofightingAI(nullptr), isAutoFightOn(false), aiThread(nullptr), background(nullptr)
{ {
OBJ_CONSTRUCTION; OBJ_CONSTRUCTION;
if(!curInt) curInt = LOCPLINT; //may happen when we are defending during network MP game if(!curInt)
{
//May happen when we are defending during network MP game -> attacker interface is just not present
curInt = defenderInt;
}
animsAreDisplayed.setn(false); animsAreDisplayed.setn(false);
pos = myRect; pos = myRect;
strongInterest = true; strongInterest = true;
givenCommand = new CondSh<BattleAction *>(NULL); givenCommand = new CondSh<BattleAction *>(NULL);
if(attackerInt && attackerInt->cb->battleGetTacticDist()) //hotseat -> check tactics for both players (defender may be local human) if(attackerInt && attackerInt->cb->battleGetTacticDist()) //hot-seat -> check tactics for both players (defender may be local human)
tacticianInterface = attackerInt; tacticianInterface = attackerInt;
else if(defenderInt && defenderInt->cb->battleGetTacticDist()) else if(defenderInt && defenderInt->cb->battleGetTacticDist())
tacticianInterface = defenderInt; tacticianInterface = defenderInt;
@@ -453,9 +460,7 @@ CBattleInterface::~CBattleInterface()
delete bigForceField[1]; delete bigForceField[1];
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);
@@ -493,6 +498,12 @@ void CBattleInterface::setPrintMouseShadow(bool set)
void CBattleInterface::activate() void CBattleInterface::activate()
{ {
if(isAutoFightOn)
{
bAutofight->activate();
return;
}
CIntObject::activate(); CIntObject::activate();
bOptions->activate(); bOptions->activate();
bSurrender->activate(); bSurrender->activate();
@@ -1265,16 +1276,16 @@ void CBattleInterface::bAutofightf()
if(spellDestSelectMode) //we are casting a spell if(spellDestSelectMode) //we are casting a spell
return; return;
static bool isAutoFightOn = false; //Stop auto-fight mode
static unique_ptr<boost::thread> aiThread = nullptr;
if(isAutoFightOn) if(isAutoFightOn)
{ {
assert(autofightingAI); assert(autofightingAI);
isAutoFightOn = false; isAutoFightOn = false;
logGlobal->traceStream() << "Stopping the autofight...";
aiThread->interrupt();
aiThread->join(); aiThread->join();
vstd::clear_pointer(autofightingAI); autofightingAI = nullptr;
aiThread = nullptr; aiThread = nullptr;
} }
else else
@@ -1284,18 +1295,7 @@ void CBattleInterface::bAutofightf()
autofightingAI->init(curInt->cb); autofightingAI->init(curInt->cb);
autofightingAI->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide()); autofightingAI->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
//Deactivate everything requestAutofightingAIToTakeAction();
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);
}
});
} }
} }
@@ -1313,7 +1313,7 @@ void CBattleInterface::bSpellf()
ESpellCastProblem::ESpellCastProblem spellCastProblem; ESpellCastProblem::ESpellCastProblem spellCastProblem;
if (curInt->cb->battleCanCastSpell(&spellCastProblem)) if (curInt->cb->battleCanCastSpell(&spellCastProblem))
{ {
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, curInt); CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, curInt.get());
GH.pushInt(spellWindow); GH.pushInt(spellWindow);
} }
else if(spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED) else if(spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED)
@@ -2057,7 +2057,7 @@ void CBattleInterface::activateStack()
const CStack *s = activeStack; const CStack *s = activeStack;
myTurn = true; myTurn = true;
if(attackerInt && defenderInt) //hotseat -> need to pick which interface "takes over" as active if(!!attackerInt && defenderInt) //hotseat -> need to pick which interface "takes over" as active
curInt = attackerInt->playerID == s->owner ? attackerInt : defenderInt; curInt = attackerInt->playerID == s->owner ? attackerInt : defenderInt;
queue->update(); queue->update();
@@ -2096,6 +2096,9 @@ void CBattleInterface::activateStack()
if(!pendingAnims.size() && !active) if(!pendingAnims.size() && !active)
activate(); activate();
if(isAutoFightOn)
requestAutofightingAIToTakeAction();
GH.fakeMouseMove(); GH.fakeMouseMove();
} }
@@ -3585,6 +3588,24 @@ InfoAboutHero CBattleInterface::enemyHero() const
return ret; return ret;
} }
void CBattleInterface::requestAutofightingAIToTakeAction()
{
assert(isAutoFightOn);
deactivate();
bAutofight->activate();
aiThread = make_unique<boost::thread>([&]
{
auto ba = new BattleAction(autofightingAI->activeStack(activeStack));
if(isAutoFightOn)
{
givenCommand->setn(ba);
}
});
}
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner) CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
: owner(_owner), town(siegeTown) : owner(_owner), town(siegeTown)
{ {

View File

@@ -140,7 +140,7 @@ private:
double getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group double getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
std::map<int, int> standingFrame; //number of frame in standing animation by stack ID, helps in showing 'random moves' std::map<int, int> standingFrame; //number of frame in standing animation by stack ID, helps in showing 'random moves'
CPlayerInterface * tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
bool tacticsMode; bool tacticsMode;
bool stackCanCastSpell; //if true, active stack could possibly cats some target spell bool stackCanCastSpell; //if true, active stack could possibly cats some target spell
bool creatureCasting; //if true, stack currently aims to cats a spell bool creatureCasting; //if true, stack currently aims to cats a spell
@@ -156,7 +156,11 @@ 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; shared_ptr<CBattleGameInterface> autofightingAI;
bool isAutoFightOn;
unique_ptr<boost::thread> aiThread;
void requestAutofightingAIToTakeAction();
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)
@@ -198,16 +202,16 @@ private:
friend class CBattleInterface; friend class CBattleInterface;
} * siegeH; } * siegeH;
CPlayerInterface * attackerInt, * defenderInt; //because LOCPLINT is not enough in hotSeat shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell
public: public:
CPlayerInterface * curInt; //current player interface shared_ptr<CPlayerInterface> curInt; //current player interface
std::list<std::pair<CBattleAnimation *, bool> > pendingAnims; //currently displayed animations <anim, initialized> std::list<std::pair<CBattleAnimation *, bool> > pendingAnims; //currently displayed animations <anim, initialized>
void addNewAnim(CBattleAnimation * anim); //adds new anim to pendingAnims void addNewAnim(CBattleAnimation * anim); //adds new anim to pendingAnims
ui32 animIDhelper; //for giving IDs for animations ui32 animIDhelper; //for giving IDs for animations
static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, shared_ptr<CPlayerInterface> att, shared_ptr<CPlayerInterface> defen); //c-tor
~CBattleInterface(); //d-tor ~CBattleInterface(); //d-tor
//std::vector<TimeInterested*> timeinterested; //animation handling //std::vector<TimeInterested*> timeinterested; //animation handling

View File

@@ -174,7 +174,7 @@ void CBattleHero::clickLeft(tribool down, bool previousState)
} }
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0); CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, myOwner->curInt); CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, myOwner->curInt.get());
GH.pushInt(spellWindow); GH.pushInt(spellWindow);
} }
} }
@@ -483,7 +483,7 @@ void CBattleResultWindow::bExitf()
return; return;
} }
CPlayerInterface * intTmp = owner->curInt; auto intTmp = owner->curInt;
GH.popInts(2); //first - we; second - battle interface GH.popInts(2); //first - we; second - battle interface
intTmp->showingDialog->setn(false); intTmp->showingDialog->setn(false);
CCS->videoh->close(); CCS->videoh->close();

View File

@@ -22,27 +22,33 @@
* *
*/ */
template<typename rett> template<typename rett>
rett * createAny(std::string dllname, std::string methodName) shared_ptr<rett> createAny(std::string dllname, std::string methodName)
{ {
char temp[50]; typedef void(*TGetAIFun)(shared_ptr<rett>&);
rett * ret=NULL; typedef void(*TGetNameFun)(char*);
rett*(*getAI)();
void(*getName)(char*); char temp[150];
TGetAIFun getAI = nullptr;
TGetNameFun getName = nullptr;
#ifdef _WIN32 #ifdef _WIN32
HINSTANCE dll = LoadLibraryA(dllname.c_str()); HINSTANCE dll = LoadLibraryA(dllname.c_str());
if (dll) if (dll)
{ {
getName = (void(*)(char*))GetProcAddress(dll,"GetAiName"); getName = (TGetNameFun)GetProcAddress(dll,"GetAiName");
getAI = (rett*(*)())GetProcAddress(dll,methodName.c_str()); getAI = (TGetAIFun)GetProcAddress(dll,methodName.c_str());
} }
#else #else
void *dll = dlopen(dllname.c_str(), RTLD_LOCAL | RTLD_LAZY); void *dll = dlopen(dllname.c_str(), RTLD_LOCAL | RTLD_LAZY);
if (dll) if (dll)
{ {
getName = (void(*)(char*))dlsym(dll,"GetAiName"); getName = (TGetNameFun)dlsym(dll,"GetAiName");
getAI = (rett*(*)())dlsym(dll,methodName.c_str()); getAI = (TGetAIFun)dlsym(dll,methodName.c_str());
} }
else else
logGlobal->errorStream() << "Error: " << dlerror(); logGlobal->errorStream() << "Error: " << dlerror();
@@ -65,8 +71,9 @@ rett * createAny(std::string dllname, std::string methodName)
getName(temp); getName(temp);
logGlobal->infoStream() << "Loaded " << temp; logGlobal->infoStream() << "Loaded " << temp;
ret = getAI();
shared_ptr<rett> ret;
getAI(ret);
if(!ret) if(!ret)
logGlobal->errorStream() << "Cannot get AI!"; logGlobal->errorStream() << "Cannot get AI!";
@@ -74,26 +81,27 @@ rett * createAny(std::string dllname, std::string methodName)
} }
template<typename rett> template<typename rett>
rett * createAnyAI(std::string dllname, std::string methodName) shared_ptr<rett> createAnyAI(std::string dllname, std::string methodName)
{ {
logGlobal->infoStream() << "Opening " << dllname; logGlobal->infoStream() << "Opening " << dllname;
std::string filename = VCMIDirs::get().libraryName(dllname); std::string filename = VCMIDirs::get().libraryName(dllname);
rett* ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
auto ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
ret->dllName = dllname; ret->dllName = dllname;
return ret; return ret;
} }
CGlobalAI * CDynLibHandler::getNewAI(std::string dllname) shared_ptr<CGlobalAI> CDynLibHandler::getNewAI(std::string dllname)
{ {
return createAnyAI<CGlobalAI>(dllname, "GetNewAI"); return createAnyAI<CGlobalAI>(dllname, "GetNewAI");
} }
CBattleGameInterface * CDynLibHandler::getNewBattleAI(std::string dllname ) shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string dllname )
{ {
return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI"); return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
} }
CScriptingModule * CDynLibHandler::getNewScriptingModule(std::string dllname) shared_ptr<CScriptingModule> CDynLibHandler::getNewScriptingModule(std::string dllname)
{ {
return createAny<CScriptingModule>(dllname, "GetNewModule"); return createAny<CScriptingModule>(dllname, "GetNewModule");
} }
@@ -187,7 +195,7 @@ void CAdventureAI::battleSpellCast(const BattleSpellCast *sc)
void CAdventureAI::battleEnd(const BattleResult *br) void CAdventureAI::battleEnd(const BattleResult *br)
{ {
battleAI->battleEnd(br); battleAI->battleEnd(br);
vstd::clear_pointer(battleAI); battleAI = nullptr;
} }
void CAdventureAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) void CAdventureAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)

View File

@@ -96,9 +96,9 @@ public:
class DLL_LINKAGE CDynLibHandler class DLL_LINKAGE CDynLibHandler
{ {
public: public:
static CGlobalAI * getNewAI(std::string dllname); static shared_ptr<CGlobalAI> getNewAI(std::string dllname);
static CBattleGameInterface * getNewBattleAI(std::string dllname); static shared_ptr<CBattleGameInterface> getNewBattleAI(std::string dllname);
static CScriptingModule * getNewScriptingModule(std::string dllname); static shared_ptr<CScriptingModule> getNewScriptingModule(std::string dllname);
}; };
class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate) class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate)
@@ -114,7 +114,7 @@ class DLL_LINKAGE CAdventureAI : public CGlobalAI
public: public:
CAdventureAI() : battleAI(NULL), cbc(NULL) {}; CAdventureAI() : battleAI(NULL), cbc(NULL) {};
CBattleGameInterface *battleAI; shared_ptr<CBattleGameInterface> battleAI;
shared_ptr<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

@@ -28,7 +28,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName); strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
} }
extern "C" DLL_EXPORT CScriptingModule* GetNewModule() extern "C" DLL_EXPORT void GetNewModule(shared_ptr<CScriptingModule> &out)
{ {
return new ERMInterpreter(); out = make_shared<ERMInterpreter>();
} }