1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-27 22:49:25 +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

@@ -10,8 +10,6 @@
#include "StdInc.h"
#include "BattleAI.h"
#include <vstd/RNG.h>
#include "StackWithBonuses.h"
#include "EnemyInfo.h"
#include "../../lib/CStopWatch.h"
@@ -26,26 +24,6 @@
#define LOGL(text) print(text)
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
class RNGStub : public vstd::RNG
{
public:
vstd::TRandI64 getInt64Range(int64_t lower, int64_t upper) override
{
return [=]()->int64_t
{
return (lower + upper)/2;
};
}
vstd::TRand getDoubleRange(double lower, double upper) override
{
return [=]()->double
{
return (lower + upper)/2;
};
}
};
enum class SpellTypes
{
ADVENTURE, BATTLE, OTHER
@@ -53,10 +31,10 @@ enum class SpellTypes
SpellTypes spellType(const CSpell * spell)
{
if(!spell->isCombatSpell() || spell->isCreatureAbility())
if(!spell->isCombat() || spell->isCreatureAbility())
return SpellTypes::OTHER;
if(spell->isOffensiveSpell() || spell->hasEffects() || spell->hasBattleEffects())
if(spell->isOffensive() || spell->hasEffects() || spell->hasBattleEffects())
return SpellTypes::BATTLE;
return SpellTypes::OTHER;
@@ -83,7 +61,9 @@ std::vector<BattleHex> CBattleAI::getBrokenWallMoatHexes() const
}
CBattleAI::CBattleAI()
: side(-1), wasWaitingForRealize(false), wasUnlockingGs(false)
: side(-1),
wasWaitingForRealize(false),
wasUnlockingGs(false)
{
}
@@ -97,12 +77,13 @@ CBattleAI::~CBattleAI()
}
}
void CBattleAI::init(std::shared_ptr<CBattleCallback> CB)
void CBattleAI::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB)
{
setCbc(CB);
env = ENV;
cb = CB;
playerID = *CB->getPlayerID(); //TODO should be sth in callback
wasWaitingForRealize = cb->waitTillRealize;
wasWaitingForRealize = CB->waitTillRealize;
wasUnlockingGs = CB->unlockGsWhenWaiting;
CB->waitTillRealize = true;
CB->unlockGsWhenWaiting = false;
@@ -131,7 +112,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
attemptCastingSpell();
if(auto ret = getCbc()->battleIsFinished())
if(auto ret = cb->battleIsFinished())
{
//spellcast may finish battle
//send special preudo-action
@@ -144,7 +125,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
return *action;
//best action is from effective owner point if view, we are effective owner as we received "activeStack"
//evaluate casting spell for spellcasting stack
boost::optional<PossibleSpellcast> bestSpellcast(boost::none);
//TODO: faerie dragon type spell should be selected by server
@@ -174,7 +155,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
}
}
HypotheticBattle hb(getCbc());
HypotheticBattle hb(env.get(), cb);
PotentialTargets targets(stack, &hb);
@@ -199,7 +180,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
);
return BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
}
}
}
else if(bestSpellcast.is_initialized())
{
@@ -210,7 +191,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
if(stack->waited())
{
//ThreatMap threatsToUs(stack); // These lines may be usefull but they are't used in the code.
auto dists = getCbc()->getReachability(stack);
auto dists = cb->getReachability(stack);
if(!targets.unreachableEnemies.empty())
{
auto closestEnemy = vstd::minElementByFun(targets.unreachableEnemies, [&](const battle::Unit * enemy) -> int
@@ -242,7 +223,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
else
return goTowardsNearest(stack, brokenWallMoat);
}
}
}
}
catch(boost::thread_interrupted &)
@@ -279,10 +260,10 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl
if(stack->coversPos(hex))
{
logAi->warn("Warning: already standing on neighbouring tile!");
//We shouldn't even be here...
return BattleAction::makeDefend(stack);
}
logAi->warn("Warning: already standing on neighbouring tile!");
//We shouldn't even be here...
return BattleAction::makeDefend(stack);
}
}
BattleHex bestNeighbor = hexes.front();
@@ -330,7 +311,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
if(cb->battleGetGateState() == EGateState::CLOSED)
{
targetHex = cb->wallPartToBattleHex(EWallPart::GATE);
}
}
else
{
EWallPart::EWallPart wallParts[] = {
@@ -381,9 +362,9 @@ void CBattleAI::attemptCastingSpell()
LOGL("Casting spells sounds like fun. Let's see...");
//Get all spells we can cast
std::vector<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());
@@ -398,7 +379,7 @@ void CBattleAI::attemptCastingSpell()
std::vector<PossibleSpellcast> possibleCasts;
for(auto spell : possibleSpells)
{
spells::BattleCast temp(getCbc().get(), hero, spells::Mode::HERO, spell);
spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell);
for(auto & target : temp.findPotentialTargets())
{
@@ -500,8 +481,6 @@ void CBattleAI::attemptCastingSpell()
return ourTurnSpan >= minTurnSpan;
};
RNGStub rngStub;
ValueMap valueOfStack;
ValueMap healthOfStack;
@@ -536,7 +515,8 @@ void CBattleAI::attemptCastingSpell()
{
bool enemyHadTurn = false;
HypotheticBattle state(cb);
HypotheticBattle state(env.get(), cb);
evaluateQueue(valueOfStack, turnOrder, &state, 0, &enemyHadTurn);
if(!enemyHadTurn)
@@ -551,13 +531,17 @@ void CBattleAI::attemptCastingSpell()
}
}
auto evaluateSpellcast = [&] (PossibleSpellcast * ps)
struct ScriptsCache
{
HypotheticBattle state(cb);
//todo: re-implement scripts context cache
};
auto evaluateSpellcast = [&] (PossibleSpellcast * ps, std::shared_ptr<ScriptsCache>)
{
HypotheticBattle state(env.get(), cb);
spells::BattleCast cast(&state, hero, spells::Mode::HERO, ps->spell);
cast.target = ps->dest;
cast.cast(&state, rngStub);
cast.castEval(state.getServerCallback(), ps->dest);
ValueMap newHealthOfStack;
ValueMap newValueOfStack;
@@ -617,10 +601,12 @@ void CBattleAI::attemptCastingSpell()
}
};
std::vector<std::function<void()>> tasks;
using EvalRunner = ThreadPool<ScriptsCache>;
EvalRunner::Tasks tasks;
for(PossibleSpellcast & psc : possibleCasts)
tasks.push_back(std::bind(evaluateSpellcast, &psc));
tasks.push_back(std::bind(evaluateSpellcast, &psc, _1));
uint32_t threadCount = boost::thread::hardware_concurrency();
@@ -632,8 +618,15 @@ void CBattleAI::attemptCastingSpell()
CStopWatch timer;
CThreadHelper threadHelper(&tasks, threadCount);
threadHelper.run();
std::vector<std::shared_ptr<ScriptsCache>> scriptsPool;
for(uint32_t idx = 0; idx < threadCount; idx++)
{
scriptsPool.emplace_back();
}
EvalRunner runner(&tasks, scriptsPool);
runner.run();
LOGFL("Evaluation took %d ms", timer.getDiff());
@@ -666,9 +659,9 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
using ValueMap = PossibleSpellcast::ValueMap;
RNGStub rngStub;
HypotheticBattle state(getCbc());
TStacks all = getCbc()->battleGetAllStacks(false);
HypotheticBattle state(env.get(), cb);
TStacks all = cb->battleGetAllStacks(false);
ValueMap healthOfStack;
ValueMap newHealthOfStack;
@@ -678,8 +671,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
}
spells::BattleCast cast(&state, stack, spells::Mode::CREATURE_ACTIVE, ps.spell);
cast.target = ps.dest;
cast.cast(&state, rngStub);
cast.castEval(state.getServerCallback(), ps.dest);
for(auto unit : all)
{
@@ -710,7 +702,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
}
ps.value = totalGain;
};
}
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
{