1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-15 00:05:02 +02:00

Entities redesign and a few ERM features

* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
This commit is contained in:
AlexVinS
2018-03-17 17:58:30 +03:00
committed by AlexVinS
parent 11bb46780a
commit ecaa9f5d0b
475 changed files with 22491 additions and 7123 deletions

View File

@ -29,7 +29,7 @@ matrix:
env: VCMI_PLATFORM='mxe' MXE_TARGET=i686-w64-mingw32.shared VCMI_CMAKE_FLAGS='-DENABLE_TEST=0' env: VCMI_PLATFORM='mxe' MXE_TARGET=i686-w64-mingw32.shared VCMI_CMAKE_FLAGS='-DENABLE_TEST=0'
sudo: required sudo: required
- os: osx - os: osx
env: VCMI_PLATFORM='mac' env: VCMI_PLATFORM='mac' VCMI_CMAKE_FLAGS='-DENABLE_TEST=0'
addons: addons:
apt: apt:

View File

@ -69,7 +69,7 @@
<Add option="-Wno-overloaded-virtual" /> <Add option="-Wno-overloaded-virtual" />
<Add option="-DBOOST_ALL_DYN_LINK" /> <Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" /> <Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" /> <Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" /> <Add option="-D_WIN32" />
<Add directory="$(#boost.include)" /> <Add directory="$(#boost.include)" />
<Add directory="../../include" /> <Add directory="../../include" />
@ -100,9 +100,6 @@
<Unit filename="common.h" /> <Unit filename="common.h" />
<Unit filename="main.cpp" /> <Unit filename="main.cpp" />
<Extensions> <Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" /> <lib_finder disable_auto="1" />
</Extensions> </Extensions>
</Project> </Project>

View File

@ -10,8 +10,6 @@
#include "StdInc.h" #include "StdInc.h"
#include "BattleAI.h" #include "BattleAI.h"
#include <vstd/RNG.h>
#include "StackWithBonuses.h" #include "StackWithBonuses.h"
#include "EnemyInfo.h" #include "EnemyInfo.h"
#include "../../lib/CStopWatch.h" #include "../../lib/CStopWatch.h"
@ -26,26 +24,6 @@
#define LOGL(text) print(text) #define LOGL(text) print(text)
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl)) #define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
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 enum class SpellTypes
{ {
ADVENTURE, BATTLE, OTHER ADVENTURE, BATTLE, OTHER
@ -53,10 +31,10 @@ enum class SpellTypes
SpellTypes spellType(const CSpell * spell) SpellTypes spellType(const CSpell * spell)
{ {
if(!spell->isCombatSpell() || spell->isCreatureAbility()) if(!spell->isCombat() || spell->isCreatureAbility())
return SpellTypes::OTHER; return SpellTypes::OTHER;
if(spell->isOffensiveSpell() || spell->hasEffects() || spell->hasBattleEffects()) if(spell->isOffensive() || spell->hasEffects() || spell->hasBattleEffects())
return SpellTypes::BATTLE; return SpellTypes::BATTLE;
return SpellTypes::OTHER; return SpellTypes::OTHER;
@ -83,7 +61,9 @@ std::vector<BattleHex> CBattleAI::getBrokenWallMoatHexes() const
} }
CBattleAI::CBattleAI() 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<CBattleCallback> CB) void CBattleAI::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB)
{ {
setCbc(CB); setCbc(CB);
env = ENV;
cb = CB; cb = CB;
playerID = *CB->getPlayerID(); //TODO should be sth in callback playerID = *CB->getPlayerID(); //TODO should be sth in callback
wasWaitingForRealize = cb->waitTillRealize; wasWaitingForRealize = CB->waitTillRealize;
wasUnlockingGs = CB->unlockGsWhenWaiting; wasUnlockingGs = CB->unlockGsWhenWaiting;
CB->waitTillRealize = true; CB->waitTillRealize = true;
CB->unlockGsWhenWaiting = false; CB->unlockGsWhenWaiting = false;
@ -131,7 +112,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
attemptCastingSpell(); attemptCastingSpell();
if(auto ret = getCbc()->battleIsFinished()) if(auto ret = cb->battleIsFinished())
{ {
//spellcast may finish battle //spellcast may finish battle
//send special preudo-action //send special preudo-action
@ -174,7 +155,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
} }
} }
HypotheticBattle hb(getCbc()); HypotheticBattle hb(env.get(), cb);
PotentialTargets targets(stack, &hb); PotentialTargets targets(stack, &hb);
@ -210,7 +191,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
if(stack->waited()) if(stack->waited())
{ {
//ThreatMap threatsToUs(stack); // These lines may be usefull but they are't used in the code. //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()) if(!targets.unreachableEnemies.empty())
{ {
auto closestEnemy = vstd::minElementByFun(targets.unreachableEnemies, [&](const battle::Unit * enemy) -> int auto closestEnemy = vstd::minElementByFun(targets.unreachableEnemies, [&](const battle::Unit * enemy) -> int
@ -330,7 +311,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
if(cb->battleGetGateState() == EGateState::CLOSED) if(cb->battleGetGateState() == EGateState::CLOSED)
{ {
targetHex = cb->wallPartToBattleHex(EWallPart::GATE); targetHex = cb->wallPartToBattleHex(EWallPart::GATE);
} }
else else
{ {
EWallPart::EWallPart wallParts[] = { EWallPart::EWallPart wallParts[] = {
@ -381,9 +362,9 @@ void CBattleAI::attemptCastingSpell()
LOGL("Casting spells sounds like fun. Let's see..."); LOGL("Casting spells sounds like fun. Let's see...");
//Get all spells we can cast //Get all spells we can cast
std::vector<const CSpell*> possibleSpells; std::vector<const CSpell*> 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()); LOGFL("I can cast %d spells.", possibleSpells.size());
@ -398,7 +379,7 @@ void CBattleAI::attemptCastingSpell()
std::vector<PossibleSpellcast> possibleCasts; std::vector<PossibleSpellcast> possibleCasts;
for(auto spell : possibleSpells) 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()) for(auto & target : temp.findPotentialTargets())
{ {
@ -500,8 +481,6 @@ void CBattleAI::attemptCastingSpell()
return ourTurnSpan >= minTurnSpan; return ourTurnSpan >= minTurnSpan;
}; };
RNGStub rngStub;
ValueMap valueOfStack; ValueMap valueOfStack;
ValueMap healthOfStack; ValueMap healthOfStack;
@ -536,7 +515,8 @@ void CBattleAI::attemptCastingSpell()
{ {
bool enemyHadTurn = false; bool enemyHadTurn = false;
HypotheticBattle state(cb); HypotheticBattle state(env.get(), cb);
evaluateQueue(valueOfStack, turnOrder, &state, 0, &enemyHadTurn); evaluateQueue(valueOfStack, turnOrder, &state, 0, &enemyHadTurn);
if(!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<ScriptsCache>)
{
HypotheticBattle state(env.get(), cb);
spells::BattleCast cast(&state, hero, spells::Mode::HERO, ps->spell); spells::BattleCast cast(&state, hero, spells::Mode::HERO, ps->spell);
cast.target = ps->dest; cast.castEval(state.getServerCallback(), ps->dest);
cast.cast(&state, rngStub);
ValueMap newHealthOfStack; ValueMap newHealthOfStack;
ValueMap newValueOfStack; ValueMap newValueOfStack;
@ -617,10 +601,12 @@ void CBattleAI::attemptCastingSpell()
} }
}; };
std::vector<std::function<void()>> tasks; using EvalRunner = ThreadPool<ScriptsCache>;
EvalRunner::Tasks tasks;
for(PossibleSpellcast & psc : possibleCasts) 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(); uint32_t threadCount = boost::thread::hardware_concurrency();
@ -632,8 +618,15 @@ void CBattleAI::attemptCastingSpell()
CStopWatch timer; CStopWatch timer;
CThreadHelper threadHelper(&tasks, threadCount); std::vector<std::shared_ptr<ScriptsCache>> scriptsPool;
threadHelper.run();
for(uint32_t idx = 0; idx < threadCount; idx++)
{
scriptsPool.emplace_back();
}
EvalRunner runner(&tasks, scriptsPool);
runner.run();
LOGFL("Evaluation took %d ms", timer.getDiff()); LOGFL("Evaluation took %d ms", timer.getDiff());
@ -666,8 +659,8 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
using ValueMap = PossibleSpellcast::ValueMap; using ValueMap = PossibleSpellcast::ValueMap;
RNGStub rngStub; RNGStub rngStub;
HypotheticBattle state(getCbc()); HypotheticBattle state(env.get(), cb);
TStacks all = getCbc()->battleGetAllStacks(false); TStacks all = cb->battleGetAllStacks(false);
ValueMap healthOfStack; ValueMap healthOfStack;
ValueMap newHealthOfStack; ValueMap newHealthOfStack;
@ -678,8 +671,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
} }
spells::BattleCast cast(&state, stack, spells::Mode::CREATURE_ACTIVE, ps.spell); spells::BattleCast cast(&state, stack, spells::Mode::CREATURE_ACTIVE, ps.spell);
cast.target = ps.dest; cast.castEval(state.getServerCallback(), ps.dest);
cast.cast(&state, rngStub);
for(auto unit : all) for(auto unit : all)
{ {
@ -710,7 +702,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
} }
ps.value = totalGain; ps.value = totalGain;
}; }
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side) void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
{ {

View File

@ -51,6 +51,7 @@ class CBattleAI : public CBattleGameInterface
{ {
int side; int side;
std::shared_ptr<CBattleCallback> cb; std::shared_ptr<CBattleCallback> cb;
std::shared_ptr<Environment> env;
//Previous setting of cb //Previous setting of cb
bool wasWaitingForRealize, wasUnlockingGs; bool wasWaitingForRealize, wasUnlockingGs;
@ -59,7 +60,7 @@ public:
CBattleAI(); CBattleAI();
~CBattleAI(); ~CBattleAI();
void init(std::shared_ptr<CBattleCallback> CB) override; void init(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
void attemptCastingSpell(); void attemptCastingSpell();
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only 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 actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
//void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero //void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
//void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack //void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
//void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, const std::vector<MetaString> & battleLog) override; //called when stack receives damage (after battleAttack()) //void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) override; //called when stack receives damage (after battleAttack())
//void battleEnd(const BattleResult *br) override; //void battleEnd(const BattleResult *br) override;
//void battleResultsApplied() override; //called when all effects of last battle are applied //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; //void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied;

View File

@ -10,8 +10,9 @@
#pragma once #pragma once
#include <vcmi/spells/Magic.h>
#include "../../lib/battle/Destination.h" #include "../../lib/battle/Destination.h"
#include "../../lib/spells/Magic.h"
class CSpell; class CSpell;

View File

@ -9,8 +9,14 @@
*/ */
#include "StdInc.h" #include "StdInc.h"
#include "StackWithBonuses.h" #include "StackWithBonuses.h"
#include "../../lib/NetPacksBase.h"
#include <vcmi/events/EventBus.h>
#include "../../lib/NetPacks.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/ScriptHandler.h"
using scripting::Pool;
void actualizeEffect(TBonusListPtr target, const Bonus & ef) 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);}); 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 //TODO: evaluate cast use
} }
HypotheticBattle::HypotheticBattle(Subject realBattle) HypotheticBattle::HypotheticBattle(const Environment * ENV, Subject realBattle)
: BattleProxy(realBattle), : BattleProxy(realBattle),
env(ENV),
bonusTreeVersion(1) bonusTreeVersion(1)
{ {
auto activeUnit = realBattle->battleActiveUnit(); auto activeUnit = realBattle->battleActiveUnit();
activeUnitId = activeUnit ? activeUnit->unitId() : -1; 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 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> & bonus) void HypotheticBattle::addUnitBonus(uint32_t id, const std::vector<Bonus> & bonus)
{ {
getForUpdate(id)->addUnitBonus(bonus); getForUpdate(id)->addUnitBonus(bonus);
@ -400,3 +419,107 @@ int64_t HypotheticBattle::getTreeVersion() const
{ {
return getBattleNode()->getTreeVersion() + bonusTreeVersion; 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();
}

View File

@ -8,6 +8,12 @@
* *
*/ */
#pragma once #pragma once
#include <vstd/RNG.h>
#include <vcmi/Environment.h>
#include <vcmi/ServerCallback.h>
#include "../../lib/HeroBonus.h" #include "../../lib/HeroBonus.h"
#include "../../lib/battle/BattleProxy.h" #include "../../lib/battle/BattleProxy.h"
#include "../../lib/battle/CUnitState.h" #include "../../lib/battle/CUnitState.h"
@ -15,10 +21,30 @@
class HypotheticBattle; class HypotheticBattle;
class CStack; 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 class StackWithBonuses : public battle::CUnitState, public virtual IBonusBearer
{ {
public: public:
std::vector<Bonus> bonusesToAdd; std::vector<Bonus> bonusesToAdd;
std::vector<Bonus> bonusesToUpdate; std::vector<Bonus> bonusesToUpdate;
std::set<std::shared_ptr<Bonus>> bonusesToRemove; std::set<std::shared_ptr<Bonus>> bonusesToRemove;
@ -53,7 +79,7 @@ public:
void removeUnitBonus(const CSelector & selector); 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: private:
const IBonusBearer * origBearer; const IBonusBearer * origBearer;
@ -72,7 +98,9 @@ class HypotheticBattle : public BattleProxy, public battle::IUnitEnvironment
public: public:
std::map<uint32_t, std::shared_ptr<StackWithBonuses>> stackStates; std::map<uint32_t, std::shared_ptr<StackWithBonuses>> stackStates;
HypotheticBattle(Subject realBattle); const Environment * env;
HypotheticBattle(const Environment * ENV, Subject realBattle);
bool unitHasAmmoCart(const battle::Unit * unit) const override; bool unitHasAmmoCart(const battle::Unit * unit) const override;
PlayerColor unitEffectiveOwner(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 setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
void moveUnit(uint32_t id, BattleHex destination) override; void moveUnit(uint32_t id, BattleHex destination) override;
void removeUnit(uint32_t id) 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> & bonus) override; void addUnitBonus(uint32_t id, const std::vector<Bonus> & bonus) override;
void updateUnitBonus(uint32_t id, const std::vector<Bonus> & bonus) override; void updateUnitBonus(uint32_t id, const std::vector<Bonus> & bonus) override;
@ -107,8 +136,59 @@ public:
int64_t getTreeVersion() const; int64_t getTreeVersion() const;
scripting::Pool * getContextPool() const override;
ServerCallback * getServerCallback();
private: 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 bonusTreeVersion;
int32_t activeUnitId; int32_t activeUnitId;
mutable uint32_t nextId; mutable uint32_t nextId;
std::unique_ptr<HypotheticServerCallback> serverCallback;
std::unique_ptr<HypotheticEnvironment> localEnvironment;
mutable std::shared_ptr<scripting::Pool> pool;
mutable std::shared_ptr<events::EventBus> eventBus;
}; };

View File

@ -12,12 +12,22 @@
#include "../../lib/CRandomGenerator.h" #include "../../lib/CRandomGenerator.h"
void CEmptyAI::init(std::shared_ptr<CCallback> CB) void CEmptyAI::saveGame(BinarySerializer & h, const int version)
{
}
void CEmptyAI::loadGame(BinaryDeserializer & h, const int version)
{
}
void CEmptyAI::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
{ {
cb = CB; cb = CB;
env = ENV;
human=false; human=false;
playerID = *cb->getMyColor(); playerID = *cb->getMyColor();
} }
void CEmptyAI::yourTurn() void CEmptyAI::yourTurn()
{ {
cb->endTurn(); cb->endTurn();

View File

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

View File

@ -63,7 +63,7 @@
<Add option="-Wno-unused-parameter" /> <Add option="-Wno-unused-parameter" />
<Add option="-Wno-overloaded-virtual" /> <Add option="-Wno-overloaded-virtual" />
<Add option="-fpermissive" /> <Add option="-fpermissive" />
<Add option="-D_WIN32_WINNT=0x0501" /> <Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" /> <Add option="-D_WIN32" />
<Add option="-DBOOST_ALL_DYN_LINK" /> <Add option="-DBOOST_ALL_DYN_LINK" />
<Add directory="$(#boost.include)" /> <Add directory="$(#boost.include)" />
@ -80,9 +80,6 @@
</Unit> </Unit>
<Unit filename="exp_funcs.cpp" /> <Unit filename="exp_funcs.cpp" />
<Extensions> <Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" /> <lib_finder disable_auto="1" />
</Extensions> </Extensions>
</Project> </Project>

View File

@ -18,6 +18,7 @@
<Linker> <Linker>
<Add option="-lboost_system$(#boost.libsuffix32)" /> <Add option="-lboost_system$(#boost.libsuffix32)" />
<Add option="-lVCMI_lib" /> <Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
</Linker> </Linker>
</Target> </Target>
<Target title="Release-win32"> <Target title="Release-win32">
@ -34,6 +35,7 @@
<Add option="-s" /> <Add option="-s" />
<Add option="-lboost_system$(#boost.libsuffix32)" /> <Add option="-lboost_system$(#boost.libsuffix32)" />
<Add option="-lVCMI_lib" /> <Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
</Linker> </Linker>
</Target> </Target>
<Target title="Debug-win64"> <Target title="Debug-win64">
@ -41,10 +43,11 @@
<Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" /> <Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x64" /> <Option object_output="obj/Debug/x64" />
<Option type="3" /> <Option type="3" />
<Option compiler="gcc" /> <Option compiler="gnu_gcc_compiler_x64" />
<Linker> <Linker>
<Add option="-lboost_system$(#boost.libsuffix64)" /> <Add option="-lboost_system$(#boost.libsuffix64)" />
<Add option="-lVCMI_lib" /> <Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib64)" />
</Linker> </Linker>
</Target> </Target>
</Build> </Build>
@ -61,13 +64,12 @@
<Add option="-Wno-overloaded-virtual" /> <Add option="-Wno-overloaded-virtual" />
<Add option="-DBOOST_ALL_DYN_LINK" /> <Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" /> <Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" /> <Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" /> <Add option="-D_WIN32" />
<Add directory="$(#boost.include)" /> <Add directory="$(#boost.include)" />
<Add directory="../../include" /> <Add directory="../../include" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add directory="$(#boost.lib32)" />
<Add directory="../.." /> <Add directory="../.." />
</Linker> </Linker>
<Unit filename="StdInc.h"> <Unit filename="StdInc.h">
@ -77,10 +79,6 @@
<Unit filename="StupidAI.cpp" /> <Unit filename="StupidAI.cpp" />
<Unit filename="StupidAI.h" /> <Unit filename="StupidAI.h" />
<Unit filename="main.cpp" /> <Unit filename="main.cpp" />
<Extensions> <Extensions />
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project> </Project>
</CodeBlocks_project_file> </CodeBlocks_project_file>

View File

@ -28,9 +28,10 @@ CStupidAI::~CStupidAI()
print("destroyed"); print("destroyed");
} }
void CStupidAI::init(std::shared_ptr<CBattleCallback> CB) void CStupidAI::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB)
{ {
print("init called, saving ptr to IBattleCallback"); print("init called, saving ptr to IBattleCallback");
env = ENV;
cbc = cb = CB; cbc = cb = CB;
} }
@ -74,10 +75,12 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
int shooters[2] = {0}; //count of shooters on hexes int shooters[2] = {0}; //count of shooters on hexes
for(int i = 0; i < 2; i++) for(int i = 0; i < 2; i++)
{
for (auto & neighbour : (i ? h2 : h1).neighbouringTiles()) for (auto & neighbour : (i ? h2 : h1).neighbouringTiles())
if(const CStack *s = cbc->battleGetStackByPos(neighbour)) if(const CStack * s = cbc->battleGetStackByPos(neighbour))
if(s->getCreature()->isShooting()) if(s->isShooter())
shooters[i]++; shooters[i]++;
}
return shooters[0] < shooters[1]; return shooters[0] < shooters[1];
} }
@ -173,7 +176,7 @@ void CStupidAI::battleAttack(const BattleAttack *ba)
print("battleAttack called"); print("battleAttack called");
} }
void CStupidAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, const std::vector<MetaString> & battleLog) void CStupidAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
{ {
print("battleStacksAttacked called"); print("battleStacksAttacked called");
} }
@ -293,15 +296,3 @@ BattleAction CStupidAI::goTowards(const CStack * stack, std::vector<BattleHex> 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);
}

View File

@ -18,19 +18,20 @@ class CStupidAI : public CBattleGameInterface
{ {
int side; int side;
std::shared_ptr<CBattleCallback> cb; std::shared_ptr<CBattleCallback> cb;
std::shared_ptr<Environment> env;
void print(const std::string &text) const; void print(const std::string &text) const;
public: public:
CStupidAI(); CStupidAI();
~CStupidAI(); ~CStupidAI();
void init(std::shared_ptr<CBattleCallback> CB) override; void init(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, const std::vector<MetaString> & battleLog) override; //called when stack receives damage (after battleAttack()) void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) override; //called when stack receives damage (after battleAttack())
void battleEnd(const BattleResult *br) override; void battleEnd(const BattleResult *br) override;
//void battleResultsApplied() override; //called when all effects of last battle are applied //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; 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 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 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: private:
BattleAction goTowards(const CStack * stack, std::vector<BattleHex> hexes) const; BattleAction goTowards(const CStack * stack, std::vector<BattleHex> hexes) const;
}; };

View File

@ -279,7 +279,7 @@ creInfo infoFromDC(const dwellingContent & dc)
ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
if (ci.creID != -1) 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. ci.level = ci.cre->level; //this is cretaure tier, while tryRealize expects dwelling level. Ignore.
} }
else else

View File

@ -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 auto obj = ai->myCb->getObj(ObjectInstanceID(g.objid)); //we assume for now that these goals are similar
if(!obj) if(!obj)
{
return -100; //hero died in the meantime return -100; //hero died in the meantime
}
else else
{ {
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).accept(this)); g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).accept(this));

View File

@ -91,7 +91,7 @@ std::string AbstractGoal::name() const //TODO: virtualize
} }
break; break;
case GET_ART_TYPE: 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; break;
case VISIT_TILE: case VISIT_TILE:
desc = "VISIT TILE " + tile.toString(); desc = "VISIT TILE " + tile.toString();

View File

@ -33,16 +33,16 @@ TSubgoal AdventureSpellCast::whatToDoToAchieve()
auto spell = getSpell(); 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()) if(!spell->isAdventure())
throw cannotFulfillGoalException(spell->name + " is not an adventure spell."); throw cannotFulfillGoalException(spell->getName() + " is not an adventure spell.");
if(!hero->canCastThisSpell(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)) 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) if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name); 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 std::string AdventureSpellCast::name() const
{ {
return "AdventureSpellCast " + spellID.toSpell()->name; return "AdventureSpellCast " + getSpell()->getName();
} }
std::string AdventureSpellCast::completeMessage() const std::string AdventureSpellCast::completeMessage() const
{ {
return "Spell casted successfully " + spellID.toSpell()->name; return "Spell cast successfully " + getSpell()->getName();
} }

View File

@ -158,7 +158,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
{ {
for(auto & creatureID : creLevel.second) for(auto & creatureID : creLevel.second)
{ {
auto creature = VLC->creh->creatures[creatureID]; auto creature = VLC->creh->objects[creatureID];
if(ai->ah->freeResources().canAfford(creature->cost)) if(ai->ah->freeResources().canAfford(creature->cost))
objs.push_back(obj); //TODO: reserve resources? objs.push_back(obj); //TODO: reserve resources?
} }

View File

@ -93,7 +93,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
continue; 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 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); auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
@ -129,7 +129,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
{ {
for(auto type : creature.second) 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)); vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
} }
} }

View File

@ -62,7 +62,7 @@ boost::optional<int> 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 //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<const CGHeroInstance*>(obj); auto hero = dynamic_cast<const CGHeroInstance*>(obj);
return getObjectValue(obj->ID, hero->type->heroClass->id); return getObjectValue(obj->ID, hero->type->heroClass->getIndex());
} }
else if(obj->ID == Obj::PRISON) else if(obj->ID == Obj::PRISON)
{ {
@ -77,7 +77,7 @@ boost::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance
{ {
for(auto & creatureID : creLevel.second) for(auto & creatureID : creLevel.second)
{ {
auto creature = VLC->creh->creatures[creatureID]; auto creature = VLC->creh->objects[creatureID];
aiValue += (creature->AIValue * creature->growth); aiValue += (creature->AIValue * creature->growth);
} }
} }

View File

@ -60,7 +60,7 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes)
cb->calculatePaths(config, hero); cb->calculatePaths(config, hero);
}; };
std::vector<Task> calculationTasks; std::vector<CThreadHelper::Task> calculationTasks;
for(HeroPtr hero : heroes) for(HeroPtr hero : heroes)
{ {

View File

@ -78,7 +78,7 @@
<Add option="-Wno-overloaded-virtual" /> <Add option="-Wno-overloaded-virtual" />
<Add option="-DBOOST_ALL_DYN_LINK" /> <Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" /> <Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" /> <Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" /> <Add option="-D_WIN32" />
<Add option="-DFL_CPP11" /> <Add option="-DFL_CPP11" />
<Add directory="$(#boost.include)" /> <Add directory="$(#boost.include)" />
@ -185,9 +185,6 @@
<Unit filename="VCAI.h" /> <Unit filename="VCAI.h" />
<Unit filename="main.cpp" /> <Unit filename="main.cpp" />
<Extensions> <Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" /> <lib_finder disable_auto="1" />
</Extensions> </Extensions>
</Project> </Project>

View File

@ -579,9 +579,10 @@ void VCAI::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
} }
void VCAI::init(std::shared_ptr<CCallback> CB) void VCAI::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
{ {
LOG_TRACE(logAi); LOG_TRACE(logAi);
env = ENV;
myCb = CB; myCb = CB;
cbc = CB; cbc = CB;
@ -1233,7 +1234,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
int count = d->creatures[i].first; int count = d->creatures[i].first;
CreatureID creID = d->creatures[i].second.back(); 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) if(count > 0)
cb->recruitCreatures(d, recruiter, creID, count, i); cb->recruitCreatures(d, recruiter, creID, count, i);
} }

View File

@ -139,7 +139,7 @@ public:
std::string getBattleAIName() const override; std::string getBattleAIName() const override;
void init(std::shared_ptr<CCallback> CB) override; void init(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
void yourTurn() override; void yourTurn() override;
void heroGotLevel(const CGHeroInstance * hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id void heroGotLevel(const CGHeroInstance * hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id

View File

@ -22,7 +22,6 @@
#include "lib/CHeroHandler.h" #include "lib/CHeroHandler.h"
#include "lib/NetPacks.h" #include "lib/NetPacks.h"
#include "client/mapHandler.h" #include "client/mapHandler.h"
#include "lib/spells/CSpellHandler.h"
#include "lib/CArtHandler.h" #include "lib/CArtHandler.h"
#include "lib/GameConstants.h" #include "lib/GameConstants.h"
#include "lib/CPlayerState.h" #include "lib/CPlayerState.h"
@ -328,26 +327,21 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
return swapCreatures(s1, s2, p1, p2); return swapCreatures(s1, s2, p1, p2);
} }
void CCallback::registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
{
cl->additionalPlayerInts[*player].push_back(gameEvents);
}
void CCallback::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents) void CCallback::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
{ {
cl->additionalBattleInts[*player].push_back(battleEvents); cl->additionalBattleInts[*player].push_back(battleEvents);
} }
void CCallback::unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
{
cl->additionalPlayerInts[*player] -= gameEvents;
}
void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents) void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
{ {
cl->additionalBattleInts[*player] -= battleEvents; cl->additionalBattleInts[*player] -= battleEvents;
} }
scripting::Pool * CBattleCallback::getContextPool() const
{
return cl->getGlobalContextPool();
}
CBattleCallback::CBattleCallback(boost::optional<PlayerColor> Player, CClient *C ) CBattleCallback::CBattleCallback(boost::optional<PlayerColor> Player, CClient *C )
{ {
player = Player; player = Player;

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "lib/CGameInfoCallback.h" #include "lib/CGameInfoCallback.h"
#include "lib/battle/CPlayerBattleCallback.h"
#include "lib/int3.h" // for int3 #include "lib/int3.h" // for int3
class CGHeroInstance; 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 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 bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
scripting::Pool * getContextPool() const override;
friend class CCallback; friend class CCallback;
friend class CClient; friend class CClient;
}; };
class CPlayerInterface;
class CCallback : public CPlayerSpecificInfoCallback, public IGameActionCallback, public CBattleCallback class CCallback : public CPlayerSpecificInfoCallback, public IGameActionCallback, public CBattleCallback
{ {
public: public:
@ -111,9 +113,7 @@ public:
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out); 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. //Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
void registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents); void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
void unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents); void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
//commands //commands

View File

@ -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 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 libavformat-dev libswscale-dev
sudo apt-get install -qq qt57declarative sudo apt-get install -qq qt57declarative
sudo apt-get install -qq libluajit-5.1-dev
#setup compiler #setup compiler
source /opt/qt57/bin/qt57-env.sh source /opt/qt57/bin/qt57-env.sh

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
brew update 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 brew install sdl2_mixer
export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH" export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH"

View File

@ -4,17 +4,17 @@
sudo apt-get install -qq nsis ninja-build sudo apt-get install -qq nsis ninja-build
# MXE repository was too slow for Travis far too often # 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 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-$MXE_TARGET-2018-02-10.tar tar -xvf mxe-i686-w64-mingw32.shared-2019-06-28.tar
sudo dpkg -i mxe-*.deb sudo dpkg -i mxe-*.deb
sudo apt-get install -f --yes sudo apt-get install -f --yes
if false; then if false; then
# Add MXE repository and key # 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 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 # Install needed packages
sudo apt-get update -qq sudo apt-get update -qq
@ -30,7 +30,8 @@ mxe-$MXE_TARGET-sdl2-mixer \
mxe-$MXE_TARGET-sdl2-ttf \ mxe-$MXE_TARGET-sdl2-ttf \
mxe-$MXE_TARGET-ffmpeg \ mxe-$MXE_TARGET-ffmpeg \
mxe-$MXE_TARGET-qt \ mxe-$MXE_TARGET-qt \
mxe-$MXE_TARGET-qtbase mxe-$MXE_TARGET-qtbase \
mxe-i686-w64-mingw32.static-luajit
fi # Disable fi # Disable

View File

@ -44,7 +44,8 @@ set(VCMI_VERSION_MAJOR 0)
set(VCMI_VERSION_MINOR 99) set(VCMI_VERSION_MINOR 99)
set(VCMI_VERSION_PATCH 0) 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_LAUNCHER "Enable compilation of launcher" ON)
option(ENABLE_TEST "Enable compilation of unit tests" ON) option(ENABLE_TEST "Enable compilation of unit tests" ON)
option(ENABLE_PCH "Enable compilation using precompiled headers" ON) option(ENABLE_PCH "Enable compilation using precompiled headers" ON)
@ -122,7 +123,6 @@ if(APPLE)
endif(APPLE) endif(APPLE)
if(WIN32) if(WIN32)
add_definitions(-DBOOST_THREAD_USE_LIB)
# Windows Vista or newer for FuzzyLite 6 to compile # Windows Vista or newer for FuzzyLite 6 to compile
add_definitions(-D_WIN32_WINNT=0x0600) add_definitions(-D_WIN32_WINNT=0x0600)
@ -231,6 +231,21 @@ if(ENABLE_LAUNCHER)
find_package(Qt5Network REQUIRED) find_package(Qt5Network REQUIRED)
endif() 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 # # Output directories #
############################################ ############################################
@ -294,6 +309,9 @@ set(SCRIPTING_LIB_DIR "${LIB_DIR}/scripting")
if(ENABLE_ERM) if(ENABLE_ERM)
add_subdirectory(scripting/erm) add_subdirectory(scripting/erm)
endif() endif()
if(ENABLE_LUA)
add_subdirectory(scripting/lua)
endif()
if(NOT MINIZIP_FOUND) if(NOT MINIZIP_FOUND)
add_subdirectory_with_folder("3rdparty" lib/minizip) add_subdirectory_with_folder("3rdparty" lib/minizip)
set(MINIZIP_LIBRARIES minizip) set(MINIZIP_LIBRARIES minizip)
@ -315,6 +333,7 @@ endif()
####################################### #######################################
install(DIRECTORY config DESTINATION ${DATA_DIR}) install(DIRECTORY config DESTINATION ${DATA_DIR})
install(DIRECTORY scripts DESTINATION ${DATA_DIR})
install(DIRECTORY Mods DESTINATION ${DATA_DIR}) install(DIRECTORY Mods DESTINATION ${DATA_DIR})
# that script is useless for Windows # that script is useless for Windows

View File

@ -727,24 +727,6 @@ namespace vstd
} }
using boost::math::round; using boost::math::round;
static std::pair<std::string, std::string> splitStringToPair(std::string input, char separator)
{
std::pair<std::string, std::string> 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::operator-=;
using vstd::make_unique; using vstd::make_unique;

View File

@ -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]]

View File

@ -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!^;

View File

@ -9,8 +9,6 @@
*/ */
#include "StdInc.h" #include "StdInc.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "../lib/CSkillHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/VCMI_Lib.h" #include "../lib/VCMI_Lib.h"
@ -24,13 +22,14 @@ CGameInfo::CGameInfo()
generaltexth = nullptr; generaltexth = nullptr;
mh = nullptr; mh = nullptr;
townh = nullptr; townh = nullptr;
globalServices = nullptr;
} }
void CGameInfo::setFromLib() void CGameInfo::setFromLib()
{ {
globalServices = VLC;
modh = VLC->modh; modh = VLC->modh;
generaltexth = VLC->generaltexth; generaltexth = VLC->generaltexth;
arth = VLC->arth;
creh = VLC->creh; creh = VLC->creh;
townh = VLC->townh; townh = VLC->townh;
heroh = VLC->heroh; heroh = VLC->heroh;
@ -39,3 +38,58 @@ void CGameInfo::setFromLib()
skillh = VLC->skillh; skillh = VLC->skillh;
objtypeh = VLC->objtypeh; 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();
}

View File

@ -9,11 +9,12 @@
*/ */
#pragma once #pragma once
#include <vcmi/Services.h>
#include "../lib/ConstTransitivePtr.h" #include "../lib/ConstTransitivePtr.h"
class CModHandler; class CModHandler;
class CMapHandler; class CMapHandler;
class CArtHandler;
class CHeroHandler; class CHeroHandler;
class CCreatureHandler; class CCreatureHandler;
class CSpellHandler; class CSpellHandler;
@ -48,11 +49,25 @@ extern CClientState * CCS;
/// CGameInfo class /// CGameInfo class
/// for allowing different functions for accessing game informations /// for allowing different functions for accessing game informations
class CGameInfo class CGameInfo : public Services
{ {
public: 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<CModHandler> modh; //public? ConstTransitivePtr<CModHandler> modh; //public?
ConstTransitivePtr<CArtHandler> arth;
ConstTransitivePtr<CHeroHandler> heroh; ConstTransitivePtr<CHeroHandler> heroh;
ConstTransitivePtr<CCreatureHandler> creh; ConstTransitivePtr<CCreatureHandler> creh;
ConstTransitivePtr<CSpellHandler> spellh; ConstTransitivePtr<CSpellHandler> spellh;
@ -65,8 +80,8 @@ public:
void setFromLib(); void setFromLib();
friend class CClient;
CGameInfo(); CGameInfo();
private:
const Services * globalServices;
}; };
extern const CGameInfo* CGI; extern const CGameInfo* CGI;

View File

@ -14,6 +14,8 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <vcmi/scripting/Service.h>
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "mapHandler.h" #include "mapHandler.h"
@ -46,9 +48,9 @@
#include "../lib/NetPacks.h" #include "../lib/NetPacks.h"
#include "CMessage.h" #include "CMessage.h"
#include "../lib/CModHandler.h" #include "../lib/CModHandler.h"
#include "../lib/ScriptHandler.h"
#include "../lib/CTownHandler.h" #include "../lib/CTownHandler.h"
#include "../lib/CArtHandler.h" #include "../lib/CArtHandler.h"
#include "../lib/CScriptingModule.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "../lib/logging/CBasicLogConfigurator.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) *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 *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<SDL_Event> events; std::queue<SDL_Event> SDLEventsQueue;
boost::mutex eventsM; boost::mutex eventsM;
static po::variables_map vm; static po::variables_map vm;
//static bool setResolution = false; //set by event handling thread after resolution is adjusted //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); void processCommand(const std::string &message);
static void setScreenRes(int w, int h, int bpp, bool fullscreen, int displayIndex, bool resetVideo=true); static void setScreenRes(int w, int h, int bpp, bool fullscreen, int displayIndex, bool resetVideo=true);
void playIntro(); void playIntro();
@ -576,29 +577,10 @@ void processCommand(const std::string &message)
// if(LOCPLINT && LOCPLINT->cingconsole) // if(LOCPLINT && LOCPLINT->cingconsole)
// LOCPLINT->cingconsole->print(message); // LOCPLINT->cingconsole->print(message);
if(ermInteractiveMode) if(message==std::string("die, fool"))
{
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"))
{ {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
else if(cn == "erm")
{
ermInteractiveMode = true;
std::cout << "erm>";
}
else if(cn==std::string("activate")) else if(cn==std::string("activate"))
{ {
int what; int what;
@ -725,6 +707,28 @@ void processCommand(const std::string &message)
std::cout << "\rExtracting done :)\n"; std::cout << "\rExtracting done :)\n";
std::cout << " Extracted files can be found in " << outPath << " directory\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") else if(message=="get txt")
{ {
std::cout << "Command accepted.\t"; std::cout << "Command accepted.\t";
@ -891,7 +895,7 @@ void processCommand(const std::string &message)
{ {
YourTurn yt; YourTurn yt;
yt.player = player; yt.player = player;
yt.daysWithoutCastle = CSH->client->getPlayer(player)->daysWithoutCastle; yt.daysWithoutCastle = CSH->client->getPlayerState(player)->daysWithoutCastle;
yt.applyCl(CSH->client); yt.applyCl(CSH->client);
}; };
@ -1360,7 +1364,7 @@ static void handleEvent(SDL_Event & ev)
{ {
boost::unique_lock<boost::mutex> lock(eventsM); boost::unique_lock<boost::mutex> lock(eventsM);
events.push(ev); SDLEventsQueue.push(ev);
} }
} }

View File

@ -13,8 +13,6 @@
#include "CMusicHandler.h" #include "CMusicHandler.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "SDLRWwrapper.h" #include "SDLRWwrapper.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/JsonNode.h" #include "../lib/JsonNode.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/Filesystem.h"

View File

@ -12,7 +12,6 @@
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/CSoundBase.h" #include "../lib/CSoundBase.h"
class CSpell;
struct _Mix_Music; struct _Mix_Music;
struct SDL_RWops; struct SDL_RWops;
typedef struct _Mix_Music Mix_Music; typedef struct _Mix_Music Mix_Music;

View File

@ -8,6 +8,9 @@
* *
*/ */
#include "StdInc.h" #include "StdInc.h"
#include <vcmi/Artifact.h>
#include "windows/CAdvmapInterface.h" #include "windows/CAdvmapInterface.h"
#include "battle/CBattleInterface.h" #include "battle/CBattleInterface.h"
#include "battle/CBattleInterfaceClasses.h" #include "battle/CBattleInterfaceClasses.h"
@ -82,7 +85,7 @@ using namespace CSDL_Ext;
void processCommand(const std::string &message, CClient *&client); void processCommand(const std::string &message, CClient *&client);
extern std::queue<SDL_Event> events; extern std::queue<SDL_Event> SDLEventsQueue;
extern boost::mutex eventsM; extern boost::mutex eventsM;
boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex; boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;
@ -144,9 +147,10 @@ CPlayerInterface::~CPlayerInterface()
if (LOCPLINT == this) if (LOCPLINT == this)
LOCPLINT = nullptr; LOCPLINT = nullptr;
} }
void CPlayerInterface::init(std::shared_ptr<CCallback> CB) void CPlayerInterface::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
{ {
cb = CB; cb = CB;
env = ENV;
initializeHeroTownList(); initializeHeroTownList();
// always recreate advmap interface to avoid possible memory-corruption bugs // 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 //check if user cancelled movement
{ {
boost::unique_lock<boost::mutex> un(eventsM); boost::unique_lock<boost::mutex> un(eventsM);
while(!events.empty()) while(!SDLEventsQueue.empty())
{ {
SDL_Event ev = events.front(); SDL_Event ev = SDLEventsQueue.front();
events.pop(); SDLEventsQueue.pop();
switch(ev.type) switch(ev.type)
{ {
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
@ -692,7 +696,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
if (settings["adventure"]["quickCombat"].Bool()) if (settings["adventure"]["quickCombat"].Bool())
{ {
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String()); 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); autofightingAI->battleStart(army1, army2, int3(0,0,0), hero1, hero2, side);
isAutoFightOn = true; isAutoFightOn = true;
cb->registerBattleInterface(autofightingAI); cb->registerBattleInterface(autofightingAI);
@ -707,7 +711,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
} }
void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects, const std::vector<MetaString> & battleLog) void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -769,7 +773,6 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
} }
battleInt->displayCustomEffects(customEffects); battleInt->displayCustomEffects(customEffects);
battleInt->displayBattleLog(battleLog);
} }
void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles)
@ -919,6 +922,14 @@ void CPlayerInterface::battleEnd(const BattleResult *br)
battleInt->battleFinished(*br); battleInt->battleFinished(*br);
} }
void CPlayerInterface::battleLogMessage(const std::vector<MetaString> & lines)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->displayBattleLog(lines);
}
void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -948,7 +959,7 @@ void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
RETURN_IF_QUICK_COMBAT; RETURN_IF_QUICK_COMBAT;
battleInt->battleTriggerEffect(bte); battleInt->battleTriggerEffect(bte);
} }
void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, const std::vector<MetaString> & battleLog) void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -977,7 +988,7 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
StackAttackedInfo to_put = {defender, elem.damageAmount, elem.killedAmount, attacker, remoteAttack, elem.killed(), elem.willRebirth(), elem.cloneKilled()}; StackAttackedInfo to_put = {defender, elem.damageAmount, elem.killedAmount, attacker, remoteAttack, elem.killed(), elem.willRebirth(), elem.cloneKilled()};
arg.push_back(to_put); arg.push_back(to_put);
} }
battleInt->stacksAreAttacked(arg, battleLog); battleInt->stacksAreAttacked(arg);
} }
void CPlayerInterface::battleAttack(const BattleAttack * ba) 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 * 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 * into a combinational one on an artifact screen. Does not require the combination of
* artifacts to be legal. * 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<bool()> onYes, CFunctionList<bool()> onNo) void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes)
{ {
const CArtifact &artifact = *CGI->arth->artifacts[artifactID]; std::string text = artifact->getDescription();
std::string text = artifact.Description();
text += "\n\n"; text += "\n\n";
std::vector<std::shared_ptr<CComponent>> scs; std::vector<std::shared_ptr<CComponent>> scs;
if(assemble) if(assembledArtifact)
{ {
const CArtifact &assembledArtifact = *CGI->arth->artifacts[assembleTo];
// You possess all of the components to... // 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. // Picture of assembled artifact at bottom.
auto sc = std::make_shared<CComponent>(CComponent::artifact, assembledArtifact.id, 0); auto sc = std::make_shared<CComponent>(CComponent::artifact, assembledArtifact->getIndex(), 0);
//sc->description = assembledArtifact.Description();
//sc->subtitle = assembledArtifact.Name();
scs.push_back(sc); scs.push_back(sc);
} }
else else
@ -1455,7 +1457,7 @@ void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembl
text += CGI->generaltexth->allTexts[733]; text += CGI->generaltexth->allTexts[733];
} }
showYesNoDialog(text, onYes, onNo, scs); showYesNoDialog(text, onYes, nullptr, scs);
} }
void CPlayerInterface::requestRealized( PackageApplied *pa ) void CPlayerInterface::requestRealized( PackageApplied *pa )
@ -2236,13 +2238,13 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK) if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
eraseCurrentPathOf(caster, false); eraseCurrentPathOf(caster, false);
const CSpell * spell = CGI->spellh->objects.at(spellID); const spells::Spell * spell = CGI->spells()->getByIndex(spellID);
if(spellID == SpellID::VIEW_EARTH) if(spellID == SpellID::VIEW_EARTH)
{ {
//TODO: implement on server side //TODO: implement on server side
int level = caster->getSpellSchoolLevel(spell); const auto level = caster->getSpellSchoolLevel(spell);
adventureInt->worldViewOptions.showAllTerrain = (level>2); adventureInt->worldViewOptions.showAllTerrain = (level > 2);
} }
auto castSoundPath = spell->getCastSound(); auto castSoundPath = spell->getCastSound();
@ -2360,7 +2362,7 @@ void CPlayerInterface::acceptTurn()
components.push_back(Component(Component::FLAG, playerColor.getNum(), 0, 0)); components.push_back(Component(Component::FLAG, playerColor.getNum(), 0, 0));
MetaString text; MetaString text;
const auto & optDaysWithoutCastle = cb->getPlayer(playerColor)->daysWithoutCastle; const auto & optDaysWithoutCastle = cb->getPlayerState(playerColor)->daysWithoutCastle;
if(optDaysWithoutCastle) if(optDaysWithoutCastle)
{ {
@ -2646,9 +2648,9 @@ bool CPlayerInterface::capturedAllEvents()
if (ignoreEvents) if (ignoreEvents)
{ {
boost::unique_lock<boost::mutex> un(eventsM); boost::unique_lock<boost::mutex> un(eventsM);
while(!events.empty()) while(!SDLEventsQueue.empty())
{ {
events.pop(); SDLEventsQueue.pop();
} }
return true; return true;
} }

View File

@ -19,6 +19,8 @@
#define sprintf_s snprintf #define sprintf_s snprintf
#endif #endif
class Artifact;
class CButton; class CButton;
class CToggleGroup; class CToggleGroup;
struct TryMoveHero; struct TryMoveHero;
@ -62,7 +64,9 @@ namespace boost
class CPlayerInterface : public CGameInterface, public IUpdateable class CPlayerInterface : public CGameInterface, public IUpdateable
{ {
const CArmedInstance * currentSelection; const CArmedInstance * currentSelection;
public: public:
std::shared_ptr<Environment> env;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos; int3 destinationTeleportPos;
@ -183,21 +187,22 @@ public:
void battleEnd(const BattleResult *br) override; //end of battle 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 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 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<MetaString> & lines) override;
void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) override; void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) override;
void battleSpellCast(const BattleSpellCast *sc) override; void battleSpellCast(const BattleSpellCast *sc) override;
void battleStacksEffectsSet(const SetStackEffect & sse) override; //called when a specific effect is set to stacks 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 battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, const std::vector<MetaString> & battleLog) override; void battleStacksAttacked(const std::vector<BattleStackAttacked> & 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 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 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<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects, const std::vector<MetaString> & battleLog) override; void battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects) override;
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override; void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override;
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
void battleGateStateChanged(const EGateState state) override; void battleGateStateChanged(const EGateState state) override;
void yourTacticPhase(int distance) override; void yourTacticPhase(int distance) override;
//-------------// //-------------//
void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<bool()> onYes, CFunctionList<bool()> onNo); void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes);
void garrisonsChanged(std::vector<const CGObjectInstance *> objs); void garrisonsChanged(std::vector<const CGObjectInstance *> objs);
void garrisonChanged(const CGObjectInstance * obj); void garrisonChanged(const CGObjectInstance * obj);
void heroKilled(const CGHeroInstance* hero); void heroKilled(const CGHeroInstance* hero);
@ -210,7 +215,7 @@ public:
void openTownWindow(const CGTownInstance * town); //shows townscreen void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
void updateInfo(const CGObjectInstance * specific); void updateInfo(const CGObjectInstance * specific);
void init(std::shared_ptr<CCallback> CB) override; void init(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
void activateForSpectator(); // TODO: spectator probably need own player interface class void activateForSpectator(); // TODO: spectator probably need own player interface class

View File

@ -45,6 +45,8 @@
#include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_generators.hpp>
#include "../lib/serializer/Cast.h" #include "../lib/serializer/Cast.h"
#include <vcmi/events/EventBus.h>
template<typename T> class CApplyOnLobby; template<typename T> class CApplyOnLobby;
#ifdef VCMI_ANDROID #ifdef VCMI_ANDROID

View File

@ -44,11 +44,12 @@
#include "lobby/CBonusSelection.h" #include "lobby/CBonusSelection.h"
#include "battle/CBattleInterface.h" #include "battle/CBattleInterface.h"
#include "../lib/CThreadHelper.h" #include "../lib/CThreadHelper.h"
#include "../lib/CScriptingModule.h"
#include "../lib/registerTypes/RegisterTypes.h" #include "../lib/registerTypes/RegisterTypes.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "CMT.h" #include "CMT.h"
#include "CServerHandler.h" #include "CServerHandler.h"
#include "../lib/ScriptHandler.h"
#include <vcmi/events/EventBus.h>
#ifdef VCMI_ANDROID #ifdef VCMI_ANDROID
#include "lib/CAndroidVMHelper.h" #include "lib/CAndroidVMHelper.h"
@ -105,6 +106,39 @@ public:
} }
}; };
CPlayerEnvironment::CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr<CCallback> 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() CClient::CClient()
{ {
@ -114,7 +148,36 @@ CClient::CClient()
registerTypesClientPacks2(*applier); registerTypesClientPacks2(*applier);
IObjectInterface::cb = this; IObjectInterface::cb = this;
gs = nullptr; 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() void CClient::newGame()
@ -122,11 +185,14 @@ void CClient::newGame()
CSH->th->update(); CSH->th->update();
CMapService mapService; CMapService mapService;
gs = new CGameState(); gs = new CGameState();
gs->preInit(VLC);
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff()); logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool()); gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff()); logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
initMapHandler(); initMapHandler();
reinitScripting();
initPlayerEnvironments();
initPlayerInterfaces(); initPlayerInterfaces();
} }
@ -168,10 +234,16 @@ void CClient::loadGame()
throw; //obviously we cannot continue here throw; //obviously we cannot continue here
} }
logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff()); logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff());
gs->preInit(VLC);
gs->updateOnLoad(CSH->si.get()); gs->updateOnLoad(CSH->si.get());
initMapHandler(); initMapHandler();
reinitScripting();
initPlayerEnvironments();
serialize(loader->serializer, loader->serializer.fileVersion); serialize(loader->serializer, loader->serializer.fileVersion);
initPlayerInterfaces(); initPlayerInterfaces();
} }
@ -190,6 +262,13 @@ void CClient::serialize(BinarySerializer & h, const int version)
h & i->second->human; h & i->second->human;
i->second->saveGame(h, version); 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) void CClient::serialize(BinaryDeserializer & h, const int version)
@ -253,6 +332,17 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
} }
nInt.reset(); 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()); 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() void CClient::endGame()
{ {
clientScripts.reset();
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads) //suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
for(auto & i : playerint) for(auto & i : playerint)
i.second->finish(); i.second->finish();
@ -296,8 +388,8 @@ void CClient::endGame()
playerint.clear(); playerint.clear();
battleints.clear(); battleints.clear();
callbacks.clear();
battleCallbacks.clear(); battleCallbacks.clear();
playerEnvironments.clear();
logNetwork->info("Deleted playerInts."); logNetwork->info("Deleted playerInts.");
logNetwork->info("Client stopped."); logNetwork->info("Client stopped.");
} }
@ -319,6 +411,24 @@ void CClient::initMapHandler()
pathCache.clear(); 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<CPlayerEnvironment>(color, this, std::make_shared<CCallback>(gs, color, this));
}
if(settings["session"]["spectate"].Bool())
{
playerEnvironments[PlayerColor::SPECTATOR] = std::make_shared<CPlayerEnvironment>(PlayerColor::SPECTATOR, this, std::make_shared<CCallback>(gs, boost::none, this));
}
}
void CClient::initPlayerInterfaces() void CClient::initPlayerInterfaces()
{ {
for(auto & elem : gs->scenarioOps->playerInfos) for(auto & elem : gs->scenarioOps->playerInfos)
@ -327,21 +437,22 @@ void CClient::initPlayerInterfaces()
if(!vstd::contains(CSH->getAllClientPlayers(CSH->c->connectionID), color)) if(!vstd::contains(CSH->getAllClientPlayers(CSH->c->connectionID), color))
continue; continue;
if(vstd::contains(playerint, color)) if(!vstd::contains(playerint, color))
continue; {
logNetwork->info("Preparing interface for player %s", color.getStr());
logNetwork->trace("Preparing interface for player %s", color.getStr());
if(elem.second.isControlledByAI()) if(elem.second.isControlledByAI())
{ {
auto AiToGive = aiNameForPlayer(elem.second, false); auto AiToGive = aiNameForPlayer(elem.second, false);
logNetwork->info("Player %s will be lead by %s", color, AiToGive); logNetwork->info("Player %s will be lead by %s", color.getStr(), AiToGive);
installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color); installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
} }
else else
{ {
logNetwork->info("Player %s will be lead by human", color.getStr());
installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color); installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
} }
} }
}
if(settings["session"]["spectate"].Bool()) if(settings["session"]["spectate"].Bool())
{ {
@ -379,41 +490,32 @@ std::string CClient::aiNameForPlayer(bool battleAI)
return goodAI; return goodAI;
} }
void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color, bool battlecb) void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, PlayerColor color, bool battlecb)
{ {
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color) playerint[color] = gameInterface;
privilegedGameEventReceivers.push_back(gameInterface);
playerint[colorUsed] = gameInterface; logGlobal->trace("\tInitializing the interface for player %s", color.getStr());
logGlobal->trace("\tInitializing the interface for player %s", colorUsed);
auto cb = std::make_shared<CCallback>(gs, color, this); auto cb = std::make_shared<CCallback>(gs, color, this);
callbacks[colorUsed] = cb; battleCallbacks[color] = cb;
battleCallbacks[colorUsed] = cb; gameInterface->init(playerEnvironments.at(color), cb);
gameInterface->init(cb);
installNewBattleInterface(gameInterface, color, battlecb); installNewBattleInterface(gameInterface, color, battlecb);
} }
void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback) void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, PlayerColor color, bool needCallback)
{ {
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color) battleints[color] = battleInterface;
privilegedBattleEventReceivers.push_back(battleInterface);
battleints[colorUsed] = battleInterface;
if(needCallback) 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<CBattleCallback>(color, this); auto cbc = std::make_shared<CBattleCallback>(color, this);
battleCallbacks[colorUsed] = cbc; battleCallbacks[color] = cbc;
battleInterface->init(cbc); battleInterface->init(playerEnvironments.at(color), cbc);
} }
} }
@ -437,14 +539,6 @@ void CClient::handlePack(CPack * pack)
delete 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) int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
{ {
static ui32 requestCounter = 0; static ui32 requestCounter = 0;
@ -464,6 +558,7 @@ int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
void CClient::battleStarted(const BattleInfo * info) void CClient::battleStarted(const BattleInfo * info)
{ {
setBattle(info);
for(auto & battleCb : battleCallbacks) for(auto & battleCb : battleCallbacks)
{ {
if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; }) 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); battleCb.second->setBattle(info);
} }
} }
// for(ui8 side : info->sides)
// if(battleCallbacks.count(side))
// battleCallbacks[side]->setBattle(info);
std::shared_ptr<CPlayerInterface> att, def; std::shared_ptr<CPlayerInterface> att, def;
auto & leftSide = info->sides[0], & rightSide = info->sides[1]; 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()) if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
battleCallbacks[PlayerColor::SPECTATOR]->setBattle(nullptr); battleCallbacks[PlayerColor::SPECTATOR]->setBattle(nullptr);
setBattle(nullptr);
} }
void CClient::startPlayerBattleAction(PlayerColor color) void CClient::startPlayerBattleAction(PlayerColor color)
@ -645,6 +739,23 @@ PlayerColor CClient::getLocalPlayer() const
return getCurrentPlayer(); return getCurrentPlayer();
} }
scripting::Pool * CClient::getGlobalContextPool() const
{
return clientScripts.get();
}
scripting::Pool * CClient::getContextPool() const
{
return clientScripts.get();
}
void CClient::reinitScripting()
{
clientEventBus = make_unique<events::EventBus>();
clientScripts.reset(new scripting::PoolImpl(this));
}
#ifdef VCMI_ANDROID #ifdef VCMI_ANDROID
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls) extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls)
{ {

View File

@ -9,8 +9,11 @@
*/ */
#pragma once #pragma once
#include <vcmi/Environment.h>
#include "../lib/IGameCallback.h" #include "../lib/IGameCallback.h"
#include "../lib/battle/BattleAction.h" #include "../lib/battle/BattleAction.h"
#include "../lib/battle/CBattleInfoCallback.h"
#include "../lib/CStopWatch.h" #include "../lib/CStopWatch.h"
#include "../lib/int3.h" #include "../lib/int3.h"
#include "../lib/CondSh.h" #include "../lib/CondSh.h"
@ -28,7 +31,6 @@ class CGameInterface;
class CCallback; class CCallback;
class BattleAction; class BattleAction;
class CClient; class CClient;
class CScriptingModule;
struct CPathsInfo; struct CPathsInfo;
class BinaryDeserializer; class BinaryDeserializer;
class BinarySerializer; class BinarySerializer;
@ -37,6 +39,16 @@ namespace boost { class thread; }
template<typename T> class CApplier; template<typename T> class CApplier;
class CBaseForCLApply; class CBaseForCLApply;
namespace scripting
{
class PoolImpl;
}
namespace events
{
class EventBus;
}
template<typename T> template<typename T>
class ThreadSafeVector class ThreadSafeVector
{ {
@ -95,32 +107,40 @@ public:
} }
}; };
/// Class which handles client - server logic class CPlayerEnvironment : public Environment
class CClient : public IGameCallback {
public:
PlayerColor player;
CClient * cl;
std::shared_ptr<CCallback> mainCallback;
CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr<CCallback> 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<CApplier<CBaseForCLApply>> applier;
mutable boost::mutex pathCacheMutex;
std::map<const CGHeroInstance *, std::shared_ptr<CPathsInfo>> pathCache;
std::map<PlayerColor, std::shared_ptr<boost::thread>> playerActionThreads;
void waitForMoveAndSend(PlayerColor color);
public: public:
std::map<PlayerColor, std::shared_ptr<CCallback>> callbacks; //callbacks given to player interfaces
std::map<PlayerColor, std::shared_ptr<CBattleCallback>> battleCallbacks; //callbacks given to player interfaces
std::vector<std::shared_ptr<IGameEventsReceiver>> privilegedGameEventReceivers; //scripting modules, spectator interfaces
std::vector<std::shared_ptr<IBattleEventsReceiver>> privilegedBattleEventReceivers; //scripting modules, spectator interfaces
std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint; std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint;
std::map<PlayerColor, std::shared_ptr<CBattleGameInterface>> battleints; std::map<PlayerColor, std::shared_ptr<CBattleGameInterface>> battleints;
std::map<PlayerColor, std::vector<std::shared_ptr<IGameEventsReceiver>>> additionalPlayerInts;
std::map<PlayerColor, std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts; std::map<PlayerColor, std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
boost::optional<BattleAction> curbaction; boost::optional<BattleAction> curbaction;
CScriptingModule * erm;
CClient(); 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 newGame();
void loadGame(); void loadGame();
@ -131,17 +151,16 @@ public:
void endGame(); void endGame();
void initMapHandler(); void initMapHandler();
void initPlayerEnvironments();
void initPlayerInterfaces(); void initPlayerInterfaces();
std::string aiNameForPlayer(const PlayerSettings & ps, bool battleAI); //empty means no AI -> human std::string aiNameForPlayer(const PlayerSettings & ps, bool battleAI); //empty means no AI -> human
std::string aiNameForPlayer(bool battleAI); std::string aiNameForPlayer(bool battleAI);
void installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color, bool battlecb = false); void installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, PlayerColor color, bool battlecb = false);
void installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true); void installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, PlayerColor color, bool needCallback = true);
static ThreadSafeVector<int> waitingRequest; //FIXME: make this normal field (need to join all threads before client destruction) static ThreadSafeVector<int> 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 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 int sendRequest(const CPackForServer * request, PlayerColor player); //returns ID given to that request
void battleStarted(const BattleInfo * info); void battleStarted(const BattleInfo * info);
@ -160,7 +179,6 @@ public:
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {}; void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {};
bool removeObject(const CGObjectInstance * obj) override {return false;}; bool removeObject(const CGObjectInstance * obj) override {return false;};
void setBlockVis(ObjectInstanceID objid, bool bv) override {};
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs = false) 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 {}; 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 putArtifact(const ArtifactLocation & al, const CArtifactInstance * a) override {};
void removeArtifact(const ArtifactLocation & al) override {}; void removeArtifact(const ArtifactLocation & al) override {};
bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}; bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;};
void synchronizeArtifactHandlerLists() override {};
void showCompInfo(ShowInInfobox * comp) override {}; void showCompInfo(ShowInInfobox * comp) override {};
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) 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 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, 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 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;}; bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;};
void giveHeroBonus(GiveBonus * bonus) override {}; void giveHeroBonus(GiveBonus * bonus) override {};
void setMovePoints(SetMovePoints * smp) override {}; void setMovePoints(SetMovePoints * smp) override {};
@ -211,4 +227,28 @@ public:
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {} void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
void changeFogOfWar(std::unordered_set<int3, ShashInt3> & tiles, PlayerColor player, bool hide) override {} void changeFogOfWar(std::unordered_set<int3, ShashInt3> & 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<PlayerColor, std::shared_ptr<CBattleCallback>> battleCallbacks; //callbacks given to player interfaces
std::map<PlayerColor, std::shared_ptr<CPlayerEnvironment>> playerEnvironments;
std::shared_ptr<scripting::PoolImpl> clientScripts;
std::unique_ptr<events::EventBus> clientEventBus;
std::shared_ptr<CApplier<CBaseForCLApply>> applier;
mutable boost::mutex pathCacheMutex;
std::map<const CGHeroInstance *, std::shared_ptr<CPathsInfo>> pathCache;
std::map<PlayerColor, std::shared_ptr<boost::thread>> playerActionThreads;
void waitForMoveAndSend(PlayerColor color);
void reinitScripting();
}; };

View File

@ -10,6 +10,14 @@
#include "StdInc.h" #include "StdInc.h"
#include "Graphics.h" #include "Graphics.h"
#include <vcmi/Entity.h>
#include <vcmi/ArtifactService.h>
#include <vcmi/CreatureService.h>
#include <vcmi/FactionService.h>
#include <vcmi/HeroTypeService.h>
#include <vcmi/SkillService.h>
#include <vcmi/spells/Service.h>
#include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CBinaryReader.h" #include "../lib/filesystem/CBinaryReader.h"
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
@ -19,19 +27,15 @@
#include "CGameInfo.h" #include "CGameInfo.h"
#include "../lib/VCMI_Lib.h" #include "../lib/VCMI_Lib.h"
#include "../CCallback.h" #include "../CCallback.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CGeneralTextHandler.h" #include "../lib/CGeneralTextHandler.h"
#include "../lib/CCreatureHandler.h"
#include "CBitmapHandler.h" #include "CBitmapHandler.h"
#include "../lib/CSkillHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/CGameState.h" #include "../lib/CGameState.h"
#include "../lib/JsonNode.h" #include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h" #include "../lib/vcmi_endian.h"
#include "../lib/CStopWatch.h" #include "../lib/CStopWatch.h"
#include "../lib/mapObjects/CObjectClassesHandler.h" #include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/mapObjects/CObjectHandler.h" #include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/CHeroHandler.h"
using namespace CSDL_Ext; using namespace CSDL_Ext;
@ -163,9 +167,9 @@ void Graphics::load()
void Graphics::loadHeroAnimations() 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)) if (!heroAnimations.count(templ.animationFile))
heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile); heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile);
@ -423,74 +427,36 @@ void Graphics::loadErmuToPicture()
assert (etp_idx == 44); 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()) if (!imageName.empty())
{ {
JsonNode entry; JsonNode entry;
entry["frame"].Float() = static_cast<double>(index); entry["frame"].Integer() = index;
entry["file"].String() = imageName; entry["file"].String() = imageName;
imageLists["SPRITES/" + listName]["images"].Vector().push_back(entry); 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() void Graphics::initializeImageLists()
{ {
for(const CCreature * creature : CGI->creh->creatures) addImageListEntries(CGI->creatures());
{ addImageListEntries(CGI->heroTypes());
addImageListEntry(creature->iconIndex, "CPRSMALL", creature->smallIconName); addImageListEntries(CGI->artifacts());
addImageListEntry(creature->iconIndex, "TWCRPORT", creature->largeIconName); addImageListEntries(CGI->factions());
} addImageListEntries(CGI->spells());
addImageListEntries(CGI->skills());
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);
}
}
} }

View File

@ -23,6 +23,7 @@ struct InfoAboutTown;
class CGObjectInstance; class CGObjectInstance;
class ObjectTemplate; class ObjectTemplate;
class CAnimation; class CAnimation;
class EntityService;
enum EFonts enum EFonts
{ {
@ -32,7 +33,9 @@ enum EFonts
/// Handles fonts, hero images, town images, various graphics /// Handles fonts, hero images, town images, various graphics
class 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 initializeBattleGraphics();
void loadPaletteAndColors(); void loadPaletteAndColors();

View File

@ -45,12 +45,6 @@
// TODO: as Tow suggested these template should all be part of CClient // TODO: as Tow suggested these template should all be part of CClient
// This will require rework spectator interface properly though // This will require rework spectator interface properly though
template<typename T, typename ... Args, typename ... Args2>
void callPrivilegedInterfaces(CClient * cl, void (T::*ptr)(Args...), Args2 && ...args)
{
for(auto &ger : cl->privilegedGameEventReceivers)
((*ger).*ptr)(std::forward<Args2>(args)...);
}
template<typename T, typename ... Args, typename ... Args2> template<typename T, typename ... Args, typename ... Args2>
bool callOnlyThatInterface(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args) bool callOnlyThatInterface(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
@ -67,7 +61,6 @@ template<typename T, typename ... Args, typename ... Args2>
bool callInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args) bool callInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
{ {
bool called = callOnlyThatInterface(cl, player, ptr, std::forward<Args2>(args)...); bool called = callOnlyThatInterface(cl, player, ptr, std::forward<Args2>(args)...);
callPrivilegedInterfaces(cl, ptr, std::forward<Args2>(args)...);
return called; return called;
} }
@ -84,18 +77,10 @@ void callOnlyThatBattleInterface(CClient * cl, PlayerColor player, void (T::*ptr
} }
} }
template<typename T, typename ... Args, typename ... Args2>
void callPrivilegedBattleInterfaces(CClient * cl, void (T::*ptr)(Args...), Args2 && ...args)
{
for(auto & ber : cl->privilegedBattleEventReceivers)
((*ber).*ptr)(std::forward<Args2>(args)...);
}
template<typename T, typename ... Args, typename ... Args2> template<typename T, typename ... Args, typename ... Args2>
void callBattleInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args) void callBattleInterfaceIfPresent(CClient * cl, PlayerColor player, void (T::*ptr)(Args...), Args2 && ...args)
{ {
callOnlyThatInterface(cl, player, ptr, std::forward<Args2>(args)...); callOnlyThatInterface(cl, player, ptr, std::forward<Args2>(args)...);
callPrivilegedBattleInterfaces(cl, ptr, std::forward<Args2>(args)...);
} }
//calls all normal interfaces and privileged ones, playerints may be updated when iterating over it, so we need a copy //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<Args2>(args)...); callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward<Args2>(args)...);
} }
callPrivilegedBattleInterfaces(cl, ptr, std::forward<Args2>(args)...);
} }
void SetResources::applyCl(CClient *cl) void SetResources::applyCl(CClient *cl)
{ {
//todo: inform on actual resource set transfered //todo: inform on actual resource set transfered
@ -307,7 +290,7 @@ void GiveBonus::applyCl(CClient *cl)
break; break;
case PLAYER: 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); callInterfaceIfPresent(cl, PlayerColor(id), &IGameEventsReceiver::playerBonusChanged, *p->getBonusList().back(), true);
} }
break; break;
@ -351,7 +334,7 @@ void RemoveBonus::applyCl(CClient *cl)
break; break;
case PLAYER: case PLAYER:
{ {
//const PlayerState *p = GS(cl)->getPlayer(id); //const PlayerState *p = GS(cl)->getPlayerState(id);
callInterfaceIfPresent(cl, PlayerColor(id), &IGameEventsReceiver::playerBonusChanged, bonus, false); callInterfaceIfPresent(cl, PlayerColor(id), &IGameEventsReceiver::playerBonusChanged, bonus, false);
} }
break; 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 //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 //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); 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 //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++) 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 && (GS(cl)->isVisible(start - int3(1, 0, 0), i->first) || GS(cl)->isVisible(end - int3(1, 0, 0), i->first)))
{ {
if(ps->human) if(ps->human)
@ -611,8 +594,6 @@ void BattleStart::applyFirstCl(CClient *cl)
info->tile, info->sides[0].hero, info->sides[1].hero); info->tile, info->sides[0].hero, info->sides[1].hero);
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, info->sides[0].armyObject, info->sides[1].armyObject, callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, info->sides[0].armyObject, info->sides[1].armyObject,
info->tile, info->sides[0].hero, info->sides[1].hero); 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) void BattleStart::applyCl(CClient *cl)
@ -651,6 +632,11 @@ void BattleSetActiveStack::applyCl(CClient *cl)
cl->startPlayerBattleAction(playerToCall); cl->startPlayerBattleAction(playerToCall);
} }
void BattleLogMessage::applyCl(CClient * cl)
{
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleLogMessage, lines);
}
void BattleTriggerEffect::applyCl(CClient * cl) void BattleTriggerEffect::applyCl(CClient * cl)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleTriggerEffect, *this); callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleTriggerEffect, *this);
@ -680,7 +666,7 @@ void BattleAttack::applyFirstCl(CClient *cl)
void BattleAttack::applyCl(CClient *cl) void BattleAttack::applyCl(CClient *cl)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, bsa, battleLog); callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, bsa);
} }
void StartAction::applyFirstCl(CClient *cl) void StartAction::applyFirstCl(CClient *cl)
@ -702,7 +688,7 @@ void SetStackEffect::applyCl(CClient *cl)
void StacksInjured::applyCl(CClient *cl) void StacksInjured::applyCl(CClient *cl)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, stacks, battleLog); callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, stacks);
} }
void BattleResultsApplied::applyCl(CClient *cl) void BattleResultsApplied::applyCl(CClient *cl)
@ -714,7 +700,7 @@ void BattleResultsApplied::applyCl(CClient *cl)
void BattleUnitsChanged::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) void BattleObstaclesChanged::applyCl(CClient *cl)
@ -795,7 +781,7 @@ void PlayerMessageClient::applyCl(CClient *cl)
if(player.isSpectator()) if(player.isSpectator())
str << "Spectator: " << text; str << "Spectator: " << text;
else else
str << cl->getPlayer(player)->nodeName() <<": " << text; str << cl->getPlayerState(player)->nodeName() <<": " << text;
if(LOCPLINT) if(LOCPLINT)
LOCPLINT->cingconsole->print(str.str()); 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); callInterfaceIfPresent(cl, cl->getTile(bm->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::availableArtifactsChanged, bm);
} }
} }
void EntitiesChanged::applyCl(CClient *cl)
{
cl->invalidatePaths();
}

View File

@ -4,6 +4,7 @@
<Project> <Project>
<Option title="VCMI_client" /> <Option title="VCMI_client" />
<Option pch_mode="2" /> <Option pch_mode="2" />
<Option default_target="Debug-win64" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Build> <Build>
<Target title="Debug-win32"> <Target title="Debug-win32">
@ -13,7 +14,6 @@
<Option object_output="../obj/Client/Debug/x86" /> <Option object_output="../obj/Client/Debug/x86" />
<Option type="1" /> <Option type="1" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option parameters="--testmap=Maps/Reclamation --spectate --spectate-skip-battle --spectate-ignore-hero" />
<Compiler> <Compiler>
<Add option="-Og" /> <Add option="-Og" />
<Add option="-g" /> <Add option="-g" />
@ -91,7 +91,7 @@
<Add option="-isystem $(#boost.include)" /> <Add option="-isystem $(#boost.include)" />
<Add option="-DBOOST_ALL_DYN_LINK" /> <Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" /> <Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" /> <Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" /> <Add option="-D_WIN32" />
<Add option="-DBOOST_UUID_RANDOM_PROVIDER_FORCE_WINCRYPT" /> <Add option="-DBOOST_UUID_RANDOM_PROVIDER_FORCE_WINCRYPT" />
<Add directory="../client" /> <Add directory="../client" />
@ -246,10 +246,6 @@
<Unit filename="windows/QuickRecruitmentWindow.cpp" /> <Unit filename="windows/QuickRecruitmentWindow.cpp" />
<Unit filename="windows/QuickRecruitmentWindow.h" /> <Unit filename="windows/QuickRecruitmentWindow.h" />
<Extensions> <Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
<DoxyBlocks> <DoxyBlocks>
<comment_style block="0" line="0" /> <comment_style block="0" line="0" />
<doxyfile_project /> <doxyfile_project />
@ -259,6 +255,7 @@
<doxyfile_dot /> <doxyfile_dot />
<general /> <general />
</DoxyBlocks> </DoxyBlocks>
<lib_finder disable_auto="1" />
</Extensions> </Extensions>
</Project> </Project>
</CodeBlocks_project_file> </CodeBlocks_project_file>

View File

@ -29,7 +29,6 @@
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/CTownHandler.h" #include "../../lib/CTownHandler.h"
#include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/spells/CSpellHandler.h"
CBattleAnimation::CBattleAnimation(CBattleInterface * _owner) CBattleAnimation::CBattleAnimation(CBattleInterface * _owner)
: owner(_owner), ID(_owner->animIDhelper++) : owner(_owner), ID(_owner->animIDhelper++)
@ -762,7 +761,7 @@ bool CShootingAnimation::init()
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS) if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
{ {
int creID = owner->siegeH->town->town->clientInfo.siegeShooter; int creID = owner->siegeH->town->town->clientInfo.siegeShooter;
shooterInfo = CGI->creh->creatures[creID]; shooterInfo = CGI->creh->operator[](creID);
} }
if(!shooterInfo->animation.missleFrameAngles.size()) 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..." 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..."
@ -770,7 +769,7 @@ bool CShootingAnimation::init()
auto & angles = shooterInfo->animation.missleFrameAngles.size() auto & angles = shooterInfo->animation.missleFrameAngles.size()
? shooterInfo->animation.missleFrameAngles ? shooterInfo->animation.missleFrameAngles
: CGI->creh->creatures[CreatureID::ARCHER]->animation.missleFrameAngles; : CGI->creh->operator[](CreatureID::ARCHER)->animation.missleFrameAngles;
ProjectileInfo spi; ProjectileInfo spi;
spi.shotDone = false; spi.shotDone = false;

View File

@ -38,6 +38,8 @@
#include "../../lib/CondSh.h" #include "../../lib/CondSh.h"
#include "../../lib/CRandomGenerator.h" #include "../../lib/CRandomGenerator.h"
#include "../../lib/spells/CSpellHandler.h" #include "../../lib/spells/CSpellHandler.h"
#include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/spells/Problem.h"
#include "../../lib/CTownHandler.h" #include "../../lib/CTownHandler.h"
#include "../../lib/CGameState.h" #include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h" #include "../../lib/mapping/CMap.h"
@ -398,7 +400,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
for(auto hex : bfield) for(auto hex : bfield)
addChild(hex.get()); addChild(hex.get());
if (tacticsMode) if(tacticsMode)
bTacticNextStack(); bTacticNextStack();
CCS->musich->stopMusic(); CCS->musich->stopMusic();
@ -415,7 +417,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
}; };
CCS->soundh->setCallback(battleIntroSoundChannel, onIntroPlayed); CCS->soundh->setCallback(battleIntroSoundChannel, onIntroPlayed);
memset(stackCountOutsideHexes, 1, GameConstants::BFIELD_SIZE *sizeof(bool)); //initialize array with trues
currentAction = PossiblePlayerBattleAction::INVALID; currentAction = PossiblePlayerBattleAction::INVALID;
selectedAction = PossiblePlayerBattleAction::INVALID; selectedAction = PossiblePlayerBattleAction::INVALID;
@ -794,7 +795,7 @@ void CBattleInterface::bSurrenderf()
if (cost >= 0) if (cost >= 0)
{ {
std::string enemyHeroName = curInt->cb->battleGetEnemyHero().name; std::string enemyHeroName = curInt->cb->battleGetEnemyHero().name;
if(enemyHeroName.empty()) if (enemyHeroName.empty())
{ {
logGlobal->warn("Surrender performed without enemy hero, should not happen!"); logGlobal->warn("Surrender performed without enemy hero, should not happen!");
enemyHeroName = "#ENEMY#"; enemyHeroName = "#ENEMY#";
@ -871,7 +872,7 @@ void CBattleInterface::bAutofightf()
blockUI(true); blockUI(true);
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String()); 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()); ai->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
curInt->autofightingAI = ai; curInt->autofightingAI = ai;
curInt->cb->registerBattleInterface(ai); curInt->cb->registerBattleInterface(ai);
@ -910,14 +911,14 @@ void CBattleInterface::bSpellf()
if (blockingBonus->source == Bonus::ARTIFACT) 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. //If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus //TODO check who *really* is source of bonus
std::string heroName = myHero->hasArt(artID) ? myHero->name : enemyHero().name; 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. //%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]) 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 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); 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 const CCreature * creature;//creature whose shots should be loaded
if(stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS) 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 else
creature = stack->getCreature(); creature = stack->getCreature();
@ -1062,7 +1063,7 @@ void CBattleInterface::stackMoved(const CStack *stack, std::vector<BattleHex> de
waitForAnims(); waitForAnims();
} }
void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos, const std::vector<MetaString> & battleLog) void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos)
{ {
for(auto & attackedInfo : attackedInfos) for(auto & attackedInfo : attackedInfos)
{ {
@ -1089,8 +1090,6 @@ void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attacked
killedBySide.at(side) += attackedInfo.amountKilled; killedBySide.at(side) += attackedInfo.amountKilled;
} }
int killed = killedBySide[0] + killedBySide[1];
for(ui8 side = 0; side < 2; side++) for(ui8 side = 0; side < 2; side++)
{ {
if(killedBySide.at(side) > killedBySide.at(1-side)) if(killedBySide.at(side) > killedBySide.at(1-side))
@ -1106,11 +1105,6 @@ void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attacked
if (attackedInfo.cloneKilled) if (attackedInfo.cloneKilled)
stackRemoved(attackedInfo.defender->ID); 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 ) 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()); displayEffect(elem.effect, stack->getPosition());
} }
//displaying message in console
displayBattleLog(sc->battleLog);
waitForAnims(); waitForAnims();
//mana absorption //mana absorption
if (sc->manaGained > 0) if (sc->manaGained > 0)
@ -1393,9 +1384,6 @@ void CBattleInterface::spellCast(const BattleSpellCast * sc)
void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse) void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
{ {
for(const MetaString & line : sse.battleLog)
console->addText(line.toString());
if(activeStack != nullptr) if(activeStack != nullptr)
redrawBackgroundWithHexes(activeStack); redrawBackgroundWithHexes(activeStack);
} }
@ -1474,28 +1462,19 @@ void CBattleInterface::displayEffect(ui32 effect, BattleHex destTile)
addNewAnim(new CEffectAnimation(this, customAnim, 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) void CBattleInterface::displaySpellCast(SpellID spellID, BattleHex destinationTile)
{ {
const CSpell *spell = spellID.toSpell(); const CSpell * spell = spellID.toSpell();
if (spell == nullptr) if(spell == nullptr)
return; 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(); const CSpell *spell = spellID.toSpell();
if (spell == nullptr) if(spell == nullptr)
return; 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) void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTile)
{ {
const CSpell *spell = spellID.toSpell(); const CSpell * spell = spellID.toSpell();
if (spell == nullptr) if(spell == nullptr)
return; 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)) if (vstd::contains(possibleActions, PossiblePlayerBattleAction::NO_LOCATION))
{ {
const spells::Caster *caster = activeStack; const spells::Caster * caster = activeStack;
const CSpell *spell = SpellID(creatureSpellToCast).toSpell(); const CSpell * spell = SpellID(creatureSpellToCast).toSpell();
const bool isCastingPossible = spell->canBeCastAt(curInt->cb.get(), spells::Mode::CREATURE_ACTIVE, caster, BattleHex::INVALID);
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) if (isCastingPossible)
{ {
@ -1800,39 +1796,6 @@ void CBattleInterface::reorderPossibleActionsPriority(const CStack * stack, Mous
std::make_heap(possibleActions.begin(), possibleActions.end(), comparer); 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) void CBattleInterface::endAction(const BattleAction* action)
{ {
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber); const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber);
@ -2571,7 +2534,16 @@ bool CBattleInterface::isCastingPossibleHere(const CStack *sactive, const CStack
else else
{ {
const spells::Mode mode = creatureCasting ? spells::Mode::CREATURE_ACTIVE : spells::Mode::HERO; 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 else
@ -3172,7 +3144,9 @@ void CBattleInterface::showHighlightedHexes(SDL_Surface *to)
if(caster && spell) //when casting spell if(caster && spell) //when casting spell
{ {
// printing shaded hex(es) // 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) for(BattleHex shadedHex : shaded)
{ {
if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1)) if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1))
@ -3691,7 +3665,17 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack *activeStack)
attackableHexes.clear(); attackableHexes.clear();
if (activeStack) if (activeStack)
occupyableHexes = curInt->cb->battleGetAvailableHexes(activeStack, true, &attackableHexes); 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 //prepare background graphic with hexes and shaded hexes
blitAt(background, 0, 0, backgroundWithHexes); blitAt(background, 0, 0, backgroundWithHexes);

View File

@ -9,7 +9,9 @@
*/ */
#pragma once #pragma once
#include "../../lib/ConstTransitivePtr.h" //may be reundant #include <vcmi/spells/Magic.h>
#include "../../lib/ConstTransitivePtr.h" //may be redundant
#include "../../lib/GameConstants.h" #include "../../lib/GameConstants.h"
#include "CBattleAnimations.h" #include "CBattleAnimations.h"
@ -50,6 +52,7 @@ class CBattleGameInterface;
struct CustomEffectInfo; struct CustomEffectInfo;
class CAnimation; class CAnimation;
class IImage; class IImage;
class CSpell;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,... /// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo struct StackAttackedInfo
@ -153,7 +156,7 @@ private:
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
std::vector<BattleHex> occupyableHexes, //hexes available for active stack std::vector<BattleHex> occupyableHexes, //hexes available for active stack
attackableHexes; //hexes attackable by 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<bool, GameConstants::BFIELD_SIZE> 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 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) 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 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 //force active stack to cast a spell if possible
void enterCreatureCastingMode(); void enterCreatureCastingMode();
void printConsoleAttacked(const CStack *defender, int dmg, int killed, const CStack *attacker, bool Multiple);
std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield
void giveCommand(EActionType action, BattleHex tile = BattleHex(), si32 additional = -1); void giveCommand(EActionType action, BattleHex tile = BattleHex(), si32 additional = -1);
void sendCommand(BattleAction *& command, const CStack * actor = nullptr); void sendCommand(BattleAction *& command, const CStack * actor = nullptr);
@ -340,7 +341,7 @@ public:
void stackActivated(const CStack *stack); //active stack has been changed void stackActivated(const CStack *stack); //active stack has been changed
void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex
void waitForAnims(); void waitForAnims();
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos, const std::vector<MetaString> & battleLog); //called when a certain amount of stacks has been attacked void stacksAreAttacked(std::vector<StackAttackedInfo> 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 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 newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of 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 displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellHit(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 battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex
void endAction(const BattleAction* action); void endAction(const BattleAction* action);

View File

@ -448,8 +448,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult & br, CPlayerInterfa
if(best != stacks.end()) //should be always but to be safe... if(best != stacks.end()) //should be always but to be safe...
{ {
icons.push_back(std::make_shared<CAnimImage>("TWCRPORT", (*best)->type->idNumber+2, 0, xs[i], 38)); icons.push_back(std::make_shared<CAnimImage>("TWCRPORT", (*best)->type->getIconIndex(), 0, xs[i], 38));
sideNames[i] = CGI->creh->creatures[(*best)->type->idNumber]->namePl; sideNames[i] = (*best)->type->getPluralName();
} }
} }
} }
@ -471,7 +471,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult & br, CPlayerInterfa
int yPos = 344 + step * 97; int yPos = 344 + step * 97;
for(auto & elem : br.casualties[step]) for(auto & elem : br.casualties[step])
{ {
icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", CGI->creh->creatures[elem.first]->iconIndex, 0, xPos, yPos)); icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", CGI->creatures()->getByIndex(elem.first)->getIconIndex(), 0, xPos, yPos));
std::ostringstream amount; std::ostringstream amount;
amount<<elem.second; amount<<elem.second;
labels.push_back(std::make_shared<CLabel>(xPos + 16, yPos + 42, FONT_SMALL, CENTER, Colors::WHITE, amount.str())); labels.push_back(std::make_shared<CLabel>(xPos + 16, yPos + 42, FONT_SMALL, CENTER, Colors::WHITE, amount.str()));

View File

@ -23,7 +23,7 @@
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../battle/CBattleInterface.h" #include "../battle/CBattleInterface.h"
extern std::queue<SDL_Event> events; extern std::queue<SDL_Event> SDLEventsQueue;
extern boost::mutex eventsM; extern boost::mutex eventsM;
boost::thread_specific_ptr<bool> inGuiThread; boost::thread_specific_ptr<bool> inGuiThread;
@ -188,18 +188,18 @@ void CGuiHandler::handleEvents()
return; return;
boost::unique_lock<boost::mutex> lock(eventsM); boost::unique_lock<boost::mutex> lock(eventsM);
while(!events.empty()) while(!SDLEventsQueue.empty())
{ {
continueEventHandling = true; continueEventHandling = true;
SDL_Event ev = events.front(); SDL_Event ev = SDLEventsQueue.front();
current = &ev; current = &ev;
events.pop(); SDLEventsQueue.pop();
// In a sequence of mouse motion events, skip all but the last one. // 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 // 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) // 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. // 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; continue;
handleCurrentEvent(); handleCurrentEvent();

View File

@ -10,6 +10,10 @@
#include "StdInc.h" #include "StdInc.h"
#include "CBonusSelection.h" #include "CBonusSelection.h"
#include <vcmi/spells/Spell.h>
#include <vcmi/spells/Service.h>
#include "CSelectionBase.h" #include "CSelectionBase.h"
#include "../CGameInfo.h" #include "../CGameInfo.h"
@ -34,9 +38,7 @@
#include "../../lib/filesystem/Filesystem.h" #include "../../lib/filesystem/Filesystem.h"
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CArtHandler.h"
#include "../../lib/CBuildingHandler.h" #include "../../lib/CBuildingHandler.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/CSkillHandler.h" #include "../../lib/CSkillHandler.h"
#include "../../lib/CTownHandler.h" #include "../../lib/CTownHandler.h"
@ -176,13 +178,13 @@ void CBonusSelection::createBonusesIcons()
{ {
case CScenarioTravel::STravelBonus::SPELL: case CScenarioTravel::STravelBonus::SPELL:
desc = CGI->generaltexth->allTexts[715]; 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; break;
case CScenarioTravel::STravelBonus::MONSTER: case CScenarioTravel::STravelBonus::MONSTER:
picNumber = bonDescs[i].info2 + 2; picNumber = bonDescs[i].info2 + 2;
desc = CGI->generaltexth->allTexts[717]; desc = CGI->generaltexth->allTexts[717];
boost::algorithm::replace_first(desc, "%d", boost::lexical_cast<std::string>(bonDescs[i].info3)); boost::algorithm::replace_first(desc, "%d", boost::lexical_cast<std::string>(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; break;
case CScenarioTravel::STravelBonus::BUILDING: case CScenarioTravel::STravelBonus::BUILDING:
{ {
@ -202,18 +204,18 @@ void CBonusSelection::createBonusesIcons()
picName = graphics->ERMUtoPicture[faction][buildID]; picName = graphics->ERMUtoPicture[faction][buildID];
picNumber = -1; picNumber = -1;
if(vstd::contains(CGI->townh->factions[faction]->town->buildings, buildID)) if(vstd::contains((*CGI->townh)[faction]->town->buildings, buildID))
desc = CGI->townh->factions[faction]->town->buildings.find(buildID)->second->Name(); desc = (*CGI->townh)[faction]->town->buildings.find(buildID)->second->Name();
break; break;
} }
case CScenarioTravel::STravelBonus::ARTIFACT: case CScenarioTravel::STravelBonus::ARTIFACT:
desc = CGI->generaltexth->allTexts[715]; 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; break;
case CScenarioTravel::STravelBonus::SPELL_SCROLL: case CScenarioTravel::STravelBonus::SPELL_SCROLL:
desc = CGI->generaltexth->allTexts[716]; 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; break;
case CScenarioTravel::STravelBonus::PRIMARY_SKILL: case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
{ {
@ -318,7 +320,7 @@ void CBonusSelection::createBonusesIcons()
} }
else 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; break;
} }

View File

@ -83,7 +83,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
TOWN_RANDOM = 38, TOWN_NONE = 39, // Special frames in ITPA TOWN_RANDOM = 38, TOWN_NONE = 39, // Special frames in ITPA
HERO_RANDOM = 163, HERO_NONE = 164 // Special frames in PortraitsSmall 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) switch(type)
{ {
@ -95,7 +95,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
case PlayerSettings::RANDOM: case PlayerSettings::RANDOM:
return TOWN_RANDOM; return TOWN_RANDOM;
default: default:
return CGI->townh->factions[factionIndex]->town->clientInfo.icons[true][false] + 2; return (*CGI->townh)[factionIndex]->town->clientInfo.icons[true][false] + 2;
} }
case HERO: case HERO:
switch(settings.hero) switch(settings.hero)
@ -108,11 +108,10 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
{ {
if(settings.heroPortrait >= 0) if(settings.heroPortrait >= 0)
return settings.heroPortrait; return settings.heroPortrait;
auto index = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero; auto index = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
return CGI->heroh->heroes[index]->imageIndex; return (*CGI->heroh)[index]->imageIndex;
} }
} }
case BONUS: case BONUS:
{ {
switch(settings.bonus) switch(settings.bonus)
@ -125,7 +124,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
return GOLD; return GOLD;
case PlayerSettings::RESOURCE: case PlayerSettings::RESOURCE:
{ {
switch(CGI->townh->factions[factionIndex]->town->primaryRes) switch((*CGI->townh)[factionIndex]->town->primaryRes)
{ {
case Res::WOOD_AND_ORE: case Res::WOOD_AND_ORE:
return WOOD_ORE; return WOOD_ORE;
@ -181,8 +180,8 @@ std::string OptionsTab::CPlayerSettingsHelper::getName()
return CGI->generaltexth->allTexts[522]; return CGI->generaltexth->allTexts[522];
default: default:
{ {
auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle; auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
return CGI->townh->factions[factionIndex]->name; return (*CGI->townh)[factionIndex]->name;
} }
} }
} }
@ -198,8 +197,8 @@ std::string OptionsTab::CPlayerSettingsHelper::getName()
{ {
if(!settings.heroName.empty()) if(!settings.heroName.empty())
return settings.heroName; return settings.heroName;
auto index = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero; auto index = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
return CGI->heroh->heroes[index]->name; return (*CGI->heroh)[index]->name;
} }
} }
} }
@ -245,8 +244,8 @@ std::string OptionsTab::CPlayerSettingsHelper::getTitle()
} }
std::string OptionsTab::CPlayerSettingsHelper::getSubtitle() std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
{ {
auto factionIndex = settings.castle >= CGI->townh->factions.size() ? 0 : settings.castle; auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle;
auto heroIndex = settings.hero >= CGI->heroh->heroes.size() ? 0 : settings.hero; auto heroIndex = settings.hero >= CGI->heroh->size() ? 0 : settings.hero;
switch(type) switch(type)
{ {
@ -255,7 +254,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
case HERO: case HERO:
{ {
if(settings.hero >= 0) if(settings.hero >= 0)
return getName() + " - " + CGI->heroh->heroes[heroIndex]->heroClass->name; return getName() + " - " + (*CGI->heroh)[heroIndex]->heroClass->name;
return getName(); return getName();
} }
@ -267,7 +266,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
return CGI->generaltexth->allTexts[87]; //500-1000 return CGI->generaltexth->allTexts[87]; //500-1000
case PlayerSettings::RESOURCE: case PlayerSettings::RESOURCE:
{ {
switch(CGI->townh->factions[factionIndex]->town->primaryRes) switch((*CGI->townh)[factionIndex]->town->primaryRes)
{ {
case Res::MERCURY: case Res::MERCURY:
return CGI->generaltexth->allTexts[694]; return CGI->generaltexth->allTexts[694];
@ -289,7 +288,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
std::string OptionsTab::CPlayerSettingsHelper::getDescription() 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) 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 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: case PlayerSettings::RESOURCE:
{ {
switch(CGI->townh->factions[factionIndex]->town->primaryRes) switch((*CGI->townh)[factionIndex]->town->primaryRes)
{ {
case Res::MERCURY: case Res::MERCURY:
return CGI->generaltexth->allTexts[690]; return CGI->generaltexth->allTexts[690];
@ -376,9 +375,9 @@ void OptionsTab::CPlayerOptionTooltipBox::genTownWindow()
pos = Rect(0, 0, 228, 290); pos = Rect(0, 0, 228, 290);
genHeader(); genHeader();
labelAssociatedCreatures = std::make_shared<CLabel>(pos.w / 2 + 8, 122, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[79]); labelAssociatedCreatures = std::make_shared<CLabel>(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<std::shared_ptr<CComponent>> components; std::vector<std::shared_ptr<CComponent>> components;
const CTown * town = CGI->townh->factions[factionIndex]->town; const CTown * town = (*CGI->townh)[factionIndex]->town;
for(auto & elem : town->creatures) for(auto & elem : town->creatures)
{ {
@ -393,10 +392,10 @@ void OptionsTab::CPlayerOptionTooltipBox::genHeroWindow()
pos = Rect(0, 0, 292, 226); pos = Rect(0, 0, 292, 226);
genHeader(); genHeader();
labelHeroSpeciality = std::make_shared<CLabel>(pos.w / 2 + 4, 117, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[78]); labelHeroSpeciality = std::make_shared<CLabel>(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<CAnimImage>("UN44", CGI->heroh->heroes[heroIndex]->imageIndex, 0, pos.w / 2 - 22, 134); imageSpeciality = std::make_shared<CAnimImage>("UN44", (*CGI->heroh)[heroIndex]->imageIndex, 0, pos.w / 2 - 22, 134);
labelSpecialityName = std::make_shared<CLabel>(pos.w / 2, 188, FONT_SMALL, CENTER, Colors::WHITE, CGI->heroh->heroes[heroIndex]->specName); labelSpecialityName = std::make_shared<CLabel>(pos.w / 2, 188, FONT_SMALL, CENTER, Colors::WHITE, (*CGI->heroh)[heroIndex]->specName);
} }
void OptionsTab::CPlayerOptionTooltipBox::genBonusWindow() void OptionsTab::CPlayerOptionTooltipBox::genBonusWindow()

View File

@ -25,7 +25,6 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CArtHandler.h" #include "../../lib/CArtHandler.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
@ -45,10 +44,11 @@ void CHeroArtPlace::createImage()
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
si32 imageIndex = 0; si32 imageIndex = 0;
if(ourArt)
imageIndex = ourArt->artType->iconIndex;
if(locked) if(locked)
imageIndex = ArtifactID::ART_LOCK; imageIndex = ArtifactID::ART_LOCK;
else if(ourArt)
imageIndex = ourArt->artType->getIconIndex();
image = std::make_shared<CAnimImage>("artifact", imageIndex); image = std::make_shared<CAnimImage>("artifact", imageIndex);
if(!ourArt) if(!ourArt)
@ -68,7 +68,7 @@ void CHeroArtPlace::lockSlot(bool on)
if (on) if (on)
image->setFrame(ArtifactID::ART_LOCK); image->setFrame(ArtifactID::ART_LOCK);
else if (ourArt) else if (ourArt)
image->setFrame(ourArt->artType->iconIndex); image->setFrame(ourArt->artType->getIconIndex());
else else
image->setFrame(0); image->setFrame(0);
} }
@ -172,7 +172,7 @@ void CHeroArtPlace::clickLeft(tribool down, bool previousState)
else if(cur->isBig()) else if(cur->isBig())
{ {
//war machines cannot go to backpack //war machines cannot go to backpack
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % cur->Name())); LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % cur->getName()));
} }
else else
{ {
@ -197,18 +197,6 @@ void CHeroArtPlace::clickLeft(tribool down, bool previousState)
(!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID)) (!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID))
{ {
setMeAsDest(); setMeAsDest();
//
// // Special case when the dest artifact can't be fit into the src slot.
// //CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
// const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->src.AOH;
// ui16 srcSlotID = ourOwner->commonInfo->src.slotID;
// if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID)))
// {
// // Put dest artifact into owner's backpack.
// ourOwner->commonInfo->src.AOH = ourOwner;
// ourOwner->commonInfo->src.slotID = ourOwner->curHero->artifacts.size() + 19;
// }
ourOwner->realizeCurrentTransaction(); ourOwner->realizeCurrentTransaction();
} }
} }
@ -226,14 +214,12 @@ bool CHeroArtPlace::askToAssemble(const CArtifactInstance *art, ArtifactPosition
for(const CArtifact *combination : assemblyPossibilities) for(const CArtifact *combination : assemblyPossibilities)
{ {
LOCPLINT->showArtifactAssemblyDialog( LOCPLINT->showArtifactAssemblyDialog(
art->artType->id, art->artType,
combination->id, combination,
true, std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), hero, slot, true, combination->id));
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), hero, slot, true, combination->id),
0);
if(assemblyPossibilities.size() > 2) if(assemblyPossibilities.size() > 2)
logGlobal->warn("More than one possibility of assembling on %s... taking only first", art->artType->Name()); logGlobal->warn("More than one possibility of assembling on %s... taking only first", art->artType->getName());
return true; return true;
} }
return false; return false;
@ -243,14 +229,14 @@ void CHeroArtPlace::clickRight(tribool down, bool previousState)
{ {
if(ourArt && down && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;] if(ourArt && down && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;]
{ {
if (slotID < GameConstants::BACKPACK_START) if(slotID < GameConstants::BACKPACK_START)
{ {
if(ourOwner->allowedAssembling) if(ourOwner->allowedAssembling)
{ {
std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero); std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
// If the artifact can be assembled, display dialog. // If the artifact can be assembled, display dialog.
if (askToAssemble(ourArt, slotID, ourOwner->curHero)) if(askToAssemble(ourArt, slotID, ourOwner->curHero))
{ {
return; return;
} }
@ -259,11 +245,9 @@ void CHeroArtPlace::clickRight(tribool down, bool previousState)
if(ourArt->canBeDisassembled()) if(ourArt->canBeDisassembled())
{ {
LOCPLINT->showArtifactAssemblyDialog( LOCPLINT->showArtifactAssemblyDialog(
ourArt->artType->id, ourArt->artType,
0, nullptr,
false, std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()));
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()),
0);
return; return;
} }
} }
@ -294,7 +278,7 @@ void CHeroArtPlace::select ()
} }
} }
CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", ourArt->artType->iconIndex)); CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", ourArt->artType->getIconIndex()));
ourOwner->commonInfo->src.setTo(this, false); ourOwner->commonInfo->src.setTo(this, false);
ourOwner->markPossibleSlots(ourArt); ourOwner->markPossibleSlots(ourArt);
@ -389,7 +373,7 @@ void CHeroArtPlace::setArtifact(const CArtifactInstance *art)
} }
image->enable(); image->enable();
image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->iconIndex); image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->getIconIndex());
text = art->getEffectiveDescription(ourOwner->curHero); text = art->getEffectiveDescription(ourOwner->curHero);
@ -414,7 +398,7 @@ void CHeroArtPlace::setArtifact(const CArtifactInstance *art)
if (locked) // Locks should appear as empty. if (locked) // Locks should appear as empty.
hoverText = CGI->generaltexth->allTexts[507]; hoverText = CGI->generaltexth->allTexts[507];
else else
hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->Name()); hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->getName());
} }
void CArtifactsOfHero::SCommonPart::reset() void CArtifactsOfHero::SCommonPart::reset()
@ -769,7 +753,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
commonInfo->src.art = dst.getArt(); commonInfo->src.art = dst.getArt();
commonInfo->src.slotID = dst.slot; commonInfo->src.slotID = dst.slot;
assert(commonInfo->src.AOH); assert(commonInfo->src.AOH);
CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", dst.getArt()->artType->iconIndex)); CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", dst.getArt()->artType->getIconIndex()));
markPossibleSlots(dst.getArt()); markPossibleSlots(dst.getArt());
} }
} }
@ -1020,7 +1004,7 @@ void CCommanderArtPlace::createImage()
int imageIndex = 0; int imageIndex = 0;
if(ourArt) if(ourArt)
imageIndex = ourArt->artType->iconIndex; imageIndex = ourArt->artType->getIconIndex();
image = std::make_shared<CAnimImage>("artifact", imageIndex); image = std::make_shared<CAnimImage>("artifact", imageIndex);
if(!ourArt) if(!ourArt)
@ -1055,7 +1039,7 @@ void CCommanderArtPlace::setArtifact(const CArtifactInstance * art)
} }
image->enable(); image->enable();
image->setFrame(art->artType->iconIndex); image->setFrame(art->artType->getIconIndex());
text = art->getEffectiveDescription(); text = art->getEffectiveDescription();

View File

@ -112,7 +112,7 @@ const std::vector<std::string> CComponent::getFileName()
case spell: return gen(spellsArr); case spell: return gen(spellsArr);
case morale: return gen(moraleArr); case morale: return gen(moraleArr);
case luck: return gen(luckArr); case luck: return gen(luckArr);
case building: return std::vector<std::string>(4, CGI->townh->factions[subtype]->town->clientInfo.buildingsIcons); case building: return std::vector<std::string>(4, (*CGI->townh)[subtype]->town->clientInfo.buildingsIcons);
case hero: return gen(heroArr); case hero: return gen(heroArr);
case flag: return gen(flagArr); case flag: return gen(flagArr);
} }
@ -127,8 +127,8 @@ size_t CComponent::getIndex()
case primskill: return subtype; case primskill: return subtype;
case secskill: return subtype*3 + 3 + val - 1; case secskill: return subtype*3 + 3 + val - 1;
case resource: return subtype; case resource: return subtype;
case creature: return CGI->creh->creatures[subtype]->iconIndex; case creature: return CGI->creatures()->getByIndex(subtype)->getIconIndex();
case artifact: return CGI->arth->artifacts[subtype]->iconIndex; case artifact: return CGI->artifacts()->getByIndex(subtype)->getIconIndex();
case experience: return 4; case experience: return 4;
case spell: return subtype; case spell: return subtype;
case morale: return val+3; case morale: return val+3;
@ -159,15 +159,15 @@ std::string CComponent::getDescription()
} }
else else
{ {
art.reset(CArtifactInstance::createScroll(static_cast<SpellID>(val))); art.reset(CArtifactInstance::createScroll(SpellID(val)));
} }
return art->getEffectiveDescription(); return art->getEffectiveDescription();
} }
case experience: return CGI->generaltexth->allTexts[241]; case experience: return CGI->generaltexth->allTexts[241];
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description; case spell: return CGI->spellh->objects[subtype]->getLevelDescription(val);
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)]; case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)]; case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description(); case building: return (*CGI->townh)[subtype]->town->buildings[BuildingID(val)]->Description();
case hero: return ""; case hero: return "";
case flag: return ""; case flag: return "";
} }
@ -193,8 +193,8 @@ std::string CComponent::getSubtitleInternal()
case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387])); case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387]));
case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->skillh->skillName(subtype); case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->skillh->skillName(subtype);
case resource: return boost::lexical_cast<std::string>(val); case resource: return boost::lexical_cast<std::string>(val);
case creature: return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing); case creature: return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->objects[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing);
case artifact: return CGI->arth->artifacts[subtype]->Name(); case artifact: return CGI->artifacts()->getByIndex(subtype)->getName();
case experience: case experience:
{ {
if(subtype == 1) //+1 level - tree of knowledge if(subtype == 1) //+1 level - tree of knowledge
@ -208,15 +208,15 @@ std::string CComponent::getSubtitleInternal()
return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut; return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut;
} }
} }
case spell: return CGI->spellh->objects[subtype]->name; case spell: return CGI->spells()->getByIndex(subtype)->getName();
case morale: return ""; case morale: return "";
case luck: return ""; case luck: return "";
case building: case building:
{ {
auto building = CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]; auto building = (*CGI->townh)[subtype]->town->buildings[BuildingID(val)];
if(!building) if(!building)
{ {
logGlobal->error("Town of faction %s has no building #%d", CGI->townh->factions[subtype]->town->faction->name, val); logGlobal->error("Town of faction %s has no building #%d", (*CGI->townh)[subtype]->town->faction->name, val);
return (boost::format("Missing building #%d") % val).str(); return (boost::format("Missing building #%d") % val).str();
} }
return building->Name(); return building->Name();
@ -224,7 +224,7 @@ std::string CComponent::getSubtitleInternal()
case hero: return ""; case hero: return "";
case flag: return CGI->generaltexth->capColors[subtype]; case flag: return CGI->generaltexth->capColors[subtype];
} }
assert(0); logGlobal->error("Invalid CComponent type: %d", (int)compType);
return ""; return "";
} }

View File

@ -355,7 +355,7 @@ void CGarrisonSlot::update()
if(creature) if(creature)
{ {
creatureImage->enable(); creatureImage->enable();
creatureImage->setFrame(creature->iconIndex); creatureImage->setFrame(creature->getIconIndex());
stackCount->enable(); stackCount->enable();
stackCount->setText(boost::lexical_cast<std::string>(myStack->count)); stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
@ -367,11 +367,11 @@ void CGarrisonSlot::update()
} }
} }
CGarrisonSlot::CGarrisonSlot(CGarrisonInt * Owner, int x, int y, SlotID IID, CGarrisonSlot::EGarrisonType Upg, const CStackInstance * Creature) CGarrisonSlot::CGarrisonSlot(CGarrisonInt * Owner, int x, int y, SlotID IID, CGarrisonSlot::EGarrisonType Upg, const CStackInstance * creature_)
: ID(IID), : ID(IID),
owner(Owner), owner(Owner),
myStack(Creature), myStack(creature_),
creature(nullptr), creature(creature_ ? creature_->type : nullptr),
upg(Upg) upg(Upg)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);

View File

@ -53,7 +53,7 @@ public:
void clickRight(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override;
void clickLeft(tribool down, bool previousState) override; void clickLeft(tribool down, bool previousState) override;
void update(); void update();
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, EGarrisonType Upg=EGarrisonType::UP, const CStackInstance * Creature=nullptr); CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, EGarrisonType Upg=EGarrisonType::UP, const CStackInstance * creature_ = nullptr);
void splitIntoParts(EGarrisonType type, int amount, int maxOfSplittedSlots); void splitIntoParts(EGarrisonType type, int amount, int maxOfSplittedSlots);
void handleSplittingShortcuts(); void handleSplittingShortcuts();

View File

@ -243,7 +243,7 @@ void CArmyTooltip::init(const InfoAboutArmy &army)
continue; continue;
} }
icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", slot.second.type->iconIndex, 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y)); icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", slot.second.type->getIconIndex(), 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y));
std::string subtitle; std::string subtitle;
if(army.army.isDetailed) if(army.army.isDetailed)
@ -443,12 +443,12 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature * cre, bool Big, bool A
TFaction faction = cre->faction; TFaction faction = cre->faction;
assert(CGI->townh->factions.size() > faction); assert(CGI->townh->size() > faction);
if(Big) if(Big)
bg = std::make_shared<CPicture>(CGI->townh->factions[faction]->creatureBg130); bg = std::make_shared<CPicture>((*CGI->townh)[faction]->creatureBg130);
else else
bg = std::make_shared<CPicture>(CGI->townh->factions[faction]->creatureBg120); bg = std::make_shared<CPicture>((*CGI->townh)[faction]->creatureBg120);
anim = std::make_shared<CCreatureAnim>(0, 0, cre->animDefName); anim = std::make_shared<CCreatureAnim>(0, 0, cre->animDefName);
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h); anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON)); anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));

View File

@ -112,11 +112,11 @@ void CBuildingRect::hover(bool on)
void CBuildingRect::clickLeft(tribool down, bool previousState) void CBuildingRect::clickLeft(tribool down, bool previousState)
{ {
if( previousState && getBuilding() && area && !down && (parent->selectedBuilding==this)) if( previousState && getBuilding() && area && !down && (parent->selectedBuilding==this))
if (!CSDL_Ext::isTransparent(area, GH.current->motion.x - pos.x, GH.current->motion.y - pos.y)) //inside building image if (!CSDL_Ext::isTransparent(area, GH.current->motion.x-pos.x, GH.current->motion.y-pos.y) ) //inside building image
{ {
auto building = getBuilding(); auto building = getBuilding();
parent->buildingClicked(building->bid, building->subId, building->upgrade); parent->buildingClicked(building->bid, building->subId, building->upgrade);
} }
} }
void CBuildingRect::clickRight(tribool down, bool previousState) void CBuildingRect::clickRight(tribool down, bool previousState)
@ -231,7 +231,7 @@ std::string CBuildingRect::getSubtitle()//hover text for building
if(availableCreatures.size()) if(availableCreatures.size())
{ {
int creaID = availableCreatures.back();//taking last of available creatures int creaID = availableCreatures.back();//taking last of available creatures
return CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures.at(creaID)->namePl; return CGI->generaltexth->allTexts[16] + " " + CGI->creh->objects.at(creaID)->namePl;
} }
else else
{ {
@ -271,7 +271,7 @@ CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstanc
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background->colorize(Town->tempOwner); background->colorize(Town->tempOwner);
const CCreature * creature = CGI->creh->creatures.at(Town->creatures.at(level).second.back()); const CCreature * creature = CGI->creh->objects.at(Town->creatures.at(level).second.back());
title = std::make_shared<CLabel>(80, 30, FONT_SMALL, CENTER, Colors::WHITE, creature->namePl); title = std::make_shared<CLabel>(80, 30, FONT_SMALL, CENTER, Colors::WHITE, creature->namePl);
animation = std::make_shared<CCreaturePic>(30, 44, creature, true, true); animation = std::make_shared<CCreaturePic>(30, 44, creature, true, true);
@ -794,9 +794,11 @@ void CCastleBuildings::enterBlacksmith(ArtifactID artifactID)
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->town->buildings.find(BuildingID::BLACKSMITH)->second->Name())); LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->town->buildings.find(BuildingID::BLACKSMITH)->second->Name()));
return; return;
} }
int price = CGI->arth->artifacts[artifactID]->price; auto art = artifactID.toArtifact(CGI->artifacts());
int price = art->getPrice();
bool possible = LOCPLINT->cb->getResourceAmount(Res::GOLD) >= price && !hero->hasArt(artifactID); bool possible = LOCPLINT->cb->getResourceAmount(Res::GOLD) >= price && !hero->hasArt(artifactID);
CreatureID cre = artifactID.toArtifact()->warMachine; CreatureID cre = art->getWarMachine();
GH.pushIntT<CBlacksmithDialog>(possible, cre, artifactID, hero->id); GH.pushIntT<CBlacksmithDialog>(possible, cre, artifactID, hero->id);
} }
@ -844,7 +846,7 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow()
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades) void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades)
{ {
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->subID, building)); std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->subID,building));
std::string descr = town->town->buildings.find(building)->second->Description(); std::string descr = town->town->buildings.find(building)->second->Description();
std::string hasNotProduced; std::string hasNotProduced;
std::string hasProduced; std::string hasProduced;
@ -878,8 +880,8 @@ void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID:
else //Mystic Pond produced something; else //Mystic Pond produced something;
{ {
descr += "\n\n" + hasProduced; descr += "\n\n" + hasProduced;
boost::algorithm::replace_first(descr, "%s", CGI->generaltexth->restypes[town->bonusValue.first]); boost::algorithm::replace_first(descr,"%s",CGI->generaltexth->restypes[town->bonusValue.first]);
boost::algorithm::replace_first(descr, "%d", boost::lexical_cast<std::string>(town->bonusValue.second)); boost::algorithm::replace_first(descr,"%d",boost::lexical_cast<std::string>(town->bonusValue.second));
} }
} }
LOCPLINT->showInfoDialog(descr, comps); LOCPLINT->showInfoDialog(descr, comps);
@ -972,9 +974,9 @@ CCreaInfo::CCreaInfo(Point position, const CGTownInstance * Town, int Level, boo
addUsedEvents(LCLICK | RCLICK | HOVER); addUsedEvents(LCLICK | RCLICK | HOVER);
ui32 creatureID = town->creatures[level].second.back(); ui32 creatureID = town->creatures[level].second.back();
creature = CGI->creh->creatures[creatureID]; creature = CGI->creh->objects[creatureID];
picture = std::make_shared<CAnimImage>("CPRSMALL", creature->iconIndex, 0, 8, 0); picture = std::make_shared<CAnimImage>("CPRSMALL", creature->getIconIndex(), 0, 8, 0);
std::string value; std::string value;
if(showAvailable) if(showAvailable)
@ -1627,7 +1629,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
Rect sizes(287, 4, 96, 18); Rect sizes(287, 4, 96, 18);
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[190], CGI->generaltexth->fcommands[0], getMyCreature()->getAttack(false))); values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[190], CGI->generaltexth->fcommands[0], getMyCreature()->getAttack(false)));
sizes.y+=20; sizes.y+=20;
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[191], CGI->generaltexth->fcommands[1], getMyCreature()->getDefence(false))); values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[191], CGI->generaltexth->fcommands[1], getMyCreature()->getDefense(false)));
sizes.y+=21; sizes.y+=21;
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[199], CGI->generaltexth->fcommands[2], getMyCreature()->getMinDamage(false), getMyCreature()->getMaxDamage(false))); values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[199], CGI->generaltexth->fcommands[2], getMyCreature()->getMinDamage(false), getMyCreature()->getMaxDamage(false)));
sizes.y+=20; sizes.y+=20;
@ -1642,9 +1644,9 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
const CCreature * CFortScreen::RecruitArea::getMyCreature() const CCreature * CFortScreen::RecruitArea::getMyCreature()
{ {
if(!town->creatures.at(level).second.empty()) // built if(!town->creatures.at(level).second.empty()) // built
return VLC->creh->creatures[town->creatures.at(level).second.back()]; return VLC->creh->objects[town->creatures.at(level).second.back()];
if(!town->town->creatures.at(level).empty()) // there are creatures on this level if(!town->town->creatures.at(level).empty()) // there are creatures on this level
return VLC->creh->creatures[town->town->creatures.at(level).front()]; return VLC->creh->objects[town->town->creatures.at(level).front()];
return nullptr; return nullptr;
} }
@ -1750,13 +1752,13 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell)
void CMageGuildScreen::Scroll::clickLeft(tribool down, bool previousState) void CMageGuildScreen::Scroll::clickLeft(tribool down, bool previousState)
{ {
if(down) if(down)
LOCPLINT->showInfoDialog(spell->getLevelInfo(0).description, std::make_shared<CComponent>(CComponent::spell, spell->id)); LOCPLINT->showInfoDialog(spell->getLevelDescription(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
} }
void CMageGuildScreen::Scroll::clickRight(tribool down, bool previousState) void CMageGuildScreen::Scroll::clickRight(tribool down, bool previousState)
{ {
if(down) if(down)
CRClickPopup::createAndPush(spell->getLevelInfo(0).description, std::make_shared<CComponent>(CComponent::spell, spell->id)); CRClickPopup::createAndPush(spell->getLevelDescription(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
} }
void CMageGuildScreen::Scroll::hover(bool on) void CMageGuildScreen::Scroll::hover(bool on)
@ -1781,7 +1783,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
animBG = std::make_shared<CPicture>("TPSMITBK", 64, 50); animBG = std::make_shared<CPicture>("TPSMITBK", 64, 50);
animBG->needRefresh = true; animBG->needRefresh = true;
const CCreature * creature = CGI->creh->creatures[creMachineID]; const CCreature * creature = CGI->creh->objects[creMachineID];
anim = std::make_shared<CCreatureAnim>(64, 50, creature->animDefName); anim = std::make_shared<CCreatureAnim>(64, 50, creature->animDefName);
anim->clipRect(113,125,200,150); anim->clipRect(113,125,200,150);
@ -1789,7 +1791,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
boost::str(boost::format(CGI->generaltexth->allTexts[274]) % creature->nameSing)); boost::str(boost::format(CGI->generaltexth->allTexts[274]) % creature->nameSing));
costText = std::make_shared<CLabel>(165, 218, FONT_MEDIUM, CENTER, Colors::WHITE, CGI->generaltexth->jktexts[43]); costText = std::make_shared<CLabel>(165, 218, FONT_MEDIUM, CENTER, Colors::WHITE, CGI->generaltexth->jktexts[43]);
costValue = std::make_shared<CLabel>(165, 290, FONT_MEDIUM, CENTER, Colors::WHITE, costValue = std::make_shared<CLabel>(165, 290, FONT_MEDIUM, CENTER, Colors::WHITE,
boost::lexical_cast<std::string>(CGI->arth->artifacts[aid]->price)); boost::lexical_cast<std::string>(aid.toArtifact(CGI->artifacts())->getPrice()));
std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing); std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing);
buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&](){ close(); }, SDLK_RETURN); buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&](){ close(); }, SDLK_RETURN);

View File

@ -10,6 +10,9 @@
#include "StdInc.h" #include "StdInc.h"
#include "CCreatureWindow.h" #include "CCreatureWindow.h"
#include <vcmi/spells/Spell.h>
#include <vcmi/spells/Service.h>
#include "../CGameInfo.h" #include "../CGameInfo.h"
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../widgets/Buttons.h" #include "../widgets/Buttons.h"
@ -26,7 +29,6 @@
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CModHandler.h" #include "../../lib/CModHandler.h"
#include "../../lib/CHeroHandler.h" #include "../../lib/CHeroHandler.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/CGameState.h" #include "../../lib/CGameState.h"
using namespace CSDL_Ext; using namespace CSDL_Ext;
@ -193,7 +195,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
std::vector<si32> spells = battleStack->activeSpells(); std::vector<si32> spells = battleStack->activeSpells();
for(si32 effect : spells) for(si32 effect : spells)
{ {
const CSpell * sp = CGI->spellh->objects[effect]; const spells::Spell * spell = CGI->spells()->getByIndex(effect);
std::string spellText; std::string spellText;
@ -204,7 +206,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
if (hasGraphics) if (hasGraphics)
{ {
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds." spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first(spellText, "%s", sp->name); boost::replace_first(spellText, "%s", spell->getName());
//FIXME: support permanent duration //FIXME: support permanent duration
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain; int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
boost::replace_first(spellText, "%d", boost::lexical_cast<std::string>(duration)); boost::replace_first(spellText, "%d", boost::lexical_cast<std::string>(duration));
@ -320,7 +322,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
}; };
auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1); auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1);
upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->creatures[upgradeInfo.info.newID[buttonIndex]]->iconIndex)); upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->iconIndex));
upgrade[buttonIndex] = upgradeBtn; upgrade[buttonIndex] = upgradeBtn;
} }
@ -520,7 +522,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
if(battleStack != nullptr) // in battle if(battleStack != nullptr) // in battle
{ {
addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(battleStack->isShooter()), battleStack->getAttack(battleStack->isShooter())); addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(battleStack->isShooter()), battleStack->getAttack(battleStack->isShooter()));
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefence(battleStack->isShooter()), battleStack->getDefence(battleStack->isShooter())); addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(battleStack->isShooter()), battleStack->getDefense(battleStack->isShooter()));
addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(battleStack->isShooter()) * dmgMultiply, battleStack->getMaxDamage(battleStack->isShooter()) * dmgMultiply); addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(battleStack->isShooter()) * dmgMultiply, battleStack->getMaxDamage(battleStack->isShooter()) * dmgMultiply);
addStatLabel(EStat::HEALTH, parent->info->creature->MaxHealth(), battleStack->MaxHealth()); addStatLabel(EStat::HEALTH, parent->info->creature->MaxHealth(), battleStack->MaxHealth());
addStatLabel(EStat::SPEED, parent->info->creature->Speed(), battleStack->Speed()); addStatLabel(EStat::SPEED, parent->info->creature->Speed(), battleStack->Speed());
@ -540,7 +542,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
const bool caster = parent->info->stackNode->valOfBonuses(Bonus::CASTS); const bool caster = parent->info->stackNode->valOfBonuses(Bonus::CASTS);
addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(shooter), parent->info->stackNode->getAttack(shooter)); addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(shooter), parent->info->stackNode->getAttack(shooter));
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefence(shooter), parent->info->stackNode->getDefence(shooter)); addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(shooter), parent->info->stackNode->getDefense(shooter));
addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(shooter) * dmgMultiply, parent->info->stackNode->getMaxDamage(shooter) * dmgMultiply); addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(shooter) * dmgMultiply, parent->info->stackNode->getMaxDamage(shooter) * dmgMultiply);
addStatLabel(EStat::HEALTH, parent->info->creature->MaxHealth(), parent->info->stackNode->MaxHealth()); addStatLabel(EStat::HEALTH, parent->info->creature->MaxHealth(), parent->info->stackNode->MaxHealth());
addStatLabel(EStat::SPEED, parent->info->creature->Speed(), parent->info->stackNode->Speed()); addStatLabel(EStat::SPEED, parent->info->creature->Speed(), parent->info->stackNode->Speed());

View File

@ -16,7 +16,6 @@
class CButton; class CButton;
struct SDL_Surface; struct SDL_Surface;
class CGHeroInstance; class CGHeroInstance;
class CArtifact;
class CHeroWindow; class CHeroWindow;
class LClickableAreaHero; class LClickableAreaHero;
class LRClickableAreaWText; class LRClickableAreaWText;

View File

@ -163,7 +163,7 @@ std::string InfoBoxAbstractHeroData::getNameText()
case HERO_EXPERIENCE: case HERO_EXPERIENCE:
return CGI->generaltexth->jktexts[6]; return CGI->generaltexth->jktexts[6];
case HERO_SPECIAL: case HERO_SPECIAL:
return CGI->heroh->heroes[getSubID()]->specName; return CGI->heroh->objects[getSubID()]->specName;
case HERO_SECONDARY_SKILL: case HERO_SECONDARY_SKILL:
if (getValue()) if (getValue())
return CGI->skillh->skillName(getSubID()); return CGI->skillh->skillName(getSubID());
@ -229,7 +229,7 @@ size_t InfoBoxAbstractHeroData::getImageIndex()
switch (type) switch (type)
{ {
case HERO_SPECIAL: case HERO_SPECIAL:
return VLC->heroh->heroes[getSubID()]->imageIndex; return CGI->heroh->objects[getSubID()]->imageIndex;
case HERO_PRIMARY_SKILL: case HERO_PRIMARY_SKILL:
return getSubID(); return getSubID();
case HERO_MANA: case HERO_MANA:
@ -256,7 +256,7 @@ void InfoBoxAbstractHeroData::prepareMessage(std::string & text, std::shared_ptr
switch (type) switch (type)
{ {
case HERO_SPECIAL: case HERO_SPECIAL:
text = CGI->heroh->heroes[getSubID()]->specDescr; text = CGI->heroh->objects[getSubID()]->specDescr;
break; break;
case HERO_PRIMARY_SKILL: case HERO_PRIMARY_SKILL:
text = CGI->generaltexth->arraytxt[2+getSubID()]; text = CGI->generaltexth->arraytxt[2+getSubID()];

View File

@ -120,7 +120,7 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
for(const auto spell : mySpells) for(const auto spell : mySpells)
{ {
int * sitesPerOurTab = spell->isCombatSpell() ? sitesPerTabBattle : sitesPerTabAdv; int * sitesPerOurTab = spell->isCombat() ? sitesPerTabBattle : sitesPerTabAdv;
++sitesPerOurTab[4]; ++sitesPerOurTab[4];
@ -332,7 +332,7 @@ void CSpellWindow::computeSpellsPerArea()
spellsCurSite.reserve(mySpells.size()); spellsCurSite.reserve(mySpells.size());
for(const CSpell * spell : mySpells) for(const CSpell * spell : mySpells)
{ {
if(spell->isCombatSpell() ^ !battleSpellsOnly if(spell->isCombat() ^ !battleSpellsOnly
&& ((selectedTab == 4) || spell->school.at((ESpellSchool)selectedTab)) && ((selectedTab == 4) || spell->school.at((ESpellSchool)selectedTab))
) )
{ {
@ -522,7 +522,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
{ {
if(mySpell && !down) if(mySpell && !down)
{ {
int spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero); auto spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero);
if(spellCost > owner->myHero->mana) //insufficient mana if(spellCost > owner->myHero->mana) //insufficient mana
{ {
owner->myInt->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana)); owner->myInt->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana));
@ -531,8 +531,8 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
//anything that is not combat spell is adventure spell //anything that is not combat spell is adventure spell
//this not an error in general to cast even creature ability with hero //this not an error in general to cast even creature ability with hero
const bool combatSpell = mySpell->isCombatSpell(); const bool combatSpell = mySpell->isCombat();
if(mySpell->isCombatSpell() != !mySpell->isAdventureSpell()) if(combatSpell == mySpell->isAdventure())
{ {
logGlobal->error("Spell have invalid flags"); logGlobal->error("Spell have invalid flags");
return; return;
@ -545,7 +545,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
if((combatSpell ^ inCombat) || inCastle) if((combatSpell ^ inCombat) || inCastle)
{ {
std::vector<std::shared_ptr<CComponent>> hlp(1, std::make_shared<CComponent>(CComponent::spell, mySpell->id, 0)); std::vector<std::shared_ptr<CComponent>> hlp(1, std::make_shared<CComponent>(CComponent::spell, mySpell->id, 0));
owner->myInt->showInfoDialog(mySpell->getLevelInfo(schoolLevel).description, hlp); owner->myInt->showInfoDialog(mySpell->getLevelDescription(schoolLevel), hlp);
} }
else if(combatSpell) else if(combatSpell)
{ {
@ -600,7 +600,7 @@ void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState)
boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(causedDmg)); boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(causedDmg));
} }
CRClickPopup::createAndPush(mySpell->getLevelInfo(schoolLevel).description + dmgInfo, std::make_shared<CComponent>(CComponent::spell, mySpell->id)); CRClickPopup::createAndPush(mySpell->getLevelDescription(schoolLevel) + dmgInfo, std::make_shared<CComponent>(CComponent::spell, mySpell->id));
} }
} }
@ -625,7 +625,7 @@ void CSpellWindow::SpellArea::setSpell(const CSpell * spell)
mySpell = spell; mySpell = spell;
if(mySpell) if(mySpell)
{ {
int whichSchool = 0; //0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, int32_t whichSchool = 0; //0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
schoolLevel = owner->myHero->getSpellSchoolLevel(mySpell, &whichSchool); schoolLevel = owner->myHero->getSpellSchoolLevel(mySpell, &whichSchool);
auto spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero); auto spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero);

View File

@ -114,9 +114,9 @@ int CTradeWindow::CTradeableItem::getIndex()
case ARTIFACT_TYPE: case ARTIFACT_TYPE:
case ARTIFACT_INSTANCE: case ARTIFACT_INSTANCE:
case ARTIFACT_PLACEHOLDER: case ARTIFACT_PLACEHOLDER:
return VLC->arth->artifacts[id]->iconIndex; return CGI->artifacts()->getByIndex(id)->getIconIndex();
case CREATURE: case CREATURE:
return VLC->creh->creatures[id]->iconIndex; return CGI->creatures()->getByIndex(id)->getIconIndex();
default: default:
return -1; return -1;
} }
@ -244,13 +244,13 @@ void CTradeWindow::CTradeableItem::hover(bool on)
{ {
case CREATURE: case CREATURE:
case CREATURE_PLACEHOLDER: case CREATURE_PLACEHOLDER:
GH.statusbar->setText(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl)); GH.statusbar->setText(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->namePl));
break; break;
case ARTIFACT_PLACEHOLDER: case ARTIFACT_PLACEHOLDER:
if(id < 0) if(id < 0)
GH.statusbar->setText(CGI->generaltexth->zelp[582].first); GH.statusbar->setText(CGI->generaltexth->zelp[582].first);
else else
GH.statusbar->setText(CGI->arth->artifacts[id]->Name()); GH.statusbar->setText(CGI->artifacts()->getByIndex(id)->getName());
break; break;
} }
} }
@ -263,13 +263,13 @@ void CTradeWindow::CTradeableItem::clickRight(tribool down, bool previousState)
{ {
case CREATURE: case CREATURE:
case CREATURE_PLACEHOLDER: case CREATURE_PLACEHOLDER:
//GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl)); //GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->namePl));
break; break;
case ARTIFACT_TYPE: case ARTIFACT_TYPE:
case ARTIFACT_PLACEHOLDER: case ARTIFACT_PLACEHOLDER:
//TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription. //TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription.
if(id >= 0) if(id >= 0)
adventureInt->handleRightClick(CGI->arth->artifacts[id]->Description(), down); adventureInt->handleRightClick(CGI->artifacts()->getByIndex(id)->getDescription(), down);
break; break;
} }
} }
@ -285,14 +285,14 @@ std::string CTradeWindow::CTradeableItem::getName(int number) const
return CGI->generaltexth->restypes[id]; return CGI->generaltexth->restypes[id];
case CREATURE: case CREATURE:
if(number == 1) if(number == 1)
return CGI->creh->creatures[id]->nameSing; return CGI->creh->objects[id]->nameSing;
else else
return CGI->creh->creatures[id]->namePl; return CGI->creh->objects[id]->namePl;
case ARTIFACT_TYPE: case ARTIFACT_TYPE:
case ARTIFACT_INSTANCE: case ARTIFACT_INSTANCE:
return CGI->arth->artifacts[id]->Name(); return CGI->artifacts()->getByIndex(id)->getName();
} }
assert(0); logGlobal->error("Invalid trade item type: %d", (int)type);
return ""; return "";
} }
@ -668,14 +668,14 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta
switch (mode) switch (mode)
{ {
case EMarketMode::CREATURE_RESOURCE: case EMarketMode::CREATURE_RESOURCE:
title = CGI->townh->factions[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->Name(); title = (*CGI->townh)[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->Name();
break; break;
case EMarketMode::RESOURCE_ARTIFACT: case EMarketMode::RESOURCE_ARTIFACT:
title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name(); title = (*CGI->townh)[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
sliderNeeded = false; sliderNeeded = false;
break; break;
case EMarketMode::ARTIFACT_RESOURCE: case EMarketMode::ARTIFACT_RESOURCE:
title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name(); title = (*CGI->townh)[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
sliderNeeded = false; sliderNeeded = false;
break; break;
default: default:

View File

@ -159,7 +159,7 @@ void CRecruitmentWindow::buy()
if(dst->ID == Obj::HERO) if(dst->ID == Obj::HERO)
{ {
txt = CGI->generaltexth->allTexts[425]; //The %s would join your hero, but there aren't enough provisions to support them. txt = CGI->generaltexth->allTexts[425]; //The %s would join your hero, but there aren't enough provisions to support them.
boost::algorithm::replace_first(txt, "%s", slider->getValue() > 1 ? CGI->creh->creatures[crid]->namePl : CGI->creh->creatures[crid]->nameSing); boost::algorithm::replace_first(txt, "%s", slider->getValue() > 1 ? CGI->creh->objects[crid]->namePl : CGI->creh->objects[crid]->nameSing);
} }
else else
{ {
@ -249,7 +249,7 @@ void CRecruitmentWindow::availableCreaturesChanged()
//create new cards //create new cards
for(auto & creature : boost::adaptors::reverse(dwelling->creatures[i].second)) for(auto & creature : boost::adaptors::reverse(dwelling->creatures[i].second))
cards.push_back(std::make_shared<CCreatureCard>(this, CGI->creh->creatures[creature], amount)); cards.push_back(std::make_shared<CCreatureCard>(this, CGI->creh->objects[creature], amount));
} }
const int creatureWidth = 102; const int creatureWidth = 102;
@ -1040,7 +1040,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
int faction = LOCPLINT->cb->getStartInfo()->playerInfos.find(LOCPLINT->playerID)->second.castle; int faction = LOCPLINT->cb->getStartInfo()->playerInfos.find(LOCPLINT->playerID)->second.castle;
auto & puzzleMap = CGI->townh->factions[faction]->puzzleMap; auto & puzzleMap = (*CGI->townh)[faction]->puzzleMap;
for(auto & elem : puzzleMap) for(auto & elem : puzzleMap)
{ {
@ -1276,10 +1276,10 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket
{ {
auto faction = town->town->faction->index; auto faction = town->town->faction->index;
auto bid = town->town->getSpecialBuilding(BuildingSubID::MAGIC_UNIVERSITY)->bid; auto bid = town->town->getSpecialBuilding(BuildingSubID::MAGIC_UNIVERSITY)->bid;
titlePic = std::make_shared<CAnimImage>(CGI->townh->factions[faction]->town->clientInfo.buildingsIcons, bid); titlePic = std::make_shared<CAnimImage>((*CGI->townh)[faction]->town->clientInfo.buildingsIcons, bid);
} }
else else
titlePic = std::make_shared<CAnimImage>(CGI->townh->factions[ETownType::CONFLUX]->town->clientInfo.buildingsIcons, BuildingID::MAGIC_UNIVERSITY); titlePic = std::make_shared<CAnimImage>((*CGI->townh)[ETownType::CONFLUX]->town->clientInfo.buildingsIcons, BuildingID::MAGIC_UNIVERSITY);
} }
else else
titlePic = std::make_shared<CPicture>("UNIVBLDG"); titlePic = std::make_shared<CPicture>("UNIVBLDG");

View File

@ -0,0 +1,50 @@
# Locate LuaJIT library
# This module defines
# LUAJIT_FOUND, if false, do not try to link to Lua
# LUA_INCLUDE_DIR, where to find lua.h
# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
#
# This module is similar to FindLua51.cmake except that it finds LuaJit instead.
FIND_PATH(LUA_INCLUDE_DIR luajit.h
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES include/luajit include/luajit-2.1 include/luajit-2.0 include/luajit-5_1-2.1 include/luajit-5_1-2.0 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
FIND_LIBRARY(LUA_LIBRARY
NAMES luajit-5.1 lua51
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw
/opt/local
/opt/csw
/opt
)
IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/luajit.h")
FILE(STRINGS "${LUA_INCLUDE_DIR}/luajit.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT .+\"")
STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
UNSET(lua_version_str)
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LuaJit
REQUIRED_VARS LUA_LIBRARY LUA_INCLUDE_DIR
VERSION_VAR LUA_VERSION_STRING)
MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY)

View File

@ -48,6 +48,10 @@
"MODS/": "MODS/":
[ [
{"type" : "dir", "path" : "Mods", "depth": 1} {"type" : "dir", "path" : "Mods", "depth": 1}
],
"SCRIPTS/":
[
{"type" : "dir", "path" : "scripts"}
] ]
} }
} }

View File

@ -92,6 +92,11 @@
"description": "List of configuration files for objects", "description": "List of configuration files for objects",
"items": { "type":"string", "format" : "textFile" } "items": { "type":"string", "format" : "textFile" }
}, },
"scripts": {
"type":"array",
"description": "List of configuration files for scripts",
"items": { "type":"string", "format" : "textFile" }
},
"spells": { "spells": {
"type":"array", "type":"array",
"description": "List of configuration files for spells", "description": "List of configuration files for spells",

View File

@ -0,0 +1,22 @@
{
"type" : "object",
"$schema" : "http://json-schema.org/draft-04/schema",
"title" : "VCMI script format",
"description" : "Format used to configure script environment",
"required" : ["source"],
"properties" : {
"source" : {
"type": "string",
"description": "Full VFS path to script source (extension required)"
},
"implements" :{
"type": "string",
"enum": ["ANYTHING", "BATTLE_EFFECT"],
"description": ""
}
}
}

27
include/vcmi/Artifact.h Normal file
View File

@ -0,0 +1,27 @@
/*
* Artifact.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class ArtifactID;
class CreatureID;
class DLL_LINKAGE Artifact : public EntityWithBonuses<ArtifactID>
{
public:
virtual bool isBig() const = 0;
virtual bool isTradable() const = 0;
virtual const std::string & getDescription() const = 0;
virtual const std::string & getEventText() const = 0;
virtual uint32_t getPrice() const = 0;
virtual CreatureID getWarMachine() const = 0;
};

View File

@ -0,0 +1,21 @@
/*
* ArtifactService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class ArtifactID;
class Artifact;
class DLL_LINKAGE ArtifactService : public EntityServiceT<ArtifactID, Artifact>
{
public:
};

45
include/vcmi/Creature.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Creature.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class CreatureID;
class DLL_LINKAGE Creature : public EntityWithBonuses<CreatureID>
{
public:
virtual const std::string & getPluralName() const = 0;
virtual const std::string & getSingularName() const = 0;
virtual uint32_t getMaxHealth() const = 0;
virtual int32_t getAdvMapAmountMin() const = 0;
virtual int32_t getAdvMapAmountMax() const = 0;
virtual int32_t getAIValue() const = 0;
virtual int32_t getFightValue() const = 0;
virtual int32_t getLevel() const = 0;
virtual int32_t getGrowth() const = 0;
virtual int32_t getHorde() const = 0;
virtual int32_t getFactionIndex() const = 0;
virtual int32_t getBaseAttack() const = 0;
virtual int32_t getBaseDefense() const = 0;
virtual int32_t getBaseDamageMin() const = 0;
virtual int32_t getBaseDamageMax() const = 0;
virtual int32_t getBaseHitPoints() const = 0;
virtual int32_t getBaseSpellPoints() const = 0;
virtual int32_t getBaseSpeed() const = 0;
virtual int32_t getBaseShots() const = 0;
virtual int32_t getCost(int32_t resIndex) const = 0;
virtual bool isDoubleWide() const = 0;
};

View File

@ -0,0 +1,21 @@
/*
* CreatureService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class CreatureID;
class Creature;
class DLL_LINKAGE CreatureService : public EntityServiceT<CreatureID, Creature>
{
public:
};

42
include/vcmi/Entity.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Entity.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
class IBonusBearer;
class DLL_LINKAGE Entity
{
public:
using IconRegistar = std::function<void(int32_t index, const std::string & listName, const std::string & imageName)>;
virtual ~Entity() = default;
virtual int32_t getIndex() const = 0;
virtual int32_t getIconIndex() const = 0;
virtual const std::string & getJsonKey() const = 0;
virtual const std::string & getName() const = 0;
virtual void registerIcons(const IconRegistar & cb) const = 0;
};
template <typename IdType>
class DLL_LINKAGE EntityT : public Entity
{
public:
virtual IdType getId() const = 0;
};
template <typename IdType>
class DLL_LINKAGE EntityWithBonuses : public EntityT<IdType>
{
public:
virtual const IBonusBearer * accessBonuses() const = 0;
};

View File

@ -0,0 +1,32 @@
/*
* EntityService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
class Entity;
class DLL_LINKAGE EntityService
{
public:
virtual ~EntityService() = default;
virtual const Entity * getBaseByIndex(const int32_t index) const = 0;
virtual void forEachBase(const std::function<void(const Entity * entity, bool & stop)> & cb) const = 0;
};
template <typename IdType, typename EntityType>
class DLL_LINKAGE EntityServiceT : public EntityService
{
public:
virtual const EntityType * getById(const IdType & id) const = 0;
virtual const EntityType * getByIndex(const int32_t index) const = 0;
virtual void forEach(const std::function<void(const EntityType * entity, bool & stop)> & cb) const = 0;
};

View File

@ -0,0 +1,36 @@
/*
* Environment.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
class Services;
class IGameInfoCallback;
class IBattleInfoCallback;
namespace events
{
class EventBus;
}
class DLL_LINKAGE Environment
{
public:
using BattleCb = ::IBattleInfoCallback;
using GameCb = ::IGameInfoCallback;
virtual ~Environment() = default;
virtual const Services * services() const = 0;
virtual const BattleCb * battle() const = 0;
virtual const GameCb * game() const = 0;
virtual vstd::CLoggerBase * logger() const = 0;
virtual events::EventBus * eventBus() const = 0;
};

21
include/vcmi/Faction.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Faction.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class FactionID;
class DLL_LINKAGE Faction : public EntityT<FactionID>
{
public:
virtual bool hasTown() const = 0;
};

View File

@ -0,0 +1,21 @@
/*
* FactionService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class FactionID;
class Faction;
class DLL_LINKAGE FactionService : public EntityServiceT<FactionID, Faction>
{
public:
};

22
include/vcmi/HeroClass.h Normal file
View File

@ -0,0 +1,22 @@
/*
* HeroClass.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class HeroClassID;
class DLL_LINKAGE HeroClass : public EntityT<HeroClassID>
{
public:
};

View File

@ -0,0 +1,21 @@
/*
* HeroClassService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class HeroClassID;
class HeroClass;
class DLL_LINKAGE HeroClassService : public EntityServiceT<HeroClassID, HeroClass>
{
public:
};

22
include/vcmi/HeroType.h Normal file
View File

@ -0,0 +1,22 @@
/*
* HeroType.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class HeroTypeID;
class DLL_LINKAGE HeroType : public EntityT<HeroTypeID>
{
public:
};

View File

@ -0,0 +1,21 @@
/*
* HeroTypeService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class HeroTypeID;
class HeroType;
class DLL_LINKAGE HeroTypeService : public EntityServiceT<HeroTypeID, HeroType>
{
public:
};

30
include/vcmi/Metatype.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Metatype.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
enum class Metatype : uint32_t
{
UNKNOWN = 0,
ARTIFACT,
ARTIFACT_INSTANCE,
CREATURE,
CREATURE_INSTANCE,
FACTION,
HERO_CLASS,
HERO_TYPE,
HERO_INSTANCE,
MAP_OBJECT_GROUP,
MAP_OBJECT_TYPE,
MAP_OBJECT_INSTANCE,
SKILL,
SPELL
};

30
include/vcmi/Player.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Player.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
class PlayerColor;
class TeamID;
class IBonusBearer;
class DLL_LINKAGE Player
{
public:
virtual PlayerColor getColor() const = 0;
virtual TeamID getTeam() const = 0;
virtual bool isHuman() const = 0;
virtual const IBonusBearer * accessBonuses() const = 0;
virtual int getResourceAmount(int type) const = 0;
};

View File

@ -0,0 +1,44 @@
/*
* ServerCallback.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace vstd
{
class RNG;
}
struct CPackForClient;
struct BattleLogMessage;
struct BattleStackMoved;
struct BattleUnitsChanged;
struct SetStackEffect;
struct StacksInjured;
struct BattleObstaclesChanged;
struct CatapultAttack;
class DLL_LINKAGE ServerCallback
{
public:
virtual void complain(const std::string & problem) = 0;
virtual bool describeChanges() const = 0;
virtual vstd::RNG * getRNG() = 0;
virtual void apply(CPackForClient * pack) = 0;
virtual void apply(BattleLogMessage * pack) = 0;
virtual void apply(BattleStackMoved * pack) = 0;
virtual void apply(BattleUnitsChanged * pack) = 0;
virtual void apply(SetStackEffect * pack) = 0;
virtual void apply(StacksInjured * pack) = 0;
virtual void apply(BattleObstaclesChanged * pack) = 0;
virtual void apply(CatapultAttack * pack) = 0;
};

57
include/vcmi/Services.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Services.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Metatype.h"
class ArtifactService;
class CreatureService;
class FactionService;
class HeroClassService;
class HeroTypeService;
class SkillService;
class JsonNode;
namespace spells
{
class Service;
namespace effects
{
class Registry;
}
}
namespace scripting
{
class Service;
}
class DLL_LINKAGE Services
{
public:
virtual ~Services() = default;
virtual const ArtifactService * artifacts() const = 0;
virtual const CreatureService * creatures() const = 0;
virtual const FactionService * factions() const = 0;
virtual const HeroClassService * heroClasses() const = 0;
virtual const HeroTypeService * heroTypes() const = 0;
virtual const scripting::Service * scripts() const = 0;
virtual const spells::Service * spells() const = 0;
virtual const SkillService * skills() const = 0;
virtual void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) = 0;
virtual const spells::effects::Registry * spellEffects() const = 0;
virtual spells::effects::Registry * spellEffects() = 0;
//TODO: put map object types registry access here
};

22
include/vcmi/Skill.h Normal file
View File

@ -0,0 +1,22 @@
/*
* Skill.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Entity.h"
class SecondarySkill;
class DLL_LINKAGE Skill : public EntityT<SecondarySkill>
{
public:
};

View File

@ -0,0 +1,21 @@
/*
* SkillService.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "EntityService.h"
class SecondarySkill;
class Skill;
class DLL_LINKAGE SkillService : public EntityServiceT<SecondarySkill, Skill>
{
public:
};

15
include/vcmi/Team.h Normal file
View File

@ -0,0 +1,15 @@
/*
* Team.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once

View File

@ -0,0 +1,13 @@
/*
* AdventureEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "ObjectVisitEnded.h"
#include "ObjectVisitStarted.h"

View File

@ -0,0 +1,45 @@
/*
* ApplyDamage.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Event.h"
#include "SubscriptionRegistry.h"
struct BattleStackAttacked;
namespace battle
{
class Unit;
}
namespace events
{
class DLL_LINKAGE ApplyDamage : public Event
{
public:
using Sub = SubscriptionRegistry<ApplyDamage>;
using PreHandler = Sub::PreHandler;
using PostHandler = Sub::PostHandler;
using ExecHandler = Sub::ExecHandler;
static Sub * getRegistry();
virtual int64_t getInitalDamage() const = 0;
virtual int64_t getDamage() const = 0;
virtual void setDamage(int64_t value) = 0;
virtual const battle::Unit * getTarget() const = 0;
friend class SubscriptionRegistry<ApplyDamage>;
};
}

View File

@ -0,0 +1,13 @@
/*
* BattleEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "ApplyDamage.h"

View File

@ -0,0 +1,29 @@
/*
* Event.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace events
{
class EventBus;
template <typename T>
class SubscriptionRegistry;
class DLL_LINKAGE Event
{
public:
virtual bool isEnabled() const = 0;
};
}

View File

@ -0,0 +1,44 @@
/*
* EventBus.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "SubscriptionRegistry.h"
class Environment;
namespace events
{
class DLL_LINKAGE EventBus : public boost::noncopyable
{
public:
template <typename E>
std::unique_ptr<EventSubscription> subscribeBefore(typename E::PreHandler && cb)
{
auto registry = E::getRegistry();
return registry->subscribeBefore(this, std::move(cb));
}
template <typename E>
std::unique_ptr<EventSubscription> subscribeAfter(typename E::PostHandler && cb)
{
auto registry = E::getRegistry();
return registry->subscribeAfter(this, std::move(cb));
}
template <typename E>
void executeEvent(E & event, const typename E::ExecHandler & execHandler = typename E::ExecHandler()) const
{
auto registry = E::getRegistry();
registry->executeEvent(this, event, execHandler);
}
};
}

View File

@ -0,0 +1,35 @@
/*
* GameResumed.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Event.h"
#include "SubscriptionRegistry.h"
namespace events
{
class DLL_LINKAGE GameResumed : public Event
{
public:
using Sub = SubscriptionRegistry<GameResumed>;
using PreHandler = Sub::PreHandler;
using PostHandler = Sub::PostHandler;
using ExecHandler = Sub::ExecHandler;
static Sub * getRegistry();
static void defaultExecute(const EventBus * bus);
friend class SubscriptionRegistry<GameResumed>;
};
}

View File

@ -0,0 +1,15 @@
/*
* GenericEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "GameResumed.h"
#include "PlayerGotTurn.h"
#include "TurnStarted.h"

View File

@ -0,0 +1,40 @@
/*
* ObjectVisitEnded.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Event.h"
#include "SubscriptionRegistry.h"
class PlayerColor;
class ObjectInstanceID;
namespace events
{
class DLL_LINKAGE ObjectVisitEnded : public Event
{
public:
using Sub = SubscriptionRegistry<ObjectVisitEnded>;
using PreHandler = Sub::PreHandler;
using PostHandler = Sub::PostHandler;
using ExecHandler = Sub::ExecHandler;
virtual PlayerColor getPlayer() const = 0;
virtual ObjectInstanceID getHero() const = 0;
static Sub * getRegistry();
static void defaultExecute(const EventBus * bus, const ExecHandler & execHandler,
const PlayerColor & player, const ObjectInstanceID & heroId);
friend class SubscriptionRegistry<ObjectVisitEnded>;
};
}

View File

@ -0,0 +1,43 @@
/*
* ObjectVisitStarted.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Event.h"
#include "SubscriptionRegistry.h"
class PlayerColor;
class ObjectInstanceID;
namespace events
{
class DLL_LINKAGE ObjectVisitStarted : public Event
{
public:
using Sub = SubscriptionRegistry<ObjectVisitStarted>;
using PreHandler = Sub::PreHandler;
using PostHandler = Sub::PostHandler;
using ExecHandler = Sub::ExecHandler;
virtual PlayerColor getPlayer() const = 0;
virtual ObjectInstanceID getHero() const = 0;
virtual ObjectInstanceID getObject() const = 0;
virtual void setEnabled(bool enable) = 0;
static Sub * getRegistry();
static void defaultExecute(const EventBus * bus, const ExecHandler & execHandler,
const PlayerColor & player, const ObjectInstanceID & heroId, const ObjectInstanceID & objId);
friend class SubscriptionRegistry<ObjectVisitStarted>;
};
}

View File

@ -0,0 +1,41 @@
/*
* PlayerGotTurn.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Event.h"
#include "SubscriptionRegistry.h"
class PlayerColor;
namespace events
{
class DLL_LINKAGE PlayerGotTurn : public Event
{
public:
using Sub = SubscriptionRegistry<PlayerGotTurn>;
using PreHandler = Sub::PreHandler;
using PostHandler = Sub::PostHandler;
using ExecHandler = Sub::ExecHandler;
static Sub * getRegistry();
static void defaultExecute(const EventBus * bus, const ExecHandler & execHandler, PlayerColor & player);
virtual PlayerColor getPlayer() const = 0;
virtual void setPlayer(const PlayerColor & value) = 0;
virtual int32_t getPlayerIndex() const = 0;
virtual void setPlayerIndex(int32_t value) = 0;
friend class SubscriptionRegistry<PlayerGotTurn>;
};
}

Some files were not shown because too many files have changed in this diff Show More