diff --git a/.travis.yml b/.travis.yml
index 1536f7227..7fabdc1f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,7 @@ matrix:
env: VCMI_PLATFORM='mxe' MXE_TARGET=i686-w64-mingw32.shared VCMI_CMAKE_FLAGS='-DENABLE_TEST=0'
sudo: required
- os: osx
- env: VCMI_PLATFORM='mac'
+ env: VCMI_PLATFORM='mac' VCMI_CMAKE_FLAGS='-DENABLE_TEST=0'
addons:
apt:
diff --git a/AI/BattleAI/BattleAI.cbp b/AI/BattleAI/BattleAI.cbp
index 4032325a6..b2c8bcfc0 100644
--- a/AI/BattleAI/BattleAI.cbp
+++ b/AI/BattleAI/BattleAI.cbp
@@ -69,7 +69,7 @@
-
+
@@ -100,9 +100,6 @@
-
-
-
diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp
index 331bc68d5..98e94495e 100644
--- a/AI/BattleAI/BattleAI.cpp
+++ b/AI/BattleAI/BattleAI.cpp
@@ -10,8 +10,6 @@
#include "StdInc.h"
#include "BattleAI.h"
-#include
-
#include "StackWithBonuses.h"
#include "EnemyInfo.h"
#include "../../lib/CStopWatch.h"
@@ -26,26 +24,6 @@
#define LOGL(text) print(text)
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
-class RNGStub : public vstd::RNG
-{
-public:
- vstd::TRandI64 getInt64Range(int64_t lower, int64_t upper) override
- {
- return [=]()->int64_t
- {
- return (lower + upper)/2;
- };
- }
-
- vstd::TRand getDoubleRange(double lower, double upper) override
- {
- return [=]()->double
- {
- return (lower + upper)/2;
- };
- }
-};
-
enum class SpellTypes
{
ADVENTURE, BATTLE, OTHER
@@ -53,10 +31,10 @@ enum class SpellTypes
SpellTypes spellType(const CSpell * spell)
{
- if(!spell->isCombatSpell() || spell->isCreatureAbility())
+ if(!spell->isCombat() || spell->isCreatureAbility())
return SpellTypes::OTHER;
- if(spell->isOffensiveSpell() || spell->hasEffects() || spell->hasBattleEffects())
+ if(spell->isOffensive() || spell->hasEffects() || spell->hasBattleEffects())
return SpellTypes::BATTLE;
return SpellTypes::OTHER;
@@ -83,7 +61,9 @@ std::vector CBattleAI::getBrokenWallMoatHexes() const
}
CBattleAI::CBattleAI()
- : side(-1), wasWaitingForRealize(false), wasUnlockingGs(false)
+ : side(-1),
+ wasWaitingForRealize(false),
+ wasUnlockingGs(false)
{
}
@@ -97,12 +77,13 @@ CBattleAI::~CBattleAI()
}
}
-void CBattleAI::init(std::shared_ptr CB)
+void CBattleAI::init(std::shared_ptr ENV, std::shared_ptr CB)
{
setCbc(CB);
+ env = ENV;
cb = CB;
playerID = *CB->getPlayerID(); //TODO should be sth in callback
- wasWaitingForRealize = cb->waitTillRealize;
+ wasWaitingForRealize = CB->waitTillRealize;
wasUnlockingGs = CB->unlockGsWhenWaiting;
CB->waitTillRealize = true;
CB->unlockGsWhenWaiting = false;
@@ -131,7 +112,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
attemptCastingSpell();
- if(auto ret = getCbc()->battleIsFinished())
+ if(auto ret = cb->battleIsFinished())
{
//spellcast may finish battle
//send special preudo-action
@@ -144,7 +125,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
return *action;
//best action is from effective owner point if view, we are effective owner as we received "activeStack"
-
+
//evaluate casting spell for spellcasting stack
boost::optional bestSpellcast(boost::none);
//TODO: faerie dragon type spell should be selected by server
@@ -174,7 +155,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
}
}
- HypotheticBattle hb(getCbc());
+ HypotheticBattle hb(env.get(), cb);
PotentialTargets targets(stack, &hb);
@@ -199,7 +180,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
);
return BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
- }
+ }
}
else if(bestSpellcast.is_initialized())
{
@@ -210,7 +191,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
if(stack->waited())
{
//ThreatMap threatsToUs(stack); // These lines may be usefull but they are't used in the code.
- auto dists = getCbc()->getReachability(stack);
+ auto dists = cb->getReachability(stack);
if(!targets.unreachableEnemies.empty())
{
auto closestEnemy = vstd::minElementByFun(targets.unreachableEnemies, [&](const battle::Unit * enemy) -> int
@@ -242,7 +223,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
else
return goTowardsNearest(stack, brokenWallMoat);
- }
+ }
}
}
catch(boost::thread_interrupted &)
@@ -279,10 +260,10 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vectorcoversPos(hex))
{
- logAi->warn("Warning: already standing on neighbouring tile!");
- //We shouldn't even be here...
- return BattleAction::makeDefend(stack);
- }
+ logAi->warn("Warning: already standing on neighbouring tile!");
+ //We shouldn't even be here...
+ return BattleAction::makeDefend(stack);
+ }
}
BattleHex bestNeighbor = hexes.front();
@@ -330,7 +311,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
if(cb->battleGetGateState() == EGateState::CLOSED)
{
targetHex = cb->wallPartToBattleHex(EWallPart::GATE);
- }
+}
else
{
EWallPart::EWallPart wallParts[] = {
@@ -381,9 +362,9 @@ void CBattleAI::attemptCastingSpell()
LOGL("Casting spells sounds like fun. Let's see...");
//Get all spells we can cast
std::vector possibleSpells;
- vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero](const CSpell *s) -> bool
+ vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero, this](const CSpell *s) -> bool
{
- return s->canBeCast(getCbc().get(), spells::Mode::HERO, hero);
+ return s->canBeCast(cb.get(), spells::Mode::HERO, hero);
});
LOGFL("I can cast %d spells.", possibleSpells.size());
@@ -398,7 +379,7 @@ void CBattleAI::attemptCastingSpell()
std::vector possibleCasts;
for(auto spell : possibleSpells)
{
- spells::BattleCast temp(getCbc().get(), hero, spells::Mode::HERO, spell);
+ spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell);
for(auto & target : temp.findPotentialTargets())
{
@@ -500,8 +481,6 @@ void CBattleAI::attemptCastingSpell()
return ourTurnSpan >= minTurnSpan;
};
- RNGStub rngStub;
-
ValueMap valueOfStack;
ValueMap healthOfStack;
@@ -536,7 +515,8 @@ void CBattleAI::attemptCastingSpell()
{
bool enemyHadTurn = false;
- HypotheticBattle state(cb);
+ HypotheticBattle state(env.get(), cb);
+
evaluateQueue(valueOfStack, turnOrder, &state, 0, &enemyHadTurn);
if(!enemyHadTurn)
@@ -551,13 +531,17 @@ void CBattleAI::attemptCastingSpell()
}
}
- auto evaluateSpellcast = [&] (PossibleSpellcast * ps)
+ struct ScriptsCache
{
- HypotheticBattle state(cb);
+ //todo: re-implement scripts context cache
+ };
+
+ auto evaluateSpellcast = [&] (PossibleSpellcast * ps, std::shared_ptr)
+ {
+ HypotheticBattle state(env.get(), cb);
spells::BattleCast cast(&state, hero, spells::Mode::HERO, ps->spell);
- cast.target = ps->dest;
- cast.cast(&state, rngStub);
+ cast.castEval(state.getServerCallback(), ps->dest);
ValueMap newHealthOfStack;
ValueMap newValueOfStack;
@@ -617,10 +601,12 @@ void CBattleAI::attemptCastingSpell()
}
};
- std::vector> tasks;
+ using EvalRunner = ThreadPool;
+
+ EvalRunner::Tasks tasks;
for(PossibleSpellcast & psc : possibleCasts)
- tasks.push_back(std::bind(evaluateSpellcast, &psc));
+ tasks.push_back(std::bind(evaluateSpellcast, &psc, _1));
uint32_t threadCount = boost::thread::hardware_concurrency();
@@ -632,8 +618,15 @@ void CBattleAI::attemptCastingSpell()
CStopWatch timer;
- CThreadHelper threadHelper(&tasks, threadCount);
- threadHelper.run();
+ std::vector> scriptsPool;
+
+ for(uint32_t idx = 0; idx < threadCount; idx++)
+ {
+ scriptsPool.emplace_back();
+ }
+
+ EvalRunner runner(&tasks, scriptsPool);
+ runner.run();
LOGFL("Evaluation took %d ms", timer.getDiff());
@@ -666,9 +659,9 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
using ValueMap = PossibleSpellcast::ValueMap;
RNGStub rngStub;
- HypotheticBattle state(getCbc());
- TStacks all = getCbc()->battleGetAllStacks(false);
-
+ HypotheticBattle state(env.get(), cb);
+ TStacks all = cb->battleGetAllStacks(false);
+
ValueMap healthOfStack;
ValueMap newHealthOfStack;
@@ -678,8 +671,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
}
spells::BattleCast cast(&state, stack, spells::Mode::CREATURE_ACTIVE, ps.spell);
- cast.target = ps.dest;
- cast.cast(&state, rngStub);
+ cast.castEval(state.getServerCallback(), ps.dest);
for(auto unit : all)
{
@@ -710,7 +702,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
}
ps.value = totalGain;
-};
+}
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
{
diff --git a/AI/BattleAI/BattleAI.h b/AI/BattleAI/BattleAI.h
index e0623619b..47dc84c47 100644
--- a/AI/BattleAI/BattleAI.h
+++ b/AI/BattleAI/BattleAI.h
@@ -51,6 +51,7 @@ class CBattleAI : public CBattleGameInterface
{
int side;
std::shared_ptr cb;
+ std::shared_ptr env;
//Previous setting of cb
bool wasWaitingForRealize, wasUnlockingGs;
@@ -59,7 +60,7 @@ public:
CBattleAI();
~CBattleAI();
- void init(std::shared_ptr CB) override;
+ void init(std::shared_ptr ENV, std::shared_ptr CB) override;
void attemptCastingSpell();
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only
@@ -74,7 +75,7 @@ public:
//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 battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
- //void battleStacksAttacked(const std::vector & bsa, const std::vector & battleLog) override; //called when stack receives damage (after battleAttack())
+ //void battleStacksAttacked(const std::vector & bsa) override; //called when stack receives damage (after battleAttack())
//void battleEnd(const BattleResult *br) override;
//void battleResultsApplied() override; //called when all effects of last battle are applied
//void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied;
diff --git a/AI/BattleAI/PossibleSpellcast.h b/AI/BattleAI/PossibleSpellcast.h
index b96698be2..806832ad5 100644
--- a/AI/BattleAI/PossibleSpellcast.h
+++ b/AI/BattleAI/PossibleSpellcast.h
@@ -10,8 +10,9 @@
#pragma once
+#include
+
#include "../../lib/battle/Destination.h"
-#include "../../lib/spells/Magic.h"
class CSpell;
diff --git a/AI/BattleAI/StackWithBonuses.cpp b/AI/BattleAI/StackWithBonuses.cpp
index 2c1a0cd79..2b3679569 100644
--- a/AI/BattleAI/StackWithBonuses.cpp
+++ b/AI/BattleAI/StackWithBonuses.cpp
@@ -9,8 +9,14 @@
*/
#include "StdInc.h"
#include "StackWithBonuses.h"
-#include "../../lib/NetPacksBase.h"
+
+#include
+
+#include "../../lib/NetPacks.h"
#include "../../lib/CStack.h"
+#include "../../lib/ScriptHandler.h"
+
+using scripting::Pool;
void actualizeEffect(TBonusListPtr target, const Bonus & ef)
{
@@ -191,19 +197,27 @@ void StackWithBonuses::removeUnitBonus(const CSelector & selector)
vstd::erase_if(bonusesToUpdate, [&](const Bonus & b){return selector(&b);});
}
-void StackWithBonuses::spendMana(const spells::PacketSender * server, const int spellCost) const
+void StackWithBonuses::spendMana(ServerCallback * server, const int spellCost) const
{
//TODO: evaluate cast use
}
-HypotheticBattle::HypotheticBattle(Subject realBattle)
+HypotheticBattle::HypotheticBattle(const Environment * ENV, Subject realBattle)
: BattleProxy(realBattle),
+ env(ENV),
bonusTreeVersion(1)
{
auto activeUnit = realBattle->battleActiveUnit();
activeUnitId = activeUnit ? activeUnit->unitId() : -1;
- nextId = 0xF0000000;
+ nextId = 0x00F00000;
+
+ eventBus.reset(new events::EventBus());
+
+ localEnvironment.reset(new HypotheticEnvironment(this, env));
+ serverCallback.reset(new HypotheticServerCallback(this));
+
+ pool.reset(new scripting::PoolImpl(localEnvironment.get(), serverCallback.get()));
}
bool HypotheticBattle::unitHasAmmoCart(const battle::Unit * unit) const
@@ -348,6 +362,11 @@ void HypotheticBattle::removeUnit(uint32_t id)
}
}
+void HypotheticBattle::updateUnit(uint32_t id, const JsonNode & data)
+{
+ //TODO:
+}
+
void HypotheticBattle::addUnitBonus(uint32_t id, const std::vector & bonus)
{
getForUpdate(id)->addUnitBonus(bonus);
@@ -400,3 +419,107 @@ int64_t HypotheticBattle::getTreeVersion() const
{
return getBattleNode()->getTreeVersion() + bonusTreeVersion;
}
+
+Pool * HypotheticBattle::getContextPool() const
+{
+ return pool.get();
+}
+
+ServerCallback * HypotheticBattle::getServerCallback()
+{
+ return serverCallback.get();
+}
+
+HypotheticBattle::HypotheticServerCallback::HypotheticServerCallback(HypotheticBattle * owner_)
+ :owner(owner_)
+{
+
+}
+
+void HypotheticBattle::HypotheticServerCallback::complain(const std::string & problem)
+{
+ logAi->error(problem);
+}
+
+bool HypotheticBattle::HypotheticServerCallback::describeChanges() const
+{
+ return false;
+}
+
+vstd::RNG * HypotheticBattle::HypotheticServerCallback::getRNG()
+{
+ return &rngStub;
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(CPackForClient * pack)
+{
+ logAi->error("Package of type %s is not allowed in battle evaluation", typeid(pack).name());
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(BattleLogMessage * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(BattleStackMoved * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(BattleUnitsChanged * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(SetStackEffect * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(StacksInjured * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(BattleObstaclesChanged * pack)
+{
+ pack->applyBattle(owner);
+}
+
+void HypotheticBattle::HypotheticServerCallback::apply(CatapultAttack * pack)
+{
+ pack->applyBattle(owner);
+}
+
+HypotheticBattle::HypotheticEnvironment::HypotheticEnvironment(HypotheticBattle * owner_, const Environment * upperEnvironment)
+ : owner(owner_),
+ env(upperEnvironment)
+{
+
+}
+
+const Services * HypotheticBattle::HypotheticEnvironment::services() const
+{
+ return env->services();
+}
+
+const Environment::BattleCb * HypotheticBattle::HypotheticEnvironment::battle() const
+{
+ return owner;
+}
+
+const Environment::GameCb * HypotheticBattle::HypotheticEnvironment::game() const
+{
+ return env->game();
+}
+
+vstd::CLoggerBase * HypotheticBattle::HypotheticEnvironment::logger() const
+{
+ return env->logger();
+}
+
+events::EventBus * HypotheticBattle::HypotheticEnvironment::eventBus() const
+{
+ return owner->eventBus.get();
+}
+
diff --git a/AI/BattleAI/StackWithBonuses.h b/AI/BattleAI/StackWithBonuses.h
index dbeb351c7..dc2ac3ce7 100644
--- a/AI/BattleAI/StackWithBonuses.h
+++ b/AI/BattleAI/StackWithBonuses.h
@@ -8,6 +8,12 @@
*
*/
#pragma once
+
+#include
+
+#include
+#include
+
#include "../../lib/HeroBonus.h"
#include "../../lib/battle/BattleProxy.h"
#include "../../lib/battle/CUnitState.h"
@@ -15,10 +21,30 @@
class HypotheticBattle;
class CStack;
+///Fake random generator, used by AI to evaluate random server behavior
+class RNGStub : public vstd::RNG
+{
+public:
+ vstd::TRandI64 getInt64Range(int64_t lower, int64_t upper) override
+ {
+ return [=]()->int64_t
+ {
+ return (lower + upper)/2;
+ };
+ }
+
+ vstd::TRand getDoubleRange(double lower, double upper) override
+ {
+ return [=]()->double
+ {
+ return (lower + upper)/2;
+ };
+ }
+};
+
class StackWithBonuses : public battle::CUnitState, public virtual IBonusBearer
{
public:
-
std::vector bonusesToAdd;
std::vector bonusesToUpdate;
std::set> bonusesToRemove;
@@ -53,7 +79,7 @@ public:
void removeUnitBonus(const CSelector & selector);
- void spendMana(const spells::PacketSender * server, const int spellCost) const override;
+ void spendMana(ServerCallback * server, const int spellCost) const override;
private:
const IBonusBearer * origBearer;
@@ -72,7 +98,9 @@ class HypotheticBattle : public BattleProxy, public battle::IUnitEnvironment
public:
std::map> stackStates;
- HypotheticBattle(Subject realBattle);
+ const Environment * env;
+
+ HypotheticBattle(const Environment * ENV, Subject realBattle);
bool unitHasAmmoCart(const battle::Unit * unit) const override;
PlayerColor unitEffectiveOwner(const battle::Unit * unit) const override;
@@ -90,6 +118,7 @@ public:
void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
void moveUnit(uint32_t id, BattleHex destination) override;
void removeUnit(uint32_t id) override;
+ void updateUnit(uint32_t id, const JsonNode & data) override;
void addUnitBonus(uint32_t id, const std::vector & bonus) override;
void updateUnitBonus(uint32_t id, const std::vector & bonus) override;
@@ -107,8 +136,59 @@ public:
int64_t getTreeVersion() const;
+ scripting::Pool * getContextPool() const override;
+
+ ServerCallback * getServerCallback();
+
private:
+
+ class HypotheticServerCallback : public ServerCallback
+ {
+ public:
+ HypotheticServerCallback(HypotheticBattle * owner_);
+
+ void complain(const std::string & problem) override;
+ bool describeChanges() const override;
+
+ vstd::RNG * getRNG() override;
+
+ void apply(CPackForClient * pack) override;
+
+ void apply(BattleLogMessage * pack) override;
+ void apply(BattleStackMoved * pack) override;
+ void apply(BattleUnitsChanged * pack) override;
+ void apply(SetStackEffect * pack) override;
+ void apply(StacksInjured * pack) override;
+ void apply(BattleObstaclesChanged * pack) override;
+ void apply(CatapultAttack * pack) override;
+ private:
+ HypotheticBattle * owner;
+ RNGStub rngStub;
+ };
+
+ class HypotheticEnvironment : public Environment
+ {
+ public:
+ HypotheticEnvironment(HypotheticBattle * owner_, const Environment * upperEnvironment);
+
+ const Services * services() const override;
+ const BattleCb * battle() const override;
+ const GameCb * game() const override;
+ vstd::CLoggerBase * logger() const override;
+ events::EventBus * eventBus() const override;
+
+ private:
+ HypotheticBattle * owner;
+ const Environment * env;
+ };
+
int32_t bonusTreeVersion;
int32_t activeUnitId;
mutable uint32_t nextId;
+
+ std::unique_ptr serverCallback;
+ std::unique_ptr localEnvironment;
+
+ mutable std::shared_ptr pool;
+ mutable std::shared_ptr eventBus;
};
diff --git a/AI/EmptyAI/CEmptyAI.cpp b/AI/EmptyAI/CEmptyAI.cpp
index f7b29f3fe..37cd7eb49 100644
--- a/AI/EmptyAI/CEmptyAI.cpp
+++ b/AI/EmptyAI/CEmptyAI.cpp
@@ -12,12 +12,22 @@
#include "../../lib/CRandomGenerator.h"
-void CEmptyAI::init(std::shared_ptr CB)
+void CEmptyAI::saveGame(BinarySerializer & h, const int version)
+{
+}
+
+void CEmptyAI::loadGame(BinaryDeserializer & h, const int version)
+{
+}
+
+void CEmptyAI::init(std::shared_ptr ENV, std::shared_ptr CB)
{
cb = CB;
+ env = ENV;
human=false;
playerID = *cb->getMyColor();
}
+
void CEmptyAI::yourTurn()
{
cb->endTurn();
diff --git a/AI/EmptyAI/CEmptyAI.h b/AI/EmptyAI/CEmptyAI.h
index 5e7f9013f..3c5df9f12 100644
--- a/AI/EmptyAI/CEmptyAI.h
+++ b/AI/EmptyAI/CEmptyAI.h
@@ -19,7 +19,10 @@ class CEmptyAI : public CGlobalAI
std::shared_ptr cb;
public:
- void init(std::shared_ptr CB) override;
+ virtual void saveGame(BinarySerializer & h, const int version) override;
+ virtual void loadGame(BinaryDeserializer & h, const int version) override;
+
+ void init(std::shared_ptr ENV, std::shared_ptr CB) override;
void yourTurn() override;
void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector &skills, QueryID queryID) override;
void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, QueryID queryID) override;
diff --git a/AI/EmptyAI/EmptyAI.cbp b/AI/EmptyAI/EmptyAI.cbp
index 77c130a35..304884fd5 100644
--- a/AI/EmptyAI/EmptyAI.cbp
+++ b/AI/EmptyAI/EmptyAI.cbp
@@ -63,7 +63,7 @@
-
+
@@ -80,9 +80,6 @@
-
-
-
diff --git a/AI/StupidAI/StupidAI.cbp b/AI/StupidAI/StupidAI.cbp
index b379d32d9..c11e07b2e 100644
--- a/AI/StupidAI/StupidAI.cbp
+++ b/AI/StupidAI/StupidAI.cbp
@@ -18,6 +18,7 @@
+
@@ -34,6 +35,7 @@
+
@@ -41,10 +43,11 @@
-
+
+
@@ -61,13 +64,12 @@
-
+
-
@@ -77,10 +79,6 @@
-
-
-
-
-
+
diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp
index 2b721f48b..d23030057 100644
--- a/AI/StupidAI/StupidAI.cpp
+++ b/AI/StupidAI/StupidAI.cpp
@@ -28,9 +28,10 @@ CStupidAI::~CStupidAI()
print("destroyed");
}
-void CStupidAI::init(std::shared_ptr CB)
+void CStupidAI::init(std::shared_ptr ENV, std::shared_ptr CB)
{
print("init called, saving ptr to IBattleCallback");
+ env = ENV;
cbc = cb = CB;
}
@@ -74,10 +75,12 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
int shooters[2] = {0}; //count of shooters on hexes
for(int i = 0; i < 2; i++)
+ {
for (auto & neighbour : (i ? h2 : h1).neighbouringTiles())
- if(const CStack *s = cbc->battleGetStackByPos(neighbour))
- if(s->getCreature()->isShooting())
- shooters[i]++;
+ if(const CStack * s = cbc->battleGetStackByPos(neighbour))
+ if(s->isShooter())
+ shooters[i]++;
+ }
return shooters[0] < shooters[1];
}
@@ -173,7 +176,7 @@ void CStupidAI::battleAttack(const BattleAttack *ba)
print("battleAttack called");
}
-void CStupidAI::battleStacksAttacked(const std::vector & bsa, const std::vector & battleLog)
+void CStupidAI::battleStacksAttacked(const std::vector & bsa)
{
print("battleStacksAttacked called");
}
@@ -293,15 +296,3 @@ BattleAction CStupidAI::goTowards(const CStack * stack, std::vector h
}
}
}
-
-void CStupidAI::saveGame(BinarySerializer & h, const int version)
-{
- //TODO to be implemented with saving/loading during the battles
- assert(0);
-}
-
-void CStupidAI::loadGame(BinaryDeserializer & h, const int version)
-{
- //TODO to be implemented with saving/loading during the battles
- assert(0);
-}
diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h
index 69a603a75..07a2ebcac 100644
--- a/AI/StupidAI/StupidAI.h
+++ b/AI/StupidAI/StupidAI.h
@@ -18,19 +18,20 @@ class CStupidAI : public CBattleGameInterface
{
int side;
std::shared_ptr cb;
+ std::shared_ptr env;
void print(const std::string &text) const;
public:
CStupidAI();
~CStupidAI();
- void init(std::shared_ptr CB) override;
+ void init(std::shared_ptr ENV, std::shared_ptr CB) override;
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
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
- void battleStacksAttacked(const std::vector & bsa, const std::vector & battleLog) override; //called when stack receives damage (after battleAttack())
+ void battleStacksAttacked(const std::vector & bsa) override; //called when stack receives damage (after battleAttack())
void battleEnd(const BattleResult *br) override;
//void battleResultsApplied() override; //called when all effects of last battle are applied
void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied;
@@ -42,9 +43,6 @@ public:
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
- virtual void saveGame(BinarySerializer & h, const int version) override;
- virtual void loadGame(BinaryDeserializer & h, const int version) override;
-
private:
BattleAction goTowards(const CStack * stack, std::vector hexes) const;
};
diff --git a/AI/VCAI/AIUtility.cpp b/AI/VCAI/AIUtility.cpp
index 963c95279..352a13e68 100644
--- a/AI/VCAI/AIUtility.cpp
+++ b/AI/VCAI/AIUtility.cpp
@@ -279,7 +279,7 @@ creInfo infoFromDC(const dwellingContent & dc)
ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
if (ci.creID != -1)
{
- ci.cre = VLC->creh->creatures[ci.creID];
+ ci.cre = VLC->creh->objects[ci.creID];
ci.level = ci.cre->level; //this is cretaure tier, while tryRealize expects dwelling level. Ignore.
}
else
diff --git a/AI/VCAI/FuzzyHelper.cpp b/AI/VCAI/FuzzyHelper.cpp
index 252d05c5c..ed5ae9c52 100644
--- a/AI/VCAI/FuzzyHelper.cpp
+++ b/AI/VCAI/FuzzyHelper.cpp
@@ -139,7 +139,9 @@ float FuzzyHelper::evaluate(Goals::VisitHero & g)
{
auto obj = ai->myCb->getObj(ObjectInstanceID(g.objid)); //we assume for now that these goals are similar
if(!obj)
+ {
return -100; //hero died in the meantime
+ }
else
{
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).accept(this));
diff --git a/AI/VCAI/Goals/AbstractGoal.cpp b/AI/VCAI/Goals/AbstractGoal.cpp
index 3aabafab3..2021d5071 100644
--- a/AI/VCAI/Goals/AbstractGoal.cpp
+++ b/AI/VCAI/Goals/AbstractGoal.cpp
@@ -91,7 +91,7 @@ std::string AbstractGoal::name() const //TODO: virtualize
}
break;
case GET_ART_TYPE:
- desc = "GET ARTIFACT OF TYPE " + VLC->arth->artifacts[aid]->Name();
+ desc = "GET ARTIFACT OF TYPE " + VLC->artifacts()->getByIndex(aid)->getName();
break;
case VISIT_TILE:
desc = "VISIT TILE " + tile.toString();
diff --git a/AI/VCAI/Goals/AdventureSpellCast.cpp b/AI/VCAI/Goals/AdventureSpellCast.cpp
index 28c1c951d..927eee3d1 100644
--- a/AI/VCAI/Goals/AdventureSpellCast.cpp
+++ b/AI/VCAI/Goals/AdventureSpellCast.cpp
@@ -33,16 +33,16 @@ TSubgoal AdventureSpellCast::whatToDoToAchieve()
auto spell = getSpell();
- logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->name, hero->name);
+ logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->getName(), hero->name);
- if(!spell->isAdventureSpell())
- throw cannotFulfillGoalException(spell->name + " is not an adventure spell.");
+ if(!spell->isAdventure())
+ throw cannotFulfillGoalException(spell->getName() + " is not an adventure spell.");
if(!hero->canCastThisSpell(spell))
- throw cannotFulfillGoalException("Hero can not cast " + spell->name);
+ throw cannotFulfillGoalException("Hero can not cast " + spell->getName());
if(hero->mana < hero->getSpellCost(spell))
- throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->name);
+ throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getName());
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name);
@@ -75,10 +75,10 @@ void AdventureSpellCast::accept(VCAI * ai)
std::string AdventureSpellCast::name() const
{
- return "AdventureSpellCast " + spellID.toSpell()->name;
+ return "AdventureSpellCast " + getSpell()->getName();
}
std::string AdventureSpellCast::completeMessage() const
{
- return "Spell casted successfully " + spellID.toSpell()->name;
+ return "Spell cast successfully " + getSpell()->getName();
}
diff --git a/AI/VCAI/Goals/GatherArmy.cpp b/AI/VCAI/Goals/GatherArmy.cpp
index df6620a81..e81a41413 100644
--- a/AI/VCAI/Goals/GatherArmy.cpp
+++ b/AI/VCAI/Goals/GatherArmy.cpp
@@ -158,7 +158,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
{
for(auto & creatureID : creLevel.second)
{
- auto creature = VLC->creh->creatures[creatureID];
+ auto creature = VLC->creh->objects[creatureID];
if(ai->ah->freeResources().canAfford(creature->cost))
objs.push_back(obj); //TODO: reserve resources?
}
diff --git a/AI/VCAI/Goals/GatherTroops.cpp b/AI/VCAI/Goals/GatherTroops.cpp
index 19cb9dcad..642429dd7 100644
--- a/AI/VCAI/Goals/GatherTroops.cpp
+++ b/AI/VCAI/Goals/GatherTroops.cpp
@@ -93,7 +93,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
continue;
}
- auto creature = VLC->creh->creatures[objid];
+ auto creature = VLC->creh->objects[objid];
if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
{
auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
@@ -110,7 +110,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
}
/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
- {
+ {
return sptr(BuildThis(bid, t).setpriority(priority));
}*/
}
@@ -129,7 +129,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
{
for(auto type : creature.second)
{
- if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
+ if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->objects[type]->cost))
vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
}
}
diff --git a/AI/VCAI/MapObjectsEvaluator.cpp b/AI/VCAI/MapObjectsEvaluator.cpp
index 96badfd53..e528d4d37 100644
--- a/AI/VCAI/MapObjectsEvaluator.cpp
+++ b/AI/VCAI/MapObjectsEvaluator.cpp
@@ -41,7 +41,7 @@ MapObjectsEvaluator::MapObjectsEvaluator()
objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = 0;
}
}
- }
+ }
}
}
@@ -62,7 +62,7 @@ boost::optional MapObjectsEvaluator::getObjectValue(const CGObjectInstance
{
//special case handling: in-game heroes have hero ID as object subID, but when reading configs available hero object subID's are hero classes
auto hero = dynamic_cast(obj);
- return getObjectValue(obj->ID, hero->type->heroClass->id);
+ return getObjectValue(obj->ID, hero->type->heroClass->getIndex());
}
else if(obj->ID == Obj::PRISON)
{
@@ -77,7 +77,7 @@ boost::optional MapObjectsEvaluator::getObjectValue(const CGObjectInstance
{
for(auto & creatureID : creLevel.second)
{
- auto creature = VLC->creh->creatures[creatureID];
+ auto creature = VLC->creh->objects[creatureID];
aiValue += (creature->AIValue * creature->growth);
}
}
diff --git a/AI/VCAI/Pathfinding/AIPathfinder.cpp b/AI/VCAI/Pathfinding/AIPathfinder.cpp
index 878a89892..545535111 100644
--- a/AI/VCAI/Pathfinding/AIPathfinder.cpp
+++ b/AI/VCAI/Pathfinding/AIPathfinder.cpp
@@ -60,7 +60,7 @@ void AIPathfinder::updatePaths(std::vector heroes)
cb->calculatePaths(config, hero);
};
- std::vector calculationTasks;
+ std::vector calculationTasks;
for(HeroPtr hero : heroes)
{
diff --git a/AI/VCAI/VCAI.cbp b/AI/VCAI/VCAI.cbp
index f63dbc85e..5b0c0548e 100644
--- a/AI/VCAI/VCAI.cbp
+++ b/AI/VCAI/VCAI.cbp
@@ -78,7 +78,7 @@
-
+
@@ -185,9 +185,6 @@
-
-
-
diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp
index f7fb1f7ed..b73440617 100644
--- a/AI/VCAI/VCAI.cpp
+++ b/AI/VCAI/VCAI.cpp
@@ -579,9 +579,10 @@ void VCAI::showWorldViewEx(const std::vector & objectPositions)
NET_EVENT_HANDLER;
}
-void VCAI::init(std::shared_ptr CB)
+void VCAI::init(std::shared_ptr ENV, std::shared_ptr CB)
{
LOG_TRACE(logAi);
+ env = ENV;
myCb = CB;
cbc = CB;
@@ -868,7 +869,7 @@ void VCAI::mainLoop()
goalsToRemove.clear();
elementarGoals.clear();
ultimateGoalsFromBasic.clear();
-
+
ah->updatePaths(getMyHeroes());
logAi->debug("Main loop: decomposing %i basic goals", basicGoals.size());
@@ -1082,7 +1083,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * destinationArmy, const CArme
&& (!destinationArmy->hasStackAtSlot(i) || destinationArmy->getCreature(i) == targetCreature))
{
auto weakest = ah->getWeakestCreature(bestArmy);
-
+
if(weakest->creature == targetCreature)
{
if(1 == source->getStackCount(j))
@@ -1233,7 +1234,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
int count = d->creatures[i].first;
CreatureID creID = d->creatures[i].second.back();
- vstd::amin(count, ah->freeResources() / VLC->creh->creatures[creID]->cost);
+ vstd::amin(count, ah->freeResources() / VLC->creh->objects[creID]->cost);
if(count > 0)
cb->recruitCreatures(d, recruiter, creID, count, i);
}
diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h
index ab7891317..c9a560305 100644
--- a/AI/VCAI/VCAI.h
+++ b/AI/VCAI/VCAI.h
@@ -139,7 +139,7 @@ public:
std::string getBattleAIName() const override;
- void init(std::shared_ptr CB) override;
+ void init(std::shared_ptr ENV, std::shared_ptr CB) override;
void yourTurn() override;
void heroGotLevel(const CGHeroInstance * hero, PrimarySkill::PrimarySkill pskill, std::vector & skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
diff --git a/CCallback.cpp b/CCallback.cpp
index b01c2f36d..81b3e9274 100644
--- a/CCallback.cpp
+++ b/CCallback.cpp
@@ -22,7 +22,6 @@
#include "lib/CHeroHandler.h"
#include "lib/NetPacks.h"
#include "client/mapHandler.h"
-#include "lib/spells/CSpellHandler.h"
#include "lib/CArtHandler.h"
#include "lib/GameConstants.h"
#include "lib/CPlayerState.h"
@@ -328,26 +327,21 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
return swapCreatures(s1, s2, p1, p2);
}
-void CCallback::registerGameInterface(std::shared_ptr gameEvents)
-{
- cl->additionalPlayerInts[*player].push_back(gameEvents);
-}
-
void CCallback::registerBattleInterface(std::shared_ptr battleEvents)
{
cl->additionalBattleInts[*player].push_back(battleEvents);
}
-void CCallback::unregisterGameInterface(std::shared_ptr gameEvents)
-{
- cl->additionalPlayerInts[*player] -= gameEvents;
-}
-
void CCallback::unregisterBattleInterface(std::shared_ptr battleEvents)
{
cl->additionalBattleInts[*player] -= battleEvents;
}
+scripting::Pool * CBattleCallback::getContextPool() const
+{
+ return cl->getGlobalContextPool();
+}
+
CBattleCallback::CBattleCallback(boost::optional Player, CClient *C )
{
player = Player;
diff --git a/CCallback.h b/CCallback.h
index 739b13564..ef83589ed 100644
--- a/CCallback.h
+++ b/CCallback.h
@@ -10,6 +10,7 @@
#pragma once
#include "lib/CGameInfoCallback.h"
+#include "lib/battle/CPlayerBattleCallback.h"
#include "lib/int3.h" // for int3
class CGHeroInstance;
@@ -92,11 +93,12 @@ public:
int battleMakeAction(const BattleAction * action) override;//for casting spells by hero - DO NOT use it for moving active stack
bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
+ scripting::Pool * getContextPool() const override;
+
friend class CCallback;
friend class CClient;
};
-class CPlayerInterface;
class CCallback : public CPlayerSpecificInfoCallback, public IGameActionCallback, public CBattleCallback
{
public:
@@ -111,9 +113,7 @@ public:
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out);
//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
- void registerGameInterface(std::shared_ptr gameEvents);
void registerBattleInterface(std::shared_ptr battleEvents);
- void unregisterGameInterface(std::shared_ptr gameEvents);
void unregisterBattleInterface(std::shared_ptr battleEvents);
//commands
diff --git a/CI/linux/before_install.sh b/CI/linux/before_install.sh
index 03247aa38..7799c3f58 100644
--- a/CI/linux/before_install.sh
+++ b/CI/linux/before_install.sh
@@ -20,6 +20,7 @@ sudo apt-get install -qq cmake ninja-build libboost1.54-all-dev zlib1g-dev
sudo apt-get install -qq libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
sudo apt-get install -qq libavformat-dev libswscale-dev
sudo apt-get install -qq qt57declarative
+sudo apt-get install -qq libluajit-5.1-dev
#setup compiler
source /opt/qt57/bin/qt57-env.sh
diff --git a/CI/mac/before_install.sh b/CI/mac/before_install.sh
index 681f6c59e..df248f45b 100644
--- a/CI/mac/before_install.sh
+++ b/CI/mac/before_install.sh
@@ -1,7 +1,7 @@
#!/bin/sh
brew update
-brew install smpeg2 libpng freetype sdl2 sdl2_ttf sdl2_image qt5 ffmpeg ninja
+brew install smpeg2 libpng freetype sdl2 sdl2_ttf sdl2_image qt5 ffmpeg ninja luajit
brew install sdl2_mixer
export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH"
diff --git a/CI/mxe/before_install.sh b/CI/mxe/before_install.sh
index 23b72bd92..82b969a34 100644
--- a/CI/mxe/before_install.sh
+++ b/CI/mxe/before_install.sh
@@ -4,17 +4,17 @@
sudo apt-get install -qq nsis ninja-build
# MXE repository was too slow for Travis far too often
-wget https://github.com/vcmi/vcmi-deps-mxe/releases/download/2018-02-10/mxe-$MXE_TARGET-2018-02-10.tar
-tar -xvf mxe-$MXE_TARGET-2018-02-10.tar
+wget https://github.com/vcmi/vcmi-deps-mxe/releases/download/2019-06-28/mxe-i686-w64-mingw32.shared-2019-06-28.tar
+tar -xvf mxe-i686-w64-mingw32.shared-2019-06-28.tar
sudo dpkg -i mxe-*.deb
sudo apt-get install -f --yes
if false; then
# Add MXE repository and key
-echo "deb http://pkg.mxe.cc/repos/apt/debian wheezy main" \
+echo "deb http://pkg.mxe.cc/repos/apt trusty main" \
| sudo tee /etc/apt/sources.list.d/mxeapt.list
-sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D43A795B73B16ABE9643FE1AFD8FFF16DB45C6AB
+sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 86B72ED9
# Install needed packages
sudo apt-get update -qq
@@ -30,7 +30,8 @@ mxe-$MXE_TARGET-sdl2-mixer \
mxe-$MXE_TARGET-sdl2-ttf \
mxe-$MXE_TARGET-ffmpeg \
mxe-$MXE_TARGET-qt \
-mxe-$MXE_TARGET-qtbase
+mxe-$MXE_TARGET-qtbase \
+mxe-i686-w64-mingw32.static-luajit
fi # Disable
diff --git a/CMakeLists.txt b/CMakeLists.txt
index efd020251..e41dbeab7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,7 +44,8 @@ set(VCMI_VERSION_MAJOR 0)
set(VCMI_VERSION_MINOR 99)
set(VCMI_VERSION_PATCH 0)
-option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF)
+option(ENABLE_ERM "Enable compilation of ERM scripting module" ON)
+option(ENABLE_LUA "Enable compilation of LUA scripting module" ON)
option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
option(ENABLE_TEST "Enable compilation of unit tests" ON)
option(ENABLE_PCH "Enable compilation using precompiled headers" ON)
@@ -122,7 +123,6 @@ if(APPLE)
endif(APPLE)
if(WIN32)
- add_definitions(-DBOOST_THREAD_USE_LIB)
# Windows Vista or newer for FuzzyLite 6 to compile
add_definitions(-D_WIN32_WINNT=0x0600)
@@ -231,6 +231,21 @@ if(ENABLE_LAUNCHER)
find_package(Qt5Network REQUIRED)
endif()
+if(ENABLE_LUA)
+ # MXE paths hardcoded for current dependencies pack - tried and could not make it work another way
+ if((MINGW) AND (${CMAKE_CROSSCOMPILING}) AND (DEFINED MSYS))
+ set(LUA_INCLUDE_DIR "/usr/lib/mxe/usr/i686-w64-mingw32.static/include/luajit-2.0")
+ set(LUA_LIBRARY "/usr/lib/mxe/usr/i686-w64-mingw32.static/lib/libluajit-5.1.a")
+ endif()
+ find_package(LuaJIT)
+ if(LUAJIT_FOUND)
+ message(STATUS "Using LuaJIT provided by system")
+ else()
+ message(STATUS "Cannot find LuaJIT! Fallback to using usual Lua.")
+ find_package(Lua REQUIRED)
+ endif()
+endif()
+
############################################
# Output directories #
############################################
@@ -294,6 +309,9 @@ set(SCRIPTING_LIB_DIR "${LIB_DIR}/scripting")
if(ENABLE_ERM)
add_subdirectory(scripting/erm)
endif()
+if(ENABLE_LUA)
+ add_subdirectory(scripting/lua)
+endif()
if(NOT MINIZIP_FOUND)
add_subdirectory_with_folder("3rdparty" lib/minizip)
set(MINIZIP_LIBRARIES minizip)
@@ -315,6 +333,7 @@ endif()
#######################################
install(DIRECTORY config DESTINATION ${DATA_DIR})
+install(DIRECTORY scripts DESTINATION ${DATA_DIR})
install(DIRECTORY Mods DESTINATION ${DATA_DIR})
# that script is useless for Windows
diff --git a/Global.h b/Global.h
index 506f0fc51..ed0bc63dd 100644
--- a/Global.h
+++ b/Global.h
@@ -727,24 +727,6 @@ namespace vstd
}
using boost::math::round;
-
- static std::pair splitStringToPair(std::string input, char separator)
- {
- std::pair ret;
- size_t splitPos = input.find(separator);
-
- if (splitPos == std::string::npos)
- {
- ret.first.clear();
- ret.second = input;
- }
- else
- {
- ret.first = input.substr(0, splitPos);
- ret.second = input.substr(splitPos + 1);
- }
- return ret;
- }
}
using vstd::operator-=;
using vstd::make_unique;
diff --git a/Mods/vcmi/Data/s/std.verm b/Mods/vcmi/Data/s/std.verm
deleted file mode 100644
index 865997ce7..000000000
--- a/Mods/vcmi/Data/s/std.verm
+++ /dev/null
@@ -1,40 +0,0 @@
-VERM
-; standard verm file, global engine things should be put here
-
-!?PI;
-; example 1 --- Hello World
-![print ^Hello world!^]
-
-; example 2 --- simple arithmetics
-![defun add [x y] [+ x y]]
-![print [add 2 3]]
-
-; example 3 --- semantic macros
-![defmacro do-n-times [times body]
- `[progn
- [setq do-counter 0]
- [setq do-max ,times]
- [do [< do-counter do-max]
- [progn
- [setq do-counter [+ do-counter 1]]
- ,body
- ]
- ]
- ]
-]
-![do-n-times 4 [print ^tekst\n^]]
-
-
-; example 4 --- conditional expression
-![if [> 2 1] [print ^Wieksze^] [print ^Mniejsze^]]
-
-; example 5 --- lambda expressions
-![[lambda [x y] [if [> x y] [print ^wieksze^] [print ^mniejsze^]]] 2 3]
-
-; example 6 --- resursion
-![defun factorial [n]
- [if [= n 0] 1
- [* n [factorial [- n 1]]]
- ]
-]
-![print [factorial 8]]
\ No newline at end of file
diff --git a/Mods/vcmi/Data/s/testy.erm b/Mods/vcmi/Data/s/testy.erm
deleted file mode 100644
index 082c1891e..000000000
--- a/Mods/vcmi/Data/s/testy.erm
+++ /dev/null
@@ -1,14 +0,0 @@
-ZVSE
-!?PI;
- !!VRv2777:S4;
- !!DO1/0/5/1&v2777<>1:P0;
-
-!?FU1;
- !!VRv2778:Sx16%2;
- !!IF&x16>3:M^Hello world number %X16! To duza liczba^;
- !!IF&v2778==0&x16<=3:M^Hello world number %X16! To mala parzysta liczba^;
- !!IF&v2778==1&x16<=3:M^Hello world number %X16! To mala nieparzysta liczba^;
-
-!?PI;
- !!VRz10:S^Composed hello ^;
- !!IF:M^%Z10%%world%%, v2777=%V2777, v2778=%V2778!^;
\ No newline at end of file
diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp
index ac607a8c3..2fe9f4fd6 100644
--- a/client/CGameInfo.cpp
+++ b/client/CGameInfo.cpp
@@ -9,8 +9,6 @@
*/
#include "StdInc.h"
#include "CGameInfo.h"
-#include "../lib/CSkillHandler.h"
-#include "../lib/CGeneralTextHandler.h"
#include "../lib/VCMI_Lib.h"
@@ -24,13 +22,14 @@ CGameInfo::CGameInfo()
generaltexth = nullptr;
mh = nullptr;
townh = nullptr;
+ globalServices = nullptr;
}
void CGameInfo::setFromLib()
{
+ globalServices = VLC;
modh = VLC->modh;
generaltexth = VLC->generaltexth;
- arth = VLC->arth;
creh = VLC->creh;
townh = VLC->townh;
heroh = VLC->heroh;
@@ -39,3 +38,58 @@ void CGameInfo::setFromLib()
skillh = VLC->skillh;
objtypeh = VLC->objtypeh;
}
+
+const ArtifactService * CGameInfo::artifacts() const
+{
+ return globalServices->artifacts();
+}
+
+const CreatureService * CGameInfo::creatures() const
+{
+ return globalServices->creatures();
+}
+
+const FactionService * CGameInfo::factions() const
+{
+ return globalServices->factions();
+}
+
+const HeroClassService * CGameInfo::heroClasses() const
+{
+ return globalServices->heroClasses();
+}
+
+const HeroTypeService * CGameInfo::heroTypes() const
+{
+ return globalServices->heroTypes();
+}
+
+const scripting::Service * CGameInfo::scripts() const
+{
+ return globalServices->scripts();
+}
+
+const spells::Service * CGameInfo::spells() const
+{
+ return globalServices->spells();
+}
+
+const SkillService * CGameInfo::skills() const
+{
+ return globalServices->skills();
+}
+
+void CGameInfo::updateEntity(Metatype metatype, int32_t index, const JsonNode & data)
+{
+ logGlobal->error("CGameInfo::updateEntity call is not expected.");
+}
+
+spells::effects::Registry * CGameInfo::spellEffects()
+{
+ return nullptr;
+}
+
+const spells::effects::Registry * CGameInfo::spellEffects() const
+{
+ return globalServices->spellEffects();
+}
diff --git a/client/CGameInfo.h b/client/CGameInfo.h
index 371b487f3..d9947c1d4 100644
--- a/client/CGameInfo.h
+++ b/client/CGameInfo.h
@@ -9,11 +9,12 @@
*/
#pragma once
+#include
+
#include "../lib/ConstTransitivePtr.h"
class CModHandler;
class CMapHandler;
-class CArtHandler;
class CHeroHandler;
class CCreatureHandler;
class CSpellHandler;
@@ -48,11 +49,25 @@ extern CClientState * CCS;
/// CGameInfo class
/// for allowing different functions for accessing game informations
-class CGameInfo
+class CGameInfo : public Services
{
public:
+ const ArtifactService * artifacts() const override;
+ const CreatureService * creatures() const override;
+ const FactionService * factions() const override;
+ const HeroClassService * heroClasses() const override;
+ const HeroTypeService * heroTypes() const override;
+ const scripting::Service * scripts() const override;
+ const spells::Service * spells() const override;
+ const SkillService * skills() const override;
+
+ void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
+
+ const spells::effects::Registry * spellEffects() const override;
+ spells::effects::Registry * spellEffects() override;
+
+
ConstTransitivePtr modh; //public?
- ConstTransitivePtr arth;
ConstTransitivePtr heroh;
ConstTransitivePtr creh;
ConstTransitivePtr spellh;
@@ -65,8 +80,8 @@ public:
void setFromLib();
- friend class CClient;
-
CGameInfo();
+private:
+ const Services * globalServices;
};
extern const CGameInfo* CGI;
diff --git a/client/CMT.cpp b/client/CMT.cpp
index 5cc09bb18..2fd21064e 100644
--- a/client/CMT.cpp
+++ b/client/CMT.cpp
@@ -14,6 +14,8 @@
#include
+#include
+
#include "gui/SDL_Extensions.h"
#include "CGameInfo.h"
#include "mapHandler.h"
@@ -46,9 +48,9 @@
#include "../lib/NetPacks.h"
#include "CMessage.h"
#include "../lib/CModHandler.h"
+#include "../lib/ScriptHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CArtHandler.h"
-#include "../lib/CScriptingModule.h"
#include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h"
#include "../lib/logging/CBasicLogConfigurator.h"
@@ -95,14 +97,13 @@ SDL_Surface *screen = nullptr, //main screen surface
*screen2 = nullptr, //and hlp surface (used to store not-active interfaces layer)
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
-std::queue events;
+std::queue SDLEventsQueue;
boost::mutex eventsM;
static po::variables_map vm;
//static bool setResolution = false; //set by event handling thread after resolution is adjusted
-static bool ermInteractiveMode = false; //structurize when time is right
void processCommand(const std::string &message);
static void setScreenRes(int w, int h, int bpp, bool fullscreen, int displayIndex, bool resetVideo=true);
void playIntro();
@@ -576,29 +577,10 @@ void processCommand(const std::string &message)
// if(LOCPLINT && LOCPLINT->cingconsole)
// LOCPLINT->cingconsole->print(message);
- if(ermInteractiveMode)
- {
- if(cn == "exit")
- {
- ermInteractiveMode = false;
- return;
- }
- else
- {
- if(CSH->client && CSH->client->erm)
- CSH->client->erm->executeUserCommand(message);
- std::cout << "erm>";
- }
- }
- else if(message==std::string("die, fool"))
+ if(message==std::string("die, fool"))
{
exit(EXIT_SUCCESS);
}
- else if(cn == "erm")
- {
- ermInteractiveMode = true;
- std::cout << "erm>";
- }
else if(cn==std::string("activate"))
{
int what;
@@ -725,6 +707,28 @@ void processCommand(const std::string &message)
std::cout << "\rExtracting done :)\n";
std::cout << " Extracted files can be found in " << outPath << " directory\n";
}
+ else if(message=="get scripts")
+ {
+ std::cout << "Command accepted.\t";
+
+ const bfs::path outPath =
+ VCMIDirs::get().userCachePath() / "extracted" / "scripts";
+
+ bfs::create_directories(outPath);
+
+ for(auto & kv : VLC->scriptHandler->objects)
+ {
+ std::string name = kv.first;
+ boost::algorithm::replace_all(name,":","_");
+
+ const scripting::ScriptImpl * script = kv.second.get();
+ bfs::path filePath = outPath / (name + ".lua");
+ bfs::ofstream file(filePath);
+ file << script->getSource();
+ }
+ std::cout << "\rExtracting done :)\n";
+ std::cout << " Extracted files can be found in " << outPath << " directory\n";
+ }
else if(message=="get txt")
{
std::cout << "Command accepted.\t";
@@ -891,7 +895,7 @@ void processCommand(const std::string &message)
{
YourTurn yt;
yt.player = player;
- yt.daysWithoutCastle = CSH->client->getPlayer(player)->daysWithoutCastle;
+ yt.daysWithoutCastle = CSH->client->getPlayerState(player)->daysWithoutCastle;
yt.applyCl(CSH->client);
};
@@ -1360,7 +1364,7 @@ static void handleEvent(SDL_Event & ev)
{
boost::unique_lock lock(eventsM);
- events.push(ev);
+ SDLEventsQueue.push(ev);
}
}
diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp
index 1a9ec649e..a95e360a6 100644
--- a/client/CMusicHandler.cpp
+++ b/client/CMusicHandler.cpp
@@ -13,8 +13,6 @@
#include "CMusicHandler.h"
#include "CGameInfo.h"
#include "SDLRWwrapper.h"
-#include "../lib/CCreatureHandler.h"
-#include "../lib/spells/CSpellHandler.h"
#include "../lib/JsonNode.h"
#include "../lib/GameConstants.h"
#include "../lib/filesystem/Filesystem.h"
diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h
index df1ede0a2..36fe6f2ec 100644
--- a/client/CMusicHandler.h
+++ b/client/CMusicHandler.h
@@ -12,7 +12,6 @@
#include "../lib/CConfigHandler.h"
#include "../lib/CSoundBase.h"
-class CSpell;
struct _Mix_Music;
struct SDL_RWops;
typedef struct _Mix_Music Mix_Music;
diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp
index f66f9221b..0f3b98866 100644
--- a/client/CPlayerInterface.cpp
+++ b/client/CPlayerInterface.cpp
@@ -8,6 +8,9 @@
*
*/
#include "StdInc.h"
+
+#include
+
#include "windows/CAdvmapInterface.h"
#include "battle/CBattleInterface.h"
#include "battle/CBattleInterfaceClasses.h"
@@ -82,7 +85,7 @@ using namespace CSDL_Ext;
void processCommand(const std::string &message, CClient *&client);
-extern std::queue events;
+extern std::queue SDLEventsQueue;
extern boost::mutex eventsM;
boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;
@@ -144,9 +147,10 @@ CPlayerInterface::~CPlayerInterface()
if (LOCPLINT == this)
LOCPLINT = nullptr;
}
-void CPlayerInterface::init(std::shared_ptr CB)
+void CPlayerInterface::init(std::shared_ptr ENV, std::shared_ptr CB)
{
cb = CB;
+ env = ENV;
initializeHeroTownList();
// always recreate advmap interface to avoid possible memory-corruption bugs
@@ -372,10 +376,10 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
//check if user cancelled movement
{
boost::unique_lock un(eventsM);
- while(!events.empty())
+ while(!SDLEventsQueue.empty())
{
- SDL_Event ev = events.front();
- events.pop();
+ SDL_Event ev = SDLEventsQueue.front();
+ SDLEventsQueue.pop();
switch(ev.type)
{
case SDL_MOUSEBUTTONDOWN:
@@ -692,7 +696,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
if (settings["adventure"]["quickCombat"].Bool())
{
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
- autofightingAI->init(cb);
+ autofightingAI->init(env, cb);
autofightingAI->battleStart(army1, army2, int3(0,0,0), hero1, hero2, side);
isAutoFightOn = true;
cb->registerBattleInterface(autofightingAI);
@@ -707,7 +711,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
BATTLE_EVENT_POSSIBLE_RETURN;
}
-void CPlayerInterface::battleUnitsChanged(const std::vector & units, const std::vector & customEffects, const std::vector & battleLog)
+void CPlayerInterface::battleUnitsChanged(const std::vector & units, const std::vector & customEffects)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN;
@@ -769,7 +773,6 @@ void CPlayerInterface::battleUnitsChanged(const std::vector & units
}
battleInt->displayCustomEffects(customEffects);
- battleInt->displayBattleLog(battleLog);
}
void CPlayerInterface::battleObstaclesChanged(const std::vector & obstacles)
@@ -919,6 +922,14 @@ void CPlayerInterface::battleEnd(const BattleResult *br)
battleInt->battleFinished(*br);
}
+void CPlayerInterface::battleLogMessage(const std::vector & lines)
+{
+ EVENT_HANDLER_CALLED_BY_CLIENT;
+ BATTLE_EVENT_POSSIBLE_RETURN;
+
+ battleInt->displayBattleLog(lines);
+}
+
void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector dest, int distance)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@@ -948,7 +959,7 @@ void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
RETURN_IF_QUICK_COMBAT;
battleInt->battleTriggerEffect(bte);
}
-void CPlayerInterface::battleStacksAttacked(const std::vector & bsa, const std::vector & battleLog)
+void CPlayerInterface::battleStacksAttacked(const std::vector & bsa)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN;
@@ -977,7 +988,7 @@ void CPlayerInterface::battleStacksAttacked(const std::vectorstacksAreAttacked(arg, battleLog);
+ battleInt->stacksAreAttacked(arg);
}
void CPlayerInterface::battleAttack(const BattleAttack * ba)
{
@@ -1424,29 +1435,20 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
* Shows the dialog that appears when right-clicking an artifact that can be assembled
* into a combinational one on an artifact screen. Does not require the combination of
* artifacts to be legal.
- * @param artifactID ID of a constituent artifact.
- * @param assembleTo ID of artifact to assemble a constituent into, not used when assemble
- * is false.
- * @param assemble True if the artifact is to be assembled, false if it is to be disassembled.
*/
-void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList onYes, CFunctionList onNo)
+void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList onYes)
{
- const CArtifact &artifact = *CGI->arth->artifacts[artifactID];
- std::string text = artifact.Description();
+ std::string text = artifact->getDescription();
text += "\n\n";
std::vector> scs;
- if(assemble)
+ if(assembledArtifact)
{
- const CArtifact &assembledArtifact = *CGI->arth->artifacts[assembleTo];
-
// You possess all of the components to...
- text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact.Name());
+ text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact->getName());
// Picture of assembled artifact at bottom.
- auto sc = std::make_shared(CComponent::artifact, assembledArtifact.id, 0);
- //sc->description = assembledArtifact.Description();
- //sc->subtitle = assembledArtifact.Name();
+ auto sc = std::make_shared(CComponent::artifact, assembledArtifact->getIndex(), 0);
scs.push_back(sc);
}
else
@@ -1455,7 +1457,7 @@ void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembl
text += CGI->generaltexth->allTexts[733];
}
- showYesNoDialog(text, onYes, onNo, scs);
+ showYesNoDialog(text, onYes, nullptr, scs);
}
void CPlayerInterface::requestRealized( PackageApplied *pa )
@@ -1612,8 +1614,8 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
{
if(reason == PlayerBlocked::EReason::UPCOMING_BATTLE)
{
- if(CSH->howManyPlayerInterfaces() > 1 && LOCPLINT != this && LOCPLINT->makingTurn == false)
- {
+ if(CSH->howManyPlayerInterfaces() > 1 && LOCPLINT != this && LOCPLINT->makingTurn == false)
+ {
//one of our players who isn't last in order got attacked not by our another player (happens for example in hotseat mode)
boost::unique_lock lock(eventsM); //TODO: copied from yourTurn, no idea if it's needed
LOCPLINT = this;
@@ -2236,13 +2238,13 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
eraseCurrentPathOf(caster, false);
- const CSpell * spell = CGI->spellh->objects.at(spellID);
+ const spells::Spell * spell = CGI->spells()->getByIndex(spellID);
if(spellID == SpellID::VIEW_EARTH)
{
//TODO: implement on server side
- int level = caster->getSpellSchoolLevel(spell);
- adventureInt->worldViewOptions.showAllTerrain = (level>2);
+ const auto level = caster->getSpellSchoolLevel(spell);
+ adventureInt->worldViewOptions.showAllTerrain = (level > 2);
}
auto castSoundPath = spell->getCastSound();
@@ -2360,7 +2362,7 @@ void CPlayerInterface::acceptTurn()
components.push_back(Component(Component::FLAG, playerColor.getNum(), 0, 0));
MetaString text;
- const auto & optDaysWithoutCastle = cb->getPlayer(playerColor)->daysWithoutCastle;
+ const auto & optDaysWithoutCastle = cb->getPlayerState(playerColor)->daysWithoutCastle;
if(optDaysWithoutCastle)
{
@@ -2646,9 +2648,9 @@ bool CPlayerInterface::capturedAllEvents()
if (ignoreEvents)
{
boost::unique_lock un(eventsM);
- while(!events.empty())
+ while(!SDLEventsQueue.empty())
{
- events.pop();
+ SDLEventsQueue.pop();
}
return true;
}
diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h
index 528b68dd4..10d06f80f 100644
--- a/client/CPlayerInterface.h
+++ b/client/CPlayerInterface.h
@@ -19,6 +19,8 @@
#define sprintf_s snprintf
#endif
+class Artifact;
+
class CButton;
class CToggleGroup;
struct TryMoveHero;
@@ -62,7 +64,9 @@ namespace boost
class CPlayerInterface : public CGameInterface, public IUpdateable
{
const CArmedInstance * currentSelection;
+
public:
+ std::shared_ptr env;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos;
@@ -183,21 +187,22 @@ public:
void battleEnd(const BattleResult *br) override; //end of battle
void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied; used for HP regen handling
void battleNewRound(int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
+ void battleLogMessage(const std::vector & lines) override;
void battleStackMoved(const CStack * stack, std::vector dest, int distance) override;
void battleSpellCast(const BattleSpellCast *sc) override;
void battleStacksEffectsSet(const SetStackEffect & sse) override; //called when a specific effect is set to stacks
void battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect
- void battleStacksAttacked(const std::vector & bsa, const std::vector & battleLog) override;
+ void battleStacksAttacked(const std::vector & bsa) override;
void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
- void battleUnitsChanged(const std::vector & units, const std::vector & customEffects, const std::vector & battleLog) override;
+ void battleUnitsChanged(const std::vector & units, const std::vector & customEffects) override;
void battleObstaclesChanged(const std::vector & obstacles) override;
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
void battleGateStateChanged(const EGateState state) override;
void yourTacticPhase(int distance) override;
//-------------//
- void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList onYes, CFunctionList onNo);
+ void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList onYes);
void garrisonsChanged(std::vector objs);
void garrisonChanged(const CGObjectInstance * obj);
void heroKilled(const CGHeroInstance* hero);
@@ -210,7 +215,7 @@ public:
void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
void updateInfo(const CGObjectInstance * specific);
- void init(std::shared_ptr CB) override;
+ void init(std::shared_ptr ENV, std::shared_ptr CB) override;
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
void activateForSpectator(); // TODO: spectator probably need own player interface class
diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp
index d38793d46..8a010a629 100644
--- a/client/CServerHandler.cpp
+++ b/client/CServerHandler.cpp
@@ -45,6 +45,8 @@
#include
#include "../lib/serializer/Cast.h"
+#include
+
template class CApplyOnLobby;
#ifdef VCMI_ANDROID
diff --git a/client/Client.cpp b/client/Client.cpp
index 4839b5122..45ccaf9b8 100644
--- a/client/Client.cpp
+++ b/client/Client.cpp
@@ -44,11 +44,12 @@
#include "lobby/CBonusSelection.h"
#include "battle/CBattleInterface.h"
#include "../lib/CThreadHelper.h"
-#include "../lib/CScriptingModule.h"
#include "../lib/registerTypes/RegisterTypes.h"
#include "gui/CGuiHandler.h"
#include "CMT.h"
#include "CServerHandler.h"
+#include "../lib/ScriptHandler.h"
+#include
#ifdef VCMI_ANDROID
#include "lib/CAndroidVMHelper.h"
@@ -105,6 +106,39 @@ public:
}
};
+CPlayerEnvironment::CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr mainCallback_)
+ : player(player_),
+ cl(cl_),
+ mainCallback(mainCallback_)
+{
+
+}
+
+const Services * CPlayerEnvironment::services() const
+{
+ return VLC;
+}
+
+vstd::CLoggerBase * CPlayerEnvironment::logger() const
+{
+ return logGlobal;
+}
+
+events::EventBus * CPlayerEnvironment::eventBus() const
+{
+ return cl->eventBus();//always get actual value
+}
+
+const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle() const
+{
+ return mainCallback.get();
+}
+
+const CPlayerEnvironment::GameCb * CPlayerEnvironment::game() const
+{
+ return mainCallback.get();
+}
+
CClient::CClient()
{
@@ -114,7 +148,36 @@ CClient::CClient()
registerTypesClientPacks2(*applier);
IObjectInterface::cb = this;
gs = nullptr;
- erm = nullptr;
+}
+
+CClient::~CClient()
+{
+ IObjectInterface::cb = nullptr;
+}
+
+const Services * CClient::services() const
+{
+ return VLC; //todo: this should be CGI
+}
+
+const CClient::BattleCb * CClient::battle() const
+{
+ return this;
+}
+
+const CClient::GameCb * CClient::game() const
+{
+ return this;
+}
+
+vstd::CLoggerBase * CClient::logger() const
+{
+ return logGlobal;
+}
+
+events::EventBus * CClient::eventBus() const
+{
+ return clientEventBus.get();
}
void CClient::newGame()
@@ -122,11 +185,14 @@ void CClient::newGame()
CSH->th->update();
CMapService mapService;
gs = new CGameState();
+ gs->preInit(VLC);
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
initMapHandler();
+ reinitScripting();
+ initPlayerEnvironments();
initPlayerInterfaces();
}
@@ -168,10 +234,16 @@ void CClient::loadGame()
throw; //obviously we cannot continue here
}
logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff());
-
+ gs->preInit(VLC);
gs->updateOnLoad(CSH->si.get());
initMapHandler();
+
+ reinitScripting();
+
+ initPlayerEnvironments();
+
serialize(loader->serializer, loader->serializer.fileVersion);
+
initPlayerInterfaces();
}
@@ -190,6 +262,13 @@ void CClient::serialize(BinarySerializer & h, const int version)
h & i->second->human;
i->second->saveGame(h, version);
}
+
+ if(version >= 800)
+ {
+ JsonNode scriptsState;
+ clientScripts->serializeState(h.saving, scriptsState);
+ h & scriptsState;
+ }
}
void CClient::serialize(BinaryDeserializer & h, const int version)
@@ -253,6 +332,17 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
}
nInt.reset();
}
+
+ {
+ JsonNode scriptsState;
+ if(version >= 800)
+ {
+ h & scriptsState;
+ }
+
+ clientScripts->serializeState(h.saving, scriptsState);
+ }
+
logNetwork->trace("Loaded client part of save %d ms", CSH->th->getDiff());
}
@@ -270,6 +360,8 @@ void CClient::save(const std::string & fname)
void CClient::endGame()
{
+ clientScripts.reset();
+
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
for(auto & i : playerint)
i.second->finish();
@@ -296,8 +388,8 @@ void CClient::endGame()
playerint.clear();
battleints.clear();
- callbacks.clear();
battleCallbacks.clear();
+ playerEnvironments.clear();
logNetwork->info("Deleted playerInts.");
logNetwork->info("Client stopped.");
}
@@ -319,6 +411,24 @@ void CClient::initMapHandler()
pathCache.clear();
}
+void CClient::initPlayerEnvironments()
+{
+ playerEnvironments.clear();
+
+ auto allPlayers = CSH->getAllClientPlayers(CSH->c->connectionID);
+
+ for(auto & color : allPlayers)
+ {
+ logNetwork->info("Preparing environment for player %s", color.getStr());
+ playerEnvironments[color] = std::make_shared(color, this, std::make_shared(gs, color, this));
+ }
+
+ if(settings["session"]["spectate"].Bool())
+ {
+ playerEnvironments[PlayerColor::SPECTATOR] = std::make_shared(PlayerColor::SPECTATOR, this, std::make_shared(gs, boost::none, this));
+ }
+}
+
void CClient::initPlayerInterfaces()
{
for(auto & elem : gs->scenarioOps->playerInfos)
@@ -327,19 +437,20 @@ void CClient::initPlayerInterfaces()
if(!vstd::contains(CSH->getAllClientPlayers(CSH->c->connectionID), color))
continue;
- if(vstd::contains(playerint, color))
- continue;
-
- logNetwork->trace("Preparing interface for player %s", color.getStr());
- if(elem.second.isControlledByAI())
+ if(!vstd::contains(playerint, color))
{
- auto AiToGive = aiNameForPlayer(elem.second, false);
- logNetwork->info("Player %s will be lead by %s", color, AiToGive);
- installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
- }
- else
- {
- installNewPlayerInterface(std::make_shared(color), color);
+ logNetwork->info("Preparing interface for player %s", color.getStr());
+ if(elem.second.isControlledByAI())
+ {
+ auto AiToGive = aiNameForPlayer(elem.second, false);
+ logNetwork->info("Player %s will be lead by %s", color.getStr(), AiToGive);
+ installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
+ }
+ else
+ {
+ logNetwork->info("Player %s will be lead by human", color.getStr());
+ installNewPlayerInterface(std::make_shared(color), color);
+ }
}
}
@@ -379,41 +490,32 @@ std::string CClient::aiNameForPlayer(bool battleAI)
return goodAI;
}
-void CClient::installNewPlayerInterface(std::shared_ptr gameInterface, boost::optional color, bool battlecb)
+void CClient::installNewPlayerInterface(std::shared_ptr gameInterface, PlayerColor color, bool battlecb)
{
boost::unique_lock un(*CPlayerInterface::pim);
- PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
- if(!color)
- privilegedGameEventReceivers.push_back(gameInterface);
+ playerint[color] = gameInterface;
- playerint[colorUsed] = gameInterface;
-
- logGlobal->trace("\tInitializing the interface for player %s", colorUsed);
+ logGlobal->trace("\tInitializing the interface for player %s", color.getStr());
auto cb = std::make_shared(gs, color, this);
- callbacks[colorUsed] = cb;
- battleCallbacks[colorUsed] = cb;
- gameInterface->init(cb);
+ battleCallbacks[color] = cb;
+ gameInterface->init(playerEnvironments.at(color), cb);
installNewBattleInterface(gameInterface, color, battlecb);
}
-void CClient::installNewBattleInterface(std::shared_ptr battleInterface, boost::optional color, bool needCallback)
+void CClient::installNewBattleInterface(std::shared_ptr battleInterface, PlayerColor color, bool needCallback)
{
boost::unique_lock un(*CPlayerInterface::pim);
- PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
- if(!color)
- privilegedBattleEventReceivers.push_back(battleInterface);
-
- battleints[colorUsed] = battleInterface;
+ battleints[color] = battleInterface;
if(needCallback)
{
- logGlobal->trace("\tInitializing the battle interface for player %s", *color);
+ logGlobal->trace("\tInitializing the battle interface for player %s", color.getStr());
auto cbc = std::make_shared(color, this);
- battleCallbacks[colorUsed] = cbc;
- battleInterface->init(cbc);
+ battleCallbacks[color] = cbc;
+ battleInterface->init(playerEnvironments.at(color), cbc);
}
}
@@ -437,14 +539,6 @@ void CClient::handlePack(CPack * pack)
delete pack;
}
-void CClient::commitPackage(CPackForClient * pack)
-{
- CommitPackage cp;
- cp.freePack = false;
- cp.packToCommit = pack;
- sendRequest(&cp, PlayerColor::NEUTRAL);
-}
-
int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
{
static ui32 requestCounter = 0;
@@ -464,6 +558,7 @@ int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
void CClient::battleStarted(const BattleInfo * info)
{
+ setBattle(info);
for(auto & battleCb : battleCallbacks)
{
if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })
@@ -472,9 +567,6 @@ void CClient::battleStarted(const BattleInfo * info)
battleCb.second->setBattle(info);
}
}
-// for(ui8 side : info->sides)
-// if(battleCallbacks.count(side))
-// battleCallbacks[side]->setBattle(info);
std::shared_ptr att, def;
auto & leftSide = info->sides[0], & rightSide = info->sides[1];
@@ -552,6 +644,8 @@ void CClient::battleFinished()
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
battleCallbacks[PlayerColor::SPECTATOR]->setBattle(nullptr);
+
+ setBattle(nullptr);
}
void CClient::startPlayerBattleAction(PlayerColor color)
@@ -645,6 +739,23 @@ PlayerColor CClient::getLocalPlayer() const
return getCurrentPlayer();
}
+scripting::Pool * CClient::getGlobalContextPool() const
+{
+ return clientScripts.get();
+}
+
+scripting::Pool * CClient::getContextPool() const
+{
+ return clientScripts.get();
+}
+
+void CClient::reinitScripting()
+{
+ clientEventBus = make_unique();
+ clientScripts.reset(new scripting::PoolImpl(this));
+}
+
+
#ifdef VCMI_ANDROID
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls)
{
diff --git a/client/Client.h b/client/Client.h
index 68e3843b7..e8c77d8fc 100644
--- a/client/Client.h
+++ b/client/Client.h
@@ -9,8 +9,11 @@
*/
#pragma once
+#include
+
#include "../lib/IGameCallback.h"
#include "../lib/battle/BattleAction.h"
+#include "../lib/battle/CBattleInfoCallback.h"
#include "../lib/CStopWatch.h"
#include "../lib/int3.h"
#include "../lib/CondSh.h"
@@ -28,7 +31,6 @@ class CGameInterface;
class CCallback;
class BattleAction;
class CClient;
-class CScriptingModule;
struct CPathsInfo;
class BinaryDeserializer;
class BinarySerializer;
@@ -37,6 +39,16 @@ namespace boost { class thread; }
template class CApplier;
class CBaseForCLApply;
+namespace scripting
+{
+ class PoolImpl;
+}
+
+namespace events
+{
+ class EventBus;
+}
+
template
class ThreadSafeVector
{
@@ -95,32 +107,40 @@ public:
}
};
-/// Class which handles client - server logic
-class CClient : public IGameCallback
+class CPlayerEnvironment : public Environment
+{
+public:
+ PlayerColor player;
+ CClient * cl;
+ std::shared_ptr mainCallback;
+
+ CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr mainCallback_);
+ const Services * services() const override;
+ vstd::CLoggerBase * logger() const override;
+ events::EventBus * eventBus() const override;
+ const BattleCb * battle() const override;
+ const GameCb * game() const override;
+};
+
+/// Class which handles client - server logic
+class CClient : public IGameCallback, public CBattleInfoCallback, public Environment
{
- std::shared_ptr> applier;
-
- mutable boost::mutex pathCacheMutex;
- std::map> pathCache;
-
- std::map> playerActionThreads;
- void waitForMoveAndSend(PlayerColor color);
-
public:
- std::map> callbacks; //callbacks given to player interfaces
- std::map> battleCallbacks; //callbacks given to player interfaces
- std::vector> privilegedGameEventReceivers; //scripting modules, spectator interfaces
- std::vector> privilegedBattleEventReceivers; //scripting modules, spectator interfaces
std::map> playerint;
std::map> battleints;
- std::map>> additionalPlayerInts;
std::map>> additionalBattleInts;
boost::optional curbaction;
- CScriptingModule * erm;
CClient();
+ ~CClient();
+
+ const Services * services() const override;
+ const BattleCb * battle() const override;
+ const GameCb * game() const override;
+ vstd::CLoggerBase * logger() const override;
+ events::EventBus * eventBus() const override;
void newGame();
void loadGame();
@@ -131,17 +151,16 @@ public:
void endGame();
void initMapHandler();
+ void initPlayerEnvironments();
void initPlayerInterfaces();
std::string aiNameForPlayer(const PlayerSettings & ps, bool battleAI); //empty means no AI -> human
std::string aiNameForPlayer(bool battleAI);
- void installNewPlayerInterface(std::shared_ptr gameInterface, boost::optional color, bool battlecb = false);
- void installNewBattleInterface(std::shared_ptr battleInterface, boost::optional color, bool needCallback = true);
-
+ void installNewPlayerInterface(std::shared_ptr gameInterface, PlayerColor color, bool battlecb = false);
+ void installNewBattleInterface(std::shared_ptr battleInterface, PlayerColor color, bool needCallback = true);
static ThreadSafeVector waitingRequest; //FIXME: make this normal field (need to join all threads before client destruction)
void handlePack(CPack * pack); //applies the given pack and deletes it
- void commitPackage(CPackForClient * pack) override;
int sendRequest(const CPackForServer * request, PlayerColor player); //returns ID given to that request
void battleStarted(const BattleInfo * info);
@@ -160,7 +179,6 @@ public:
void changeSpells(const CGHeroInstance * hero, bool give, const std::set & spells) override {};
bool removeObject(const CGObjectInstance * obj) override {return false;};
- void setBlockVis(ObjectInstanceID objid, bool bv) override {};
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs = false) override {};
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs = false) override {};
@@ -190,7 +208,6 @@ public:
void putArtifact(const ArtifactLocation & al, const CArtifactInstance * a) override {};
void removeArtifact(const ArtifactLocation & al) override {};
bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;};
- void synchronizeArtifactHandlerLists() override {};
void showCompInfo(ShowInInfobox * comp) override {};
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {};
@@ -199,7 +216,6 @@ public:
void startBattlePrimary(const CArmedInstance * army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank = false, const CGTownInstance * town = nullptr) override {}; //use hero=nullptr for no hero
void startBattleI(const CArmedInstance * army1, const CArmedInstance * army2, int3 tile, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used
void startBattleI(const CArmedInstance * army1, const CArmedInstance * army2, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
- void setAmount(ObjectInstanceID objid, ui32 val) override {};
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;};
void giveHeroBonus(GiveBonus * bonus) override {};
void setMovePoints(SetMovePoints * smp) override {};
@@ -211,4 +227,28 @@ public:
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
void changeFogOfWar(std::unordered_set & tiles, PlayerColor player, bool hide) override {}
+
+ void setObjProperty(ObjectInstanceID objid, int prop, si64 val) override {}
+
+ void showInfoDialog(InfoWindow * iw) override {};
+ void showInfoDialog(const std::string & msg, PlayerColor player) override {};
+
+ scripting::Pool * getGlobalContextPool() const override;
+ scripting::Pool * getContextPool() const override;
+private:
+ std::map> battleCallbacks; //callbacks given to player interfaces
+ std::map> playerEnvironments;
+
+ std::shared_ptr clientScripts;
+ std::unique_ptr clientEventBus;
+
+ std::shared_ptr> applier;
+
+ mutable boost::mutex pathCacheMutex;
+ std::map> pathCache;
+
+ std::map> playerActionThreads;
+
+ void waitForMoveAndSend(PlayerColor color);
+ void reinitScripting();
};
diff --git a/client/Graphics.cpp b/client/Graphics.cpp
index 236e5c52c..93351c81e 100644
--- a/client/Graphics.cpp
+++ b/client/Graphics.cpp
@@ -10,6 +10,14 @@
#include "StdInc.h"
#include "Graphics.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CBinaryReader.h"
#include "gui/SDL_Extensions.h"
@@ -19,19 +27,15 @@
#include "CGameInfo.h"
#include "../lib/VCMI_Lib.h"
#include "../CCallback.h"
-#include "../lib/CHeroHandler.h"
-#include "../lib/CTownHandler.h"
#include "../lib/CGeneralTextHandler.h"
-#include "../lib/CCreatureHandler.h"
#include "CBitmapHandler.h"
-#include "../lib/CSkillHandler.h"
-#include "../lib/spells/CSpellHandler.h"
#include "../lib/CGameState.h"
#include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h"
#include "../lib/CStopWatch.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
+#include "../lib/CHeroHandler.h"
using namespace CSDL_Ext;
@@ -163,9 +167,9 @@ void Graphics::load()
void Graphics::loadHeroAnimations()
{
- for(auto & elem : CGI->heroh->classes.heroClasses)
+ for(auto & elem : CGI->heroh->classes.objects)
{
- for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->id)->getTemplates())
+ for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates())
{
if (!heroAnimations.count(templ.animationFile))
heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile);
@@ -423,74 +427,36 @@ void Graphics::loadErmuToPicture()
assert (etp_idx == 44);
}
-void Graphics::addImageListEntry(size_t index, std::string listName, std::string imageName)
+void Graphics::addImageListEntry(size_t index, const std::string & listName, const std::string & imageName)
{
if (!imageName.empty())
{
JsonNode entry;
- entry["frame"].Float() = static_cast(index);
+ entry["frame"].Integer() = index;
entry["file"].String() = imageName;
imageLists["SPRITES/" + listName]["images"].Vector().push_back(entry);
}
}
+void Graphics::addImageListEntries(const EntityService * service)
+{
+ auto cb = std::bind(&Graphics::addImageListEntry, this, _1, _2, _3);
+
+ auto loopCb = [&](const Entity * entity, bool & stop)
+ {
+ entity->registerIcons(cb);
+ };
+
+ service->forEachBase(loopCb);
+}
+
void Graphics::initializeImageLists()
{
- for(const CCreature * creature : CGI->creh->creatures)
- {
- addImageListEntry(creature->iconIndex, "CPRSMALL", creature->smallIconName);
- addImageListEntry(creature->iconIndex, "TWCRPORT", creature->largeIconName);
- }
-
- for(const CHero * hero : CGI->heroh->heroes)
- {
- addImageListEntry(hero->imageIndex, "UN32", hero->iconSpecSmall);
- addImageListEntry(hero->imageIndex, "UN44", hero->iconSpecLarge);
- addImageListEntry(hero->imageIndex, "PORTRAITSLARGE", hero->portraitLarge);
- addImageListEntry(hero->imageIndex, "PORTRAITSSMALL", hero->portraitSmall);
- }
-
- for(const CArtifact * art : CGI->arth->artifacts)
- {
- addImageListEntry(art->iconIndex, "ARTIFACT", art->image);
- addImageListEntry(art->iconIndex, "ARTIFACTLARGE", art->large);
- }
-
- for(const CFaction * faction : CGI->townh->factions)
- {
- if (faction->town)
- {
- auto & info = faction->town->clientInfo;
- addImageListEntry(info.icons[0][0], "ITPT", info.iconLarge[0][0]);
- addImageListEntry(info.icons[0][1], "ITPT", info.iconLarge[0][1]);
- addImageListEntry(info.icons[1][0], "ITPT", info.iconLarge[1][0]);
- addImageListEntry(info.icons[1][1], "ITPT", info.iconLarge[1][1]);
-
- addImageListEntry(info.icons[0][0] + 2, "ITPA", info.iconSmall[0][0]);
- addImageListEntry(info.icons[0][1] + 2, "ITPA", info.iconSmall[0][1]);
- addImageListEntry(info.icons[1][0] + 2, "ITPA", info.iconSmall[1][0]);
- addImageListEntry(info.icons[1][1] + 2, "ITPA", info.iconSmall[1][1]);
- }
- }
-
- for(const CSpell * spell : CGI->spellh->objects)
- {
- addImageListEntry(spell->id, "SPELLS", spell->iconBook);
- addImageListEntry(spell->id+1, "SPELLINT", spell->iconEffect);
- addImageListEntry(spell->id, "SPELLBON", spell->iconScenarioBonus);
- addImageListEntry(spell->id, "SPELLSCR", spell->iconScroll);
- }
-
- for(const CSkill * skill : CGI->skillh->objects)
- {
- for(int level = 1; level <= 3; level++)
- {
- int frame = 2 + level + 3 * skill->id;
- const CSkill::LevelInfo & skillAtLevel = skill->at(level);
- addImageListEntry(frame, "SECSK32", skillAtLevel.iconSmall);
- addImageListEntry(frame, "SECSKILL", skillAtLevel.iconMedium);
- addImageListEntry(frame, "SECSK82", skillAtLevel.iconLarge);
- }
- }
+ addImageListEntries(CGI->creatures());
+ addImageListEntries(CGI->heroTypes());
+ addImageListEntries(CGI->artifacts());
+ addImageListEntries(CGI->factions());
+ addImageListEntries(CGI->spells());
+ addImageListEntries(CGI->skills());
}
diff --git a/client/Graphics.h b/client/Graphics.h
index ba6fa7bf8..9cc4fd92a 100644
--- a/client/Graphics.h
+++ b/client/Graphics.h
@@ -23,6 +23,7 @@ struct InfoAboutTown;
class CGObjectInstance;
class ObjectTemplate;
class CAnimation;
+class EntityService;
enum EFonts
{
@@ -32,7 +33,9 @@ enum EFonts
/// Handles fonts, hero images, town images, various graphics
class Graphics
{
- void addImageListEntry(size_t index, std::string listName, std::string imageName);
+ void addImageListEntry(size_t index, const std::string & listName, const std::string & imageName);
+
+ void addImageListEntries(const EntityService * service);
void initializeBattleGraphics();
void loadPaletteAndColors();
diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp
index 02b30eb84..d2c67c840 100644
--- a/client/NetPacksClient.cpp
+++ b/client/NetPacksClient.cpp
@@ -45,12 +45,6 @@
// TODO: as Tow suggested these template should all be part of CClient
// This will require rework spectator interface properly though
-template
-void callPrivilegedInterfaces(CClient * cl, void (T::*ptr)(Args...), Args2 && ...args)
-{
- for(auto &ger : cl->privilegedGameEventReceivers)
- ((*ger).*ptr)(std::forward(args)...);
-}
template
bool callOnlyThatInterface(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
@@ -67,7 +61,6 @@ template
bool callInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
{
bool called = callOnlyThatInterface(cl, player, ptr, std::forward(args)...);
- callPrivilegedInterfaces(cl, ptr, std::forward(args)...);
return called;
}
@@ -84,18 +77,10 @@ void callOnlyThatBattleInterface(CClient * cl, PlayerColor player, void (T::*ptr
}
}
-template
-void callPrivilegedBattleInterfaces(CClient * cl, void (T::*ptr)(Args...), Args2 && ...args)
-{
- for(auto & ber : cl->privilegedBattleEventReceivers)
- ((*ber).*ptr)(std::forward(args)...);
-}
-
template
void callBattleInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
{
callOnlyThatInterface(cl, player, ptr, std::forward(args)...);
- callPrivilegedBattleInterfaces(cl, ptr, std::forward(args)...);
}
//calls all normal interfaces and privileged ones, playerints may be updated when iterating over it, so we need a copy
@@ -116,10 +101,8 @@ void callBattleInterfaceIfPresentForBothSides(CClient * cl, void (T::*ptr)(Args.
{
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward(args)...);
}
- callPrivilegedBattleInterfaces(cl, ptr, std::forward(args)...);
}
-
void SetResources::applyCl(CClient *cl)
{
//todo: inform on actual resource set transfered
@@ -307,7 +290,7 @@ void GiveBonus::applyCl(CClient *cl)
break;
case PLAYER:
{
- const PlayerState *p = GS(cl)->getPlayer(PlayerColor(id));
+ const PlayerState *p = GS(cl)->getPlayerState(PlayerColor(id));
callInterfaceIfPresent(cl, PlayerColor(id), &IGameEventsReceiver::playerBonusChanged, *p->getBonusList().back(), true);
}
break;
@@ -351,7 +334,7 @@ void RemoveBonus::applyCl(CClient *cl)
break;
case PLAYER:
{
- //const PlayerState *p = GS(cl)->getPlayer(id);
+ //const PlayerState *p = GS(cl)->getPlayerState(id);
callInterfaceIfPresent(cl, PlayerColor(id), &IGameEventsReceiver::playerBonusChanged, bonus, false);
}
break;
@@ -370,7 +353,7 @@ void RemoveObject::applyFirstCl(CClient *cl)
{
//below line contains little cheat for AI so it will be aware of deletion of enemy heroes that moved or got re-covered by FoW
//TODO: loose requirements as next AI related crashes appear, for example another player collects object that got re-covered by FoW, unsure if AI code workarounds this
- if(GS(cl)->isVisible(o, i->first) || (!cl->getPlayer(i->first)->human && o->ID == Obj::HERO && o->tempOwner != i->first))
+ if(GS(cl)->isVisible(o, i->first) || (!cl->getPlayerState(i->first)->human && o->ID == Obj::HERO && o->tempOwner != i->first))
i->second->objectRemoved(o);
}
}
@@ -387,7 +370,7 @@ void TryMoveHero::applyFirstCl(CClient *cl)
//check if playerint will have the knowledge about movement - if not, directly update maphandler
for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++)
{
- auto ps = GS(cl)->getPlayer(i->first);
+ auto ps = GS(cl)->getPlayerState(i->first);
if(ps && (GS(cl)->isVisible(start - int3(1, 0, 0), i->first) || GS(cl)->isVisible(end - int3(1, 0, 0), i->first)))
{
if(ps->human)
@@ -611,8 +594,6 @@ void BattleStart::applyFirstCl(CClient *cl)
info->tile, info->sides[0].hero, info->sides[1].hero);
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, info->sides[0].armyObject, info->sides[1].armyObject,
info->tile, info->sides[0].hero, info->sides[1].hero);
- callPrivilegedBattleInterfaces(cl, &IBattleEventsReceiver::battleStartBefore, info->sides[0].armyObject, info->sides[1].armyObject,
- info->tile, info->sides[0].hero, info->sides[1].hero);
}
void BattleStart::applyCl(CClient *cl)
@@ -651,6 +632,11 @@ void BattleSetActiveStack::applyCl(CClient *cl)
cl->startPlayerBattleAction(playerToCall);
}
+void BattleLogMessage::applyCl(CClient * cl)
+{
+ callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleLogMessage, lines);
+}
+
void BattleTriggerEffect::applyCl(CClient * cl)
{
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleTriggerEffect, *this);
@@ -680,7 +666,7 @@ void BattleAttack::applyFirstCl(CClient *cl)
void BattleAttack::applyCl(CClient *cl)
{
- callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, bsa, battleLog);
+ callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, bsa);
}
void StartAction::applyFirstCl(CClient *cl)
@@ -702,7 +688,7 @@ void SetStackEffect::applyCl(CClient *cl)
void StacksInjured::applyCl(CClient *cl)
{
- callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, stacks, battleLog);
+ callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, stacks);
}
void BattleResultsApplied::applyCl(CClient *cl)
@@ -714,7 +700,7 @@ void BattleResultsApplied::applyCl(CClient *cl)
void BattleUnitsChanged::applyCl(CClient * cl)
{
- callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, changedStacks, customEffects, battleLog);
+ callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, changedStacks, customEffects);
}
void BattleObstaclesChanged::applyCl(CClient *cl)
@@ -795,7 +781,7 @@ void PlayerMessageClient::applyCl(CClient *cl)
if(player.isSpectator())
str << "Spectator: " << text;
else
- str << cl->getPlayer(player)->nodeName() <<": " << text;
+ str << cl->getPlayerState(player)->nodeName() <<": " << text;
if(LOCPLINT)
LOCPLINT->cingconsole->print(str.str());
}
@@ -918,3 +904,9 @@ void SetAvailableArtifacts::applyCl(CClient *cl)
callInterfaceIfPresent(cl, cl->getTile(bm->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::availableArtifactsChanged, bm);
}
}
+
+
+void EntitiesChanged::applyCl(CClient *cl)
+{
+ cl->invalidatePaths();
+}
diff --git a/client/VCMI_client.cbp b/client/VCMI_client.cbp
index d488c8b57..845082b67 100644
--- a/client/VCMI_client.cbp
+++ b/client/VCMI_client.cbp
@@ -4,6 +4,7 @@
+
@@ -13,7 +14,6 @@
-
@@ -91,7 +91,7 @@
-
+
@@ -246,10 +246,6 @@
-
-
-
-
@@ -259,6 +255,7 @@
+
diff --git a/client/battle/CBattleAnimations.cpp b/client/battle/CBattleAnimations.cpp
index b39932a78..3ca1b7935 100644
--- a/client/battle/CBattleAnimations.cpp
+++ b/client/battle/CBattleAnimations.cpp
@@ -29,7 +29,6 @@
#include "../../lib/CStack.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/mapObjects/CGTownInstance.h"
-#include "../../lib/spells/CSpellHandler.h"
CBattleAnimation::CBattleAnimation(CBattleInterface * _owner)
: owner(_owner), ID(_owner->animIDhelper++)
@@ -762,15 +761,15 @@ bool CShootingAnimation::init()
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
{
int creID = owner->siegeH->town->town->clientInfo.siegeShooter;
- shooterInfo = CGI->creh->creatures[creID];
+ shooterInfo = CGI->creh->operator[](creID);
}
if(!shooterInfo->animation.missleFrameAngles.size())
logAnim->error("Mod error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Trying to use archer's data instead..."
, shooterInfo->nameSing);
-
- auto & angles = shooterInfo->animation.missleFrameAngles.size()
+
+ auto & angles = shooterInfo->animation.missleFrameAngles.size()
? shooterInfo->animation.missleFrameAngles
- : CGI->creh->creatures[CreatureID::ARCHER]->animation.missleFrameAngles;
+ : CGI->creh->operator[](CreatureID::ARCHER)->animation.missleFrameAngles;
ProjectileInfo spi;
spi.shotDone = false;
diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp
index 648d35ab0..ab6d49219 100644
--- a/client/battle/CBattleInterface.cpp
+++ b/client/battle/CBattleInterface.cpp
@@ -38,6 +38,8 @@
#include "../../lib/CondSh.h"
#include "../../lib/CRandomGenerator.h"
#include "../../lib/spells/CSpellHandler.h"
+#include "../../lib/spells/ISpellMechanics.h"
+#include "../../lib/spells/Problem.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
@@ -398,7 +400,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
for(auto hex : bfield)
addChild(hex.get());
- if (tacticsMode)
+ if(tacticsMode)
bTacticNextStack();
CCS->musich->stopMusic();
@@ -415,7 +417,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
};
CCS->soundh->setCallback(battleIntroSoundChannel, onIntroPlayed);
- memset(stackCountOutsideHexes, 1, GameConstants::BFIELD_SIZE *sizeof(bool)); //initialize array with trues
currentAction = PossiblePlayerBattleAction::INVALID;
selectedAction = PossiblePlayerBattleAction::INVALID;
@@ -579,7 +580,7 @@ void CBattleInterface::keyPressed(const SDL_KeyboardEvent & key)
if(!battleActionsStarted)
CCS->soundh->stopSound(battleIntroSoundChannel);
else
- endCastingSpell();
+ endCastingSpell();
}
}
void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
@@ -794,7 +795,7 @@ void CBattleInterface::bSurrenderf()
if (cost >= 0)
{
std::string enemyHeroName = curInt->cb->battleGetEnemyHero().name;
- if(enemyHeroName.empty())
+ if (enemyHeroName.empty())
{
logGlobal->warn("Surrender performed without enemy hero, should not happen!");
enemyHeroName = "#ENEMY#";
@@ -871,7 +872,7 @@ void CBattleInterface::bAutofightf()
blockUI(true);
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
- ai->init(curInt->cb);
+ ai->init(curInt->env, curInt->cb);
ai->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
curInt->autofightingAI = ai;
curInt->cb->registerBattleInterface(ai);
@@ -910,14 +911,14 @@ void CBattleInterface::bSpellf()
if (blockingBonus->source == Bonus::ARTIFACT)
{
- const int artID = blockingBonus->sid;
+ const int32_t artID = blockingBonus->sid;
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus
std::string heroName = myHero->hasArt(artID) ? myHero->name : enemyHero().name;
//%s wields the %s, an ancient artifact which creates a p dead to all magic.
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
- % heroName % CGI->arth->artifacts[artID]->Name()));
+ % heroName % CGI->artifacts()->getByIndex(artID)->getName()));
}
}
}
@@ -964,7 +965,7 @@ void CBattleInterface::unitAdded(const CStack * stack)
if(stack->initialPosition < 0) //turret
{
- const CCreature *turretCreature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter];
+ const CCreature *turretCreature = CGI->creh->objects[siegeH->town->town->clientInfo.siegeShooter];
creAnims[stack->ID] = AnimationControls::getAnimation(turretCreature);
@@ -1012,7 +1013,7 @@ void CBattleInterface::initStackProjectile(const CStack * stack)
{
const CCreature * creature;//creature whose shots should be loaded
if(stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
- creature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter];
+ creature = CGI->creh->objects[siegeH->town->town->clientInfo.siegeShooter];
else
creature = stack->getCreature();
@@ -1062,7 +1063,7 @@ void CBattleInterface::stackMoved(const CStack *stack, std::vector de
waitForAnims();
}
-void CBattleInterface::stacksAreAttacked(std::vector attackedInfos, const std::vector & battleLog)
+void CBattleInterface::stacksAreAttacked(std::vector attackedInfos)
{
for(auto & attackedInfo : attackedInfos)
{
@@ -1089,8 +1090,6 @@ void CBattleInterface::stacksAreAttacked(std::vector attacked
killedBySide.at(side) += attackedInfo.amountKilled;
}
- int killed = killedBySide[0] + killedBySide[1];
-
for(ui8 side = 0; side < 2; side++)
{
if(killedBySide.at(side) > killedBySide.at(1-side))
@@ -1106,11 +1105,6 @@ void CBattleInterface::stacksAreAttacked(std::vector attacked
if (attackedInfo.cloneKilled)
stackRemoved(attackedInfo.defender->ID);
}
-
- if(!battleLog.empty())
- displayBattleLog(battleLog);
- else
- printConsoleAttacked(attackedInfos.front().defender, damage, killed, attackedInfos.front().attacker, (targets > 1)); //creatures perish
}
void CBattleInterface::stackAttacking( const CStack *attacker, BattleHex dest, const CStack *attacked, bool shooting )
@@ -1377,9 +1371,6 @@ void CBattleInterface::spellCast(const BattleSpellCast * sc)
displayEffect(elem.effect, stack->getPosition());
}
- //displaying message in console
- displayBattleLog(sc->battleLog);
-
waitForAnims();
//mana absorption
if (sc->manaGained > 0)
@@ -1393,9 +1384,6 @@ void CBattleInterface::spellCast(const BattleSpellCast * sc)
void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
{
- for(const MetaString & line : sse.battleLog)
- console->addText(line.toString());
-
if(activeStack != nullptr)
redrawBackgroundWithHexes(activeStack);
}
@@ -1474,28 +1462,19 @@ void CBattleInterface::displayEffect(ui32 effect, BattleHex destTile)
addNewAnim(new CEffectAnimation(this, customAnim, destTile));
}
-void CBattleInterface::displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile)
-{
- if (animation.pause > 0)
- {
- addNewAnim(new CDummyAnimation(this, animation.pause));
- }
- else
- {
- addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
- }
-}
-
void CBattleInterface::displaySpellCast(SpellID spellID, BattleHex destinationTile)
{
- const CSpell *spell = spellID.toSpell();
+ const CSpell * spell = spellID.toSpell();
- if (spell == nullptr)
+ if(spell == nullptr)
return;
- for (const CSpell::TAnimation & animation : spell->animationInfo.cast)
+ for(const CSpell::TAnimation & animation : spell->animationInfo.cast)
{
- displaySpellAnimation(animation, destinationTile);
+ if(animation.pause > 0)
+ addNewAnim(new CDummyAnimation(this, animation.pause));
+ else
+ addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
}
}
@@ -1503,25 +1482,32 @@ void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destination
{
const CSpell *spell = spellID.toSpell();
- if (spell == nullptr)
+ if(spell == nullptr)
return;
- for (const CSpell::TAnimation & animation : spell->animationInfo.affect)
+ for(const CSpell::TAnimation & animation : spell->animationInfo.affect)
{
- displaySpellAnimation(animation, destinationTile);
+ if(animation.pause > 0)
+ addNewAnim(new CDummyAnimation(this, animation.pause));
+ else
+ addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
+
}
}
void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTile)
{
- const CSpell *spell = spellID.toSpell();
+ const CSpell * spell = spellID.toSpell();
- if (spell == nullptr)
+ if(spell == nullptr)
return;
- for (const CSpell::TAnimation & animation : spell->animationInfo.hit)
+ for(const CSpell::TAnimation & animation : spell->animationInfo.hit)
{
- displaySpellAnimation(animation, destinationTile);
+ if(animation.pause > 0)
+ addNewAnim(new CDummyAnimation(this, animation.pause));
+ else
+ addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
}
}
@@ -1712,9 +1698,19 @@ void CBattleInterface::enterCreatureCastingMode()
if (vstd::contains(possibleActions, PossiblePlayerBattleAction::NO_LOCATION))
{
- const spells::Caster *caster = activeStack;
- const CSpell *spell = SpellID(creatureSpellToCast).toSpell();
- const bool isCastingPossible = spell->canBeCastAt(curInt->cb.get(), spells::Mode::CREATURE_ACTIVE, caster, BattleHex::INVALID);
+ const spells::Caster * caster = activeStack;
+ const CSpell * spell = SpellID(creatureSpellToCast).toSpell();
+
+ spells::Target target;
+ target.emplace_back();
+
+
+ spells::BattleCast cast(curInt->cb.get(), caster, spells::Mode::CREATURE_ACTIVE, spell);
+
+ auto m = spell->battleMechanics(&cast);
+ spells::detail::ProblemImpl ignored;
+
+ const bool isCastingPossible = m->canBeCastAt(ignored, target);
if (isCastingPossible)
{
@@ -1732,7 +1728,7 @@ void CBattleInterface::enterCreatureCastingMode()
auto actionFilterPredicate = [](const PossiblePlayerBattleAction x)
{
return (x != PossiblePlayerBattleAction::ANY_LOCATION) && (x != PossiblePlayerBattleAction::NO_LOCATION) &&
- (x != PossiblePlayerBattleAction::FREE_LOCATION) && (x != PossiblePlayerBattleAction::AIMED_SPELL_CREATURE) &&
+ (x != PossiblePlayerBattleAction::FREE_LOCATION) && (x != PossiblePlayerBattleAction::AIMED_SPELL_CREATURE) &&
(x != PossiblePlayerBattleAction::OBSTACLE);
};
@@ -1766,7 +1762,7 @@ void CBattleInterface::reorderPossibleActionsPriority(const CStack * stack, Mous
case PossiblePlayerBattleAction::OBSTACLE:
if(!stack->hasBonusOfType(Bonus::NO_SPELLCAST_BY_DEFAULT) && context == MouseHoveredHexContext::OCCUPIED_HEX)
return 1;
- else
+ else
return 100;//bottom priority
break;
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL:
@@ -1784,9 +1780,9 @@ void CBattleInterface::reorderPossibleActionsPriority(const CStack * stack, Mous
case PossiblePlayerBattleAction::MOVE_STACK:
return 8; break;
case PossiblePlayerBattleAction::CATAPULT:
- return 9; break;
+ return 9; break;
case PossiblePlayerBattleAction::HEAL:
- return 10; break;
+ return 10; break;
default:
return 200; break;
}
@@ -1800,39 +1796,6 @@ void CBattleInterface::reorderPossibleActionsPriority(const CStack * stack, Mous
std::make_heap(possibleActions.begin(), possibleActions.end(), comparer);
}
-void CBattleInterface::printConsoleAttacked(const CStack * defender, int dmg, int killed, const CStack * attacker, bool multiple)
-{
- std::string formattedText;
- if(attacker) //ignore if stacks were killed by spell
- {
- MetaString text;
- attacker->addText(text, MetaString::GENERAL_TXT, 376);
- attacker->addNameReplacement(text);
- text.addReplacement(dmg);
- formattedText = text.toString();
- }
-
- if(killed > 0)
- {
- if(attacker)
- formattedText.append(" ");
-
- boost::format txt;
- if(killed > 1)
- {
- txt = boost::format(CGI->generaltexth->allTexts[379]) % killed % (multiple ? CGI->generaltexth->allTexts[43] : defender->getCreature()->namePl); // creatures perish
- }
- else //killed == 1
- {
- txt = boost::format(CGI->generaltexth->allTexts[378]) % (multiple ? CGI->generaltexth->allTexts[42] : defender->getCreature()->nameSing); // creature perishes
- }
- std::string trimmed = boost::to_string(txt);
- boost::algorithm::trim(trimmed); // these default h3 texts have unnecessary new lines, so get rid of them before displaying
- formattedText.append(trimmed);
- }
- console->addText(formattedText);
-}
-
void CBattleInterface::endAction(const BattleAction* action)
{
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber);
@@ -2571,7 +2534,16 @@ bool CBattleInterface::isCastingPossibleHere(const CStack *sactive, const CStack
else
{
const spells::Mode mode = creatureCasting ? spells::Mode::CREATURE_ACTIVE : spells::Mode::HERO;
- isCastingPossible = sp->canBeCastAt(curInt->cb.get(), mode, caster, myNumber);
+
+ spells::Target target;
+ target.emplace_back(myNumber);
+
+ spells::BattleCast cast(curInt->cb.get(), caster, mode, sp);
+
+ auto m = sp->battleMechanics(&cast);
+ spells::detail::ProblemImpl problem; //todo: display problem in status bar
+
+ isCastingPossible = m->canBeCastAt(problem, target);
}
}
else
@@ -3050,7 +3022,7 @@ void CBattleInterface::show(SDL_Surface *to)
showProjectiles(to);
if(battleActionsStarted)
- updateBattleAnimations();
+ updateBattleAnimations();
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
@@ -3064,7 +3036,7 @@ void CBattleInterface::show(SDL_Surface *to)
//we may have changed active interface (another side in hot-seat),
// so we can't continue drawing with old setting.
show(to);
- }
+ }
}
void CBattleInterface::showBackground(SDL_Surface *to)
@@ -3172,7 +3144,9 @@ void CBattleInterface::showHighlightedHexes(SDL_Surface *to)
if(caster && spell) //when casting spell
{
// printing shaded hex(es)
- auto shaded = spell->rangeInHexes(curInt->cb.get(), mode, caster, currentlyHoveredHex);
+ spells::BattleCast event(curInt->cb.get(), caster, mode, spell);
+ auto shaded = spell->battleMechanics(&event)->rangeInHexes(currentlyHoveredHex);
+
for(BattleHex shadedHex : shaded)
{
if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1))
@@ -3691,7 +3665,17 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack *activeStack)
attackableHexes.clear();
if (activeStack)
occupyableHexes = curInt->cb->battleGetAvailableHexes(activeStack, true, &attackableHexes);
- curInt->cb->battleGetStackCountOutsideHexes(stackCountOutsideHexes);
+
+ auto fillStackCountOutsideHexes = [&]()
+ {
+ auto accessibility = curInt->cb->getAccesibility();
+
+ for(int i = 0; i < accessibility.size(); i++)
+ stackCountOutsideHexes.at(i) = (accessibility[i] == EAccessibility::ACCESSIBLE);
+ };
+
+ fillStackCountOutsideHexes();
+
//prepare background graphic with hexes and shaded hexes
blitAt(background, 0, 0, backgroundWithHexes);
diff --git a/client/battle/CBattleInterface.h b/client/battle/CBattleInterface.h
index ad8151f90..79ace75df 100644
--- a/client/battle/CBattleInterface.h
+++ b/client/battle/CBattleInterface.h
@@ -9,7 +9,9 @@
*/
#pragma once
-#include "../../lib/ConstTransitivePtr.h" //may be reundant
+#include
+
+#include "../../lib/ConstTransitivePtr.h" //may be redundant
#include "../../lib/GameConstants.h"
#include "CBattleAnimations.h"
@@ -50,6 +52,7 @@ class CBattleGameInterface;
struct CustomEffectInfo;
class CAnimation;
class IImage;
+class CSpell;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo
@@ -153,7 +156,7 @@ private:
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
std::vector occupyableHexes, //hexes available for active stack
attackableHexes; //hexes attackable by active stack
- bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
+ std::array stackCountOutsideHexes; // hexes that when in front of a unit cause it's amount box to move back
BattleHex previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
BattleHex currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
int attackingHex; //hex from which the stack would perform attack with current cursor
@@ -187,8 +190,6 @@ private:
//force active stack to cast a spell if possible
void enterCreatureCastingMode();
- void printConsoleAttacked(const CStack *defender, int dmg, int killed, const CStack *attacker, bool Multiple);
-
std::list projectiles; //projectiles flying on battlefield
void giveCommand(EActionType action, BattleHex tile = BattleHex(), si32 additional = -1);
void sendCommand(BattleAction *& command, const CStack * actor = nullptr);
@@ -340,7 +341,7 @@ public:
void stackActivated(const CStack *stack); //active stack has been changed
void stackMoved(const CStack *stack, std::vector destHex, int distance); //stack with id number moved to destHex
void waitForAnims();
- void stacksAreAttacked(std::vector attackedInfos, const std::vector & battleLog); //called when a certain amount of stacks has been attacked
+ void stacksAreAttacked(std::vector attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(const CStack *attacker, BattleHex dest, const CStack *attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of round
@@ -361,8 +362,6 @@ public:
void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
- void displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile);
-
void battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex
void endAction(const BattleAction* action);
diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp
index 02689ecdb..fb32093fd 100644
--- a/client/battle/CBattleInterfaceClasses.cpp
+++ b/client/battle/CBattleInterfaceClasses.cpp
@@ -448,8 +448,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult & br, CPlayerInterfa
if(best != stacks.end()) //should be always but to be safe...
{
- icons.push_back(std::make_shared("TWCRPORT", (*best)->type->idNumber+2, 0, xs[i], 38));
- sideNames[i] = CGI->creh->creatures[(*best)->type->idNumber]->namePl;
+ icons.push_back(std::make_shared("TWCRPORT", (*best)->type->getIconIndex(), 0, xs[i], 38));
+ sideNames[i] = (*best)->type->getPluralName();
}
}
}
@@ -471,7 +471,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult & br, CPlayerInterfa
int yPos = 344 + step * 97;
for(auto & elem : br.casualties[step])
{
- icons.push_back(std::make_shared("CPRSMALL", CGI->creh->creatures[elem.first]->iconIndex, 0, xPos, yPos));
+ icons.push_back(std::make_shared("CPRSMALL", CGI->creatures()->getByIndex(elem.first)->getIconIndex(), 0, xPos, yPos));
std::ostringstream amount;
amount<(xPos + 16, yPos + 42, FONT_SMALL, CENTER, Colors::WHITE, amount.str()));
diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp
index 64f65db1c..bf386b492 100644
--- a/client/gui/CGuiHandler.cpp
+++ b/client/gui/CGuiHandler.cpp
@@ -23,7 +23,7 @@
#include "../CPlayerInterface.h"
#include "../battle/CBattleInterface.h"
-extern std::queue events;
+extern std::queue SDLEventsQueue;
extern boost::mutex eventsM;
boost::thread_specific_ptr inGuiThread;
@@ -188,18 +188,18 @@ void CGuiHandler::handleEvents()
return;
boost::unique_lock lock(eventsM);
- while(!events.empty())
+ while(!SDLEventsQueue.empty())
{
continueEventHandling = true;
- SDL_Event ev = events.front();
+ SDL_Event ev = SDLEventsQueue.front();
current = &ev;
- events.pop();
+ SDLEventsQueue.pop();
// In a sequence of mouse motion events, skip all but the last one.
// This prevents freezes when every motion event takes longer to handle than interval at which
// the events arrive (like dragging on the minimap in world view, with redraw at every event)
// so that the events would start piling up faster than they can be processed.
- if ((ev.type == SDL_MOUSEMOTION) && !events.empty() && (events.front().type == SDL_MOUSEMOTION))
+ if ((ev.type == SDL_MOUSEMOTION) && !SDLEventsQueue.empty() && (SDLEventsQueue.front().type == SDL_MOUSEMOTION))
continue;
handleCurrentEvent();
diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp
index 02d712521..64f82a6de 100644
--- a/client/lobby/CBonusSelection.cpp
+++ b/client/lobby/CBonusSelection.cpp
@@ -10,6 +10,10 @@
#include "StdInc.h"
#include "CBonusSelection.h"
+
+#include
+#include
+
#include "CSelectionBase.h"
#include "../CGameInfo.h"
@@ -34,9 +38,7 @@
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/CGeneralTextHandler.h"
-#include "../../lib/CArtHandler.h"
#include "../../lib/CBuildingHandler.h"
-#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/CSkillHandler.h"
#include "../../lib/CTownHandler.h"
@@ -176,13 +178,13 @@ void CBonusSelection::createBonusesIcons()
{
case CScenarioTravel::STravelBonus::SPELL:
desc = CGI->generaltexth->allTexts[715];
- boost::algorithm::replace_first(desc, "%s", CGI->spellh->objects[bonDescs[i].info2]->name);
+ boost::algorithm::replace_first(desc, "%s", CGI->spells()->getByIndex(bonDescs[i].info2)->getName());
break;
case CScenarioTravel::STravelBonus::MONSTER:
picNumber = bonDescs[i].info2 + 2;
desc = CGI->generaltexth->allTexts[717];
boost::algorithm::replace_first(desc, "%d", boost::lexical_cast(bonDescs[i].info3));
- boost::algorithm::replace_first(desc, "%s", CGI->creh->creatures[bonDescs[i].info2]->namePl);
+ boost::algorithm::replace_first(desc, "%s", CGI->creatures()->getByIndex(bonDescs[i].info2)->getPluralName());
break;
case CScenarioTravel::STravelBonus::BUILDING:
{
@@ -202,18 +204,18 @@ void CBonusSelection::createBonusesIcons()
picName = graphics->ERMUtoPicture[faction][buildID];
picNumber = -1;
- if(vstd::contains(CGI->townh->factions[faction]->town->buildings, buildID))
- desc = CGI->townh->factions[faction]->town->buildings.find(buildID)->second->Name();
+ if(vstd::contains((*CGI->townh)[faction]->town->buildings, buildID))
+ desc = (*CGI->townh)[faction]->town->buildings.find(buildID)->second->Name();
break;
}
case CScenarioTravel::STravelBonus::ARTIFACT:
desc = CGI->generaltexth->allTexts[715];
- boost::algorithm::replace_first(desc, "%s", CGI->arth->artifacts[bonDescs[i].info2]->Name());
+ boost::algorithm::replace_first(desc, "%s", CGI->artifacts()->getByIndex(bonDescs[i].info2)->getName());
break;
case CScenarioTravel::STravelBonus::SPELL_SCROLL:
desc = CGI->generaltexth->allTexts[716];
- boost::algorithm::replace_first(desc, "%s", CGI->spellh->objects[bonDescs[i].info2]->name);
+ boost::algorithm::replace_first(desc, "%s", CGI->spells()->getByIndex(bonDescs[i].info2)->getName());
break;
case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
{
@@ -318,7 +320,7 @@ void CBonusSelection::createBonusesIcons()
}
else
{
- boost::algorithm::replace_first(desc, "%s", CGI->heroh->heroes[bonDescs[i].info2]->name);
+ boost::algorithm::replace_first(desc, "%s", CGI->heroh->objects[bonDescs[i].info2]->name);
}
break;
}
diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp
index 1c0de4ce6..2cbbde96e 100644
--- a/client/lobby/OptionsTab.cpp
+++ b/client/lobby/OptionsTab.cpp
@@ -83,7 +83,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
TOWN_RANDOM = 38, TOWN_NONE = 39, // Special frames in ITPA
HERO_RANDOM = 163, HERO_NONE = 164 // Special frames in PortraitsSmall
};
- auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle;
+ auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
switch(type)
{
@@ -95,7 +95,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
case PlayerSettings::RANDOM:
return TOWN_RANDOM;
default:
- return CGI->townh->factions[factionIndex]->town->clientInfo.icons[true][false] + 2;
+ return (*CGI->townh)[factionIndex]->town->clientInfo.icons[true][false] + 2;
}
case HERO:
switch(settings.hero)
@@ -108,11 +108,10 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
{
if(settings.heroPortrait >= 0)
return settings.heroPortrait;
- auto index = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero;
- return CGI->heroh->heroes[index]->imageIndex;
+ auto index = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
+ return (*CGI->heroh)[index]->imageIndex;
}
}
-
case BONUS:
{
switch(settings.bonus)
@@ -125,7 +124,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
return GOLD;
case PlayerSettings::RESOURCE:
{
- switch(CGI->townh->factions[factionIndex]->town->primaryRes)
+ switch((*CGI->townh)[factionIndex]->town->primaryRes)
{
case Res::WOOD_AND_ORE:
return WOOD_ORE;
@@ -181,11 +180,11 @@ std::string OptionsTab::CPlayerSettingsHelper::getName()
return CGI->generaltexth->allTexts[522];
default:
{
- auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle;
- return CGI->townh->factions[factionIndex]->name;
- }
+ auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
+ return (*CGI->townh)[factionIndex]->name;
}
}
+ }
case HERO:
{
switch(settings.hero)
@@ -198,8 +197,8 @@ std::string OptionsTab::CPlayerSettingsHelper::getName()
{
if(!settings.heroName.empty())
return settings.heroName;
- auto index = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero;
- return CGI->heroh->heroes[index]->name;
+ auto index = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
+ return (*CGI->heroh)[index]->name;
}
}
}
@@ -245,8 +244,8 @@ std::string OptionsTab::CPlayerSettingsHelper::getTitle()
}
std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
{
- auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle;
- auto heroIndex = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero;
+ auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
+ auto heroIndex = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
switch(type)
{
@@ -255,7 +254,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
case HERO:
{
if(settings.hero >= 0)
- return getName() + " - " + CGI->heroh->heroes[heroIndex]->heroClass->name;
+ return getName() + " - " + (*CGI->heroh)[heroIndex]->heroClass->name;
return getName();
}
@@ -267,7 +266,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
return CGI->generaltexth->allTexts[87]; //500-1000
case PlayerSettings::RESOURCE:
{
- switch(CGI->townh->factions[factionIndex]->town->primaryRes)
+ switch((*CGI->townh)[factionIndex]->town->primaryRes)
{
case Res::MERCURY:
return CGI->generaltexth->allTexts[694];
@@ -289,7 +288,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
std::string OptionsTab::CPlayerSettingsHelper::getDescription()
{
- auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle;
+ auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
switch(type)
{
@@ -309,7 +308,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getDescription()
return CGI->generaltexth->allTexts[92]; //At the start of the game, 500-1000 gold is added to your Kingdom's resource pool
case PlayerSettings::RESOURCE:
{
- switch(CGI->townh->factions[factionIndex]->town->primaryRes)
+ switch((*CGI->townh)[factionIndex]->town->primaryRes)
{
case Res::MERCURY:
return CGI->generaltexth->allTexts[690];
@@ -376,9 +375,9 @@ void OptionsTab::CPlayerOptionTooltipBox::genTownWindow()
pos = Rect(0, 0, 228, 290);
genHeader();
labelAssociatedCreatures = std::make_shared(pos.w / 2 + 8, 122, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[79]);
- auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle;
+ auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
std::vector> components;
- const CTown * town = CGI->townh->factions[factionIndex]->town;
+ const CTown * town = (*CGI->townh)[factionIndex]->town;
for(auto & elem : town->creatures)
{
@@ -393,10 +392,10 @@ void OptionsTab::CPlayerOptionTooltipBox::genHeroWindow()
pos = Rect(0, 0, 292, 226);
genHeader();
labelHeroSpeciality = std::make_shared(pos.w / 2 + 4, 117, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[78]);
- auto heroIndex = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero;
+ auto heroIndex = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
- imageSpeciality = std::make_shared("UN44", CGI->heroh->heroes[heroIndex]->imageIndex, 0, pos.w / 2 - 22, 134);
- labelSpecialityName = std::make_shared(pos.w / 2, 188, FONT_SMALL, CENTER, Colors::WHITE, CGI->heroh->heroes[heroIndex]->specName);
+ imageSpeciality = std::make_shared