1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Merge remote-tracking branch 'upstream/develop' into launcher-size-support

This commit is contained in:
nordsoft 2023-09-08 01:51:52 +02:00
commit 8c94d082c8
412 changed files with 4960 additions and 4248 deletions

View File

@ -52,7 +52,7 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
setCbc(CB); setCbc(CB);
env = ENV; env = ENV;
cb = CB; cb = CB;
playerID = *CB->getPlayerID(); //TODO should be sth in callback playerID = *CB->getPlayerID();
wasWaitingForRealize = CB->waitTillRealize; wasWaitingForRealize = CB->waitTillRealize;
wasUnlockingGs = CB->unlockGsWhenWaiting; wasUnlockingGs = CB->unlockGsWhenWaiting;
CB->waitTillRealize = false; CB->waitTillRealize = false;
@ -66,9 +66,9 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
autobattlePreferences = autocombatPreferences; autobattlePreferences = autocombatPreferences;
} }
BattleAction CBattleAI::useHealingTent(const CStack *stack) BattleAction CBattleAI::useHealingTent(const BattleID & battleID, const CStack *stack)
{ {
auto healingTargets = cb->battleGetStacks(CBattleInfoEssentials::ONLY_MINE); auto healingTargets = cb->getBattle(battleID)->battleGetStacks(CBattleInfoEssentials::ONLY_MINE);
std::map<int, const CStack*> woundHpToStack; std::map<int, const CStack*> woundHpToStack;
for(const auto * stack : healingTargets) for(const auto * stack : healingTargets)
{ {
@ -82,12 +82,12 @@ BattleAction CBattleAI::useHealingTent(const CStack *stack)
return BattleAction::makeHeal(stack, woundHpToStack.rbegin()->second); //last element of the woundHpToStack is the most wounded stack return BattleAction::makeHeal(stack, woundHpToStack.rbegin()->second); //last element of the woundHpToStack is the most wounded stack
} }
void CBattleAI::yourTacticPhase(int distance) void CBattleAI::yourTacticPhase(const BattleID & battleID, int distance)
{ {
cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide()));
} }
float getStrengthRatio(std::shared_ptr<CBattleCallback> cb, int side) static float getStrengthRatio(std::shared_ptr<CBattleInfoCallback> cb, int side)
{ {
auto stacks = cb->battleGetAllStacks(); auto stacks = cb->battleGetAllStacks();
auto our = 0, enemy = 0; auto our = 0, enemy = 0;
@ -108,7 +108,7 @@ float getStrengthRatio(std::shared_ptr<CBattleCallback> cb, int side)
return enemy == 0 ? 1.0f : static_cast<float>(our) / enemy; return enemy == 0 ? 1.0f : static_cast<float>(our) / enemy;
} }
void CBattleAI::activeStack(const CStack * stack ) void CBattleAI::activeStack(const BattleID & battleID, const CStack * stack )
{ {
LOG_TRACE_PARAMS(logAi, "stack: %s", stack->nodeName()); LOG_TRACE_PARAMS(logAi, "stack: %s", stack->nodeName());
@ -128,12 +128,12 @@ void CBattleAI::activeStack(const CStack * stack )
{ {
if(stack->creatureId() == CreatureID::CATAPULT) if(stack->creatureId() == CreatureID::CATAPULT)
{ {
cb->battleMakeUnitAction(useCatapult(stack)); cb->battleMakeUnitAction(battleID, useCatapult(battleID, stack));
return; return;
} }
if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON) && stack->hasBonusOfType(BonusType::HEALER)) if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON) && stack->hasBonusOfType(BonusType::HEALER))
{ {
cb->battleMakeUnitAction(useHealingTent(stack)); cb->battleMakeUnitAction(battleID, useHealingTent(battleID, stack));
return; return;
} }
@ -141,7 +141,7 @@ void CBattleAI::activeStack(const CStack * stack )
logAi->trace("Build evaluator and targets"); logAi->trace("Build evaluator and targets");
#endif #endif
BattleEvaluator evaluator(env, cb, stack, playerID, side, getStrengthRatio(cb, side)); BattleEvaluator evaluator(env, cb, stack, playerID, battleID, side, getStrengthRatio(cb->getBattle(battleID), side));
result = evaluator.selectStackAction(stack); result = evaluator.selectStackAction(stack);
@ -157,9 +157,9 @@ void CBattleAI::activeStack(const CStack * stack )
logAi->trace("Spellcast attempt completed in %lld", timeElapsed(start)); logAi->trace("Spellcast attempt completed in %lld", timeElapsed(start));
if(auto action = considerFleeingOrSurrendering()) if(auto action = considerFleeingOrSurrendering(battleID))
{ {
cb->battleMakeUnitAction(*action); cb->battleMakeUnitAction(battleID, *action);
return; return;
} }
} }
@ -183,17 +183,17 @@ void CBattleAI::activeStack(const CStack * stack )
logAi->trace("BattleAI decission made in %lld", timeElapsed(start)); logAi->trace("BattleAI decission made in %lld", timeElapsed(start));
cb->battleMakeUnitAction(result); cb->battleMakeUnitAction(battleID, result);
} }
BattleAction CBattleAI::useCatapult(const CStack * stack) BattleAction CBattleAI::useCatapult(const BattleID & battleID, const CStack * stack)
{ {
BattleAction attack; BattleAction attack;
BattleHex targetHex = BattleHex::INVALID; BattleHex targetHex = BattleHex::INVALID;
if(cb->battleGetGateState() == EGateState::CLOSED) if(cb->getBattle(battleID)->battleGetGateState() == EGateState::CLOSED)
{ {
targetHex = cb->wallPartToBattleHex(EWallPart::GATE); targetHex = cb->getBattle(battleID)->wallPartToBattleHex(EWallPart::GATE);
} }
else else
{ {
@ -209,11 +209,11 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
for(auto wallPart : wallParts) for(auto wallPart : wallParts)
{ {
auto wallState = cb->battleGetWallState(wallPart); auto wallState = cb->getBattle(battleID)->battleGetWallState(wallPart);
if(wallState == EWallState::REINFORCED || wallState == EWallState::INTACT || wallState == EWallState::DAMAGED) if(wallState == EWallState::REINFORCED || wallState == EWallState::INTACT || wallState == EWallState::DAMAGED)
{ {
targetHex = cb->wallPartToBattleHex(wallPart); targetHex = cb->getBattle(battleID)->wallPartToBattleHex(wallPart);
break; break;
} }
} }
@ -234,7 +234,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
return attack; return attack;
} }
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
{ {
LOG_TRACE(logAi); LOG_TRACE(logAi);
side = Side; side = Side;
@ -244,20 +244,20 @@ void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2
void CBattleAI::print(const std::string &text) const void CBattleAI::print(const std::string &text) const
{ {
logAi->trace("%s Battle AI[%p]: %s", playerID.getStr(), this, text); logAi->trace("%s Battle AI[%p]: %s", playerID.toString(), this, text);
} }
std::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering() std::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering(const BattleID & battleID)
{ {
BattleStateInfoForRetreat bs; BattleStateInfoForRetreat bs;
bs.canFlee = cb->battleCanFlee(); bs.canFlee = cb->getBattle(battleID)->battleCanFlee();
bs.canSurrender = cb->battleCanSurrender(playerID); bs.canSurrender = cb->getBattle(battleID)->battleCanSurrender(playerID);
bs.ourSide = cb->battleGetMySide(); bs.ourSide = cb->getBattle(battleID)->battleGetMySide();
bs.ourHero = cb->battleGetMyHero(); bs.ourHero = cb->getBattle(battleID)->battleGetMyHero();
bs.enemyHero = nullptr; bs.enemyHero = nullptr;
for(auto stack : cb->battleGetAllStacks(false)) for(auto stack : cb->getBattle(battleID)->battleGetAllStacks(false))
{ {
if(stack->alive()) if(stack->alive())
{ {
@ -266,7 +266,7 @@ std::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
else else
{ {
bs.enemyStacks.push_back(stack); bs.enemyStacks.push_back(stack);
bs.enemyHero = cb->battleGetOwnerHero(stack); bs.enemyHero = cb->getBattle(battleID)->battleGetOwnerHero(stack);
} }
} }
} }
@ -278,7 +278,7 @@ std::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
return std::nullopt; return std::nullopt;
} }
auto result = cb->makeSurrenderRetreatDecision(bs); auto result = cb->makeSurrenderRetreatDecision(battleID, bs);
if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30) if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30)
{ {

View File

@ -71,16 +71,16 @@ public:
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override; void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override; void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override;
void activeStack(const CStack * stack) override; //called when it's turn of that stack void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack
void yourTacticPhase(int distance) override; void yourTacticPhase(const BattleID & battleID, int distance) override;
std::optional<BattleAction> considerFleeingOrSurrendering(); std::optional<BattleAction> considerFleeingOrSurrendering(const BattleID & battleID);
void print(const std::string &text) const; void print(const std::string &text) const;
BattleAction useCatapult(const CStack *stack); BattleAction useCatapult(const BattleID & battleID, const CStack *stack);
BattleAction useHealingTent(const CStack *stack); BattleAction useHealingTent(const BattleID & battleID, const CStack *stack);
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override; void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) 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
//void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack //void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack

View File

@ -53,12 +53,12 @@ std::vector<BattleHex> BattleEvaluator::getBrokenWallMoatHexes() const
for(EWallPart wallPart : { EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL }) for(EWallPart wallPart : { EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL })
{ {
auto state = cb->battleGetWallState(wallPart); auto state = cb->getBattle(battleID)->battleGetWallState(wallPart);
if(state != EWallState::DESTROYED) if(state != EWallState::DESTROYED)
continue; continue;
auto wallHex = cb->wallPartToBattleHex((EWallPart)wallPart); auto wallHex = cb->getBattle(battleID)->wallPartToBattleHex((EWallPart)wallPart);
auto moatHex = wallHex.cloneInDirection(BattleHex::LEFT); auto moatHex = wallHex.cloneInDirection(BattleHex::LEFT);
result.push_back(moatHex); result.push_back(moatHex);
@ -70,15 +70,15 @@ std::vector<BattleHex> BattleEvaluator::getBrokenWallMoatHexes() const
std::optional<PossibleSpellcast> BattleEvaluator::findBestCreatureSpell(const CStack *stack) std::optional<PossibleSpellcast> BattleEvaluator::findBestCreatureSpell(const CStack *stack)
{ {
//TODO: faerie dragon type spell should be selected by server //TODO: faerie dragon type spell should be selected by server
SpellID creatureSpellToCast = cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED); SpellID creatureSpellToCast = cb->getBattle(battleID)->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED);
if(stack->hasBonusOfType(BonusType::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE) if(stack->hasBonusOfType(BonusType::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE)
{ {
const CSpell * spell = creatureSpellToCast.toSpell(); const CSpell * spell = creatureSpellToCast.toSpell();
if(spell->canBeCast(getCbc().get(), spells::Mode::CREATURE_ACTIVE, stack)) if(spell->canBeCast(cb->getBattle(battleID).get(), spells::Mode::CREATURE_ACTIVE, stack))
{ {
std::vector<PossibleSpellcast> possibleCasts; std::vector<PossibleSpellcast> possibleCasts;
spells::BattleCast temp(getCbc().get(), stack, spells::Mode::CREATURE_ACTIVE, spell); spells::BattleCast temp(cb->getBattle(battleID).get(), stack, spells::Mode::CREATURE_ACTIVE, spell);
for(auto & target : temp.findPotentialTargets()) for(auto & target : temp.findPotentialTargets())
{ {
PossibleSpellcast ps; PossibleSpellcast ps;
@ -201,7 +201,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
if(score <= EvaluationResult::INEFFECTIVE_SCORE if(score <= EvaluationResult::INEFFECTIVE_SCORE
&& !stack->hasBonusOfType(BonusType::FLYING) && !stack->hasBonusOfType(BonusType::FLYING)
&& stack->unitSide() == BattleSide::ATTACKER && stack->unitSide() == BattleSide::ATTACKER
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL) && cb->getBattle(battleID)->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
{ {
auto brokenWallMoat = getBrokenWallMoatHexes(); auto brokenWallMoat = getBrokenWallMoatHexes();
@ -228,8 +228,8 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector<BattleHex> hexes) BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector<BattleHex> hexes)
{ {
auto reachability = cb->getReachability(stack); auto reachability = cb->getBattle(battleID)->getReachability(stack);
auto avHexes = cb->battleGetAvailableHexes(reachability, stack, false); auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false);
if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked
{ {
@ -325,16 +325,16 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
bool BattleEvaluator::canCastSpell() bool BattleEvaluator::canCastSpell()
{ {
auto hero = cb->battleGetMyHero(); auto hero = cb->getBattle(battleID)->battleGetMyHero();
if(!hero) if(!hero)
return false; return false;
return cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK; return cb->getBattle(battleID)->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK;
} }
bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
{ {
auto hero = cb->battleGetMyHero(); auto hero = cb->getBattle(battleID)->battleGetMyHero();
if(!hero) if(!hero)
return false; return false;
@ -343,7 +343,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
std::vector<const CSpell*> possibleSpells; std::vector<const CSpell*> possibleSpells;
vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero, this](const CSpell *s) -> bool vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero, this](const CSpell *s) -> bool
{ {
return s->canBeCast(cb.get(), spells::Mode::HERO, hero); return s->canBeCast(cb->getBattle(battleID).get(), spells::Mode::HERO, hero);
}); });
LOGFL("I can cast %d spells.", possibleSpells.size()); LOGFL("I can cast %d spells.", possibleSpells.size());
@ -358,7 +358,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
std::vector<PossibleSpellcast> possibleCasts; std::vector<PossibleSpellcast> possibleCasts;
for(auto spell : possibleSpells) for(auto spell : possibleSpells)
{ {
spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell); spells::BattleCast temp(cb->getBattle(battleID).get(), hero, spells::Mode::HERO, spell);
if(spell->getTargetType() == spells::AimType::LOCATION) if(spell->getTargetType() == spells::AimType::LOCATION)
continue; continue;
@ -390,7 +390,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
for(auto & round : queue) for(auto & round : queue)
{ {
if(!firstRound) if(!firstRound)
state->nextRound(0);//todo: set actual value? state->nextRound();
for(auto unit : round) for(auto unit : round)
{ {
if(!vstd::contains(values, unit->unitId())) if(!vstd::contains(values, unit->unitId()))
@ -468,7 +468,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
ValueMap valueOfStack; ValueMap valueOfStack;
ValueMap healthOfStack; ValueMap healthOfStack;
TStacks all = cb->battleGetAllStacks(false); TStacks all = cb->getBattle(battleID)->battleGetAllStacks(false);
size_t ourRemainingTurns = 0; size_t ourRemainingTurns = 0;
@ -477,7 +477,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
healthOfStack[unit->unitId()] = unit->getAvailableHealth(); healthOfStack[unit->unitId()] = unit->getAvailableHealth();
valueOfStack[unit->unitId()] = 0; valueOfStack[unit->unitId()] = 0;
if(cb->battleGetOwner(unit) == playerID && unit->canMove() && !unit->moved()) if(cb->getBattle(battleID)->battleGetOwner(unit) == playerID && unit->canMove() && !unit->moved())
ourRemainingTurns++; ourRemainingTurns++;
} }
@ -494,12 +494,12 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
std::vector<battle::Units> turnOrder; std::vector<battle::Units> turnOrder;
cb->battleGetTurnOrder(turnOrder, amount, 2); //no more than 1 turn after current, each unit at least once cb->getBattle(battleID)->battleGetTurnOrder(turnOrder, amount, 2); //no more than 1 turn after current, each unit at least once
{ {
bool enemyHadTurn = false; bool enemyHadTurn = false;
auto state = std::make_shared<HypotheticBattle>(env.get(), cb); auto state = std::make_shared<HypotheticBattle>(env.get(), cb->getBattle(battleID));
evaluateQueue(valueOfStack, turnOrder, state, 0, &enemyHadTurn); evaluateQueue(valueOfStack, turnOrder, state, 0, &enemyHadTurn);
@ -531,7 +531,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
logAi->trace("Evaluating %s", ps.spell->getNameTranslated()); logAi->trace("Evaluating %s", ps.spell->getNameTranslated());
#endif #endif
auto state = std::make_shared<HypotheticBattle>(env.get(), cb); auto state = std::make_shared<HypotheticBattle>(env.get(), cb->getBattle(battleID));
spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps.spell); spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps.spell);
cast.castEval(state->getServerCallback(), ps.dest); cast.castEval(state->getServerCallback(), ps.dest);
@ -540,7 +540,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
{ {
auto original = cb->battleGetUnitByID(u->unitId()); auto original = cb->getBattle(battleID)->battleGetUnitByID(u->unitId());
return !original || u->speed() != original->speed(); return !original || u->speed() != original->speed();
}); });
@ -583,7 +583,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
if(oldHealth != newHealth) if(oldHealth != newHealth)
{ {
auto damage = std::abs(oldHealth - newHealth); auto damage = std::abs(oldHealth - newHealth);
auto originalDefender = cb->battleGetUnitByID(unit->unitId()); auto originalDefender = cb->getBattle(battleID)->battleGetUnitByID(unit->unitId());
auto dpsReduce = AttackPossibility::calculateDamageReduce( auto dpsReduce = AttackPossibility::calculateDamageReduce(
nullptr, nullptr,
@ -639,7 +639,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
spellcast.setTarget(castToPerform.dest); spellcast.setTarget(castToPerform.dest);
spellcast.side = side; spellcast.side = side;
spellcast.stackNumber = (!side) ? -1 : -2; spellcast.stackNumber = (!side) ? -1 : -2;
cb->battleMakeSpellAction(spellcast); cb->battleMakeSpellAction(battleID, spellcast);
activeActionMade = true; activeActionMade = true;
return true; return true;
@ -656,8 +656,8 @@ void BattleEvaluator::evaluateCreatureSpellcast(const CStack * stack, PossibleSp
using ValueMap = PossibleSpellcast::ValueMap; using ValueMap = PossibleSpellcast::ValueMap;
RNGStub rngStub; RNGStub rngStub;
HypotheticBattle state(env.get(), cb); HypotheticBattle state(env.get(), cb->getBattle(battleID));
TStacks all = cb->battleGetAllStacks(false); TStacks all = cb->getBattle(battleID)->battleGetAllStacks(false);
ValueMap healthOfStack; ValueMap healthOfStack;
ValueMap newHealthOfStack; ValueMap newHealthOfStack;
@ -686,7 +686,7 @@ void BattleEvaluator::evaluateCreatureSpellcast(const CStack * stack, PossibleSp
auto healthDiff = newHealthOfStack[unitId] - healthOfStack[unitId]; auto healthDiff = newHealthOfStack[unitId] - healthOfStack[unitId];
if(localUnit->unitOwner() != getCbc()->getPlayerID()) if(localUnit->unitOwner() != cb->getBattle(battleID)->getPlayerID())
healthDiff = -healthDiff; healthDiff = -healthDiff;
if(healthDiff < 0) if(healthDiff < 0)
@ -703,7 +703,7 @@ void BattleEvaluator::evaluateCreatureSpellcast(const CStack * stack, PossibleSp
void BattleEvaluator::print(const std::string & text) const void BattleEvaluator::print(const std::string & text) const
{ {
logAi->trace("%s Battle AI[%p]: %s", playerID.getStr(), this, text); logAi->trace("%s Battle AI[%p]: %s", playerID.toString(), this, text);
} }

View File

@ -32,6 +32,7 @@ class BattleEvaluator
bool activeActionMade = false; bool activeActionMade = false;
std::optional<AttackPossibility> cachedAttack; std::optional<AttackPossibility> cachedAttack;
PlayerColor playerID; PlayerColor playerID;
BattleID battleID;
int side; int side;
float cachedScore; float cachedScore;
DamageCache damageCache; DamageCache damageCache;
@ -52,11 +53,12 @@ public:
std::shared_ptr<CBattleCallback> cb, std::shared_ptr<CBattleCallback> cb,
const battle::Unit * activeStack, const battle::Unit * activeStack,
PlayerColor playerID, PlayerColor playerID,
BattleID battleID,
int side, int side,
float strengthRatio) float strengthRatio)
:scoreEvaluator(cb, env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio) :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio), battleID(battleID)
{ {
hb = std::make_shared<HypotheticBattle>(env.get(), cb); hb = std::make_shared<HypotheticBattle>(env.get(), cb->getBattle(battleID));
damageCache.buildDamageCache(hb, side); damageCache.buildDamageCache(hb, side);
targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb); targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb);
@ -70,9 +72,10 @@ public:
DamageCache & damageCache, DamageCache & damageCache,
const battle::Unit * activeStack, const battle::Unit * activeStack,
PlayerColor playerID, PlayerColor playerID,
BattleID battleID,
int side, int side,
float strengthRatio) float strengthRatio)
:scoreEvaluator(cb, env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio) :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio), battleID(battleID)
{ {
targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb); targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb);
cachedScore = EvaluationResult::INEFFECTIVE_SCORE; cachedScore = EvaluationResult::INEFFECTIVE_SCORE;

View File

@ -133,4 +133,4 @@ public:
float getPositiveEffectMultiplier() { return 1; } float getPositiveEffectMultiplier() { return 1; }
float getNegativeEffectMultiplier() { return negativeEffectMultiplier; } float getNegativeEffectMultiplier() { return negativeEffectMultiplier; }
}; };

View File

@ -231,7 +231,7 @@ void StackWithBonuses::removeUnitBonus(const CSelector & selector)
std::string StackWithBonuses::getDescription() const std::string StackWithBonuses::getDescription() const
{ {
std::ostringstream oss; std::ostringstream oss;
oss << unitOwner().getStr(); oss << unitOwner().toString();
oss << " battle stack [" << unitId() << "]: " << getCount() << " of "; oss << " battle stack [" << unitId() << "]: " << getCount() << " of ";
if(type) if(type)
oss << type->getJsonKey(); oss << type->getJsonKey();
@ -320,12 +320,17 @@ battle::Units HypotheticBattle::getUnitsIf(battle::UnitFilter predicate) const
return ret; return ret;
} }
BattleID HypotheticBattle::getBattleID() const
{
return subject->getBattle()->getBattleID();
}
int32_t HypotheticBattle::getActiveStackID() const int32_t HypotheticBattle::getActiveStackID() const
{ {
return activeUnitId; return activeUnitId;
} }
void HypotheticBattle::nextRound(int32_t roundNr) void HypotheticBattle::nextRound()
{ {
//TODO:HypotheticBattle::nextRound //TODO:HypotheticBattle::nextRound
for(auto unit : battleAliveUnits()) for(auto unit : battleAliveUnits())
@ -462,6 +467,24 @@ int64_t HypotheticBattle::getActualDamage(const DamageRange & damage, int32_t at
return (damage.min + damage.max) / 2; return (damage.min + damage.max) / 2;
} }
std::vector<SpellID> HypotheticBattle::getUsedSpells(ui8 side) const
{
// TODO
return {};
}
int3 HypotheticBattle::getLocation() const
{
// TODO
return int3(-1, -1, -1);
}
bool HypotheticBattle::isCreatureBank() const
{
// TODO
return false;
}
int64_t HypotheticBattle::getTreeVersion() const int64_t HypotheticBattle::getTreeVersion() const
{ {
return getBonusBearer()->getTreeVersion() + bonusTreeVersion; return getBonusBearer()->getTreeVersion() + bonusTreeVersion;
@ -552,8 +575,9 @@ const Services * HypotheticBattle::HypotheticEnvironment::services() const
return env->services(); return env->services();
} }
const Environment::BattleCb * HypotheticBattle::HypotheticEnvironment::battle() const const Environment::BattleCb * HypotheticBattle::HypotheticEnvironment::battle(const BattleID & battleID) const
{ {
assert(battleID == owner->getBattleID());
return owner; return owner;
} }

View File

@ -110,11 +110,13 @@ public:
std::shared_ptr<StackWithBonuses> getForUpdate(uint32_t id); std::shared_ptr<StackWithBonuses> getForUpdate(uint32_t id);
BattleID getBattleID() const override;
int32_t getActiveStackID() const override; int32_t getActiveStackID() const override;
battle::Units getUnitsIf(battle::UnitFilter predicate) const override; battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
void nextRound(int32_t roundNr) override; void nextRound() override;
void nextTurn(uint32_t unitId) override; void nextTurn(uint32_t unitId) override;
void addUnit(uint32_t id, const JsonNode & data) override; void addUnit(uint32_t id, const JsonNode & data) override;
@ -136,6 +138,9 @@ public:
uint32_t nextUnitId() const override; uint32_t nextUnitId() const override;
int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const override; int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const override;
std::vector<SpellID> getUsedSpells(ui8 side) const override;
int3 getLocation() const override;
bool isCreatureBank() const override;
int64_t getTreeVersion() const; int64_t getTreeVersion() const;
@ -177,7 +182,7 @@ private:
HypotheticEnvironment(HypotheticBattle * owner_, const Environment * upperEnvironment); HypotheticEnvironment(HypotheticBattle * owner_, const Environment * upperEnvironment);
const Services * services() const override; const Services * services() const override;
const BattleCb * battle() const override; const BattleCb * battle(const BattleID & battleID) const override;
const GameCb * game() const override; const GameCb * game() const override;
vstd::CLoggerBase * logger() const override; vstd::CLoggerBase * logger() const override;
events::EventBus * eventBus() const override; events::EventBus * eventBus() const override;

View File

@ -27,7 +27,7 @@ void CEmptyAI::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_p
cb = CB; cb = CB;
env = ENV; env = ENV;
human=false; human=false;
playerID = *cb->getMyColor(); playerID = *cb->getPlayerID();
} }
void CEmptyAI::yourTurn(QueryID queryID) void CEmptyAI::yourTurn(QueryID queryID)
@ -36,14 +36,14 @@ void CEmptyAI::yourTurn(QueryID queryID)
cb->endTurn(); cb->endTurn();
} }
void CEmptyAI::activeStack(const CStack * stack) void CEmptyAI::activeStack(const BattleID & battleID, const CStack * stack)
{ {
cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack));
} }
void CEmptyAI::yourTacticPhase(int distance) void CEmptyAI::yourTacticPhase(const BattleID & battleID, int distance)
{ {
cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide()));
} }
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)
@ -76,7 +76,7 @@ void CEmptyAI::showMapObjectSelectDialog(QueryID askID, const Component & icon,
cb->selectionMade(0, askID); cb->selectionMade(0, askID);
} }
std::optional<BattleAction> CEmptyAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) std::optional<BattleAction> CEmptyAI::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
{ {
return std::nullopt; return std::nullopt;
} }

View File

@ -24,15 +24,15 @@ public:
void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override; void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
void yourTurn(QueryID queryID) override; void yourTurn(QueryID queryID) override;
void yourTacticPhase(int distance) override; void yourTacticPhase(const BattleID & battleID, int distance) override;
void activeStack(const CStack * stack) override; void activeStack(const BattleID & battleID, const CStack * stack) override;
void heroGotLevel(const CGHeroInstance *hero, PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override; void heroGotLevel(const CGHeroInstance *hero, 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;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override;
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override; void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
}; };
#define NAME "EmptyAI 0.1" #define NAME "EmptyAI 0.1"

View File

@ -21,6 +21,7 @@
#include "../../lib/serializer/BinarySerializer.h" #include "../../lib/serializer/BinarySerializer.h"
#include "../../lib/serializer/BinaryDeserializer.h" #include "../../lib/serializer/BinaryDeserializer.h"
#include "../../lib/battle/BattleStateInfoForRetreat.h" #include "../../lib/battle/BattleStateInfoForRetreat.h"
#include "../../lib/battle/BattleInfo.h"
#include "AIGateway.h" #include "AIGateway.h"
#include "Goals/Goals.h" #include "Goals/Goals.h"
@ -192,7 +193,7 @@ void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & vic
{ {
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString()); LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString());
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.getStr(), player, player.getStr(), (victoryLossCheckResult.victory() ? "won" : "lost")); logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.toString(), player, player.toString(), (victoryLossCheckResult.victory() ? "won" : "lost"));
// some whitespace to flush stream // some whitespace to flush stream
logAi->debug(std::string(200, ' ')); logAi->debug(std::string(200, ' '));
@ -201,12 +202,12 @@ void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & vic
{ {
if(victoryLossCheckResult.victory()) if(victoryLossCheckResult.victory())
{ {
logAi->debug("AIGateway: Player %d (%s) won. I won! Incredible!", player, player.getStr()); logAi->debug("AIGateway: Player %d (%s) won. I won! Incredible!", player, player.toString());
logAi->debug("Turn nr %d", myCb->getDate()); logAi->debug("Turn nr %d", myCb->getDate());
} }
else else
{ {
logAi->debug("AIGateway: Player %d (%s) lost. It's me. What a disappointment! :(", player, player.getStr()); logAi->debug("AIGateway: Player %d (%s) lost. It's me. What a disappointment! :(", player, player.toString());
} }
// some whitespace to flush stream // some whitespace to flush stream
@ -387,7 +388,7 @@ void AIGateway::heroCreated(const CGHeroInstance * h)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
} }
void AIGateway::advmapSpellCast(const CGHeroInstance * caster, int spellID) void AIGateway::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{ {
LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID); LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
@ -510,7 +511,7 @@ void AIGateway::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositio
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
} }
std::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) std::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
{ {
LOG_TRACE(logAi); LOG_TRACE(logAi);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
@ -535,7 +536,7 @@ void AIGateway::initGameInterface(std::shared_ptr<Environment> env, std::shared_
cbc = CB; cbc = CB;
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
playerID = *myCb->getMyColor(); playerID = *myCb->getPlayerID();
myCb->waitTillRealize = true; myCb->waitTillRealize = true;
myCb->unlockGsWhenWaiting = true; myCb->unlockGsWhenWaiting = true;
@ -776,7 +777,7 @@ void AIGateway::makeTurn()
MAKING_TURN; MAKING_TURN;
auto day = cb->getDate(Date::DAY); auto day = cb->getDate(Date::DAY);
logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.getStr(), day); logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day);
boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex); boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
setThreadName("AIGateway::makeTurn"); setThreadName("AIGateway::makeTurn");
@ -1080,23 +1081,23 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
} }
} }
void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
{ {
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE);
status.setBattle(ONGOING_BATTLE); status.setBattle(ONGOING_BATTLE);
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString()); battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed); CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed);
} }
void AIGateway::battleEnd(const BattleResult * br, QueryID queryID) void AIGateway::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID)
{ {
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(status.getBattle() == ONGOING_BATTLE); assert(status.getBattle() == ONGOING_BATTLE);
status.setBattle(ENDING_BATTLE); status.setBattle(ENDING_BATTLE);
bool won = br->winner == myCb->battleGetMySide(); bool won = br->winner == myCb->getBattle(battleID)->battleGetMySide();
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename); logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename);
battlename.clear(); battlename.clear();
if (queryID != QueryID::NONE) if (queryID != QueryID::NONE)
@ -1108,7 +1109,7 @@ void AIGateway::battleEnd(const BattleResult * br, QueryID queryID)
answerQuery(queryID, confirmAction); answerQuery(queryID, confirmAction);
}); });
} }
CAdventureAI::battleEnd(br, queryID); CAdventureAI::battleEnd(battleID, br, queryID);
} }
void AIGateway::waitTillFree() void AIGateway::waitTillFree()
@ -1421,7 +1422,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
void AIGateway::endTurn() void AIGateway::endTurn()
{ {
logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr()); logAi->info("Player %d (%s) ends turn", playerID, playerID.toString());
if(!status.haveTurn()) if(!status.haveTurn())
{ {
logAi->error("Not having turn at the end of turn???"); logAi->error("Not having turn at the end of turn???");
@ -1441,7 +1442,7 @@ void AIGateway::endTurn()
} }
while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over
logGlobal->info("Player %d (%s) ended turn", playerID, playerID.getStr()); logGlobal->info("Player %d (%s) ended turn", playerID, playerID.toString());
} }
void AIGateway::buildArmyIn(const CGTownInstance * t) void AIGateway::buildArmyIn(const CGTownInstance * t)

View File

@ -152,7 +152,7 @@ public:
void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override; void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override;
void playerBonusChanged(const Bonus & bonus, bool gain) override; void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override; void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override; void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override; void requestRealized(PackageApplied * pa) override;
void receivedResource() override; void receivedResource() override;
@ -167,10 +167,10 @@ public:
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override; void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override; void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
void battleEnd(const BattleResult * br, QueryID queryID) override; void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
void makeTurn(); void makeTurn();

View File

@ -68,7 +68,7 @@ PriorityEvaluator::~PriorityEvaluator()
void PriorityEvaluator::initVisitTile() void PriorityEvaluator::initVisitTile()
{ {
auto file = CResourceHandler::get()->load(ResourceID("config/ai/object-priorities.txt"))->readAll(); auto file = CResourceHandler::get()->load(ResourcePath("config/ai/object-priorities.txt"))->readAll();
std::string str = std::string((char *)file.first.get(), file.second); std::string str = std::string((char *)file.first.get(), file.second);
engine = fl::FllImporter().fromString(str); engine = fl::FllImporter().fromString(str);
armyLossPersentageVariable = engine->getInputVariable("armyLoss"); armyLossPersentageVariable = engine->getInputVariable("armyLoss");

View File

@ -1208,7 +1208,7 @@ bool AINodeStorage::hasBetterChain(
"Block ineficient battle move %s->%s, hero: %s[%X], army %lld, mp diff: %i", "Block ineficient battle move %s->%s, hero: %s[%X], army %lld, mp diff: %i",
source->coord.toString(), source->coord.toString(),
candidateNode->coord.toString(), candidateNode->coord.toString(),
candidateNode->actor->hero->name, candidateNode->actor->hero->getNameTranslated(),
candidateNode->actor->chainMask, candidateNode->actor->chainMask,
candidateNode->actor->armyValue, candidateNode->actor->armyValue,
node.moveRemains - candidateNode->moveRemains); node.moveRemains - candidateNode->moveRemains);
@ -1232,7 +1232,7 @@ bool AINodeStorage::hasBetterChain(
"Block ineficient move because of stronger army %s->%s, hero: %s[%X], army %lld, mp diff: %i", "Block ineficient move because of stronger army %s->%s, hero: %s[%X], army %lld, mp diff: %i",
source->coord.toString(), source->coord.toString(),
candidateNode->coord.toString(), candidateNode->coord.toString(),
candidateNode->actor->hero->name, candidateNode->actor->hero->getNameTranslated(),
candidateNode->actor->chainMask, candidateNode->actor->chainMask,
candidateNode->actor->armyValue, candidateNode->actor->armyValue,
node.moveRemains - candidateNode->moveRemains); node.moveRemains - candidateNode->moveRemains);
@ -1258,7 +1258,7 @@ bool AINodeStorage::hasBetterChain(
"Block ineficient move because of stronger hero %s->%s, hero: %s[%X], army %lld, mp diff: %i", "Block ineficient move because of stronger hero %s->%s, hero: %s[%X], army %lld, mp diff: %i",
source->coord.toString(), source->coord.toString(),
candidateNode->coord.toString(), candidateNode->coord.toString(),
candidateNode->actor->hero->name, candidateNode->actor->hero->getNameTranslated(),
candidateNode->actor->chainMask, candidateNode->actor->chainMask,
candidateNode->actor->armyValue, candidateNode->actor->armyValue,
node.moveRemains - candidateNode->moveRemains); node.moveRemains - candidateNode->moveRemains);

View File

@ -14,6 +14,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
#include "../../lib/battle/BattleAction.h" #include "../../lib/battle/BattleAction.h"
#include "../../lib/battle/BattleInfo.h"
static std::shared_ptr<CBattleCallback> cbc; static std::shared_ptr<CBattleCallback> cbc;
@ -53,12 +54,12 @@ void CStupidAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
initBattleInterface(ENV, CB); initBattleInterface(ENV, CB);
} }
void CStupidAI::actionFinished(const BattleAction &action) void CStupidAI::actionFinished(const BattleID & battleID, const BattleAction &action)
{ {
print("actionFinished called"); print("actionFinished called");
} }
void CStupidAI::actionStarted(const BattleAction &action) void CStupidAI::actionStarted(const BattleID & battleID, const BattleAction &action)
{ {
print("actionStarted called"); print("actionStarted called");
} }
@ -71,11 +72,11 @@ public:
std::vector<BattleHex> attackFrom; //for melee fight std::vector<BattleHex> attackFrom; //for melee fight
EnemyInfo(const CStack * _s) : s(_s), adi(0), adr(0) EnemyInfo(const CStack * _s) : s(_s), adi(0), adr(0)
{} {}
void calcDmg(const CStack * ourStack) void calcDmg(const BattleID & battleID, const CStack * ourStack)
{ {
// FIXME: provide distance info for Jousting bonus // FIXME: provide distance info for Jousting bonus
DamageEstimation retal; DamageEstimation retal;
DamageEstimation dmg = cbc->battleEstimateDamage(ourStack, s, 0, &retal); DamageEstimation dmg = cbc->getBattle(battleID)->battleEstimateDamage(ourStack, s, 0, &retal);
adi = static_cast<int>((dmg.damage.min + dmg.damage.max) / 2); adi = static_cast<int>((dmg.damage.min + dmg.damage.max) / 2);
adr = static_cast<int>((retal.damage.min + retal.damage.max) / 2); adr = static_cast<int>((retal.damage.min + retal.damage.max) / 2);
} }
@ -91,14 +92,14 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr); return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
} }
static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2) static bool willSecondHexBlockMoreEnemyShooters(const BattleID & battleID, const BattleHex &h1, const BattleHex &h2)
{ {
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 auto * s = cbc->battleGetUnitByPos(neighbour)) if(const auto * s = cbc->getBattle(battleID)->battleGetUnitByPos(neighbour))
if(s->isShooter()) if(s->isShooter())
shooters[i]++; shooters[i]++;
} }
@ -106,16 +107,16 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
return shooters[0] < shooters[1]; return shooters[0] < shooters[1];
} }
void CStupidAI::yourTacticPhase(int distance) void CStupidAI::yourTacticPhase(const BattleID & battleID, int distance)
{ {
cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide()));
} }
void CStupidAI::activeStack( const CStack * stack ) void CStupidAI::activeStack(const BattleID & battleID, const CStack * stack)
{ {
//boost::this_thread::sleep_for(boost::chrono::seconds(2)); //boost::this_thread::sleep_for(boost::chrono::seconds(2));
print("activeStack called for " + stack->nodeName()); print("activeStack called for " + stack->nodeName());
ReachabilityInfo dists = cb->getReachability(stack); ReachabilityInfo dists = cb->getBattle(battleID)->getReachability(stack);
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable; std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
if(stack->creatureId() == CreatureID::CATAPULT) if(stack->creatureId() == CreatureID::CATAPULT)
@ -128,24 +129,24 @@ void CStupidAI::activeStack( const CStack * stack )
attack.side = side; attack.side = side;
attack.stackNumber = stack->unitId(); attack.stackNumber = stack->unitId();
cb->battleMakeUnitAction(attack); cb->battleMakeUnitAction(battleID, attack);
return; return;
} }
else if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON)) else if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON))
{ {
cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack));
return; return;
} }
for (const CStack *s : cb->battleGetStacks(CBattleCallback::ONLY_ENEMY)) for (const CStack *s : cb->getBattle(battleID)->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY))
{ {
if(cb->battleCanShoot(stack, s->getPosition())) if(cb->getBattle(battleID)->battleCanShoot(stack, s->getPosition()))
{ {
enemiesShootable.push_back(s); enemiesShootable.push_back(s);
} }
else else
{ {
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false); std::vector<BattleHex> avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(stack, false);
for (BattleHex hex : avHexes) for (BattleHex hex : avHexes)
{ {
@ -168,21 +169,23 @@ void CStupidAI::activeStack( const CStack * stack )
} }
for ( auto & enemy : enemiesReachable ) for ( auto & enemy : enemiesReachable )
enemy.calcDmg( stack ); enemy.calcDmg(battleID, stack);
for ( auto & enemy : enemiesShootable ) for ( auto & enemy : enemiesShootable )
enemy.calcDmg( stack ); enemy.calcDmg(battleID, stack);
if(enemiesShootable.size()) if(enemiesShootable.size())
{ {
const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable); const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable);
cb->battleMakeUnitAction(BattleAction::makeShotAttack(stack, ei.s)); cb->battleMakeUnitAction(battleID, BattleAction::makeShotAttack(stack, ei.s));
return; return;
} }
else if(enemiesReachable.size()) else if(enemiesReachable.size())
{ {
const EnemyInfo &ei= *std::max_element(enemiesReachable.begin(), enemiesReachable.end(), &isMoreProfitable); const EnemyInfo &ei= *std::max_element(enemiesReachable.begin(), enemiesReachable.end(), &isMoreProfitable);
cb->battleMakeUnitAction(BattleAction::makeMeleeAttack(stack, ei.s->getPosition(), *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), &willSecondHexBlockMoreEnemyShooters))); BattleHex targetHex = *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), [&](auto a, auto b) { return willSecondHexBlockMoreEnemyShooters(battleID, a, b);});
cb->battleMakeUnitAction(battleID, BattleAction::makeMeleeAttack(stack, ei.s->getPosition(), targetHex));
return; return;
} }
else if(enemiesUnreachable.size()) //due to #955 - a buggy battle may occur when there are no enemies else if(enemiesUnreachable.size()) //due to #955 - a buggy battle may occur when there are no enemies
@ -194,26 +197,26 @@ void CStupidAI::activeStack( const CStack * stack )
if(dists.distToNearestNeighbour(stack, closestEnemy->s) < GameConstants::BFIELD_SIZE) if(dists.distToNearestNeighbour(stack, closestEnemy->s) < GameConstants::BFIELD_SIZE)
{ {
cb->battleMakeUnitAction(goTowards(stack, closestEnemy->s->getAttackableHexes(stack))); cb->battleMakeUnitAction(battleID, goTowards(battleID, stack, closestEnemy->s->getAttackableHexes(stack)));
return; return;
} }
} }
cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack));
return; return;
} }
void CStupidAI::battleAttack(const BattleAttack *ba) void CStupidAI::battleAttack(const BattleID & battleID, const BattleAttack *ba)
{ {
print("battleAttack called"); print("battleAttack called");
} }
void CStupidAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) void CStupidAI::battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged)
{ {
print("battleStacksAttacked called"); print("battleStacksAttacked called");
} }
void CStupidAI::battleEnd(const BattleResult *br, QueryID queryID) void CStupidAI::battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID)
{ {
print("battleEnd called"); print("battleEnd called");
} }
@ -223,38 +226,38 @@ void CStupidAI::battleEnd(const BattleResult *br, QueryID queryID)
// print("battleResultsApplied called"); // print("battleResultsApplied called");
// } // }
void CStupidAI::battleNewRoundFirst(int round) void CStupidAI::battleNewRoundFirst(const BattleID & battleID)
{ {
print("battleNewRoundFirst called"); print("battleNewRoundFirst called");
} }
void CStupidAI::battleNewRound(int round) void CStupidAI::battleNewRound(const BattleID & battleID)
{ {
print("battleNewRound called"); print("battleNewRound called");
} }
void CStupidAI::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) void CStupidAI::battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport)
{ {
print("battleStackMoved called"); print("battleStackMoved called");
} }
void CStupidAI::battleSpellCast(const BattleSpellCast *sc) void CStupidAI::battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc)
{ {
print("battleSpellCast called"); print("battleSpellCast called");
} }
void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse) void CStupidAI::battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse)
{ {
print("battleStacksEffectsSet called"); print("battleStacksEffectsSet called");
} }
void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
{ {
print("battleStart called"); print("battleStart called");
side = Side; side = Side;
} }
void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca) void CStupidAI::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca)
{ {
print("battleCatapultAttacked called"); print("battleCatapultAttacked called");
} }
@ -264,10 +267,10 @@ void CStupidAI::print(const std::string &text) const
logAi->trace("CStupidAI [%p]: %s", this, text); logAi->trace("CStupidAI [%p]: %s", this, text);
} }
BattleAction CStupidAI::goTowards(const CStack * stack, std::vector<BattleHex> hexes) const BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> hexes) const
{ {
auto reachability = cb->getReachability(stack); auto reachability = cb->getBattle(battleID)->getReachability(stack);
auto avHexes = cb->battleGetAvailableHexes(reachability, stack, false); auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false);
if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked
{ {

View File

@ -11,6 +11,7 @@
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../../lib/battle/ReachabilityInfo.h" #include "../../lib/battle/ReachabilityInfo.h"
#include "../../lib/CGameInterface.h"
class EnemyInfo; class EnemyInfo;
@ -30,25 +31,26 @@ public:
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override; void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override; void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override;
void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
void activeStack(const CStack * stack) override; //called when it's turn of that stack
void yourTacticPhase(int distance) override;
void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack void actionFinished(const BattleID & battleID, const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override; //called when stack receives damage (after battleAttack()) void actionStarted(const BattleID & battleID, const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
void battleEnd(const BattleResult *br, QueryID queryID) override; void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack
void yourTacticPhase(const BattleID & battleID, int distance) override;
void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //called when stack is performing attack
void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override; //called when stack receives damage (after battleAttack())
void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) 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(const BattleID & battleID) override; //called at the beginning of each turn before changes are applied;
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(const BattleID & battleID) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) override; void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) override;
void battleSpellCast(const BattleSpellCast *sc) override; void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks
//void battleTriggerEffect(const BattleTriggerEffect & bte) override; //void battleTriggerEffect(const BattleTriggerEffect & bte) override;
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) 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 BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
private: private:
BattleAction goTowards(const CStack * stack, std::vector<BattleHex> hexes) const; BattleAction goTowards(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> hexes) const;
}; };

View File

@ -204,7 +204,7 @@ void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryL
{ {
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString()); LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString());
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.getStr(), player, player.getStr(), (victoryLossCheckResult.victory() ? "won" : "lost")); logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.toString(), player, player.toString(), (victoryLossCheckResult.victory() ? "won" : "lost"));
if(player == playerID) if(player == playerID)
{ {
if(victoryLossCheckResult.victory()) if(victoryLossCheckResult.victory())
@ -214,7 +214,7 @@ void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryL
} }
else else
{ {
logAi->debug("VCAI: Player %d (%s) lost. It's me. What a disappointment! :(", player, player.getStr()); logAi->debug("VCAI: Player %d (%s) lost. It's me. What a disappointment! :(", player, player.toString());
} }
finish(); finish();
@ -475,7 +475,7 @@ void VCAI::heroCreated(const CGHeroInstance * h)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
} }
void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID) void VCAI::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{ {
LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID); LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
@ -600,7 +600,7 @@ void VCAI::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<C
ah->init(CB.get()); ah->init(CB.get());
NET_EVENT_HANDLER; //sets ah->rm->cb NET_EVENT_HANDLER; //sets ah->rm->cb
playerID = *myCb->getMyColor(); playerID = *myCb->getPlayerID();
myCb->waitTillRealize = true; myCb->waitTillRealize = true;
myCb->unlockGsWhenWaiting = true; myCb->unlockGsWhenWaiting = true;
@ -779,7 +779,7 @@ void VCAI::makeTurn()
MAKING_TURN; MAKING_TURN;
auto day = cb->getDate(Date::DAY); auto day = cb->getDate(Date::DAY);
logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.getStr(), day); logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day);
boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex); boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
setThreadName("VCAI::makeTurn"); setThreadName("VCAI::makeTurn");
@ -1577,23 +1577,23 @@ void VCAI::completeGoal(Goals::TSubgoal goal)
} }
void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
{ {
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE);
status.setBattle(ONGOING_BATTLE); status.setBattle(ONGOING_BATTLE);
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString()); battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed); CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed);
} }
void VCAI::battleEnd(const BattleResult * br, QueryID queryID) void VCAI::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID)
{ {
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(status.getBattle() == ONGOING_BATTLE); assert(status.getBattle() == ONGOING_BATTLE);
status.setBattle(ENDING_BATTLE); status.setBattle(ENDING_BATTLE);
bool won = br->winner == myCb->battleGetMySide(); bool won = br->winner == myCb->getBattle(battleID)->battleGetMySide();
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename); logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename);
battlename.clear(); battlename.clear();
if (queryID != QueryID::NONE) if (queryID != QueryID::NONE)
@ -1605,7 +1605,7 @@ void VCAI::battleEnd(const BattleResult * br, QueryID queryID)
answerQuery(queryID, confirmAction); answerQuery(queryID, confirmAction);
}); });
} }
CAdventureAI::battleEnd(br, queryID); CAdventureAI::battleEnd(battleID, br, queryID);
} }
void VCAI::waitTillFree() void VCAI::waitTillFree()
@ -2288,7 +2288,7 @@ HeroPtr VCAI::primaryHero() const
void VCAI::endTurn() void VCAI::endTurn()
{ {
logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr()); logAi->info("Player %d (%s) ends turn", playerID, playerID.toString());
if(!status.haveTurn()) if(!status.haveTurn())
{ {
logAi->error("Not having turn at the end of turn???"); logAi->error("Not having turn at the end of turn???");
@ -2300,7 +2300,7 @@ void VCAI::endTurn()
} }
while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over
logGlobal->info("Player %d (%s) ended turn", playerID, playerID.getStr()); logGlobal->info("Player %d (%s) ended turn", playerID, playerID.toString());
} }
void VCAI::striveToGoal(Goals::TSubgoal basicGoal) void VCAI::striveToGoal(Goals::TSubgoal basicGoal)
@ -2894,7 +2894,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
return true; return true;
} }
std::optional<BattleAction> VCAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) std::optional<BattleAction> VCAI::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
{ {
return std::nullopt; return std::nullopt;
} }

View File

@ -185,7 +185,7 @@ public:
void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override; void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override;
void playerBonusChanged(const Bonus & bonus, bool gain) override; void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override; void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override; void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override; void requestRealized(PackageApplied * pa) override;
void receivedResource() override; void receivedResource() override;
@ -201,9 +201,9 @@ public:
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override; void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
void battleEnd(const BattleResult * br, QueryID queryID) override; void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
void makeTurn(); void makeTurn();
void mainLoop(); void mainLoop();

View File

@ -168,14 +168,10 @@ bool CCallback::swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation
* @param assembleTo If assemble is true, this represents the artifact ID of the combination * @param assembleTo If assemble is true, this represents the artifact ID of the combination
* artifact to assemble to. Otherwise it's not used. * artifact to assemble to. Otherwise it's not used.
*/ */
bool CCallback::assembleArtifacts (const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) void CCallback::assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)
{ {
if (player != hero->tempOwner)
return false;
AssembleArtifacts aa(hero->id, artifactSlot, assemble, assembleTo); AssembleArtifacts aa(hero->id, artifactSlot, assemble, assembleTo);
sendRequest(&aa); sendRequest(&aa);
return true;
} }
void CCallback::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) void CCallback::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap)
@ -203,16 +199,17 @@ bool CCallback::buildBuilding(const CGTownInstance *town, BuildingID buildingID)
return true; return true;
} }
void CBattleCallback::battleMakeSpellAction(const BattleAction & action) void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const BattleAction & action)
{ {
assert(action.actionType == EActionType::HERO_SPELL); assert(action.actionType == EActionType::HERO_SPELL);
MakeAction mca(action); MakeAction mca(action);
mca.battleID = battleID;
sendRequest(&mca); sendRequest(&mca);
} }
int CBattleCallback::sendRequest(const CPackForServer * request) int CBattleCallback::sendRequest(const CPackForServer * request)
{ {
int requestID = cl->sendRequest(request, *player); int requestID = cl->sendRequest(request, *getPlayerID());
if(waitTillRealize) if(waitTillRealize)
{ {
logGlobal->trace("We'll wait till request %d is answered.\n", requestID); logGlobal->trace("We'll wait till request %d is answered.\n", requestID);
@ -226,8 +223,7 @@ int CBattleCallback::sendRequest(const CPackForServer * request)
void CCallback::swapGarrisonHero( const CGTownInstance *town ) void CCallback::swapGarrisonHero( const CGTownInstance *town )
{ {
if(town->tempOwner == *player if(town->tempOwner == *player || (town->garrisonHero && town->garrisonHero->tempOwner == *player ))
|| (town->garrisonHero && town->garrisonHero->tempOwner == *player ))
{ {
GarrisonHeroSwap pack(town->id); GarrisonHeroSwap pack(town->id);
sendRequest(&pack); sendRequest(&pack);
@ -236,7 +232,7 @@ void CCallback::swapGarrisonHero( const CGTownInstance *town )
void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid) void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid)
{ {
if(hero->tempOwner != player) return; if(hero->tempOwner != *player) return;
BuyArtifact pack(hero->id,aid); BuyArtifact pack(hero->id,aid);
sendRequest(&pack); sendRequest(&pack);
@ -297,8 +293,8 @@ void CCallback::buildBoat( const IShipyard *obj )
sendRequest(&bb); sendRequest(&bb);
} }
CCallback::CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C): CCallback::CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C)
CBattleCallback(Player, C) : CBattleCallback(Player, C)
{ {
gs = GS; gs = GS;
@ -306,10 +302,7 @@ CCallback::CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient
unlockGsWhenWaiting = false; unlockGsWhenWaiting = false;
} }
CCallback::~CCallback() CCallback::~CCallback() = default;
{
//trivial, but required. Don`t remove.
}
bool CCallback::canMoveBetween(const int3 &a, const int3 &b) bool CCallback::canMoveBetween(const int3 &a, const int3 &b)
{ {
@ -322,6 +315,11 @@ std::shared_ptr<const CPathsInfo> CCallback::getPathsInfo(const CGHeroInstance *
return cl->getPathsInfo(h); return cl->getPathsInfo(h);
} }
std::optional<PlayerColor> CCallback::getPlayerID() const
{
return CBattleCallback::getPlayerID();
}
int3 CCallback::getGuardingCreaturePosition(int3 tile) int3 CCallback::getGuardingCreaturePosition(int3 tile)
{ {
if (!gs->map->isInTheMap(tile)) if (!gs->map->isInTheMap(tile))
@ -364,36 +362,51 @@ void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver>
cl->additionalBattleInts[*player] -= battleEvents; cl->additionalBattleInts[*player] -= battleEvents;
} }
#if SCRIPTING_ENABLED CBattleCallback::CBattleCallback(std::optional<PlayerColor> player, CClient * C):
scripting::Pool * CBattleCallback::getContextPool() const cl(C),
player(player)
{ {
return cl->getGlobalContextPool();
}
#endif
CBattleCallback::CBattleCallback(std::optional<PlayerColor> Player, CClient * C)
{
player = Player;
cl = C;
} }
void CBattleCallback::battleMakeUnitAction(const BattleAction & action) void CBattleCallback::battleMakeUnitAction(const BattleID & battleID, const BattleAction & action)
{ {
assert(!cl->gs->curB->tacticDistance); assert(!cl->gs->getBattle(battleID)->tacticDistance);
MakeAction ma; MakeAction ma;
ma.ba = action; ma.ba = action;
ma.battleID = battleID;
sendRequest(&ma); sendRequest(&ma);
} }
void CBattleCallback::battleMakeTacticAction( const BattleAction & action ) void CBattleCallback::battleMakeTacticAction(const BattleID & battleID, const BattleAction & action )
{ {
assert(cl->gs->curB->tacticDistance); assert(cl->gs->getBattle(battleID)->tacticDistance);
MakeAction ma; MakeAction ma;
ma.ba = action; ma.ba = action;
ma.battleID = battleID;
sendRequest(&ma); sendRequest(&ma);
} }
std::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) std::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
{ {
return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleState); return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleID, battleState);
}
std::shared_ptr<CPlayerBattleCallback> CBattleCallback::getBattle(const BattleID & battleID)
{
return activeBattles.at(battleID);
}
std::optional<PlayerColor> CBattleCallback::getPlayerID() const
{
return player;
}
void CBattleCallback::onBattleStarted(const IBattleInfo * info)
{
activeBattles[info->getBattleID()] = std::make_shared<CPlayerBattleCallback>(info, *getPlayerID());
}
void CBattleCallback::onBattleEnded(const BattleID & battleID)
{
activeBattles.erase(battleID);
} }

View File

@ -53,10 +53,13 @@ public:
bool waitTillRealize = false; //if true, request functions will return after they are realized by server bool waitTillRealize = false; //if true, request functions will return after they are realized by server
bool unlockGsWhenWaiting = false;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback! bool unlockGsWhenWaiting = false;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback!
//battle //battle
virtual void battleMakeSpellAction(const BattleAction & action) = 0; virtual void battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) = 0;
virtual void battleMakeUnitAction(const BattleAction & action) = 0; virtual void battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) = 0;
virtual void battleMakeTacticAction(const BattleAction & action) = 0; virtual void battleMakeTacticAction(const BattleID & battleID, const BattleAction & action) = 0;
virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0; virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0;
virtual std::shared_ptr<CPlayerBattleCallback> getBattle(const BattleID & battleID) = 0;
virtual std::optional<PlayerColor> getPlayerID() const = 0;
}; };
class IGameActionCallback class IGameActionCallback
@ -86,7 +89,7 @@ public:
virtual int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2, int val)=0;//split creatures from the first stack virtual int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2, int val)=0;//split creatures from the first stack
//virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes //virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
virtual bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)=0; virtual bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)=0;
virtual bool assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0; virtual void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0;
virtual void eraseArtifactByClient(const ArtifactLocation & al)=0; virtual void eraseArtifactByClient(const ArtifactLocation & al)=0;
virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0; virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0;
virtual void endTurn()=0; virtual void endTurn()=0;
@ -108,30 +111,34 @@ public:
virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) = 0; virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) = 0;
}; };
class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback class CBattleCallback : public IBattleCallback
{ {
std::map<BattleID, std::shared_ptr<CPlayerBattleCallback>> activeBattles;
std::optional<PlayerColor> player;
protected: protected:
int sendRequest(const CPackForServer * request); //returns requestID (that'll be matched to requestID in PackageApplied) int sendRequest(const CPackForServer * request); //returns requestID (that'll be matched to requestID in PackageApplied)
CClient *cl; CClient *cl;
public: public:
CBattleCallback(std::optional<PlayerColor> Player, CClient * C); CBattleCallback(std::optional<PlayerColor> player, CClient * C);
void battleMakeSpellAction(const BattleAction & action) override;//for casting spells by hero - DO NOT use it for moving active stack void battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) override;//for casting spells by hero - DO NOT use it for moving active stack
void battleMakeUnitAction(const BattleAction & action) override; void battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) override;
void battleMakeTacticAction(const BattleAction & action) override; // performs tactic phase actions void battleMakeTacticAction(const BattleID & battleID, const BattleAction & action) override; // performs tactic phase actions
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
#if SCRIPTING_ENABLED std::shared_ptr<CPlayerBattleCallback> getBattle(const BattleID & battleID) override;
scripting::Pool * getContextPool() const override; std::optional<PlayerColor> getPlayerID() const override;
#endif
void onBattleStarted(const IBattleInfo * info);
void onBattleEnded(const BattleID & battleID);
friend class CCallback; friend class CCallback;
friend class CClient; friend class CClient;
}; };
class CCallback : public CPlayerSpecificInfoCallback, class CCallback : public CPlayerSpecificInfoCallback, public CBattleCallback, public IGameActionCallback
public IGameActionCallback,
public CBattleCallback
{ {
public: public:
CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C); CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C);
@ -142,6 +149,8 @@ public:
virtual int3 getGuardingCreaturePosition(int3 tile); virtual int3 getGuardingCreaturePosition(int3 tile);
virtual std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h); virtual std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
std::optional<PlayerColor> getPlayerID() const override;
//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 registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents); void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents); void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
@ -161,7 +170,7 @@ public:
int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) override; int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) override;
bool dismissHero(const CGHeroInstance * hero) override; bool dismissHero(const CGHeroInstance * hero) override;
bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override; bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override;
bool assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override; void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override;
void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) override; void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) override;
void eraseArtifactByClient(const ArtifactLocation & al) override; void eraseArtifactByClient(const ArtifactLocation & al) override;
bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override; bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -251,7 +251,7 @@ int main(int argc, char * argv[])
// Some basic data validation to produce better error messages in cases of incorrect install // Some basic data validation to produce better error messages in cases of incorrect install
auto testFile = [](std::string filename, std::string message) auto testFile = [](std::string filename, std::string message)
{ {
if (!CResourceHandler::get()->existsResource(ResourceID(filename))) if (!CResourceHandler::get()->existsResource(ResourcePath(filename)))
handleFatalError(message, false); handleFatalError(message, false);
}; };
@ -423,10 +423,10 @@ int main(int argc, char * argv[])
//plays intro, ends when intro is over or button has been pressed (handles events) //plays intro, ends when intro is over or button has been pressed (handles events)
void playIntro() void playIntro()
{ {
if(CCS->videoh->openAndPlayVideo("3DOLOGO.SMK", 0, 1, true, true)) if(CCS->videoh->openAndPlayVideo(VideoPath::builtin("3DOLOGO.SMK"), 0, 1, true, true))
{ {
if (CCS->videoh->openAndPlayVideo("NWCLOGO.SMK", 0, 1, true, true)) if (CCS->videoh->openAndPlayVideo(VideoPath::builtin("NWCLOGO.SMK"), 0, 1, true, true))
CCS->videoh->openAndPlayVideo("H3INTRO.SMK", 0, 1, true, true); CCS->videoh->openAndPlayVideo(VideoPath::builtin("H3INTRO.SMK"), 0, 1, true, true);
} }
} }

View File

@ -84,6 +84,7 @@ set(client_SRCS
renderSDL/CTrueTypeFont.cpp renderSDL/CTrueTypeFont.cpp
renderSDL/CursorHardware.cpp renderSDL/CursorHardware.cpp
renderSDL/CursorSoftware.cpp renderSDL/CursorSoftware.cpp
renderSDL/RenderHandler.cpp
renderSDL/SDLImage.cpp renderSDL/SDLImage.cpp
renderSDL/SDLImageLoader.cpp renderSDL/SDLImageLoader.cpp
renderSDL/SDLRWwrapper.cpp renderSDL/SDLRWwrapper.cpp
@ -235,6 +236,7 @@ set(client_HEADERS
render/IFont.h render/IFont.h
render/IImage.h render/IImage.h
render/IImageLoader.h render/IImageLoader.h
render/IRenderHandler.h
render/IScreenHandler.h render/IScreenHandler.h
renderSDL/CBitmapFont.h renderSDL/CBitmapFont.h
@ -242,6 +244,7 @@ set(client_HEADERS
renderSDL/CTrueTypeFont.h renderSDL/CTrueTypeFont.h
renderSDL/CursorHardware.h renderSDL/CursorHardware.h
renderSDL/CursorSoftware.h renderSDL/CursorSoftware.h
renderSDL/RenderHandler.h
renderSDL/SDLImage.h renderSDL/SDLImage.h
renderSDL/SDLImageLoader.h renderSDL/SDLImageLoader.h
renderSDL/SDLRWwrapper.h renderSDL/SDLRWwrapper.h
@ -462,6 +465,7 @@ endif()
if(NOT WIN32 AND NOT APPLE AND NOT ANDROID) if(NOT WIN32 AND NOT APPLE AND NOT ANDROID)
#FIXME: move to client makefile? #FIXME: move to client makefile?
install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.16x16.png" DESTINATION share/icons/hicolor/16x16/apps RENAME vcmiclient.png) install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.16x16.png" DESTINATION share/icons/hicolor/16x16/apps RENAME vcmiclient.png)
install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.22x22.png" DESTINATION share/icons/hicolor/22x22/apps RENAME vcmiclient.png)
install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.32x32.png" DESTINATION share/icons/hicolor/32x32/apps RENAME vcmiclient.png) install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.32x32.png" DESTINATION share/icons/hicolor/32x32/apps RENAME vcmiclient.png)
install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.48x48.png" DESTINATION share/icons/hicolor/48x48/apps RENAME vcmiclient.png) install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.48x48.png" DESTINATION share/icons/hicolor/48x48/apps RENAME vcmiclient.png)
install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.64x64.png" DESTINATION share/icons/hicolor/64x64/apps RENAME vcmiclient.png) install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.64x64.png" DESTINATION share/icons/hicolor/64x64/apps RENAME vcmiclient.png)

View File

@ -75,7 +75,7 @@ void CSoundHandler::onVolumeChange(const JsonNode &volumeNode)
CSoundHandler::CSoundHandler(): CSoundHandler::CSoundHandler():
listener(settings.listen["general"]["sound"]), listener(settings.listen["general"]["sound"]),
ambientConfig(JsonNode(ResourceID("config/ambientSounds.json"))) ambientConfig(JsonPath::builtin("config/ambientSounds.json"))
{ {
listener(std::bind(&CSoundHandler::onVolumeChange, this, _1)); listener(std::bind(&CSoundHandler::onVolumeChange, this, _1));
@ -119,25 +119,25 @@ void CSoundHandler::release()
} }
// Allocate an SDL chunk and cache it. // Allocate an SDL chunk and cache it.
Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache) Mix_Chunk *CSoundHandler::GetSoundChunk(const AudioPath & sound, bool cache)
{ {
try try
{ {
if (cache && soundChunks.find(sound) != soundChunks.end()) if (cache && soundChunks.find(sound) != soundChunks.end())
return soundChunks[sound].first; return soundChunks[sound].first;
auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll(); auto data = CResourceHandler::get()->load(sound.addPrefix("SOUNDS/"))->readAll();
SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second); SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second);
Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
if (cache) if (cache)
soundChunks.insert(std::pair<std::string, CachedChunk>(sound, std::make_pair (chunk, std::move (data.first)))); soundChunks.insert({sound, std::make_pair (chunk, std::move (data.first))});
return chunk; return chunk;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logGlobal->warn("Cannot get sound %s chunk: %s", sound, e.what()); logGlobal->warn("Cannot get sound %s chunk: %s", sound.getOriginalName(), e.what());
return nullptr; return nullptr;
} }
} }
@ -153,7 +153,7 @@ int CSoundHandler::ambientDistToVolume(int distance) const
return volume * (int)ambientConfig["volume"].Integer() / 100; return volume * (int)ambientConfig["volume"].Integer() / 100;
} }
void CSoundHandler::ambientStopSound(std::string soundId) void CSoundHandler::ambientStopSound(const AudioPath & soundId)
{ {
stopSound(ambientChannels[soundId]); stopSound(ambientChannels[soundId]);
setChannelVolume(ambientChannels[soundId], volume); setChannelVolume(ambientChannels[soundId], volume);
@ -163,13 +163,13 @@ void CSoundHandler::ambientStopSound(std::string soundId)
int CSoundHandler::playSound(soundBase::soundID soundID, int repeats) int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
{ {
assert(soundID < soundBase::sound_after_last); assert(soundID < soundBase::sound_after_last);
auto sound = sounds[soundID]; auto sound = AudioPath::builtin(sounds[soundID]);
logGlobal->trace("Attempt to play sound %d with file name %s with cache", soundID, sound); logGlobal->trace("Attempt to play sound %d with file name %s with cache", soundID, sound.getOriginalName());
return playSound(sound, repeats, true); return playSound(sound, repeats, true);
} }
int CSoundHandler::playSound(std::string sound, int repeats, bool cache) int CSoundHandler::playSound(const AudioPath & sound, int repeats, bool cache)
{ {
if (!initialized || sound.empty()) if (!initialized || sound.empty())
return -1; return -1;
@ -182,7 +182,7 @@ int CSoundHandler::playSound(std::string sound, int repeats, bool cache)
channel = Mix_PlayChannel(-1, chunk, repeats); channel = Mix_PlayChannel(-1, chunk, repeats);
if (channel == -1) if (channel == -1)
{ {
logGlobal->error("Unable to play sound file %s , error %s", sound, Mix_GetError()); logGlobal->error("Unable to play sound file %s , error %s", sound.getOriginalName(), Mix_GetError());
if (!cache) if (!cache)
Mix_FreeChunk(chunk); Mix_FreeChunk(chunk);
} }
@ -290,14 +290,14 @@ int CSoundHandler::ambientGetRange() const
return static_cast<int>(ambientConfig["range"].Integer()); return static_cast<int>(ambientConfig["range"].Integer());
} }
void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg) void CSoundHandler::ambientUpdateChannels(std::map<AudioPath, int> soundsArg)
{ {
boost::mutex::scoped_lock guard(mutex); boost::mutex::scoped_lock guard(mutex);
std::vector<std::string> stoppedSounds; std::vector<AudioPath> stoppedSounds;
for(auto & pair : ambientChannels) for(auto & pair : ambientChannels)
{ {
const std::string & soundId = pair.first; const auto & soundId = pair.first;
const int channel = pair.second; const int channel = pair.second;
if(!vstd::contains(soundsArg, soundId)) if(!vstd::contains(soundsArg, soundId))
@ -320,7 +320,7 @@ void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
for(auto & pair : soundsArg) for(auto & pair : soundsArg)
{ {
const std::string & soundId = pair.first; const auto & soundId = pair.first;
const int distance = pair.second; const int distance = pair.second;
if(!vstd::contains(ambientChannels, soundId)) if(!vstd::contains(ambientChannels, soundId))
@ -357,7 +357,7 @@ CMusicHandler::CMusicHandler():
{ {
listener(std::bind(&CMusicHandler::onVolumeChange, this, _1)); listener(std::bind(&CMusicHandler::onVolumeChange, this, _1));
auto mp3files = CResourceHandler::get()->getFilteredFiles([](const ResourceID & id) -> bool auto mp3files = CResourceHandler::get()->getFilteredFiles([](const ResourcePath & id) -> bool
{ {
if(id.getType() != EResType::SOUND) if(id.getType() != EResType::SOUND)
return false; return false;
@ -369,12 +369,12 @@ CMusicHandler::CMusicHandler():
return true; return true;
}); });
for(const ResourceID & file : mp3files) for(const ResourcePath & file : mp3files)
{ {
if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat")) if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat"))
addEntryToSet("battle", file.getName()); addEntryToSet("battle", AudioPath::fromResource(file));
else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme")) else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme"))
addEntryToSet("enemy-turn", file.getName()); addEntryToSet("enemy-turn", AudioPath::fromResource(file));
} }
} }
@ -383,11 +383,11 @@ void CMusicHandler::loadTerrainMusicThemes()
{ {
for (const auto & terrain : CGI->terrainTypeHandler->objects) for (const auto & terrain : CGI->terrainTypeHandler->objects)
{ {
addEntryToSet("terrain_" + terrain->getJsonKey(), "Music/" + terrain->musicFilename); addEntryToSet("terrain_" + terrain->getJsonKey(), terrain->musicFilename);
} }
} }
void CMusicHandler::addEntryToSet(const std::string & set, const std::string & musicURI) void CMusicHandler::addEntryToSet(const std::string & set, const AudioPath & musicURI)
{ {
musicsSet[set].push_back(musicURI); musicsSet[set].push_back(musicURI);
} }
@ -421,7 +421,7 @@ void CMusicHandler::release()
CAudioBase::release(); CAudioBase::release();
} }
void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart) void CMusicHandler::playMusic(const AudioPath & musicURI, bool loop, bool fromStart)
{ {
boost::mutex::scoped_lock guard(mutex); boost::mutex::scoped_lock guard(mutex);
@ -451,7 +451,7 @@ void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bo
return; return;
// in this mode - play random track from set // in this mode - play random track from set
queueNext(this, whichSet, "", loop, fromStart); queueNext(this, whichSet, AudioPath(), loop, fromStart);
} }
void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued) void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
@ -468,7 +468,7 @@ void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
} }
} }
void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart) void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const AudioPath & musicURI, bool looped, bool fromStart)
{ {
queueNext(std::make_unique<MusicEntry>(owner, setName, musicURI, looped, fromStart)); queueNext(std::make_unique<MusicEntry>(owner, setName, musicURI, looped, fromStart));
} }
@ -523,7 +523,7 @@ void CMusicHandler::musicFinishedCallback()
}); });
} }
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart): MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, const AudioPath & musicURI, bool looped, bool fromStart):
owner(owner), owner(owner),
music(nullptr), music(nullptr),
playing(false), playing(false),
@ -552,39 +552,43 @@ MusicEntry::~MusicEntry()
Mix_HaltMusic(); Mix_HaltMusic();
} }
logGlobal->trace("Del-ing music file %s", currentName); logGlobal->trace("Del-ing music file %s", currentName.getOriginalName());
if (music) if (music)
Mix_FreeMusic(music); Mix_FreeMusic(music);
} }
void MusicEntry::load(std::string musicURI) void MusicEntry::load(const AudioPath & musicURI)
{ {
if (music) if (music)
{ {
logGlobal->trace("Del-ing music file %s", currentName); logGlobal->trace("Del-ing music file %s", currentName.getOriginalName());
Mix_FreeMusic(music); Mix_FreeMusic(music);
music = nullptr; music = nullptr;
} }
currentName = musicURI; if (CResourceHandler::get()->existsResource(musicURI))
currentName = musicURI;
else
currentName = musicURI.addPrefix("MUSIC/");
music = nullptr; music = nullptr;
logGlobal->trace("Loading music file %s", musicURI); logGlobal->trace("Loading music file %s", currentName.getOriginalName());
try try
{ {
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::SOUND))); auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(currentName));
music = Mix_LoadMUS_RW(musicFile, SDL_TRUE); music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logGlobal->error("Failed to load music. setName=%s\tmusicURI=%s", setName, musicURI); logGlobal->error("Failed to load music. setName=%s\tmusicURI=%s", setName, currentName.getOriginalName());
logGlobal->error("Exception: %s", e.what()); logGlobal->error("Exception: %s", e.what());
} }
if(!music) if(!music)
{ {
logGlobal->warn("Warning: Cannot open %s: %s", currentName, Mix_GetError()); logGlobal->warn("Warning: Cannot open %s: %s", currentName.getOriginalName(), Mix_GetError());
return; return;
} }
} }
@ -601,7 +605,7 @@ bool MusicEntry::play()
load(*iter); load(*iter);
} }
logGlobal->trace("Playing music file %s", currentName); logGlobal->trace("Playing music file %s", currentName.getOriginalName());
if (!fromStart && owner->trackPositions.count(currentName) > 0 && owner->trackPositions[currentName] > 0) if (!fromStart && owner->trackPositions.count(currentName) > 0 && owner->trackPositions[currentName] > 0)
{ {
@ -646,7 +650,7 @@ bool MusicEntry::stop(int fade_ms)
assert(startTime != uint32_t(-1)); assert(startTime != uint32_t(-1));
float playDuration = (endTime - startTime + startPosition) / 1000.f; float playDuration = (endTime - startTime + startPosition) / 1000.f;
owner->trackPositions[currentName] = playDuration; owner->trackPositions[currentName] = playDuration;
logGlobal->trace("Stopping music file %s at %f", currentName, playDuration); logGlobal->trace("Stopping music file %s at %f", currentName.getOriginalName(), playDuration);
Mix_FadeOutMusic(fade_ms); Mix_FadeOutMusic(fade_ms);
return true; return true;
@ -664,7 +668,7 @@ bool MusicEntry::isSet(std::string set)
return !setName.empty() && set == setName; return !setName.empty() && set == setName;
} }
bool MusicEntry::isTrack(std::string track) bool MusicEntry::isTrack(const AudioPath & track)
{ {
return setName.empty() && track == currentName; return setName.empty() && track == currentName;
} }

View File

@ -35,15 +35,14 @@ public:
class CSoundHandler: public CAudioBase class CSoundHandler: public CAudioBase
{ {
private: private:
//soundBase::soundID getSoundID(const std::string &fileName);
//update volume on configuration change //update volume on configuration change
SettingsListener listener; SettingsListener listener;
void onVolumeChange(const JsonNode &volumeNode); void onVolumeChange(const JsonNode &volumeNode);
using CachedChunk = std::pair<Mix_Chunk *, std::unique_ptr<ui8[]>>; using CachedChunk = std::pair<Mix_Chunk *, std::unique_ptr<ui8[]>>;
std::map<std::string, CachedChunk> soundChunks; std::map<AudioPath, CachedChunk> soundChunks;
Mix_Chunk *GetSoundChunk(std::string &sound, bool cache); Mix_Chunk *GetSoundChunk(const AudioPath & sound, bool cache);
/// have entry for every currently active channel /// have entry for every currently active channel
/// vector will be empty if callback was not set /// vector will be empty if callback was not set
@ -54,12 +53,12 @@ private:
boost::mutex mutexCallbacks; boost::mutex mutexCallbacks;
int ambientDistToVolume(int distance) const; int ambientDistToVolume(int distance) const;
void ambientStopSound(std::string soundId); void ambientStopSound(const AudioPath & soundId);
void updateChannelVolume(int channel); void updateChannelVolume(int channel);
const JsonNode ambientConfig; const JsonNode ambientConfig;
std::map<std::string, int> ambientChannels; std::map<AudioPath, int> ambientChannels;
std::map<int, int> channelVolumes; std::map<int, int> channelVolumes;
void initCallback(int channel, const std::function<void()> & function); void initCallback(int channel, const std::function<void()> & function);
@ -76,7 +75,7 @@ public:
// Sounds // Sounds
int playSound(soundBase::soundID soundID, int repeats=0); int playSound(soundBase::soundID soundID, int repeats=0);
int playSound(std::string sound, int repeats=0, bool cache=false); int playSound(const AudioPath & sound, int repeats=0, bool cache=false);
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec); int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
void stopSound(int handler); void stopSound(int handler);
@ -84,16 +83,13 @@ public:
void soundFinishedCallback(int channel); void soundFinishedCallback(int channel);
int ambientGetRange() const; int ambientGetRange() const;
void ambientUpdateChannels(std::map<std::string, int> currentSounds); void ambientUpdateChannels(std::map<AudioPath, int> currentSounds);
void ambientStopAllChannels(); void ambientStopAllChannels();
// Sets // Sets
std::vector<soundBase::soundID> battleIntroSounds; std::vector<soundBase::soundID> battleIntroSounds;
}; };
// Helper //now it looks somewhat useless
#define battle_sound(creature,what_sound) creature->sounds.what_sound
class CMusicHandler; class CMusicHandler;
//Class for handling one music file //Class for handling one music file
@ -109,16 +105,16 @@ class MusicEntry
uint32_t startPosition; uint32_t startPosition;
//if not null - set from which music will be randomly selected //if not null - set from which music will be randomly selected
std::string setName; std::string setName;
std::string currentName; AudioPath currentName;
void load(std::string musicURI); void load(const AudioPath & musicURI);
public: public:
MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart); MusicEntry(CMusicHandler *owner, std::string setName, const AudioPath & musicURI, bool looped, bool fromStart);
~MusicEntry(); ~MusicEntry();
bool isSet(std::string setName); bool isSet(std::string setName);
bool isTrack(std::string trackName); bool isTrack(const AudioPath & trackName);
bool isPlaying(); bool isPlaying();
bool play(); bool play();
@ -135,20 +131,20 @@ private:
std::unique_ptr<MusicEntry> current; std::unique_ptr<MusicEntry> current;
std::unique_ptr<MusicEntry> next; std::unique_ptr<MusicEntry> next;
void queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart); void queueNext(CMusicHandler *owner, const std::string & setName, const AudioPath & musicURI, bool looped, bool fromStart);
void queueNext(std::unique_ptr<MusicEntry> queued); void queueNext(std::unique_ptr<MusicEntry> queued);
void musicFinishedCallback(); void musicFinishedCallback();
/// map <set name> -> <list of URI's to tracks belonging to the said set> /// map <set name> -> <list of URI's to tracks belonging to the said set>
std::map<std::string, std::vector<std::string>> musicsSet; std::map<std::string, std::vector<AudioPath>> musicsSet;
/// stored position, in seconds at which music player should resume playing this track /// stored position, in seconds at which music player should resume playing this track
std::map<std::string, float> trackPositions; std::map<AudioPath, float> trackPositions;
public: public:
CMusicHandler(); CMusicHandler();
/// add entry with URI musicURI in set. Track will have ID musicID /// add entry with URI musicURI in set. Track will have ID musicID
void addEntryToSet(const std::string & set, const std::string & musicURI); void addEntryToSet(const std::string & set, const AudioPath & musicURI);
void init() override; void init() override;
void loadTerrainMusicThemes(); void loadTerrainMusicThemes();
@ -156,7 +152,7 @@ public:
void setVolume(ui32 percent) override; void setVolume(ui32 percent) override;
/// play track by URI, if loop = true music will be looped /// play track by URI, if loop = true music will be looped
void playMusic(const std::string & musicURI, bool loop, bool fromStart); void playMusic(const AudioPath & musicURI, bool loop, bool fromStart);
/// play random track from this set /// play random track from this set
void playMusicFromSet(const std::string & musicSet, bool loop, bool fromStart); void playMusicFromSet(const std::string & musicSet, bool loop, bool fromStart);
/// play random track from set (musicSet, entryID) /// play random track from set (musicSet, entryID)

View File

@ -125,7 +125,7 @@ struct HeroObjectRetriever
CPlayerInterface::CPlayerInterface(PlayerColor Player): CPlayerInterface::CPlayerInterface(PlayerColor Player):
localState(std::make_unique<PlayerLocalState>(*this)) localState(std::make_unique<PlayerLocalState>(*this))
{ {
logGlobal->trace("\tHuman player interface for player %s being constructed", Player.getStr()); logGlobal->trace("\tHuman player interface for player %s being constructed", Player.toString());
destinationTeleport = ObjectInstanceID(); destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1); destinationTeleportPos = int3(-1);
GH.defActionsDef = 0; GH.defActionsDef = 0;
@ -147,7 +147,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
CPlayerInterface::~CPlayerInterface() CPlayerInterface::~CPlayerInterface()
{ {
logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.getStr()); logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.toString());
delete showingDialog; delete showingDialog;
delete cingconsole; delete cingconsole;
if (LOCPLINT == this) if (LOCPLINT == this)
@ -658,7 +658,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID build
} }
} }
void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) void CPlayerInterface::battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2)
{ {
// when battle starts, game will send battleStart pack *before* movement confirmation // when battle starts, game will send battleStart pack *before* movement confirmation
// and since network thread wait for battle intro to play, movement confirmation will only happen after intro // and since network thread wait for battle intro to play, movement confirmation will only happen after intro
@ -670,7 +670,7 @@ void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreat
waitForAllDialogs(); waitForAllDialogs();
} }
void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -685,7 +685,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool(); autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool();
autofightingAI->initBattleInterface(env, cb, autocombatPreferences); autofightingAI->initBattleInterface(env, cb, autocombatPreferences);
autofightingAI->battleStart(army1, army2, tile, hero1, hero2, side, false); autofightingAI->battleStart(battleID, army1, army2, tile, hero1, hero2, side, false);
isAutoFightOn = true; isAutoFightOn = true;
cb->registerBattleInterface(autofightingAI); cb->registerBattleInterface(autofightingAI);
} }
@ -697,7 +697,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) void CPlayerInterface::battleUnitsChanged(const BattleID & battleID, const std::vector<UnitChanges> & units)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -708,7 +708,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
{ {
case UnitChanges::EOperation::RESET_STATE: case UnitChanges::EOperation::RESET_STATE:
{ {
const CStack * stack = cb->battleGetStackByID(info.id ); const CStack * stack = cb->getBattle(battleID)->battleGetStackByID(info.id );
if(!stack) if(!stack)
{ {
@ -723,7 +723,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
break; break;
case UnitChanges::EOperation::ADD: case UnitChanges::EOperation::ADD:
{ {
const CStack * unit = cb->battleGetStackByID(info.id); const CStack * unit = cb->getBattle(battleID)->battleGetStackByID(info.id);
if(!unit) if(!unit)
{ {
logGlobal->error("Invalid unit ID %d", info.id); logGlobal->error("Invalid unit ID %d", info.id);
@ -739,7 +739,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
} }
} }
void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) void CPlayerInterface::battleObstaclesChanged(const BattleID & battleID, const std::vector<ObstacleChanges> & obstacles)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -751,7 +751,7 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges>
{ {
if(change.operation == BattleChanges::EOperation::ADD) if(change.operation == BattleChanges::EOperation::ADD)
{ {
auto instance = cb->battleGetObstacleByID(change.id); auto instance = cb->getBattle(battleID)->battleGetObstacleByID(change.id);
if(instance) if(instance)
newObstacles.push_back(instance); newObstacles.push_back(instance);
else else
@ -770,7 +770,7 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges>
battleInt->fieldController->redrawBackgroundWithHexes(); battleInt->fieldController->redrawBackgroundWithHexes();
} }
void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca) void CPlayerInterface::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -778,15 +778,15 @@ void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
battleInt->stackIsCatapulting(ca); battleInt->stackIsCatapulting(ca);
} }
void CPlayerInterface::battleNewRound(int round) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn void CPlayerInterface::battleNewRound(const BattleID & battleID) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->newRound(round); battleInt->newRound();
} }
void CPlayerInterface::actionStarted(const BattleAction &action) void CPlayerInterface::actionStarted(const BattleID & battleID, const BattleAction &action)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -794,7 +794,7 @@ void CPlayerInterface::actionStarted(const BattleAction &action)
battleInt->startAction(action); battleInt->startAction(action);
} }
void CPlayerInterface::actionFinished(const BattleAction &action) void CPlayerInterface::actionFinished(const BattleID & battleID, const BattleAction &action)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -802,17 +802,17 @@ void CPlayerInterface::actionFinished(const BattleAction &action)
battleInt->endAction(action); battleInt->endAction(action);
} }
void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack void CPlayerInterface::activeStack(const BattleID & battleID, const CStack * stack) //called when it's turn of that stack
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
logGlobal->trace("Awaiting command for %s", stack->nodeName()); logGlobal->trace("Awaiting command for %s", stack->nodeName());
assert(!cb->battleIsFinished()); assert(!cb->getBattle(battleID)->battleIsFinished());
if (cb->battleIsFinished()) if (cb->getBattle(battleID)->battleIsFinished())
{ {
logGlobal->error("Received CPlayerInterface::activeStack after battle is finished!"); logGlobal->error("Received CPlayerInterface::activeStack after battle is finished!");
cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack));
return ; return ;
} }
@ -823,7 +823,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn
//FIXME: we want client rendering to proceed while AI is making actions //FIXME: we want client rendering to proceed while AI is making actions
// so unlock mutex while AI is busy since this might take quite a while, especially if hero has many spells // so unlock mutex while AI is busy since this might take quite a while, especially if hero has many spells
auto unlockPim = vstd::makeUnlockGuard(*pim); auto unlockPim = vstd::makeUnlockGuard(*pim);
autofightingAI->activeStack(stack); autofightingAI->activeStack(battleID, stack);
return; return;
} }
@ -835,7 +835,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn
if(!battleInt) if(!battleInt)
{ {
// probably battle is finished already // probably battle is finished already
cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack));
} }
{ {
@ -845,7 +845,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn
} }
} }
void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID) void CPlayerInterface::battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
if(isAutoFightOn || autofightingAI) if(isAutoFightOn || autofightingAI)
@ -880,7 +880,7 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
battleInt->battleFinished(*br, queryID); battleInt->battleFinished(*br, queryID);
} }
void CPlayerInterface::battleLogMessage(const std::vector<MetaString> & lines) void CPlayerInterface::battleLogMessage(const BattleID & battleID, const std::vector<MetaString> & lines)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -888,28 +888,28 @@ void CPlayerInterface::battleLogMessage(const std::vector<MetaString> & lines)
battleInt->displayBattleLog(lines); battleInt->displayBattleLog(lines);
} }
void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) void CPlayerInterface::battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->stackMoved(stack, dest, distance, teleport); battleInt->stackMoved(stack, dest, distance, teleport);
} }
void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc ) void CPlayerInterface::battleSpellCast(const BattleID & battleID, const BattleSpellCast * sc)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->spellCast(sc); battleInt->spellCast(sc);
} }
void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse ) void CPlayerInterface::battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->battleStacksEffectsSet(sse); battleInt->battleStacksEffectsSet(sse);
} }
void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte) void CPlayerInterface::battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -923,7 +923,7 @@ void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
battleInt->windowObject->heroManaPointsChanged(manaDrainedHero); battleInt->windowObject->heroManaPointsChanged(manaDrainedHero);
} }
} }
void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) void CPlayerInterface::battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -931,8 +931,8 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
std::vector<StackAttackedInfo> arg; std::vector<StackAttackedInfo> arg;
for(auto & elem : bsa) for(auto & elem : bsa)
{ {
const CStack * defender = cb->battleGetStackByID(elem.stackAttacked, false); const CStack * defender = cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked, false);
const CStack * attacker = cb->battleGetStackByID(elem.attackerID, false); const CStack * attacker = cb->getBattle(battleID)->battleGetStackByID(elem.attackerID, false);
assert(defender); assert(defender);
@ -955,13 +955,13 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
} }
battleInt->stacksAreAttacked(arg); battleInt->stacksAreAttacked(arg);
} }
void CPlayerInterface::battleAttack(const BattleAttack * ba) void CPlayerInterface::battleAttack(const BattleID & battleID, const BattleAttack * ba)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
StackAttackInfo info; StackAttackInfo info;
info.attacker = cb->battleGetStackByID(ba->stackAttacking); info.attacker = cb->getBattle(battleID)->battleGetStackByID(ba->stackAttacking);
info.defender = nullptr; info.defender = nullptr;
info.indirectAttack = ba->shot(); info.indirectAttack = ba->shot();
info.lucky = ba->lucky(); info.lucky = ba->lucky();
@ -979,11 +979,11 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
if(!elem.isSecondary()) if(!elem.isSecondary())
{ {
assert(info.defender == nullptr); assert(info.defender == nullptr);
info.defender = cb->battleGetStackByID(elem.stackAttacked); info.defender = cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked);
} }
else else
{ {
info.secondaryDefender.push_back(cb->battleGetStackByID(elem.stackAttacked)); info.secondaryDefender.push_back(cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked));
} }
} }
assert(info.defender != nullptr); assert(info.defender != nullptr);
@ -992,7 +992,7 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
battleInt->stackAttacking(info); battleInt->stackAttacking(info);
} }
void CPlayerInterface::battleGateStateChanged(const EGateState state) void CPlayerInterface::battleGateStateChanged(const BattleID & battleID, const EGateState state)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
@ -1000,7 +1000,7 @@ void CPlayerInterface::battleGateStateChanged(const EGateState state)
battleInt->gateStateChanged(state); battleInt->gateStateChanged(state);
} }
void CPlayerInterface::yourTacticPhase(int distance) void CPlayerInterface::yourTacticPhase(const BattleID & battleID, int distance)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
} }
@ -1112,11 +1112,11 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
for (auto & component : components) for (auto & component : components)
intComps.push_back(std::make_shared<CSelectableComponent>(component)); //will be deleted by CSelWindow::close intComps.push_back(std::make_shared<CSelectableComponent>(component)); //will be deleted by CSelWindow::close
std::vector<std::pair<std::string,CFunctionList<void()> > > pom; std::vector<std::pair<AnimationPath,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0)); pom.push_back({ AnimationPath::builtin("IOKAY.DEF"),0});
if (cancel) if (cancel)
{ {
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0)); pom.push_back({AnimationPath::builtin("ICANCEL.DEF"),0});
} }
int charperline = 35; int charperline = 35;
@ -1288,7 +1288,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
* 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.
*/ */
void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes) void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<void()> onYes)
{ {
std::string text = artifact->getDescriptionTranslated(); std::string text = artifact->getDescriptionTranslated();
text += "\n\n"; text += "\n\n";
@ -1657,7 +1657,7 @@ void CPlayerInterface::viewWorldMap()
adventureInt->openWorldView(); adventureInt->openWorldView();
} }
void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID) void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1667,8 +1667,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK) if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
localState->erasePath(caster); localState->erasePath(caster);
const spells::Spell * spell = CGI->spells()->getByIndex(spellID); auto castSoundPath = spellID.toSpell()->getCastSound();
auto castSoundPath = spell->getCastSound();
if(!castSoundPath.empty()) if(!castSoundPath.empty())
CCS->soundh->playSound(castSoundPath); CCS->soundh->playSound(castSoundPath);
} }
@ -1705,12 +1704,12 @@ void CPlayerInterface::tryDigging(const CGHeroInstance * h)
showInfoDialog(CGI->generaltexth->allTexts[msgToShow]); showInfoDialog(CGI->generaltexth->allTexts[msgToShow]);
} }
void CPlayerInterface::battleNewRoundFirst( int round ) void CPlayerInterface::battleNewRoundFirst(const BattleID & battleID)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->newRoundFirst(round); battleInt->newRoundFirst();
} }
void CPlayerInterface::stopMovement() void CPlayerInterface::stopMovement()
@ -1992,22 +1991,22 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
elem.coord = h->convertFromVisitablePos(elem.coord); elem.coord = h->convertFromVisitablePos(elem.coord);
int soundChannel = -1; int soundChannel = -1;
std::string soundName; AudioPath soundName;
auto getMovementSoundFor = [&](const CGHeroInstance * hero, int3 posPrev, int3 posNext, EPathNodeAction moveType) -> std::string auto getMovementSoundFor = [&](const CGHeroInstance * hero, int3 posPrev, int3 posNext, EPathNodeAction moveType) -> AudioPath
{ {
if (moveType == EPathNodeAction::TELEPORT_BATTLE || moveType == EPathNodeAction::TELEPORT_BLOCKING_VISIT || moveType == EPathNodeAction::TELEPORT_NORMAL) if (moveType == EPathNodeAction::TELEPORT_BATTLE || moveType == EPathNodeAction::TELEPORT_BLOCKING_VISIT || moveType == EPathNodeAction::TELEPORT_NORMAL)
return ""; return {};
if (moveType == EPathNodeAction::EMBARK || moveType == EPathNodeAction::DISEMBARK) if (moveType == EPathNodeAction::EMBARK || moveType == EPathNodeAction::DISEMBARK)
return ""; return {};
if (moveType == EPathNodeAction::BLOCKING_VISIT) if (moveType == EPathNodeAction::BLOCKING_VISIT)
return ""; return {};
// flying movement sound // flying movement sound
if (hero->hasBonusOfType(BonusType::FLYING_MOVEMENT)) if (hero->hasBonusOfType(BonusType::FLYING_MOVEMENT))
return "HORSE10.wav"; return AudioPath::builtin("HORSE10.wav");
auto prevTile = cb->getTile(h->convertToVisitablePos(posPrev)); auto prevTile = cb->getTile(h->convertToVisitablePos(posPrev));
auto nextTile = cb->getTile(h->convertToVisitablePos(posNext)); auto nextTile = cb->getTile(h->convertToVisitablePos(posNext));
@ -2073,7 +2072,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{ {
// Start a new sound for the hero movement or let the existing one carry on. // Start a new sound for the hero movement or let the existing one carry on.
std::string newSoundName = getMovementSoundFor(h, prevCoord, nextCoord, path.nodes[i-1].action); AudioPath newSoundName = getMovementSoundFor(h, prevCoord, nextCoord, path.nodes[i-1].action);
if(newSoundName != soundName) if(newSoundName != soundName)
{ {
@ -2126,7 +2125,7 @@ void CPlayerInterface::showWorldViewEx(const std::vector<ObjectPosInfo>& objectP
adventureInt->openWorldView(objectPositions, showTerrain ); adventureInt->openWorldView(objectPositions, showTerrain );
} }
std::optional<BattleAction> CPlayerInterface::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) std::optional<BattleAction> CPlayerInterface::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
{ {
return std::nullopt; return std::nullopt;
} }

View File

@ -128,7 +128,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override; void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override; void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override; void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; //called when a hero casts a spell void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override; //called when a hero casts a spell
void tileHidden(const std::unordered_set<int3> &pos) override; //called when given tiles become hidden under fog of war void tileHidden(const std::unordered_set<int3> &pos) override; //called when given tiles become hidden under fog of war
void tileRevealed(const std::unordered_set<int3> &pos) override; //called when fog of war disappears from given tiles void tileRevealed(const std::unordered_set<int3> &pos) override; //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj) override; void newObject(const CGObjectInstance * obj) override;
@ -152,27 +152,27 @@ protected: // Call-ins from server, should not be called directly, but only via
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override; void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
//for battles //for battles
void actionFinished(const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero void actionFinished(const BattleID & battleID, const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero
void actionStarted(const BattleAction& action) override;//occurs BEFORE action taken by active stack or by the hero void actionStarted(const BattleID & battleID, const BattleAction& action) override;//occurs BEFORE action taken by active stack or by the hero
void activeStack(const CStack * stack) override; //called when it's turn of that stack void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack
void battleAttack(const BattleAttack *ba) override; //stack performs attack void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //stack performs attack
void battleEnd(const BattleResult *br, QueryID queryID) override; //end of battle void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) 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(const BattleID & battleID) 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(const BattleID & battleID) 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 battleLogMessage(const BattleID & battleID, const std::vector<MetaString> & lines) override;
void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) override; void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) override;
void battleSpellCast(const BattleSpellCast *sc) override; void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
void battleStacksEffectsSet(const SetStackEffect & sse) override; //called when a specific effect is set to stacks void battleStacksEffectsSet(const BattleID & battleID, 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 BattleID & battleID, const BattleTriggerEffect & bte) override; //various one-shot effect
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override; void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) 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 BattleID & battleID, 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, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
void battleUnitsChanged(const std::vector<UnitChanges> & units) override; void battleUnitsChanged(const BattleID & battleID, const std::vector<UnitChanges> & units) override;
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override; void battleObstaclesChanged(const BattleID & battleID, const std::vector<ObstacleChanges> & obstacles) override;
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
void battleGateStateChanged(const EGateState state) override; void battleGateStateChanged(const BattleID & battleID, const EGateState state) override;
void yourTacticPhase(int distance) override; void yourTacticPhase(const BattleID & battleID, int distance) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
public: // public interface for use by client via LOCPLINT access public: // public interface for use by client via LOCPLINT access
@ -185,7 +185,7 @@ public: // public interface for use by client via LOCPLINT access
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard; void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2); void showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2);
void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes); void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<void()> onYes);
void waitWhileDialog(bool unlockPim = true); void waitWhileDialog(bool unlockPim = true);
void waitForAllDialogs(bool unlockPim = true); void waitForAllDialogs(bool unlockPim = true);
void openTownWindow(const CGTownInstance * town); //shows townscreen void openTownWindow(const CGTownInstance * town); //shows townscreen

View File

@ -748,7 +748,7 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
if(save) if(save)
{ {
resetStateForLobby(StartInfo::LOAD_GAME); resetStateForLobby(StartInfo::LOAD_GAME);
mapInfo->saveInit(ResourceID(filename, EResType::SAVEGAME)); mapInfo->saveInit(ResourcePath(filename, EResType::SAVEGAME));
screenType = ESelectionScreen::loadGame; screenType = ESelectionScreen::loadGame;
} }
else else

View File

@ -70,30 +70,32 @@ CVideoPlayer::CVideoPlayer()
, doLoop(false) , doLoop(false)
{} {}
bool CVideoPlayer::open(std::string fname, bool scale) bool CVideoPlayer::open(const VideoPath & fname, bool scale)
{ {
return open(fname, true, false); return open(fname, true, false);
} }
// loop = to loop through the video // loop = to loop through the video
// useOverlay = directly write to the screen. // useOverlay = directly write to the screen.
bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scale) bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverlay, bool scale)
{ {
close(); close();
this->fname = fname;
doLoop = loop; doLoop = loop;
frameTime = 0; frameTime = 0;
ResourceID resource(std::string("Video/") + fname, EResType::VIDEO); if (CResourceHandler::get()->existsResource(videoToOpen))
fname = videoToOpen;
else
fname = videoToOpen.addPrefix("VIDEO/");
if (!CResourceHandler::get()->existsResource(resource)) if (!CResourceHandler::get()->existsResource(fname))
{ {
logGlobal->error("Error: video %s was not found", resource.getName()); logGlobal->error("Error: video %s was not found", fname.getName());
return false; return false;
} }
data = CResourceHandler::get()->load(resource); data = CResourceHandler::get()->load(fname);
static const int BUFFER_SIZE = 4096; static const int BUFFER_SIZE = 4096;
@ -382,7 +384,8 @@ void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, boo
void CVideoPlayer::close() void CVideoPlayer::close()
{ {
fname.clear(); fname = VideoPath();
if (sws) if (sws)
{ {
sws_freeContext(sws); sws_freeContext(sws);
@ -467,7 +470,7 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
return true; return true;
} }
bool CVideoPlayer::openAndPlayVideo(std::string name, int x, int y, bool stopOnKey, bool scale) bool CVideoPlayer::openAndPlayVideo(const VideoPath & name, int x, int y, bool stopOnKey, bool scale)
{ {
open(name, false, true, scale); open(name, false, true, scale);
bool ret = playVideo(x, y, stopOnKey); bool ret = playVideo(x, y, stopOnKey);

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../lib/Rect.h" #include "../lib/Rect.h"
#include "../lib/filesystem/ResourcePath.h"
struct SDL_Surface; struct SDL_Surface;
struct SDL_Texture; struct SDL_Texture;
@ -17,7 +18,7 @@ struct SDL_Texture;
class IVideoPlayer class IVideoPlayer
{ {
public: public:
virtual bool open(std::string name, bool scale = false)=0; //true - succes virtual bool open(const VideoPath & name, bool scale = false)=0; //true - succes
virtual void close()=0; virtual void close()=0;
virtual bool nextFrame()=0; virtual bool nextFrame()=0;
virtual void show(int x, int y, SDL_Surface *dst, bool update = true)=0; virtual void show(int x, int y, SDL_Surface *dst, bool update = true)=0;
@ -30,10 +31,10 @@ public:
class IMainVideoPlayer : public IVideoPlayer class IMainVideoPlayer : public IVideoPlayer
{ {
public: public:
std::string fname; //name of current video file (empty if idle) VideoPath fname; //name of current video file (empty if idle)
virtual void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true){} virtual void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true){}
virtual bool openAndPlayVideo(std::string name, int x, int y, bool stopOnKey = false, bool scale = false) virtual bool openAndPlayVideo(const VideoPath & name, int x, int y, bool stopOnKey = false, bool scale = false)
{ {
return false; return false;
} }
@ -49,7 +50,7 @@ public:
bool nextFrame() override {return false;}; bool nextFrame() override {return false;};
void close() override {}; void close() override {};
bool wait() override {return false;}; bool wait() override {return false;};
bool open(std::string name, bool scale = false) override {return false;}; bool open(const VideoPath & name, bool scale = false) override {return false;};
}; };
#ifndef DISABLE_VIDEO #ifndef DISABLE_VIDEO
@ -85,14 +86,14 @@ class CVideoPlayer : public IMainVideoPlayer
bool doLoop; // loop through video bool doLoop; // loop through video
bool playVideo(int x, int y, bool stopOnKey); bool playVideo(int x, int y, bool stopOnKey);
bool open(std::string fname, bool loop, bool useOverlay = false, bool scale = false); bool open(const VideoPath & fname, bool loop, bool useOverlay = false, bool scale = false);
public: public:
CVideoPlayer(); CVideoPlayer();
~CVideoPlayer(); ~CVideoPlayer();
bool init(); bool init();
bool open(std::string fname, bool scale = false) override; bool open(const VideoPath & fname, bool scale = false) override;
void close() override; void close() override;
bool nextFrame() override; // display next frame bool nextFrame() override; // display next frame
@ -101,7 +102,7 @@ public:
void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true) override; //moves to next frame if appropriate, and blits it or blits only if redraw parameter is set true void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true) override; //moves to next frame if appropriate, and blits it or blits only if redraw parameter is set true
// Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played) // Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
bool openAndPlayVideo(std::string name, int x, int y, bool stopOnKey = false, bool scale = false) override; bool openAndPlayVideo(const VideoPath & name, int x, int y, bool stopOnKey = false, bool scale = false) override;
//TODO: //TODO:
bool wait() override {return false;}; bool wait() override {return false;};

View File

@ -122,9 +122,9 @@ events::EventBus * CPlayerEnvironment::eventBus() const
return cl->eventBus();//always get actual value return cl->eventBus();//always get actual value
} }
const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle() const const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle(const BattleID & battleID) const
{ {
return mainCallback.get(); return mainCallback->getBattle(battleID).get();
} }
const CPlayerEnvironment::GameCb * CPlayerEnvironment::game() const const CPlayerEnvironment::GameCb * CPlayerEnvironment::game() const
@ -153,9 +153,9 @@ const Services * CClient::services() const
return VLC; //todo: this should be CGI return VLC; //todo: this should be CGI
} }
const CClient::BattleCb * CClient::battle() const const CClient::BattleCb * CClient::battle(const BattleID & battleID) const
{ {
return this; return nullptr; //todo?
} }
const CClient::GameCb * CClient::game() const const CClient::GameCb * CClient::game() const
@ -222,7 +222,7 @@ void CClient::loadGame(CGameState * initializedGameState)
// try to deserialize client data including sleepingHeroes // try to deserialize client data including sleepingHeroes
try try
{ {
boost::filesystem::path clientSaveName = *CResourceHandler::get()->getResourceName(ResourceID(CSH->si->mapname, EResType::CLIENT_SAVEGAME)); boost::filesystem::path clientSaveName = *CResourceHandler::get()->getResourceName(ResourcePath(CSH->si->mapname, EResType::CLIENT_SAVEGAME));
if(clientSaveName.empty()) if(clientSaveName.empty())
throw std::runtime_error("Cannot open client part of " + CSH->si->mapname); throw std::runtime_error("Cannot open client part of " + CSH->si->mapname);
@ -345,7 +345,7 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
void CClient::save(const std::string & fname) void CClient::save(const std::string & fname)
{ {
if(gs->curB) if(!gs->currentBattles.empty())
{ {
logNetwork->error("Game cannot be saved during battle!"); logNetwork->error("Game cannot be saved during battle!");
return; return;
@ -408,7 +408,7 @@ void CClient::initPlayerEnvironments()
bool hasHumanPlayer = false; bool hasHumanPlayer = false;
for(auto & color : allPlayers) for(auto & color : allPlayers)
{ {
logNetwork->info("Preparing environment for player %s", color.getStr()); logNetwork->info("Preparing environment for player %s", color.toString());
playerEnvironments[color] = std::make_shared<CPlayerEnvironment>(color, this, std::make_shared<CCallback>(gs, color, this)); playerEnvironments[color] = std::make_shared<CPlayerEnvironment>(color, this, std::make_shared<CCallback>(gs, color, this));
if(!hasHumanPlayer && gs->players[color].isHuman()) if(!hasHumanPlayer && gs->players[color].isHuman())
@ -439,7 +439,7 @@ void CClient::initPlayerInterfaces()
if(!vstd::contains(playerint, color)) if(!vstd::contains(playerint, color))
{ {
logNetwork->info("Preparing interface for player %s", color.getStr()); logNetwork->info("Preparing interface for player %s", color.toString());
if(playerInfo.second.isControlledByAI()) if(playerInfo.second.isControlledByAI())
{ {
bool alliedToHuman = false; bool alliedToHuman = false;
@ -448,12 +448,12 @@ void CClient::initPlayerInterfaces()
alliedToHuman = true; alliedToHuman = true;
auto AiToGive = aiNameForPlayer(playerInfo.second, false, alliedToHuman); auto AiToGive = aiNameForPlayer(playerInfo.second, false, alliedToHuman);
logNetwork->info("Player %s will be lead by %s", color.getStr(), AiToGive); logNetwork->info("Player %s will be lead by %s", color.toString(), AiToGive);
installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color); installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
} }
else else
{ {
logNetwork->info("Player %s will be lead by human", color.getStr()); logNetwork->info("Player %s will be lead by human", color.toString());
installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color); installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
} }
} }
@ -503,7 +503,7 @@ void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInte
playerint[color] = gameInterface; playerint[color] = gameInterface;
logGlobal->trace("\tInitializing the interface for player %s", color.getStr()); logGlobal->trace("\tInitializing the interface for player %s", color.toString());
auto cb = std::make_shared<CCallback>(gs, color, this); auto cb = std::make_shared<CCallback>(gs, color, this);
battleCallbacks[color] = cb; battleCallbacks[color] = cb;
gameInterface->initGameInterface(playerEnvironments.at(color), cb); gameInterface->initGameInterface(playerEnvironments.at(color), cb);
@ -519,7 +519,7 @@ void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> ba
if(needCallback) if(needCallback)
{ {
logGlobal->trace("\tInitializing the battle interface for player %s", color.getStr()); logGlobal->trace("\tInitializing the battle interface for player %s", color.toString());
auto cbc = std::make_shared<CBattleCallback>(color, this); auto cbc = std::make_shared<CBattleCallback>(color, this);
battleCallbacks[color] = cbc; battleCallbacks[color] = cbc;
battleInterface->initBattleInterface(playerEnvironments.at(color), cbc); battleInterface->initBattleInterface(playerEnvironments.at(color), cbc);
@ -565,14 +565,12 @@ 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; })
|| !battleCb.first.isValidPlayer()) || !battleCb.first.isValidPlayer())
{ {
battleCb.second->setBattle(info); battleCb.second->onBattleStarted(info);
} }
} }
@ -583,7 +581,7 @@ void CClient::battleStarted(const BattleInfo * info)
auto callBattleStart = [&](PlayerColor color, ui8 side) auto callBattleStart = [&](PlayerColor color, ui8 side)
{ {
if(vstd::contains(battleints, color)) if(vstd::contains(battleints, color))
battleints[color]->battleStart(leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed); battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed);
}; };
callBattleStart(leftSide.color, 0); callBattleStart(leftSide.color, 0);
@ -601,11 +599,11 @@ void CClient::battleStarted(const BattleInfo * info)
//Remove player interfaces for auto battle (quickCombat option) //Remove player interfaces for auto battle (quickCombat option)
if(att && att->isAutoFightOn) if(att && att->isAutoFightOn)
{ {
if (att->cb->battleGetTacticDist()) if (att->cb->getBattle(info->battleID)->battleGetTacticDist())
{ {
auto side = att->cb->playerToSide(att->playerID); auto side = att->cb->getBattle(info->battleID)->playerToSide(att->playerID);
auto action = BattleAction::makeEndOFTacticPhase(*side); auto action = BattleAction::makeEndOFTacticPhase(*side);
att->cb->battleMakeTacticAction(action); att->cb->battleMakeTacticAction(info->battleID, action);
} }
att.reset(); att.reset();
@ -617,15 +615,15 @@ void CClient::battleStarted(const BattleInfo * info)
if(att || def) if(att || def)
{ {
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def); CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def);
} }
else if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool()) else if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
{ {
//TODO: This certainly need improvement //TODO: This certainly need improvement
auto spectratorInt = std::dynamic_pointer_cast<CPlayerInterface>(playerint[PlayerColor::SPECTATOR]); auto spectratorInt = std::dynamic_pointer_cast<CPlayerInterface>(playerint[PlayerColor::SPECTATOR]);
spectratorInt->cb->setBattle(info); spectratorInt->cb->onBattleStarted(info);
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt); CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt);
} }
} }
@ -634,24 +632,21 @@ void CClient::battleStarted(const BattleInfo * info)
auto tacticianColor = info->sides[info->tacticsSide].color; auto tacticianColor = info->sides[info->tacticsSide].color;
if (vstd::contains(battleints, tacticianColor)) if (vstd::contains(battleints, tacticianColor))
battleints[tacticianColor]->yourTacticPhase(info->tacticDistance); battleints[tacticianColor]->yourTacticPhase(info->battleID, info->tacticDistance);
} }
} }
void CClient::battleFinished() void CClient::battleFinished(const BattleID & battleID)
{ {
for(auto & side : gs->curB->sides) for(auto & side : gs->getBattle(battleID)->sides)
if(battleCallbacks.count(side.color)) if(battleCallbacks.count(side.color))
battleCallbacks[side.color]->setBattle(nullptr); battleCallbacks[side.color]->onBattleEnded(battleID);
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]->onBattleEnded(battleID);
setBattle(nullptr);
gs->curB.dellNull();
} }
void CClient::startPlayerBattleAction(PlayerColor color) void CClient::startPlayerBattleAction(const BattleID & battleID, PlayerColor color)
{ {
assert(vstd::contains(battleints, color)); assert(vstd::contains(battleints, color));
@ -661,7 +656,7 @@ void CClient::startPlayerBattleAction(PlayerColor color)
auto unlock = vstd::makeUnlockGuardIf(*CPlayerInterface::pim, !battleints[color]->human); auto unlock = vstd::makeUnlockGuardIf(*CPlayerInterface::pim, !battleints[color]->human);
assert(vstd::contains(battleints, color)); assert(vstd::contains(battleints, color));
battleints[color]->activeStack(gs->curB->battleGetStackByID(gs->curB->activeStack, false)); battleints[color]->activeStack(battleID, gs->getBattle(battleID)->battleGetStackByID(gs->getBattle(battleID)->activeStack, false));
} }
} }
@ -698,11 +693,6 @@ scripting::Pool * CClient::getGlobalContextPool() const
{ {
return clientScripts.get(); return clientScripts.get();
} }
scripting::Pool * CClient::getContextPool() const
{
return clientScripts.get();
}
#endif #endif
void CClient::reinitScripting() void CClient::reinitScripting()

View File

@ -13,7 +13,6 @@
#include <vcmi/Environment.h> #include <vcmi/Environment.h>
#include "../lib/IGameCallback.h" #include "../lib/IGameCallback.h"
#include "../lib/battle/CBattleInfoCallback.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -25,6 +24,7 @@ class CGameInterface;
class BinaryDeserializer; class BinaryDeserializer;
class BinarySerializer; class BinarySerializer;
class BattleAction; class BattleAction;
class BattleInfo;
template<typename T> class CApplier; template<typename T> class CApplier;
@ -105,12 +105,12 @@ public:
const Services * services() const override; const Services * services() const override;
vstd::CLoggerBase * logger() const override; vstd::CLoggerBase * logger() const override;
events::EventBus * eventBus() const override; events::EventBus * eventBus() const override;
const BattleCb * battle() const override; const BattleCb * battle(const BattleID & battle) const override;
const GameCb * game() const override; const GameCb * game() const override;
}; };
/// Class which handles client - server logic /// Class which handles client - server logic
class CClient : public IGameCallback, public CBattleInfoCallback, public Environment class CClient : public IGameCallback, public Environment
{ {
public: public:
std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint; std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint;
@ -124,7 +124,7 @@ public:
~CClient(); ~CClient();
const Services * services() const override; const Services * services() const override;
const BattleCb * battle() const override; const BattleCb * battle(const BattleID & battle) const override;
const GameCb * game() const override; const GameCb * game() const override;
vstd::CLoggerBase * logger() const override; vstd::CLoggerBase * logger() const override;
events::EventBus * eventBus() const override; events::EventBus * eventBus() const override;
@ -151,8 +151,8 @@ public:
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);
void battleFinished(); void battleFinished(const BattleID & battleID);
void startPlayerBattleAction(PlayerColor color); void startPlayerBattleAction(const BattleID & battleID, PlayerColor color);
void invalidatePaths(); void invalidatePaths();
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h); std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
@ -220,7 +220,6 @@ public:
#if SCRIPTING_ENABLED #if SCRIPTING_ENABLED
scripting::Pool * getGlobalContextPool() const override; scripting::Pool * getGlobalContextPool() const override;
scripting::Pool * getContextPool() const override;
#endif #endif
private: private:

View File

@ -17,6 +17,7 @@
#include "CServerHandler.h" #include "CServerHandler.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "gui/WindowHandler.h" #include "gui/WindowHandler.h"
#include "render/IRenderHandler.h"
#include "../lib/NetPacks.h" #include "../lib/NetPacks.h"
#include "ClientNetPackVisitors.h" #include "ClientNetPackVisitors.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
@ -97,7 +98,7 @@ void ClientCommandManager::handleGoSoloCommand()
if(elem.second.human) if(elem.second.human)
{ {
auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(elem.first), false, false); auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(elem.first), false, false);
printCommandMessage("Player " + elem.first.getStr() + " will be lead by " + AiToGive, ELogLevel::INFO); printCommandMessage("Player " + elem.first.toString() + " will be lead by " + AiToGive, ELogLevel::INFO);
CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), elem.first); CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), elem.first);
} }
} }
@ -182,12 +183,12 @@ void ClientCommandManager::handleNotDialogCommand()
void ClientCommandManager::handleConvertTextCommand() void ClientCommandManager::handleConvertTextCommand()
{ {
logGlobal->info("Searching for available maps"); logGlobal->info("Searching for available maps");
std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) std::unordered_set<ResourcePath> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
{ {
return ident.getType() == EResType::MAP; return ident.getType() == EResType::MAP;
}); });
std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) std::unordered_set<ResourcePath> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
{ {
return ident.getType() == EResType::CAMPAIGN; return ident.getType() == EResType::CAMPAIGN;
}); });
@ -292,7 +293,7 @@ void ClientCommandManager::handleGetTextCommand()
VCMIDirs::get().userExtractedPath(); VCMIDirs::get().userExtractedPath();
auto list = auto list =
CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident) CResourceHandler::get()->getFilteredFiles([](const ResourcePath & ident)
{ {
return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/"); return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
}); });
@ -317,7 +318,7 @@ void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBu
{ {
std::string URI; std::string URI;
singleWordBuffer >> URI; singleWordBuffer >> URI;
std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI); auto anim = GH.renderHandler().loadAnimation(AnimationPath::builtin(URI));
anim->preload(); anim->preload();
anim->exportBitmaps(VCMIDirs::get().userExtractedPath()); anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
} }
@ -327,11 +328,11 @@ void ClientCommandManager::handleExtractCommand(std::istringstream& singleWordBu
std::string URI; std::string URI;
singleWordBuffer >> URI; singleWordBuffer >> URI;
if(CResourceHandler::get()->existsResource(ResourceID(URI))) if(CResourceHandler::get()->existsResource(ResourcePath(URI)))
{ {
const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI; const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll(); auto data = CResourceHandler::get()->load(ResourcePath(URI))->readAll();
boost::filesystem::create_directories(outPath.parent_path()); boost::filesystem::create_directories(outPath.parent_path());
std::ofstream outFile(outPath.c_str(), std::ofstream::binary); std::ofstream outFile(outPath.c_str(), std::ofstream::binary);

View File

@ -95,18 +95,18 @@ void callAllInterfaces(CClient & cl, void (T::*ptr)(Args...), 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
template<typename T, typename ... Args, typename ... Args2> template<typename T, typename ... Args, typename ... Args2>
void callBattleInterfaceIfPresentForBothSides(CClient & cl, void (T::*ptr)(Args...), Args2 && ...args) void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & battleID, void (T::*ptr)(Args...), Args2 && ...args)
{ {
assert(cl.gameState()->curB); assert(cl.gameState()->getBattle(battleID));
if (!cl.gameState()->curB) if (!cl.gameState()->getBattle(battleID))
{ {
logGlobal->error("Attempt to call battle interface without ongoing battle!"); logGlobal->error("Attempt to call battle interface without ongoing battle!");
return; return;
} }
callOnlyThatBattleInterface(cl, cl.gameState()->curB->sides[0].color, ptr, std::forward<Args2>(args)...); callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[0].color, ptr, std::forward<Args2>(args)...);
callOnlyThatBattleInterface(cl, cl.gameState()->curB->sides[1].color, ptr, std::forward<Args2>(args)...); callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[1].color, ptr, std::forward<Args2>(args)...);
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt) if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt)
{ {
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward<Args2>(args)...); callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward<Args2>(args)...);
@ -306,14 +306,13 @@ void ApplyClientNetPackVisitor::visitBulkMoveArtifacts(BulkMoveArtifacts & pack)
} }
}; };
ArtifactLocation srcLoc(pack.srcArtHolder, pack.artsPack0.front().srcPos); auto srcOwner = std::get<ConstTransitivePtr<CGHeroInstance>>(pack.srcArtHolder)->tempOwner;
ArtifactLocation dstLoc(pack.dstArtHolder, pack.artsPack0.front().dstPos); auto dstOwner = std::get<ConstTransitivePtr<CGHeroInstance>>(pack.dstArtHolder)->tempOwner;
// Begin a session of bulk movement of arts. It is not necessary but useful for the client optimization. // Begin a session of bulk movement of arts. It is not necessary but useful for the client optimization.
callInterfaceIfPresent(cl, srcLoc.owningPlayer(), &IGameEventsReceiver::bulkArtMovementStart, pack.artsPack0.size() + pack.artsPack1.size()); callInterfaceIfPresent(cl, srcOwner, &IGameEventsReceiver::bulkArtMovementStart, pack.artsPack0.size() + pack.artsPack1.size());
if(srcOwner != dstOwner)
if (srcLoc.owningPlayer() != dstLoc.owningPlayer()) callInterfaceIfPresent(cl, dstOwner, &IGameEventsReceiver::bulkArtMovementStart, pack.artsPack0.size() + pack.artsPack1.size());
callInterfaceIfPresent(cl, dstLoc.owningPlayer(), &IGameEventsReceiver::bulkArtMovementStart, pack.artsPack0.size() + pack.artsPack1.size());
applyMove(pack.artsPack0); applyMove(pack.artsPack0);
if(pack.swap) if(pack.swap)
@ -715,11 +714,11 @@ void ApplyClientNetPackVisitor::visitMapObjectSelectDialog(MapObjectSelectDialog
void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack) void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack)
{ {
// Cannot use the usual code because curB is not set yet // Cannot use the usual code because curB is not set yet
callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
} }
@ -730,12 +729,12 @@ void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack)
void ApplyFirstClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack) void ApplyFirstClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleNewRoundFirst, pack.round); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleNewRoundFirst, pack.battleID);
} }
void ApplyClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack) void ApplyClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleNewRound, pack.round); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleNewRound, pack.battleID);
} }
void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & pack) void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & pack)
@ -743,56 +742,56 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack &
if(!pack.askPlayerInterface) if(!pack.askPlayerInterface)
return; return;
const CStack *activated = gs.curB->battleGetStackByID(pack.stack); const CStack *activated = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack);
PlayerColor playerToCall; //pack.player that will move activated stack PlayerColor playerToCall; //pack.player that will move activated stack
if (activated->hasBonusOfType(BonusType::HYPNOTIZED)) if (activated->hasBonusOfType(BonusType::HYPNOTIZED))
{ {
playerToCall = (gs.curB->sides[0].color == activated->unitOwner() playerToCall = (gs.getBattle(pack.battleID)->sides[0].color == activated->unitOwner()
? gs.curB->sides[1].color ? gs.getBattle(pack.battleID)->sides[1].color
: gs.curB->sides[0].color); : gs.getBattle(pack.battleID)->sides[0].color);
} }
else else
{ {
playerToCall = activated->unitOwner(); playerToCall = activated->unitOwner();
} }
cl.startPlayerBattleAction(playerToCall); cl.startPlayerBattleAction(pack.battleID, playerToCall);
} }
void ApplyClientNetPackVisitor::visitBattleLogMessage(BattleLogMessage & pack) void ApplyClientNetPackVisitor::visitBattleLogMessage(BattleLogMessage & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleLogMessage, pack.lines); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleLogMessage, pack.battleID, pack.lines);
} }
void ApplyClientNetPackVisitor::visitBattleTriggerEffect(BattleTriggerEffect & pack) void ApplyClientNetPackVisitor::visitBattleTriggerEffect(BattleTriggerEffect & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleTriggerEffect, pack); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleTriggerEffect, pack.battleID, pack);
} }
void ApplyFirstClientNetPackVisitor::visitBattleUpdateGateState(BattleUpdateGateState & pack) void ApplyFirstClientNetPackVisitor::visitBattleUpdateGateState(BattleUpdateGateState & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleGateStateChanged, pack.state); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleGateStateChanged, pack.battleID, pack.state);
} }
void ApplyFirstClientNetPackVisitor::visitBattleResult(BattleResult & pack) void ApplyFirstClientNetPackVisitor::visitBattleResult(BattleResult & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleEnd, &pack, pack.queryID); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleEnd, pack.battleID, &pack, pack.queryID);
cl.battleFinished(); cl.battleFinished(pack.battleID);
} }
void ApplyFirstClientNetPackVisitor::visitBattleStackMoved(BattleStackMoved & pack) void ApplyFirstClientNetPackVisitor::visitBattleStackMoved(BattleStackMoved & pack)
{ {
const CStack * movedStack = gs.curB->battleGetStackByID(pack.stack); const CStack * movedStack = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack);
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStackMoved, movedStack, pack.tilesToMove, pack.distance, pack.teleporting); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStackMoved, pack.battleID, movedStack, pack.tilesToMove, pack.distance, pack.teleporting);
} }
void ApplyFirstClientNetPackVisitor::visitBattleAttack(BattleAttack & pack) void ApplyFirstClientNetPackVisitor::visitBattleAttack(BattleAttack & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleAttack, &pack); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleAttack, pack.battleID, &pack);
// battleStacksAttacked should be excuted before BattleAttack.applyGs() to play animation before damaging unit // battleStacksAttacked should be excuted before BattleAttack.applyGs() to play animation before damaging unit
// so this has to be here instead of ApplyClientNetPackVisitor::visitBattleAttack() // so this has to be here instead of ApplyClientNetPackVisitor::visitBattleAttack()
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, pack.bsa, pack.shot()); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksAttacked, pack.battleID, pack.bsa, pack.shot());
} }
void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack) void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack)
@ -802,23 +801,23 @@ void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack)
void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack) void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack)
{ {
cl.currentBattleAction = std::make_unique<BattleAction>(pack.ba); cl.currentBattleAction = std::make_unique<BattleAction>(pack.ba);
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionStarted, pack.ba); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::actionStarted, pack.battleID, pack.ba);
} }
void ApplyClientNetPackVisitor::visitBattleSpellCast(BattleSpellCast & pack) void ApplyClientNetPackVisitor::visitBattleSpellCast(BattleSpellCast & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleSpellCast, &pack); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleSpellCast, pack.battleID, &pack);
} }
void ApplyClientNetPackVisitor::visitSetStackEffect(SetStackEffect & pack) void ApplyClientNetPackVisitor::visitSetStackEffect(SetStackEffect & pack)
{ {
//informing about effects //informing about effects
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksEffectsSet, pack); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksEffectsSet, pack.battleID, pack);
} }
void ApplyClientNetPackVisitor::visitStacksInjured(StacksInjured & pack) void ApplyClientNetPackVisitor::visitStacksInjured(StacksInjured & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, pack.stacks, false); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksAttacked, pack.battleID, pack.stacks, false);
} }
void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied & pack) void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied & pack)
@ -830,24 +829,24 @@ void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied &
void ApplyClientNetPackVisitor::visitBattleUnitsChanged(BattleUnitsChanged & pack) void ApplyClientNetPackVisitor::visitBattleUnitsChanged(BattleUnitsChanged & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, pack.changedStacks); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleUnitsChanged, pack.battleID, pack.changedStacks);
} }
void ApplyClientNetPackVisitor::visitBattleObstaclesChanged(BattleObstaclesChanged & pack) void ApplyClientNetPackVisitor::visitBattleObstaclesChanged(BattleObstaclesChanged & pack)
{ {
//inform interfaces about removed obstacles //inform interfaces about removed obstacles
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleObstaclesChanged, pack.changes); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleObstaclesChanged, pack.battleID, pack.changes);
} }
void ApplyClientNetPackVisitor::visitCatapultAttack(CatapultAttack & pack) void ApplyClientNetPackVisitor::visitCatapultAttack(CatapultAttack & pack)
{ {
//inform interfaces about catapult attack //inform interfaces about catapult attack
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleCatapultAttacked, pack); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleCatapultAttacked, pack.battleID, pack);
} }
void ApplyClientNetPackVisitor::visitEndAction(EndAction & pack) void ApplyClientNetPackVisitor::visitEndAction(EndAction & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionFinished, *cl.currentBattleAction); callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::actionFinished, pack.battleID, *cl.currentBattleAction);
cl.currentBattleAction.reset(); cl.currentBattleAction.reset();
} }
@ -875,7 +874,7 @@ void ApplyClientNetPackVisitor::visitPlayerBlocked(PlayerBlocked & pack)
void ApplyClientNetPackVisitor::visitYourTurn(YourTurn & pack) void ApplyClientNetPackVisitor::visitYourTurn(YourTurn & pack)
{ {
logNetwork->debug("Server gives turn to %s", pack.player.getStr()); logNetwork->debug("Server gives turn to %s", pack.player.toString());
callAllInterfaces(cl, &IGameEventsReceiver::playerStartsTurn, pack.player); callAllInterfaces(cl, &IGameEventsReceiver::playerStartsTurn, pack.player);
callOnlyThatInterface(cl, pack.player, &CGameInterface::yourTurn, pack.queryID); callOnlyThatInterface(cl, pack.player, &CGameInterface::yourTurn, pack.queryID);
@ -883,12 +882,12 @@ void ApplyClientNetPackVisitor::visitYourTurn(YourTurn & pack)
void ApplyClientNetPackVisitor::visitTurnTimeUpdate(TurnTimeUpdate & pack) void ApplyClientNetPackVisitor::visitTurnTimeUpdate(TurnTimeUpdate & pack)
{ {
logNetwork->debug("Server sets turn timer {turn: %d, base: %d, battle: %d, creature: %d} for %s", pack.turnTimer.turnTimer, pack.turnTimer.baseTimer, pack.turnTimer.battleTimer, pack.turnTimer.creatureTimer, pack.player.getStr()); logNetwork->debug("Server sets turn timer {turn: %d, base: %d, battle: %d, creature: %d} for %s", pack.turnTimer.turnTimer, pack.turnTimer.baseTimer, pack.turnTimer.battleTimer, pack.turnTimer.creatureTimer, pack.player.toString());
} }
void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & pack) void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & pack)
{ {
logNetwork->debug("pack.player %s sends a message: %s", pack.player.getStr(), pack.text); logNetwork->debug("pack.player %s sends a message: %s", pack.player.toString(), pack.text);
std::ostringstream str; std::ostringstream str;
if(pack.player.isSpectator()) if(pack.player.isSpectator())

View File

@ -153,15 +153,34 @@ void AdventureMapInterface::deactivate()
void AdventureMapInterface::showAll(Canvas & to) void AdventureMapInterface::showAll(Canvas & to)
{ {
CIntObject::showAll(to); CIntObject::showAll(to);
dim(to);
LOCPLINT->cingconsole->show(to); LOCPLINT->cingconsole->show(to);
} }
void AdventureMapInterface::show(Canvas & to) void AdventureMapInterface::show(Canvas & to)
{ {
CIntObject::show(to); CIntObject::show(to);
dim(to);
LOCPLINT->cingconsole->show(to); LOCPLINT->cingconsole->show(to);
} }
void AdventureMapInterface::dim(Canvas & to)
{
for (auto window : GH.windows().findWindows<IShowActivatable>())
{
std::shared_ptr<AdventureMapInterface> casted = std::dynamic_pointer_cast<AdventureMapInterface>(window);
if (!casted && !window->isPopupWindow())
{
int backgroundDimLevel = settings["adventure"]["backgroundDimLevel"].Integer();
Rect targetRect(0, 0, GH.screenDimensions().x, GH.screenDimensions().y);
ColorRGBA colorToFill(0, 0, 0, std::clamp<int>(backgroundDimLevel, 0, 255));
if(backgroundDimLevel > 0)
to.drawColor(targetRect, colorToFill);
return;
}
}
}
void AdventureMapInterface::tick(uint32_t msPassed) void AdventureMapInterface::tick(uint32_t msPassed)
{ {
handleMapScrollingUpdate(msPassed); handleMapScrollingUpdate(msPassed);

View File

@ -89,6 +89,9 @@ private:
/// casts current spell at specified location /// casts current spell at specified location
void performSpellcasting(const int3 & castTarget); void performSpellcasting(const int3 & castTarget);
/// dim interface if some windows opened
void dim(Canvas & to);
protected: protected:
/// CIntObject interface implementation /// CIntObject interface implementation

View File

@ -22,6 +22,7 @@
#include "../mapView/MapView.h" #include "../mapView/MapView.h"
#include "../render/CAnimation.h" #include "../render/CAnimation.h"
#include "../render/IImage.h" #include "../render/IImage.h"
#include "../render/IRenderHandler.h"
#include "../widgets/Buttons.h" #include "../widgets/Buttons.h"
#include "../widgets/Images.h" #include "../widgets/Images.h"
#include "../widgets/TextControls.h" #include "../widgets/TextControls.h"
@ -30,7 +31,7 @@
#include "../PlayerLocalState.h" #include "../PlayerLocalState.h"
#include "../../lib/constants/StringConstants.h" #include "../../lib/constants/StringConstants.h"
#include "../../lib/filesystem/ResourceID.h" #include "../../lib/filesystem/ResourcePath.h"
AdventureMapWidget::AdventureMapWidget( std::shared_ptr<AdventureMapShortcuts> shortcuts ) AdventureMapWidget::AdventureMapWidget( std::shared_ptr<AdventureMapShortcuts> shortcuts )
: shortcuts(shortcuts) : shortcuts(shortcuts)
@ -56,13 +57,10 @@ AdventureMapWidget::AdventureMapWidget( std::shared_ptr<AdventureMapShortcuts> s
for (const auto & entry : shortcuts->getShortcuts()) for (const auto & entry : shortcuts->getShortcuts())
addShortcut(entry.shortcut, entry.callback); addShortcut(entry.shortcut, entry.callback);
const JsonNode config(ResourceID("config/widgets/adventureMap.json")); const JsonNode config(JsonPath::builtin("config/widgets/adventureMap.json"));
for(const auto & entry : config["options"]["imagesPlayerColored"].Vector()) for(const auto & entry : config["options"]["imagesPlayerColored"].Vector())
{ playerColorerImages.push_back(ImagePath::fromJson(entry));
ResourceID resourceName(entry.String(), EResType::IMAGE);
playerColorerImages.push_back(resourceName.getName());
}
build(config); build(config);
addUsedEvents(KEYBOARD); addUsedEvents(KEYBOARD);
@ -127,24 +125,24 @@ Rect AdventureMapWidget::readArea(const JsonNode & source, const Rect & bounding
return Rect(topLeft + boundingBox.topLeft(), dimensions); return Rect(topLeft + boundingBox.topLeft(), dimensions);
} }
std::shared_ptr<IImage> AdventureMapWidget::loadImage(const std::string & name) std::shared_ptr<IImage> AdventureMapWidget::loadImage(const JsonNode & name)
{ {
ResourceID resource(name, EResType::IMAGE); ImagePath resource = ImagePath::fromJson(name);
if(images.count(resource.getName()) == 0) if(images.count(resource) == 0)
images[resource.getName()] = IImage::createFromFile(resource.getName()); images[resource] = GH.renderHandler().loadImage(resource);
return images[resource.getName()]; return images[resource];
} }
std::shared_ptr<CAnimation> AdventureMapWidget::loadAnimation(const std::string & name) std::shared_ptr<CAnimation> AdventureMapWidget::loadAnimation(const JsonNode & name)
{ {
ResourceID resource(name, EResType::ANIMATION); AnimationPath resource = AnimationPath::fromJson(name);
if(animations.count(resource.getName()) == 0) if(animations.count(resource) == 0)
animations[resource.getName()] = std::make_shared<CAnimation>(resource.getName()); animations[resource] = GH.renderHandler().loadAnimation(resource);
return animations[resource.getName()]; return animations[resource];
} }
std::shared_ptr<CIntObject> AdventureMapWidget::buildInfobox(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildInfobox(const JsonNode & input)
@ -158,15 +156,14 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapImage(const JsonNode & i
{ {
Rect targetArea = readTargetArea(input["area"]); Rect targetArea = readTargetArea(input["area"]);
Rect sourceArea = readSourceArea(input["sourceArea"], input["area"]); Rect sourceArea = readSourceArea(input["sourceArea"], input["area"]);
std::string image = input["image"].String();
return std::make_shared<CFilledTexture>(loadImage(image), targetArea, sourceArea); return std::make_shared<CFilledTexture>(loadImage(input["image"]), targetArea, sourceArea);
} }
std::shared_ptr<CIntObject> AdventureMapWidget::buildMapButton(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildMapButton(const JsonNode & input)
{ {
auto position = readTargetArea(input["area"]); auto position = readTargetArea(input["area"]);
auto image = input["image"].String(); auto image = AnimationPath::fromJson(input["image"]);
auto help = readHintText(input["help"]); auto help = readHintText(input["help"]);
bool playerColored = input["playerColored"].Bool(); bool playerColored = input["playerColored"].Bool();
@ -259,9 +256,8 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapIcon(const JsonNode & in
Rect area = readTargetArea(input["area"]); Rect area = readTargetArea(input["area"]);
size_t index = input["index"].Integer(); size_t index = input["index"].Integer();
size_t perPlayer = input["perPlayer"].Integer(); size_t perPlayer = input["perPlayer"].Integer();
std::string image = input["image"].String();
return std::make_shared<CAdventureMapIcon>(area.topLeft(), loadAnimation(image), index, perPlayer); return std::make_shared<CAdventureMapIcon>(area.topLeft(), loadAnimation(input["image"]), index, perPlayer);
} }
std::shared_ptr<CIntObject> AdventureMapWidget::buildMapTownList(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildMapTownList(const JsonNode & input)
@ -298,7 +294,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMinimap(const JsonNode & in
std::shared_ptr<CIntObject> AdventureMapWidget::buildResourceDateBar(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildResourceDateBar(const JsonNode & input)
{ {
Rect area = readTargetArea(input["area"]); Rect area = readTargetArea(input["area"]);
std::string image = input["image"].String(); auto image = ImagePath::fromJson(input["image"]);
auto result = std::make_shared<CResDataBar>(image, area.topLeft()); auto result = std::make_shared<CResDataBar>(image, area.topLeft());
@ -320,7 +316,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildResourceDateBar(const JsonN
std::shared_ptr<CIntObject> AdventureMapWidget::buildStatusBar(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildStatusBar(const JsonNode & input)
{ {
Rect area = readTargetArea(input["area"]); Rect area = readTargetArea(input["area"]);
std::string image = input["image"].String(); auto image = ImagePath::fromJson(input["image"]);
auto background = std::make_shared<CFilledTexture>(image, area); auto background = std::make_shared<CFilledTexture>(image, area);
@ -330,7 +326,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildStatusBar(const JsonNode &
std::shared_ptr<CIntObject> AdventureMapWidget::buildTexturePlayerColored(const JsonNode & input) std::shared_ptr<CIntObject> AdventureMapWidget::buildTexturePlayerColored(const JsonNode & input)
{ {
logGlobal->debug("Building widget CFilledTexture"); logGlobal->debug("Building widget CFilledTexture");
auto image = input["image"].String(); auto image = ImagePath::fromJson(input["image"]);
Rect area = readTargetArea(input["area"]); Rect area = readTargetArea(input["area"]);
return std::make_shared<FilledTexturePlayerColored>(image, area); return std::make_shared<FilledTexturePlayerColored>(image, area);
} }

View File

@ -29,11 +29,11 @@ class AdventureMapWidget : public InterfaceObjectConfigurable
std::vector<Rect> subwidgetSizes; std::vector<Rect> subwidgetSizes;
/// list of images on which player-colored palette will be applied /// list of images on which player-colored palette will be applied
std::vector<std::string> playerColorerImages; std::vector<ImagePath> playerColorerImages;
/// list of named images shared between widgets /// list of named images shared between widgets
std::map<std::string, std::shared_ptr<IImage>> images; std::map<ImagePath, std::shared_ptr<IImage>> images;
std::map<std::string, std::shared_ptr<CAnimation>> animations; std::map<AnimationPath, std::shared_ptr<CAnimation>> animations;
/// Widgets that require access from adventure map /// Widgets that require access from adventure map
std::shared_ptr<CHeroList> heroList; std::shared_ptr<CHeroList> heroList;
@ -48,8 +48,8 @@ class AdventureMapWidget : public InterfaceObjectConfigurable
Rect readSourceArea(const JsonNode & source, const JsonNode & sourceCommon); Rect readSourceArea(const JsonNode & source, const JsonNode & sourceCommon);
Rect readArea(const JsonNode & source, const Rect & boundingBox); Rect readArea(const JsonNode & source, const Rect & boundingBox);
std::shared_ptr<IImage> loadImage(const std::string & name); std::shared_ptr<IImage> loadImage(const JsonNode & name);
std::shared_ptr<CAnimation> loadAnimation(const std::string & name); std::shared_ptr<CAnimation> loadAnimation(const JsonNode & name);
std::shared_ptr<CIntObject> buildInfobox(const JsonNode & input); std::shared_ptr<CIntObject> buildInfobox(const JsonNode & input);
std::shared_ptr<CIntObject> buildMapImage(const JsonNode & input); std::shared_ptr<CIntObject> buildMapImage(const JsonNode & input);

View File

@ -25,22 +25,22 @@
#include "../../lib/StartInfo.h" #include "../../lib/StartInfo.h"
AdventureOptions::AdventureOptions() AdventureOptions::AdventureOptions()
: CWindowObject(PLAYER_COLORED, "ADVOPTS") : CWindowObject(PLAYER_COLORED, ImagePath::builtin("ADVOPTS"))
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
viewWorld = std::make_shared<CButton>(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD); viewWorld = std::make_shared<CButton>(Point(24, 23), AnimationPath::builtin("ADVVIEW.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD);
viewWorld->addCallback( [] { LOCPLINT->viewWorldMap(); }); viewWorld->addCallback( [] { LOCPLINT->viewWorldMap(); });
exit = std::make_shared<CButton>(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&AdventureOptions::close, this), EShortcut::GLOBAL_RETURN); exit = std::make_shared<CButton>(Point(204, 313), AnimationPath::builtin("IOK6432.DEF"), CButton::tooltip(), std::bind(&AdventureOptions::close, this), EShortcut::GLOBAL_RETURN);
scenInfo = std::make_shared<CButton>(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_SCENARIO); scenInfo = std::make_shared<CButton>(Point(24, 198), AnimationPath::builtin("ADVINFO.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_SCENARIO);
scenInfo->addCallback(AdventureOptions::showScenarioInfo); scenInfo->addCallback(AdventureOptions::showScenarioInfo);
puzzle = std::make_shared<CButton>(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_PUZZLE); puzzle = std::make_shared<CButton>(Point(24, 81), AnimationPath::builtin("ADVPUZ.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_PUZZLE);
puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
dig = std::make_shared<CButton>(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_DIG_GRAIL); dig = std::make_shared<CButton>(Point(24, 139), AnimationPath::builtin("ADVDIG.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_DIG_GRAIL);
if(const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero()) if(const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero())
dig->addCallback(std::bind(&CPlayerInterface::tryDigging, LOCPLINT, h)); dig->addCallback(std::bind(&CPlayerInterface::tryDigging, LOCPLINT, h));
else else

View File

@ -105,7 +105,7 @@ void CInGameConsole::print(const std::string & txt)
} }
GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
CCS->soundh->playSound("CHAT"); CCS->soundh->playSound(AudioPath::builtin("CHAT"));
} }
bool CInGameConsole::captureThisKey(EShortcut key) bool CInGameConsole::captureThisKey(EShortcut key)

View File

@ -51,7 +51,7 @@ CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo()
CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero) CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("ADSTATHR"); background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATHR"));
if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool()) if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool())
heroTooltip = std::make_shared<CInteractableHeroTooltip>(Point(0,0), hero); heroTooltip = std::make_shared<CInteractableHeroTooltip>(Point(0,0), hero);
@ -62,7 +62,7 @@ CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero)
CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town) CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("ADSTATCS"); background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATCS"));
if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool()) if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool())
townTooltip = std::make_shared<CInteractableTownTooltip>(Point(0,0), town); townTooltip = std::make_shared<CInteractableTownTooltip>(Point(0,0), town);
@ -88,36 +88,36 @@ CInfoBar::VisibleDateInfo::VisibleDateInfo()
forceRefresh.push_back(label); forceRefresh.push_back(label);
} }
std::string CInfoBar::VisibleDateInfo::getNewDayName() AnimationPath CInfoBar::VisibleDateInfo::getNewDayName()
{ {
if(LOCPLINT->cb->getDate(Date::DAY) == 1) if(LOCPLINT->cb->getDate(Date::DAY) == 1)
return "NEWDAY"; return AnimationPath::builtin("NEWDAY");
if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1)
return "NEWDAY"; return AnimationPath::builtin("NEWDAY");
switch(LOCPLINT->cb->getDate(Date::WEEK)) switch(LOCPLINT->cb->getDate(Date::WEEK))
{ {
case 1: case 1:
return "NEWWEEK1"; return AnimationPath::builtin("NEWWEEK1");
case 2: case 2:
return "NEWWEEK2"; return AnimationPath::builtin("NEWWEEK2");
case 3: case 3:
return "NEWWEEK3"; return AnimationPath::builtin("NEWWEEK3");
case 4: case 4:
return "NEWWEEK4"; return AnimationPath::builtin("NEWWEEK4");
default: default:
return ""; return AnimationPath();
} }
} }
CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("ADSTATNX"); background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATNX"));
banner = std::make_shared<CAnimImage>("CREST58", player.getNum(), 0, 20, 51); banner = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), player.getNum(), 0, 20, 51);
sand = std::make_shared<CShowableAnim>(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame sand = std::make_shared<CShowableAnim>(99, 51, AnimationPath::builtin("HOURSAND"), 0, 100); // H3 uses around 100 ms per frame
glass = std::make_shared<CShowableAnim>(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi glass = std::make_shared<CShowableAnim>(99, 51, AnimationPath::builtin("HOURGLAS"), CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi
} }
CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
@ -148,14 +148,14 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
} }
//generate widgets //generate widgets
background = std::make_shared<CPicture>("ADSTATIN"); background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATIN"));
allyLabel = std::make_shared<CLabel>(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":"); allyLabel = std::make_shared<CLabel>(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":");
enemyLabel = std::make_shared<CLabel>(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":"); enemyLabel = std::make_shared<CLabel>(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":");
int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4; int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4;
for(PlayerColor & player : allies) for(PlayerColor & player : allies)
{ {
auto image = std::make_shared<CAnimImage>("ITGFLAGS", player.getNum(), 0, posx, 102); auto image = std::make_shared<CAnimImage>(AnimationPath::builtin("ITGFLAGS"), player.getNum(), 0, posx, 102);
posx += image->pos.w; posx += image->pos.w;
flags.push_back(image); flags.push_back(image);
} }
@ -163,14 +163,14 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4; posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4;
for(PlayerColor & player : enemies) for(PlayerColor & player : enemies)
{ {
auto image = std::make_shared<CAnimImage>("ITGFLAGS", player.getNum(), 0, posx, 132); auto image = std::make_shared<CAnimImage>(AnimationPath::builtin("ITGFLAGS"), player.getNum(), 0, posx, 132);
posx += image->pos.w; posx += image->pos.w;
flags.push_back(image); flags.push_back(image);
} }
for(size_t i=0; i<halls.size(); i++) for(size_t i=0; i<halls.size(); i++)
{ {
hallIcons.push_back(std::make_shared<CAnimImage>("itmtl", i, 0, 6 + 42 * (int)i , 11)); hallIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("itmtl"), i, 0, 6 + 42 * (int)i , 11));
if(halls[i]) if(halls[i])
hallLabels.push_back(std::make_shared<CLabel>( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(halls[i]))); hallLabels.push_back(std::make_shared<CLabel>( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(halls[i])));
} }
@ -180,7 +180,7 @@ CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector<Component
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("ADSTATOT", 1, 0); background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATOT"), 1, 0);
auto fullRect = Rect(CInfoBar::offset, CInfoBar::offset, data_width - 2 * CInfoBar::offset, data_height - 2 * CInfoBar::offset); auto fullRect = Rect(CInfoBar::offset, CInfoBar::offset, data_width - 2 * CInfoBar::offset, data_height - 2 * CInfoBar::offset);
auto textRect = fullRect; auto textRect = fullRect;
auto imageRect = fullRect; auto imageRect = fullRect;

View File

@ -11,6 +11,7 @@
#include "../gui/CIntObject.h" #include "../gui/CIntObject.h"
#include "CConfigHandler.h" #include "CConfigHandler.h"
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -86,7 +87,7 @@ private:
std::shared_ptr<CShowableAnim> animation; std::shared_ptr<CShowableAnim> animation;
std::shared_ptr<CLabel> label; std::shared_ptr<CLabel> label;
std::string getNewDayName(); AnimationPath getNewDayName();
public: public:
VisibleDateInfo(); VisibleDateInfo();
}; };

View File

@ -206,9 +206,9 @@ void CList::selectPrev()
CHeroList::CEmptyHeroItem::CEmptyHeroItem() CHeroList::CEmptyHeroItem::CEmptyHeroItem()
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
movement = std::make_shared<CAnimImage>("IMOBIL", 0, 0, 0, 1); movement = std::make_shared<CAnimImage>(AnimationPath::builtin("IMOBIL"), 0, 0, 0, 1);
portrait = std::make_shared<CPicture>("HPSXXX", movement->pos.w + 1, 0); portrait = std::make_shared<CPicture>(ImagePath::builtin("HPSXXX"), movement->pos.w + 1, 0);
mana = std::make_shared<CAnimImage>("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); mana = std::make_shared<CAnimImage>(AnimationPath::builtin("IMANA"), 0, 0, movement->pos.w + portrait->pos.w + 2, 1 );
pos.w = mana->pos.w + mana->pos.x - pos.x; pos.w = mana->pos.w + mana->pos.x - pos.x;
pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h);
@ -219,9 +219,9 @@ CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero)
hero(Hero) hero(Hero)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
movement = std::make_shared<CAnimImage>("IMOBIL", 0, 0, 0, 1); movement = std::make_shared<CAnimImage>(AnimationPath::builtin("IMOBIL"), 0, 0, 0, 1);
portrait = std::make_shared<CAnimImage>("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1); portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), hero->portrait, 0, movement->pos.w + 1);
mana = std::make_shared<CAnimImage>("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); mana = std::make_shared<CAnimImage>(AnimationPath::builtin("IMANA"), 0, 0, movement->pos.w + portrait->pos.w + 2, 1);
pos.w = mana->pos.w + mana->pos.x - pos.x; pos.w = mana->pos.w + mana->pos.x - pos.x;
pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h);
@ -238,7 +238,7 @@ void CHeroList::CHeroItem::update()
std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection() std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection()
{ {
return std::make_shared<CPicture>("HPSYYY", movement->pos.w + 1, 0); return std::make_shared<CPicture>(ImagePath::builtin("HPSYYY"), movement->pos.w + 1, 0);
} }
void CHeroList::CHeroItem::select(bool on) void CHeroList::CHeroItem::select(bool on)
@ -319,7 +319,7 @@ std::shared_ptr<CIntObject> CTownList::createItem(size_t index)
{ {
if (LOCPLINT->localState->getOwnedTowns().size() > index) if (LOCPLINT->localState->getOwnedTowns().size() > index)
return std::make_shared<CTownItem>(this, LOCPLINT->localState->getOwnedTown(index)); return std::make_shared<CTownItem>(this, LOCPLINT->localState->getOwnedTown(index));
return std::make_shared<CAnimImage>("ITPA", 0); return std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 0);
} }
CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town): CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town):
@ -327,14 +327,14 @@ CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town):
town(Town) town(Town)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
picture = std::make_shared<CAnimImage>("ITPA", 0); picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 0);
pos = picture->pos; pos = picture->pos;
update(); update();
} }
std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection() std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection()
{ {
return std::make_shared<CAnimImage>("ITPA", 1); return std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 1);
} }
void CTownList::CTownItem::update() void CTownList::CTownItem::update()

View File

@ -94,7 +94,7 @@ CMinimap::CMinimap(const Rect & position)
pos.w = position.w; pos.w = position.w;
pos.h = position.h; pos.h = position.h;
aiShield = std::make_shared<CPicture>("AIShield"); aiShield = std::make_shared<CPicture>(ImagePath::builtin("AIShield"));
aiShield->disable(); aiShield->disable();
} }

View File

@ -24,7 +24,7 @@
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
#include "../../lib/ResourceSet.h" #include "../../lib/ResourceSet.h"
CResDataBar::CResDataBar(const std::string & imageName, const Point & position) CResDataBar::CResDataBar(const ImagePath & imageName, const Point & position)
{ {
pos.x += position.x; pos.x += position.x;
pos.y += position.y; pos.y += position.y;
@ -37,7 +37,7 @@ CResDataBar::CResDataBar(const std::string & imageName, const Point & position)
pos.h = background->pos.h; pos.h = background->pos.h;
} }
CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist): CResDataBar::CResDataBar(const ImagePath & defname, int x, int y, int offx, int offy, int resdist, int datedist):
CResDataBar(defname, Point(x,y)) CResDataBar(defname, Point(x,y))
{ {
for (int i = 0; i < 7 ; i++) for (int i = 0; i < 7 ; i++)

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../gui/CIntObject.h" #include "../gui/CIntObject.h"
#include "../../lib/filesystem/ResourcePath.h"
/// Resources bar which shows information about how many gold, crystals,... you have /// Resources bar which shows information about how many gold, crystals,... you have
/// Current date is displayed too /// Current date is displayed too
@ -25,10 +26,10 @@ class CResDataBar : public CIntObject
public: public:
/// For dynamically-sized UI windows, e.g. adventure map interface /// For dynamically-sized UI windows, e.g. adventure map interface
CResDataBar(const std::string & imageName, const Point & position); CResDataBar(const ImagePath & imageName, const Point & position);
/// For fixed-size UI windows, e.g. CastleInterface /// For fixed-size UI windows, e.g. CastleInterface
CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); CResDataBar(const ImagePath & defname, int x, int y, int offx, int offy, int resdist, int datedist);
void setDatePosition(const Point & position); void setDatePosition(const Point & position);
void setResourcePosition(const GameResID & resource, const Point & position); void setResourcePosition(const GameResID & resource, const Point & position);

View File

@ -123,9 +123,9 @@ void MapAudioPlayer::removeObject(const CGObjectInstance * obj)
vstd::erase(objects[z][x][y], obj->id); vstd::erase(objects[z][x][y], obj->id);
} }
std::vector<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile) std::vector<AudioPath> MapAudioPlayer::getAmbientSounds(const int3 & tile)
{ {
std::vector<std::string> result; std::vector<AudioPath> result;
for(auto & objectID : objects[tile.z][tile.x][tile.y]) for(auto & objectID : objects[tile.z][tile.x][tile.y])
{ {
@ -140,15 +140,15 @@ std::vector<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile)
} }
if(CGI->mh->getMap()->isCoastalTile(tile)) if(CGI->mh->getMap()->isCoastalTile(tile))
result.emplace_back("LOOPOCEA"); result.emplace_back(AudioPath::builtin("LOOPOCEA"));
return result; return result;
} }
void MapAudioPlayer::updateAmbientSounds() void MapAudioPlayer::updateAmbientSounds()
{ {
std::map<std::string, int> currentSounds; std::map<AudioPath, int> currentSounds;
auto updateSounds = [&](const std::string& soundId, int distance) -> void auto updateSounds = [&](const AudioPath& soundId, int distance) -> void
{ {
if(vstd::contains(currentSounds, soundId)) if(vstd::contains(currentSounds, soundId))
currentSounds[soundId] = std::min(currentSounds[soundId], distance); currentSounds[soundId] = std::min(currentSounds[soundId], distance);

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../mapView/IMapRendererObserver.h" #include "../mapView/IMapRendererObserver.h"
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
class ObjectInstanceID; class ObjectInstanceID;
@ -29,7 +30,7 @@ class MapAudioPlayer : public IMapObjectObserver
void addObject(const CGObjectInstance * obj); void addObject(const CGObjectInstance * obj);
void removeObject(const CGObjectInstance * obj); void removeObject(const CGObjectInstance * obj);
std::vector<std::string> getAmbientSounds(const int3 & tile); std::vector<AudioPath> getAmbientSounds(const int3 & tile);
void updateAmbientSounds(); void updateAmbientSounds();
void updateMusic(); void updateMusic();
void update(); void update();

View File

@ -25,7 +25,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/CPlayerState.h" #include "../../lib/CPlayerState.h"
#include "../../lib/filesystem/ResourceID.h" #include "../../lib/filesystem/ResourcePath.h"
TurnTimerWidget::DrawRect::DrawRect(const Rect & r, const ColorRGBA & c): TurnTimerWidget::DrawRect::DrawRect(const Rect & r, const ColorRGBA & c):
CIntObject(), rect(r), color(c) CIntObject(), rect(r), color(c)
@ -47,7 +47,7 @@ TurnTimerWidget::TurnTimerWidget():
recActions &= ~DEACTIVATE; recActions &= ~DEACTIVATE;
const JsonNode config(ResourceID("config/widgets/turnTimer.json")); const JsonNode config(JsonPath::builtin("config/widgets/turnTimer.json"));
build(config); build(config);
@ -77,7 +77,7 @@ void TurnTimerWidget::setTime(PlayerColor player, int time)
&& newTime != turnTime && newTime != turnTime
&& notifications.count(newTime)) && notifications.count(newTime))
{ {
CCS->soundh->playSound(variables["notificationSound"].String()); CCS->soundh->playSound(AudioPath::fromJson(variables["notificationSound"]));
} }
turnTime = newTime; turnTime = newTime;

View File

@ -171,7 +171,7 @@ void BattleActionsController::enterCreatureCastingMode()
spells::Target target; spells::Target target;
target.emplace_back(); target.emplace_back();
spells::BattleCast cast(owner.curInt->cb.get(), caster, spells::Mode::CREATURE_ACTIVE, spell); spells::BattleCast cast(owner.getBattle().get(), caster, spells::Mode::CREATURE_ACTIVE, spell);
auto m = spell->battleMechanics(&cast); auto m = spell->battleMechanics(&cast);
spells::detail::ProblemImpl ignored; spells::detail::ProblemImpl ignored;
@ -207,7 +207,7 @@ std::vector<PossiblePlayerBattleAction> BattleActionsController::getPossibleActi
data.creatureSpellsToCast.push_back(spell->id); data.creatureSpellsToCast.push_back(spell->id);
data.tacticsMode = owner.tacticsMode; data.tacticsMode = owner.tacticsMode;
auto allActions = owner.curInt->cb->getClientActionsForStack(stack, data); auto allActions = owner.getBattle()->getClientActionsForStack(stack, data);
allActions.push_back(PossiblePlayerBattleAction::HERO_INFO); allActions.push_back(PossiblePlayerBattleAction::HERO_INFO);
allActions.push_back(PossiblePlayerBattleAction::CREATURE_INFO); allActions.push_back(PossiblePlayerBattleAction::CREATURE_INFO);
@ -231,7 +231,7 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac
case PossiblePlayerBattleAction::OBSTACLE: case PossiblePlayerBattleAction::OBSTACLE:
if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && targetStack != nullptr) if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && targetStack != nullptr)
{ {
PlayerColor stackOwner = owner.curInt->cb->battleGetOwner(targetStack); PlayerColor stackOwner = owner.getBattle()->battleGetOwner(targetStack);
bool enemyTargetingPositiveSpellcast = item.spell().toSpell()->isPositive() && stackOwner != LOCPLINT->playerID; bool enemyTargetingPositiveSpellcast = item.spell().toSpell()->isPositive() && stackOwner != LOCPLINT->playerID;
bool friendTargetingNegativeSpellcast = item.spell().toSpell()->isNegative() && stackOwner == LOCPLINT->playerID; bool friendTargetingNegativeSpellcast = item.spell().toSpell()->isNegative() && stackOwner == LOCPLINT->playerID;
@ -300,12 +300,12 @@ void BattleActionsController::castThisSpell(SpellID spellID)
//choosing possible targets //choosing possible targets
const CGHeroInstance *castingHero = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? owner.attackingHeroInstance : owner.defendingHeroInstance; const CGHeroInstance *castingHero = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? owner.attackingHeroInstance : owner.defendingHeroInstance;
assert(castingHero); // code below assumes non-null hero assert(castingHero); // code below assumes non-null hero
PossiblePlayerBattleAction spellSelMode = owner.curInt->cb->getCasterAction(spellID.toSpell(), castingHero, spells::Mode::HERO); PossiblePlayerBattleAction spellSelMode = owner.getBattle()->getCasterAction(spellID.toSpell(), castingHero, spells::Mode::HERO);
if (spellSelMode.get() == PossiblePlayerBattleAction::NO_LOCATION) //user does not have to select location if (spellSelMode.get() == PossiblePlayerBattleAction::NO_LOCATION) //user does not have to select location
{ {
heroSpellToCast->aimToHex(BattleHex::INVALID); heroSpellToCast->aimToHex(BattleHex::INVALID);
owner.curInt->cb->battleMakeSpellAction(*heroSpellToCast); owner.curInt->cb->battleMakeSpellAction(owner.getBattleID(), *heroSpellToCast);
endCastingSpell(); endCastingSpell();
} }
else else
@ -353,10 +353,10 @@ const CSpell * BattleActionsController::getCurrentSpell(BattleHex hoveredHex)
const CStack * BattleActionsController::getStackForHex(BattleHex hoveredHex) const CStack * BattleActionsController::getStackForHex(BattleHex hoveredHex)
{ {
const CStack * shere = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); const CStack * shere = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
if(shere) if(shere)
return shere; return shere;
return owner.curInt->cb->battleGetStackByPos(hoveredHex, false); return owner.getBattle()->battleGetStackByPos(hoveredHex, false);
} }
void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, BattleHex targetHex) void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, BattleHex targetHex)
@ -400,7 +400,7 @@ void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action,
} }
case PossiblePlayerBattleAction::SHOOT: case PossiblePlayerBattleAction::SHOOT:
if (owner.curInt->cb->battleHasShootingPenalty(owner.stacksController->getActiveStack(), targetHex)) if (owner.getBattle()->battleHasShootingPenalty(owner.stacksController->getActiveStack(), targetHex))
CCS->curh->set(Cursor::Combat::SHOOT_PENALTY); CCS->curh->set(Cursor::Combat::SHOOT_PENALTY);
else else
CCS->curh->set(Cursor::Combat::SHOOT); CCS->curh->set(Cursor::Combat::SHOOT);
@ -482,7 +482,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
case PossiblePlayerBattleAction::ATTACK_AND_RETURN: //TODO: allow to disable return case PossiblePlayerBattleAction::ATTACK_AND_RETURN: //TODO: allow to disable return
{ {
BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex); BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex);
DamageEstimation estimation = owner.curInt->cb->battleEstimateDamage(owner.stacksController->getActiveStack(), targetStack, attackFromHex); DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(owner.stacksController->getActiveStack(), targetStack, attackFromHex);
estimation.kills.max = std::min<int64_t>(estimation.kills.max, targetStack->getCount()); estimation.kills.max = std::min<int64_t>(estimation.kills.max, targetStack->getCount());
estimation.kills.min = std::min<int64_t>(estimation.kills.min, targetStack->getCount()); estimation.kills.min = std::min<int64_t>(estimation.kills.min, targetStack->getCount());
@ -493,7 +493,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
{ {
const auto * shooter = owner.stacksController->getActiveStack(); const auto * shooter = owner.stacksController->getActiveStack();
DamageEstimation estimation = owner.curInt->cb->battleEstimateDamage(shooter, targetStack, shooter->getPosition()); DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(shooter, targetStack, shooter->getPosition());
estimation.kills.max = std::min<int64_t>(estimation.kills.max, targetStack->getCount()); estimation.kills.max = std::min<int64_t>(estimation.kills.max, targetStack->getCount());
estimation.kills.min = std::min<int64_t>(estimation.kills.min, targetStack->getCount()); estimation.kills.min = std::min<int64_t>(estimation.kills.min, targetStack->getCount());
@ -593,7 +593,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
case PossiblePlayerBattleAction::ATTACK: case PossiblePlayerBattleAction::ATTACK:
case PossiblePlayerBattleAction::WALK_AND_ATTACK: case PossiblePlayerBattleAction::WALK_AND_ATTACK:
case PossiblePlayerBattleAction::ATTACK_AND_RETURN: case PossiblePlayerBattleAction::ATTACK_AND_RETURN:
if(owner.curInt->cb->battleCanAttack(owner.stacksController->getActiveStack(), targetStack, targetHex)) if(owner.getBattle()->battleCanAttack(owner.stacksController->getActiveStack(), targetStack, targetHex))
{ {
if (owner.fieldController->isTileAttackable(targetHex)) // move isTileAttackable to be part of battleCanAttack? if (owner.fieldController->isTileAttackable(targetHex)) // move isTileAttackable to be part of battleCanAttack?
return true; return true;
@ -601,7 +601,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
return false; return false;
case PossiblePlayerBattleAction::SHOOT: case PossiblePlayerBattleAction::SHOOT:
return owner.curInt->cb->battleCanShoot(owner.stacksController->getActiveStack(), targetHex); return owner.getBattle()->battleCanShoot(owner.stacksController->getActiveStack(), targetHex);
case PossiblePlayerBattleAction::NO_LOCATION: case PossiblePlayerBattleAction::NO_LOCATION:
return false; return false;
@ -615,7 +615,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL: case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL:
if(targetStack && targetStackOwned && targetStack != owner.stacksController->getActiveStack() && targetStack->alive()) //only positive spells for other allied creatures if(targetStack && targetStackOwned && targetStack != owner.stacksController->getActiveStack() && targetStack->alive()) //only positive spells for other allied creatures
{ {
int spellID = owner.curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), targetStack, CBattleInfoCallback::RANDOM_GENIE); int spellID = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), targetStack, CBattleInfoCallback::RANDOM_GENIE);
return spellID > -1; return spellID > -1;
} }
return false; return false;
@ -658,7 +658,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B
{ {
if(owner.stacksController->getActiveStack()->doubleWide()) if(owner.stacksController->getActiveStack()->doubleWide())
{ {
std::vector<BattleHex> acc = owner.curInt->cb->battleGetAvailableHexes(owner.stacksController->getActiveStack(), false); std::vector<BattleHex> acc = owner.getBattle()->battleGetAvailableHexes(owner.stacksController->getActiveStack(), false);
BattleHex shiftedDest = targetHex.cloneInDirection(owner.stacksController->getActiveStack()->destShiftDir(), false); BattleHex shiftedDest = targetHex.cloneInDirection(owner.stacksController->getActiveStack()->destShiftDir(), false);
if(vstd::contains(acc, targetHex)) if(vstd::contains(acc, targetHex))
owner.giveCommand(EActionType::WALK, targetHex); owner.giveCommand(EActionType::WALK, targetHex);
@ -770,7 +770,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B
heroSpellToCast->aimToHex(targetHex); heroSpellToCast->aimToHex(targetHex);
break; break;
} }
owner.curInt->cb->battleMakeSpellAction(*heroSpellToCast); owner.curInt->cb->battleMakeSpellAction(owner.getBattleID(), *heroSpellToCast);
endCastingSpell(); endCastingSpell();
} }
selectedStack = nullptr; selectedStack = nullptr;
@ -886,7 +886,7 @@ void BattleActionsController::tryActivateStackSpellcasting(const CStack *casterS
{ {
// faerie dragon can cast only one, randomly selected spell until their next move // faerie dragon can cast only one, randomly selected spell until their next move
//TODO: faerie dragon type spell should be selected by server //TODO: faerie dragon type spell should be selected by server
const auto * spellToCast = owner.curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), casterStack, CBattleInfoCallback::RANDOM_AIMED).toSpell(); const auto * spellToCast = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), casterStack, CBattleInfoCallback::RANDOM_AIMED).toSpell();
if (spellToCast) if (spellToCast)
creatureSpells.push_back(spellToCast); creatureSpells.push_back(spellToCast);
@ -933,7 +933,7 @@ bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell,
target.emplace_back(targetStack); target.emplace_back(targetStack);
target.emplace_back(targetHex); target.emplace_back(targetHex);
spells::BattleCast cast(owner.curInt->cb.get(), caster, mode, currentSpell); spells::BattleCast cast(owner.getBattle().get(), caster, mode, currentSpell);
auto m = currentSpell->battleMechanics(&cast); auto m = currentSpell->battleMechanics(&cast);
spells::detail::ProblemImpl problem; //todo: display problem in status bar spells::detail::ProblemImpl problem; //todo: display problem in status bar
@ -943,7 +943,7 @@ bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell,
bool BattleActionsController::canStackMoveHere(const CStack * stackToMove, BattleHex myNumber) const bool BattleActionsController::canStackMoveHere(const CStack * stackToMove, BattleHex myNumber) const
{ {
std::vector<BattleHex> acc = owner.curInt->cb->battleGetAvailableHexes(stackToMove, false); std::vector<BattleHex> acc = owner.getBattle()->battleGetAvailableHexes(stackToMove, false);
BattleHex shiftedDest = myNumber.cloneInDirection(stackToMove->destShiftDir(), false); BattleHex shiftedDest = myNumber.cloneInDirection(stackToMove->destShiftDir(), false);
if (vstd::contains(acc, myNumber)) if (vstd::contains(acc, myNumber))
@ -1006,7 +1006,7 @@ void BattleActionsController::onHexRightClicked(BattleHex clickedHex)
return; return;
} }
auto selectedStack = owner.curInt->cb->battleGetStackByPos(clickedHex, true); auto selectedStack = owner.getBattle()->battleGetStackByPos(clickedHex, true);
if (selectedStack != nullptr) if (selectedStack != nullptr)
GH.windows().createAndPushWindow<CStackWindow>(selectedStack, true); GH.windows().createAndPushWindow<CStackWindow>(selectedStack, true);

View File

@ -24,6 +24,7 @@
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../gui/CursorHandler.h" #include "../gui/CursorHandler.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../render/IRenderHandler.h"
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
@ -114,7 +115,7 @@ void StackActionAnimation::setGroup( ECreatureAnimType group )
currGroup = group; currGroup = group;
} }
void StackActionAnimation::setSound( std::string sound ) void StackActionAnimation::setSound( const AudioPath & sound )
{ {
this->sound = sound; this->sound = sound;
} }
@ -179,7 +180,7 @@ HittedAnimation::HittedAnimation(BattleInterface & owner, const CStack * stack)
: StackActionAnimation(owner, stack) : StackActionAnimation(owner, stack)
{ {
setGroup(ECreatureAnimType::HITTED); setGroup(ECreatureAnimType::HITTED);
setSound(battle_sound(stack->unitType(), wince)); setSound(stack->unitType()->sounds.wince);
logAnim->debug("Created HittedAnimation for %s", stack->getName()); logAnim->debug("Created HittedAnimation for %s", stack->getName());
} }
@ -187,14 +188,14 @@ DefenceAnimation::DefenceAnimation(BattleInterface & owner, const CStack * stack
: StackActionAnimation(owner, stack) : StackActionAnimation(owner, stack)
{ {
setGroup(ECreatureAnimType::DEFENCE); setGroup(ECreatureAnimType::DEFENCE);
setSound(battle_sound(stack->unitType(), defend)); setSound(stack->unitType()->sounds.defend);
logAnim->debug("Created DefenceAnimation for %s", stack->getName()); logAnim->debug("Created DefenceAnimation for %s", stack->getName());
} }
DeathAnimation::DeathAnimation(BattleInterface & owner, const CStack * stack, bool ranged): DeathAnimation::DeathAnimation(BattleInterface & owner, const CStack * stack, bool ranged):
StackActionAnimation(owner, stack) StackActionAnimation(owner, stack)
{ {
setSound(battle_sound(stack->unitType(), killed)); setSound(stack->unitType()->sounds.killed);
if(ranged && myAnim->framesInGroup(ECreatureAnimType::DEATH_RANGED) > 0) if(ranged && myAnim->framesInGroup(ECreatureAnimType::DEATH_RANGED) > 0)
setGroup(ECreatureAnimType::DEATH_RANGED); setGroup(ECreatureAnimType::DEATH_RANGED);
@ -315,7 +316,7 @@ MeleeAttackAnimation::MeleeAttackAnimation(BattleInterface & owner, const CStack
: AttackAnimation(owner, attacker, _dest, _attacked) : AttackAnimation(owner, attacker, _dest, _attacked)
{ {
logAnim->debug("Created MeleeAttackAnimation for %s", attacker->getName()); logAnim->debug("Created MeleeAttackAnimation for %s", attacker->getName());
setSound(battle_sound(getCreature(), attack)); setSound(getCreature()->sounds.attack);
setGroup(selectGroup(multiAttack)); setGroup(selectGroup(multiAttack));
} }
@ -356,7 +357,7 @@ bool MovementAnimation::init()
if (moveSoundHander == -1) if (moveSoundHander == -1)
{ {
moveSoundHander = CCS->soundh->playSound(battle_sound(stack->unitType(), move), -1); moveSoundHander = CCS->soundh->playSound(stack->unitType()->sounds.move, -1);
} }
Point begPosition = owner.stacksController->getStackPositionAtHex(prevHex, stack); Point begPosition = owner.stacksController->getStackPositionAtHex(prevHex, stack);
@ -453,7 +454,7 @@ bool MovementEndAnimation::init()
logAnim->debug("CMovementEndAnimation::init: stack %s", stack->getName()); logAnim->debug("CMovementEndAnimation::init: stack %s", stack->getName());
myAnim->pos.moveTo(owner.stacksController->getStackPositionAtHex(nextHex, stack)); myAnim->pos.moveTo(owner.stacksController->getStackPositionAtHex(nextHex, stack));
CCS->soundh->playSound(battle_sound(stack->unitType(), endMoving)); CCS->soundh->playSound(stack->unitType()->sounds.endMoving);
if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_END)) if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_END))
{ {
@ -494,7 +495,7 @@ bool MovementStartAnimation::init()
} }
logAnim->debug("CMovementStartAnimation::init: stack %s", stack->getName()); logAnim->debug("CMovementStartAnimation::init: stack %s", stack->getName());
CCS->soundh->playSound(battle_sound(stack->unitType(), startMoving)); CCS->soundh->playSound(stack->unitType()->sounds.startMoving);
if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_START)) if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_START))
{ {
@ -632,7 +633,7 @@ RangedAttackAnimation::RangedAttackAnimation(BattleInterface & owner_, const CSt
: AttackAnimation(owner_, attacker, dest_, defender), : AttackAnimation(owner_, attacker, dest_, defender),
projectileEmitted(false) projectileEmitted(false)
{ {
setSound(battle_sound(getCreature(), shoot)); setSound(getCreature()->sounds.shoot);
} }
bool RangedAttackAnimation::init() bool RangedAttackAnimation::init()
@ -806,8 +807,8 @@ void CatapultAnimation::tick(uint32_t msPassed)
explosionEmitted = true; explosionEmitted = true;
Point shotTarget = owner.stacksController->getStackPositionAtHex(dest, defendingStack) + Point(225, 225) - Point(126, 105); Point shotTarget = owner.stacksController->getStackPositionAtHex(dest, defendingStack) + Point(225, 225) - Point(126, 105);
std::string soundFilename = (catapultDamage > 0) ? "WALLHIT" : "WALLMISS"; auto soundFilename = AudioPath::builtin((catapultDamage > 0) ? "WALLHIT" : "WALLMISS");
std::string effectFilename = (catapultDamage > 0) ? "SGEXPL" : "CSGRCK"; AnimationPath effectFilename = AnimationPath::builtin((catapultDamage > 0) ? "SGEXPL" : "CSGRCK");
CCS->soundh->playSound( soundFilename ); CCS->soundh->playSound( soundFilename );
owner.stacksController->addNewAnim( new EffectAnimation(owner, effectFilename, shotTarget)); owner.stacksController->addNewAnim( new EffectAnimation(owner, effectFilename, shotTarget));
@ -879,42 +880,42 @@ uint32_t CastAnimation::getAttackClimaxFrame() const
return maxFrames / 2; return maxFrames / 2;
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, int effects, bool reversed):
BattleAnimation(owner), BattleAnimation(owner),
animation(std::make_shared<CAnimation>(animationName)), animation(GH.renderHandler().loadAnimation(animationName)),
effectFlags(effects), effectFlags(effects),
effectFinished(false), effectFinished(false),
reversed(reversed) reversed(reversed)
{ {
logAnim->debug("CPointEffectAnimation::init: effect %s", animationName); logAnim->debug("CPointEffectAnimation::init: effect %s", animationName.getName());
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<BattleHex> hex, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<BattleHex> hex, int effects, bool reversed):
EffectAnimation(owner, animationName, effects, reversed) EffectAnimation(owner, animationName, effects, reversed)
{ {
battlehexes = hex; battlehexes = hex;
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, BattleHex hex, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, BattleHex hex, int effects, bool reversed):
EffectAnimation(owner, animationName, effects, reversed) EffectAnimation(owner, animationName, effects, reversed)
{ {
assert(hex.isValid()); assert(hex.isValid());
battlehexes.push_back(hex); battlehexes.push_back(hex);
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<Point> pos, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<Point> pos, int effects, bool reversed):
EffectAnimation(owner, animationName, effects, reversed) EffectAnimation(owner, animationName, effects, reversed)
{ {
positions = pos; positions = pos;
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, int effects, bool reversed):
EffectAnimation(owner, animationName, effects, reversed) EffectAnimation(owner, animationName, effects, reversed)
{ {
positions.push_back(pos); positions.push_back(pos);
} }
EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, BattleHex hex, int effects, bool reversed): EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, BattleHex hex, int effects, bool reversed):
EffectAnimation(owner, animationName, effects, reversed) EffectAnimation(owner, animationName, effects, reversed)
{ {
assert(hex.isValid()); assert(hex.isValid());
@ -970,7 +971,7 @@ bool EffectAnimation::init()
} }
else else
{ {
const auto * destStack = owner.getCurrentPlayerInterface()->cb->battleGetUnitByPos(battlehexes[i], false); const auto * destStack = owner.getBattle()->battleGetUnitByPos(battlehexes[i], false);
Rect tilePos = owner.fieldController->hexPositionLocal(battlehexes[i]); Rect tilePos = owner.fieldController->hexPositionLocal(battlehexes[i]);
be.pos.x = tilePos.x + tilePos.w/2 - first->width()/2; be.pos.x = tilePos.x + tilePos.w/2 - first->width()/2;

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../../lib/filesystem/ResourcePath.h"
#include "BattleConstants.h" #include "BattleConstants.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -68,11 +69,11 @@ class StackActionAnimation : public BattleStackAnimation
{ {
ECreatureAnimType nextGroup; ECreatureAnimType nextGroup;
ECreatureAnimType currGroup; ECreatureAnimType currGroup;
std::string sound; AudioPath sound;
public: public:
void setNextGroup( ECreatureAnimType group ); void setNextGroup( ECreatureAnimType group );
void setGroup( ECreatureAnimType group ); void setGroup( ECreatureAnimType group );
void setSound( std::string sound ); void setSound( const AudioPath & sound );
ECreatureAnimType getGroup() const; ECreatureAnimType getGroup() const;
@ -334,17 +335,17 @@ public:
}; };
/// Create animation with screen-wide effect /// Create animation with screen-wide effect
EffectAnimation(BattleInterface & owner, std::string animationName, int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, int effects = 0, bool reversed = false);
/// Create animation positioned at point(s). Note that positions must be are absolute, including battleint position offset /// Create animation positioned at point(s). Note that positions must be are absolute, including battleint position offset
EffectAnimation(BattleInterface & owner, std::string animationName, Point pos , int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos , int effects = 0, bool reversed = false);
EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<Point> pos , int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<Point> pos , int effects = 0, bool reversed = false);
/// Create animation positioned at certain hex(es) /// Create animation positioned at certain hex(es)
EffectAnimation(BattleInterface & owner, std::string animationName, BattleHex hex , int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, BattleHex hex , int effects = 0, bool reversed = false);
EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<BattleHex> hex, int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<BattleHex> hex, int effects = 0, bool reversed = false);
EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, BattleHex hex, int effects = 0, bool reversed = false); EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, BattleHex hex, int effects = 0, bool reversed = false);
~EffectAnimation(); ~EffectAnimation();
bool init() override; bool init() override;

View File

@ -27,7 +27,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/battle/BattleAction.h" #include "../../lib/battle/BattleAction.h"
#include "../../lib/filesystem/ResourceID.h" #include "../../lib/filesystem/ResourcePath.h"
#include "../../lib/NetPacks.h" #include "../../lib/NetPacks.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/IGameEventsReceiver.h" #include "../../lib/IGameEventsReceiver.h"
@ -41,14 +41,14 @@ BattleEffectsController::BattleEffectsController(BattleInterface & owner):
void BattleEffectsController::displayEffect(EBattleEffect effect, const BattleHex & destTile) void BattleEffectsController::displayEffect(EBattleEffect effect, const BattleHex & destTile)
{ {
displayEffect(effect, "", destTile); displayEffect(effect, AudioPath(), destTile);
} }
void BattleEffectsController::displayEffect(EBattleEffect effect, std::string soundFile, const BattleHex & destTile) void BattleEffectsController::displayEffect(EBattleEffect effect, const AudioPath & soundFile, const BattleHex & destTile)
{ {
size_t effectID = static_cast<size_t>(effect); size_t effectID = static_cast<size_t>(effect);
std::string customAnim = graphics->battleACToDef[effectID][0]; AnimationPath customAnim = AnimationPath::builtinTODO(graphics->battleACToDef[effectID][0]);
CCS->soundh->playSound( soundFile ); CCS->soundh->playSound( soundFile );
@ -59,7 +59,7 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
{ {
owner.checkForAnimations(); owner.checkForAnimations();
const CStack * stack = owner.curInt->cb->battleGetStackByID(bte.stackID); const CStack * stack = owner.getBattle()->battleGetStackByID(bte.stackID);
if(!stack) if(!stack)
{ {
logGlobal->error("Invalid stack ID %d", bte.stackID); logGlobal->error("Invalid stack ID %d", bte.stackID);
@ -69,22 +69,22 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
switch(static_cast<BonusType>(bte.effect)) switch(static_cast<BonusType>(bte.effect))
{ {
case BonusType::HP_REGENERATION: case BonusType::HP_REGENERATION:
displayEffect(EBattleEffect::REGENERATION, "REGENER", stack->getPosition()); displayEffect(EBattleEffect::REGENERATION, AudioPath::builtin("REGENER"), stack->getPosition());
break; break;
case BonusType::MANA_DRAIN: case BonusType::MANA_DRAIN:
displayEffect(EBattleEffect::MANA_DRAIN, "MANADRAI", stack->getPosition()); displayEffect(EBattleEffect::MANA_DRAIN, AudioPath::builtin("MANADRAI"), stack->getPosition());
break; break;
case BonusType::POISON: case BonusType::POISON:
displayEffect(EBattleEffect::POISON, "POISON", stack->getPosition()); displayEffect(EBattleEffect::POISON, AudioPath::builtin("POISON"), stack->getPosition());
break; break;
case BonusType::FEAR: case BonusType::FEAR:
displayEffect(EBattleEffect::FEAR, "FEAR", stack->getPosition()); displayEffect(EBattleEffect::FEAR, AudioPath::builtin("FEAR"), stack->getPosition());
break; break;
case BonusType::MORALE: case BonusType::MORALE:
{ {
std::string hlp = CGI->generaltexth->allTexts[33]; std::string hlp = CGI->generaltexth->allTexts[33];
boost::algorithm::replace_first(hlp,"%s",(stack->getName())); boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
displayEffect(EBattleEffect::GOOD_MORALE, "GOODMRLE", stack->getPosition()); displayEffect(EBattleEffect::GOOD_MORALE, AudioPath::builtin("GOODMRLE"), stack->getPosition());
owner.appendBattleLog(hlp); owner.appendBattleLog(hlp);
break; break;
} }
@ -98,7 +98,7 @@ void BattleEffectsController::startAction(const BattleAction & action)
{ {
owner.checkForAnimations(); owner.checkForAnimations();
const CStack *stack = owner.curInt->cb->battleGetStackByID(action.stackNumber); const CStack *stack = owner.getBattle()->battleGetStackByID(action.stackNumber);
switch(action.actionType) switch(action.actionType)
{ {
@ -107,7 +107,7 @@ void BattleEffectsController::startAction(const BattleAction & action)
break; break;
case EActionType::BAD_MORALE: case EActionType::BAD_MORALE:
owner.appendBattleLog(stack->formatGeneralMessage(-34)); owner.appendBattleLog(stack->formatGeneralMessage(-34));
displayEffect(EBattleEffect::BAD_MORALE, "BADMRLE", stack->getPosition()); displayEffect(EBattleEffect::BAD_MORALE, AudioPath::builtin("BADMRLE"), stack->getPosition());
break; break;
} }
@ -132,7 +132,7 @@ void BattleEffectsController::collectRenderableObjects(BattleRenderer & renderer
void BattleEffectsController::loadColorMuxers() void BattleEffectsController::loadColorMuxers()
{ {
const JsonNode config(ResourceID("config/battleEffects.json")); const JsonNode config(JsonPath::builtin("config/battleEffects.json"));
for(auto & muxer : config["colorMuxers"].Struct()) for(auto & muxer : config["colorMuxers"].Struct())
{ {

View File

@ -11,6 +11,7 @@
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../../lib/Point.h" #include "../../lib/Point.h"
#include "../../lib/filesystem/ResourcePath.h"
#include "BattleConstants.h" #include "BattleConstants.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -64,7 +65,7 @@ public:
//displays custom effect on the battlefield //displays custom effect on the battlefield
void displayEffect(EBattleEffect effect, const BattleHex & destTile); void displayEffect(EBattleEffect effect, const BattleHex & destTile);
void displayEffect(EBattleEffect effect, std::string soundFile, const BattleHex & destTile); void displayEffect(EBattleEffect effect, const AudioPath & soundFile, const BattleHex & destTile);
void battleTriggerEffect(const BattleTriggerEffect & bte); void battleTriggerEffect(const BattleTriggerEffect & bte);

View File

@ -26,6 +26,7 @@
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IImage.h" #include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h" #include "../renderSDL/SDL_Extensions.h"
#include "../render/IRenderHandler.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h" #include "../gui/CursorHandler.h"
#include "../adventureMap/CInGameConsole.h" #include "../adventureMap/CInGameConsole.h"
@ -120,20 +121,20 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
//preparing cells and hexes //preparing cells and hexes
cellBorder = IImage::createFromFile("CCELLGRD.BMP", EImageBlitMode::COLORKEY); cellBorder = GH.renderHandler().loadImage(ImagePath::builtin("CCELLGRD.BMP"), EImageBlitMode::COLORKEY);
cellShade = IImage::createFromFile("CCELLSHD.BMP"); cellShade = GH.renderHandler().loadImage(ImagePath::builtin("CCELLSHD.BMP"));
cellUnitMovementHighlight = IImage::createFromFile("UnitMovementHighlight.PNG", EImageBlitMode::COLORKEY); cellUnitMovementHighlight = GH.renderHandler().loadImage(ImagePath::builtin("UnitMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
cellUnitMaxMovementHighlight = IImage::createFromFile("UnitMaxMovementHighlight.PNG", EImageBlitMode::COLORKEY); cellUnitMaxMovementHighlight = GH.renderHandler().loadImage(ImagePath::builtin("UnitMaxMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
attackCursors = std::make_shared<CAnimation>("CRCOMBAT"); attackCursors = GH.renderHandler().loadAnimation(AnimationPath::builtin("CRCOMBAT"));
attackCursors->preload(); attackCursors->preload();
initializeHexEdgeMaskToFrameIndex(); initializeHexEdgeMaskToFrameIndex();
rangedFullDamageLimitImages = std::make_shared<CAnimation>("battle/rangeHighlights/rangeHighlightsGreen.json"); rangedFullDamageLimitImages = GH.renderHandler().loadAnimation(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsGreen.json"));
rangedFullDamageLimitImages->preload(); rangedFullDamageLimitImages->preload();
shootingRangeLimitImages = std::make_shared<CAnimation>("battle/rangeHighlights/rangeHighlightsRed.json"); shootingRangeLimitImages = GH.renderHandler().loadAnimation(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsRed.json"));
shootingRangeLimitImages->preload(); shootingRangeLimitImages->preload();
flipRangeLimitImagesIntoPositions(rangedFullDamageLimitImages); flipRangeLimitImagesIntoPositions(rangedFullDamageLimitImages);
@ -141,17 +142,17 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
if(!owner.siegeController) if(!owner.siegeController)
{ {
auto bfieldType = owner.curInt->cb->battleGetBattlefieldType(); auto bfieldType = owner.getBattle()->battleGetBattlefieldType();
if(bfieldType == BattleField::NONE) if(bfieldType == BattleField::NONE)
logGlobal->error("Invalid battlefield returned for current battle"); logGlobal->error("Invalid battlefield returned for current battle");
else else
background = IImage::createFromFile(bfieldType.getInfo()->graphics, EImageBlitMode::OPAQUE); background = GH.renderHandler().loadImage(bfieldType.getInfo()->graphics, EImageBlitMode::OPAQUE);
} }
else else
{ {
std::string backgroundName = owner.siegeController->getBattleBackgroundName(); auto backgroundName = owner.siegeController->getBattleBackgroundName();
background = IImage::createFromFile(backgroundName, EImageBlitMode::OPAQUE); background = GH.renderHandler().loadImage(backgroundName, EImageBlitMode::OPAQUE);
} }
pos.w = background->width(); pos.w = background->width();
@ -284,7 +285,7 @@ void BattleFieldController::redrawBackgroundWithHexes()
const CStack *activeStack = owner.stacksController->getActiveStack(); const CStack *activeStack = owner.stacksController->getActiveStack();
std::vector<BattleHex> attackableHexes; std::vector<BattleHex> attackableHexes;
if(activeStack) if(activeStack)
occupiableHexes = owner.curInt->cb->battleGetAvailableHexes(activeStack, false, true, &attackableHexes); occupiableHexes = owner.getBattle()->battleGetAvailableHexes(activeStack, false, true, &attackableHexes);
// prepare background graphic with hexes and shaded hexes // prepare background graphic with hexes and shaded hexes
backgroundWithHexes->draw(background, Point(0,0)); backgroundWithHexes->draw(background, Point(0,0));
@ -339,7 +340,7 @@ std::set<BattleHex> BattleFieldController::getHighlightedHexesForActiveStack()
auto hoveredHex = getHoveredHex(); auto hoveredHex = getHoveredHex();
std::set<BattleHex> set = owner.curInt->cb->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex); std::set<BattleHex> set = owner.getBattle()->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex);
for(BattleHex hex : set) for(BattleHex hex : set)
result.insert(hex); result.insert(hex);
@ -359,10 +360,10 @@ std::set<BattleHex> BattleFieldController::getMovementRangeForHoveredStack()
auto hoveredHex = getHoveredHex(); auto hoveredHex = getHoveredHex();
// add possible movement hexes for stack under mouse // add possible movement hexes for stack under mouse
const CStack * const hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); const CStack * const hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
if(hoveredStack) if(hoveredStack)
{ {
std::vector<BattleHex> v = owner.curInt->cb->battleGetAvailableHexes(hoveredStack, true, true, nullptr); std::vector<BattleHex> v = owner.getBattle()->battleGetAvailableHexes(hoveredStack, true, true, nullptr);
for(BattleHex hex : v) for(BattleHex hex : v)
result.insert(hex); result.insert(hex);
} }
@ -387,7 +388,7 @@ std::set<BattleHex> BattleFieldController::getHighlightedHexesForSpellRange()
if(caster && spell) //when casting spell if(caster && spell) //when casting spell
{ {
// printing shaded hex(es) // printing shaded hex(es)
spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell); spells::BattleCast event(owner.getBattle().get(), caster, mode, spell);
auto shadedHexes = spell->battleMechanics(&event)->rangeInHexes(hoveredHex); auto shadedHexes = spell->battleMechanics(&event)->rangeInHexes(hoveredHex);
for(BattleHex shadedHex : shadedHexes) for(BattleHex shadedHex : shadedHexes)
@ -407,10 +408,10 @@ std::set<BattleHex> BattleFieldController::getHighlightedHexesForMovementTarget(
if(!stack) if(!stack)
return {}; return {};
std::vector<BattleHex> availableHexes = owner.curInt->cb->battleGetAvailableHexes(stack, false, false, nullptr); std::vector<BattleHex> availableHexes = owner.getBattle()->battleGetAvailableHexes(stack, false, false, nullptr);
auto hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); auto hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
if(owner.curInt->cb->battleCanAttack(stack, hoveredStack, hoveredHex)) if(owner.getBattle()->battleCanAttack(stack, hoveredStack, hoveredHex))
{ {
if(isTileAttackable(hoveredHex)) if(isTileAttackable(hoveredHex))
{ {
@ -670,7 +671,7 @@ BattleHex BattleFieldController::getHoveredHex()
const CStack* BattleFieldController::getHoveredStack() const CStack* BattleFieldController::getHoveredStack()
{ {
auto hoveredHex = getHoveredHex(); auto hoveredHex = getHoveredHex();
const CStack* hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); const CStack* hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
return hoveredStack; return hoveredStack;
} }
@ -856,7 +857,7 @@ bool BattleFieldController::isTileAttackable(const BattleHex & number) const
void BattleFieldController::updateAccessibleHexes() void BattleFieldController::updateAccessibleHexes()
{ {
auto accessibility = owner.curInt->cb->getAccesibility(); auto accessibility = owner.getBattle()->getAccesibility();
for(int i = 0; i < accessibility.size(); i++) for(int i = 0; i < accessibility.size(); i++)
stackCountOutsideHexes[i] = (accessibility[i] == EAccessibility::ACCESSIBLE || (accessibility[i] == EAccessibility::SIDE_COLUMN)); stackCountOutsideHexes[i] = (accessibility[i] == EAccessibility::ACCESSIBLE || (accessibility[i] == EAccessibility::SIDE_COLUMN));

View File

@ -45,7 +45,7 @@
#include "../../lib/TerrainHandler.h" #include "../../lib/TerrainHandler.h"
#include "../../lib/CThreadHelper.h" #include "../../lib/CThreadHelper.h"
BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, BattleInterface::BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2,
const CGHeroInstance *hero1, const CGHeroInstance *hero2, const CGHeroInstance *hero1, const CGHeroInstance *hero2,
std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> att,
std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> defen,
@ -55,6 +55,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
, attackerInt(att) , attackerInt(att)
, defenderInt(defen) , defenderInt(defen)
, curInt(att) , curInt(att)
, battleID(battleID)
, battleOpeningDelayActive(true) , battleOpeningDelayActive(true)
{ {
if(spectatorInt) if(spectatorInt)
@ -68,9 +69,9 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
} }
//hot-seat -> check tactics for both players (defender may be local human) //hot-seat -> check tactics for both players (defender may be local human)
if(attackerInt && attackerInt->cb->battleGetTacticDist()) if(attackerInt && attackerInt->cb->getBattle(getBattleID())->battleGetTacticDist())
tacticianInterface = attackerInt; tacticianInterface = attackerInt;
else if(defenderInt && defenderInt->cb->battleGetTacticDist()) else if(defenderInt && defenderInt->cb->getBattle(getBattleID())->battleGetTacticDist())
tacticianInterface = defenderInt; tacticianInterface = defenderInt;
//if we found interface of player with tactics, then enter tactics mode //if we found interface of player with tactics, then enter tactics mode
@ -80,7 +81,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
this->army1 = army1; this->army1 = army1;
this->army2 = army2; this->army2 = army2;
const CGTownInstance *town = curInt->cb->battleGetDefendedTown(); const CGTownInstance *town = getBattle()->battleGetDefendedTown();
if(town && town->hasFort()) if(town && town->hasFort())
siegeController.reset(new BattleSiegeController(*this, town)); siegeController.reset(new BattleSiegeController(*this, town));
@ -223,12 +224,12 @@ void BattleInterface::stackAttacking( const StackAttackInfo & attackInfo )
stacksController->stackAttacking(attackInfo); stacksController->stackAttacking(attackInfo);
} }
void BattleInterface::newRoundFirst( int round ) void BattleInterface::newRoundFirst()
{ {
waitForAnimations(); waitForAnimations();
} }
void BattleInterface::newRound(int number) void BattleInterface::newRound()
{ {
console->addText(CGI->generaltexth->allTexts[412]); console->addText(CGI->generaltexth->allTexts[412]);
} }
@ -241,10 +242,10 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID sp
actor = stacksController->getActiveStack(); actor = stacksController->getActiveStack();
} }
auto side = curInt->cb->playerToSide(curInt->playerID); auto side = getBattle()->playerToSide(curInt->playerID);
if(!side) if(!side)
{ {
logGlobal->error("Player %s is not in battle", curInt->playerID.getStr()); logGlobal->error("Player %s is not in battle", curInt->playerID.toString());
return; return;
} }
@ -265,11 +266,11 @@ void BattleInterface::sendCommand(BattleAction command, const CStack * actor)
{ {
logGlobal->trace("Setting command for %s", (actor ? actor->nodeName() : "hero")); logGlobal->trace("Setting command for %s", (actor ? actor->nodeName() : "hero"));
stacksController->setActiveStack(nullptr); stacksController->setActiveStack(nullptr);
curInt->cb->battleMakeUnitAction(command); curInt->cb->battleMakeUnitAction(battleID, command);
} }
else else
{ {
curInt->cb->battleMakeTacticAction(command); curInt->cb->battleMakeTacticAction(battleID, command);
stacksController->setActiveStack(nullptr); stacksController->setActiveStack(nullptr);
//next stack will be activated when action ends //next stack will be activated when action ends
} }
@ -353,7 +354,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
if(!spell) if(!spell)
return; return;
const std::string & castSoundPath = spell->getCastSound(); const AudioPath & castSoundPath = spell->getCastSound();
if (!castSoundPath.empty()) if (!castSoundPath.empty())
{ {
@ -368,13 +369,13 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
if ( sc->activeCast ) if ( sc->activeCast )
{ {
const CStack * casterStack = curInt->cb->battleGetStackByID(sc->casterStack); const CStack * casterStack = getBattle()->battleGetStackByID(sc->casterStack);
if(casterStack != nullptr ) if(casterStack != nullptr )
{ {
addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]()
{ {
stacksController->addNewAnim(new CastAnimation(*this, casterStack, targetedTile, curInt->cb->battleGetStackByPos(targetedTile), spell)); stacksController->addNewAnim(new CastAnimation(*this, casterStack, targetedTile, getBattle()->battleGetStackByPos(targetedTile), spell));
displaySpellCast(spell, casterStack->getPosition()); displaySpellCast(spell, casterStack->getPosition());
}); });
} }
@ -385,7 +386,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]()
{ {
stacksController->addNewAnim(new HeroCastAnimation(*this, hero, targetedTile, curInt->cb->battleGetStackByPos(targetedTile), spell)); stacksController->addNewAnim(new HeroCastAnimation(*this, hero, targetedTile, getBattle()->battleGetStackByPos(targetedTile), spell));
}); });
} }
} }
@ -397,7 +398,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
//queuing affect animation //queuing affect animation
for(auto & elem : sc->affectedCres) for(auto & elem : sc->affectedCres)
{ {
auto stack = curInt->cb->battleGetStackByID(elem, false); auto stack = getBattle()->battleGetStackByID(elem, false);
assert(stack); assert(stack);
if(stack) if(stack)
{ {
@ -409,7 +410,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
for(auto & elem : sc->reflectedCres) for(auto & elem : sc->reflectedCres)
{ {
auto stack = curInt->cb->battleGetStackByID(elem, false); auto stack = getBattle()->battleGetStackByID(elem, false);
assert(stack); assert(stack);
addToAnimationStage(EAnimationEvents::HIT, [=](){ addToAnimationStage(EAnimationEvents::HIT, [=](){
effectsController->displayEffect(EBattleEffect::MAGIC_MIRROR, stack->getPosition()); effectsController->displayEffect(EBattleEffect::MAGIC_MIRROR, stack->getPosition());
@ -419,13 +420,13 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
if (!sc->resistedCres.empty()) if (!sc->resistedCres.empty())
{ {
addToAnimationStage(EAnimationEvents::HIT, [=](){ addToAnimationStage(EAnimationEvents::HIT, [=](){
CCS->soundh->playSound("MAGICRES"); CCS->soundh->playSound(AudioPath::builtin("MAGICRES"));
}); });
} }
for(auto & elem : sc->resistedCres) for(auto & elem : sc->resistedCres)
{ {
auto stack = curInt->cb->battleGetStackByID(elem, false); auto stack = getBattle()->battleGetStackByID(elem, false);
assert(stack); assert(stack);
addToAnimationStage(EAnimationEvents::HIT, [=](){ addToAnimationStage(EAnimationEvents::HIT, [=](){
effectsController->displayEffect(EBattleEffect::RESISTANCE, stack->getPosition()); effectsController->displayEffect(EBattleEffect::RESISTANCE, stack->getPosition());
@ -440,8 +441,8 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
bool side = sc->side; bool side = sc->side;
addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){ addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){
stacksController->addNewAnim(new EffectAnimation(*this, side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero)); stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero));
stacksController->addNewAnim(new EffectAnimation(*this, side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero)); stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero));
}); });
} }
@ -487,7 +488,7 @@ void BattleInterface::displaySpellAnimationQueue(const CSpell * spell, const CSp
if (!animation.effectName.empty()) if (!animation.effectName.empty())
{ {
const CStack * destStack = getCurrentPlayerInterface()->cb->battleGetStackByPos(destinationTile, false); const CStack * destStack = getBattle()->battleGetStackByPos(destinationTile, false);
if (destStack) if (destStack)
stacksController->addNewAnim(new ColorTransformAnimation(*this, destStack, animation.effectName, spell )); stacksController->addNewAnim(new ColorTransformAnimation(*this, destStack, animation.effectName, spell ));
@ -566,12 +567,22 @@ bool BattleInterface::makingTurn() const
return stacksController->getActiveStack() != nullptr; return stacksController->getActiveStack() != nullptr;
} }
BattleID BattleInterface::getBattleID() const
{
return battleID;
}
std::shared_ptr<CPlayerBattleCallback> BattleInterface::getBattle() const
{
return curInt->cb->getBattle(battleID);
}
void BattleInterface::endAction(const BattleAction &action) void BattleInterface::endAction(const BattleAction &action)
{ {
// it is possible that tactics mode ended while opening music is still playing // it is possible that tactics mode ended while opening music is still playing
waitForAnimations(); waitForAnimations();
const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber); const CStack *stack = getBattle()->battleGetStackByID(action.stackNumber);
// Activate stack from stackToActivate because this might have been temporary disabled, e.g., during spell cast // Activate stack from stackToActivate because this might have been temporary disabled, e.g., during spell cast
activateStack(); activateStack();
@ -606,7 +617,7 @@ void BattleInterface::startAction(const BattleAction & action)
if (!action.isUnitAction()) if (!action.isUnitAction())
return; return;
assert(curInt->cb->battleGetStackByID(action.stackNumber)); assert(getBattle()->battleGetStackByID(action.stackNumber));
windowObject->updateQueue(); windowObject->updateQueue();
effectsController->startAction(action); effectsController->startAction(action);
} }
@ -616,10 +627,10 @@ void BattleInterface::tacticPhaseEnd()
stacksController->setActiveStack(nullptr); stacksController->setActiveStack(nullptr);
tacticsMode = false; tacticsMode = false;
auto side = tacticianInterface->cb->playerToSide(tacticianInterface->playerID); auto side = tacticianInterface->cb->getBattle(battleID)->playerToSide(tacticianInterface->playerID);
auto action = BattleAction::makeEndOFTacticPhase(*side); auto action = BattleAction::makeEndOFTacticPhase(*side);
tacticianInterface->cb->battleMakeTacticAction(action); tacticianInterface->cb->battleMakeTacticAction(battleID, action);
} }
static bool immobile(const CStack *s) static bool immobile(const CStack *s)
@ -635,7 +646,7 @@ void BattleInterface::tacticNextStack(const CStack * current)
//no switching stacks when the current one is moving //no switching stacks when the current one is moving
checkForAnimations(); checkForAnimations();
TStacks stacksOfMine = tacticianInterface->cb->battleGetStacks(CBattleCallback::ONLY_MINE); TStacks stacksOfMine = tacticianInterface->cb->getBattle(battleID)->battleGetStacks(CPlayerBattleCallback::ONLY_MINE);
vstd::erase_if (stacksOfMine, &immobile); vstd::erase_if (stacksOfMine, &immobile);
if (stacksOfMine.empty()) if (stacksOfMine.empty())
{ {
@ -687,7 +698,7 @@ void BattleInterface::requestAutofightingAIToTakeAction()
{ {
assert(curInt->isAutoFightOn); assert(curInt->isAutoFightOn);
if(curInt->cb->battleIsFinished()) if(getBattle()->battleIsFinished())
{ {
return; // battle finished with spellcast return; // battle finished with spellcast
} }
@ -716,7 +727,7 @@ void BattleInterface::requestAutofightingAIToTakeAction()
boost::thread aiThread([this, activeStack]() boost::thread aiThread([this, activeStack]()
{ {
setThreadName("autofightingAI"); setThreadName("autofightingAI");
curInt->autofightingAI->activeStack(activeStack); curInt->autofightingAI->activeStack(battleID, activeStack);
}); });
aiThread.detach(); aiThread.detach();
} }

View File

@ -30,6 +30,7 @@ struct BattleTriggerEffect;
struct BattleHex; struct BattleHex;
struct InfoAboutHero; struct InfoAboutHero;
class ObstacleChanges; class ObstacleChanges;
class CPlayerBattleCallback;
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END
@ -115,6 +116,9 @@ class BattleInterface
/// if set to true, battle is still starting and waiting for intro sound to end / key press from player /// if set to true, battle is still starting and waiting for intro sound to end / key press from player
bool battleOpeningDelayActive; bool battleOpeningDelayActive;
/// ID of ongoing battle
BattleID battleID;
void playIntroSoundAndUnlockInterface(); void playIntroSoundAndUnlockInterface();
void onIntroSoundPlayed(); void onIntroSoundPlayed();
public: public:
@ -149,7 +153,10 @@ public:
bool makingTurn() const; bool makingTurn() const;
BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr); BattleID getBattleID() const;
std::shared_ptr<CPlayerBattleCallback> getBattle() const;
BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
~BattleInterface(); ~BattleInterface();
void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player
@ -196,8 +203,8 @@ public:
void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance, bool teleport); //stack with id number moved to destHex void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance, bool teleport); //stack with id number moved to destHex
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //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 StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest void stackAttacking(const StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round ); void newRoundFirst();
void newRound(int number); //caled when round is ended; number is the number of round void newRound(); //caled when round is ended;
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
void battleFinished(const BattleResult& br, QueryID queryID); //called when battle is finished - battleresult window should be printed void battleFinished(const BattleResult& br, QueryID queryID); //called when battle is finished - battleresult window should be printed
void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell

View File

@ -37,6 +37,7 @@
#include "../windows/CMessage.h" #include "../windows/CMessage.h"
#include "../windows/CSpellWindow.h" #include "../windows/CSpellWindow.h"
#include "../render/CAnimation.h" #include "../render/CAnimation.h"
#include "../render/IRenderHandler.h"
#include "../adventureMap/CInGameConsole.h" #include "../adventureMap/CInGameConsole.h"
#include "../../CCallback.h" #include "../../CCallback.h"
@ -289,7 +290,7 @@ void BattleHero::heroLeftClicked()
if(!hero || !owner.makingTurn()) if(!hero || !owner.makingTurn())
return; return;
if(owner.getCurrentPlayerInterface()->cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions if(owner.getBattle()->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions
{ {
CCS->curh->set(Cursor::Map::POINTER); CCS->curh->set(Cursor::Map::POINTER);
GH.windows().createAndPushWindow<CSpellWindow>(hero, owner.getCurrentPlayerInterface()); GH.windows().createAndPushWindow<CSpellWindow>(hero, owner.getCurrentPlayerInterface());
@ -342,7 +343,7 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
currentFrame(0.f), currentFrame(0.f),
flagCurrentFrame(0.f) flagCurrentFrame(0.f)
{ {
std::string animationPath; AnimationPath animationPath;
if(!hero->type->battleImage.empty()) if(!hero->type->battleImage.empty())
animationPath = hero->type->battleImage; animationPath = hero->type->battleImage;
@ -352,7 +353,7 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
else else
animationPath = hero->type->heroClass->imageBattleMale; animationPath = hero->type->heroClass->imageBattleMale;
animation = std::make_shared<CAnimation>(animationPath); animation = GH.renderHandler().loadAnimation(animationPath);
animation->preload(); animation->preload();
pos.w = 64; pos.w = 64;
@ -364,9 +365,9 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
animation->verticalFlip(); animation->verticalFlip();
if(defender) if(defender)
flagAnimation = std::make_shared<CAnimation>("CMFLAGR"); flagAnimation = GH.renderHandler().loadAnimation(AnimationPath::builtin("CMFLAGR"));
else else
flagAnimation = std::make_shared<CAnimation>("CMFLAGL"); flagAnimation = GH.renderHandler().loadAnimation(AnimationPath::builtin("CMFLAGL"));
flagAnimation->preload(); flagAnimation->preload();
flagAnimation->playerColored(hero->tempOwner); flagAnimation->playerColored(hero->tempOwner);
@ -386,7 +387,7 @@ HeroInfoBasicPanel::HeroInfoBasicPanel(const InfoAboutHero & hero, Point * posit
if(initializeBackground) if(initializeBackground)
{ {
background = std::make_shared<CPicture>("CHRPOP"); background = std::make_shared<CPicture>(ImagePath::builtin("CHRPOP"));
background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE); background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
background->colorize(hero.owner); background->colorize(hero.owner);
} }
@ -406,7 +407,7 @@ void HeroInfoBasicPanel::initializeData(const InfoAboutHero & hero)
auto currentSpellPoints = hero.details->mana; auto currentSpellPoints = hero.details->mana;
auto maxSpellPoints = hero.details->manaLimit; auto maxSpellPoints = hero.details->manaLimit;
icons.push_back(std::make_shared<CAnimImage>("PortraitsLarge", hero.portrait, 0, 10, 6)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero.portrait, 0, 10, 6));
//primary stats //primary stats
labels.push_back(std::make_shared<CLabel>(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":")); labels.push_back(std::make_shared<CLabel>(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":"));
@ -423,8 +424,8 @@ void HeroInfoBasicPanel::initializeData(const InfoAboutHero & hero)
labels.push_back(std::make_shared<CLabel>(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":")); labels.push_back(std::make_shared<CLabel>(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":"));
labels.push_back(std::make_shared<CLabel>(9, 143, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[385] + ":")); labels.push_back(std::make_shared<CLabel>(9, 143, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[385] + ":"));
icons.push_back(std::make_shared<CAnimImage>("IMRL22", morale + 3, 0, 47, 131)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("IMRL22"), morale + 3, 0, 47, 131));
icons.push_back(std::make_shared<CAnimImage>("ILCK22", luck + 3, 0, 47, 143)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("ILCK22"), luck + 3, 0, 47, 143));
//spell points //spell points
labels.push_back(std::make_shared<CLabel>(39, 174, EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[387])); labels.push_back(std::make_shared<CLabel>(39, 174, EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[387]));
@ -446,7 +447,7 @@ void HeroInfoBasicPanel::show(Canvas & to)
} }
HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position) HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position)
: CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP") : CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, ImagePath::builtin("CHRPOP"))
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
if (position != nullptr) if (position != nullptr)
@ -462,16 +463,16 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("CPRESULT"); background = std::make_shared<CPicture>(ImagePath::builtin("CPRESULT"));
background->colorize(owner.playerID); background->colorize(owner.playerID);
pos = center(background->pos); pos = center(background->pos);
exit = std::make_shared<CButton>(Point(384, 505), "iok6432.def", std::make_pair("", ""), [&](){ bExitf();}, EShortcut::GLOBAL_ACCEPT); exit = std::make_shared<CButton>(Point(384, 505), AnimationPath::builtin("iok6432.def"), std::make_pair("", ""), [&](){ bExitf();}, EShortcut::GLOBAL_ACCEPT);
exit->setBorderColor(Colors::METALLIC_GOLD); exit->setBorderColor(Colors::METALLIC_GOLD);
if(allowReplay) if(allowReplay)
{ {
repeat = std::make_shared<CButton>(Point(24, 505), "icn6432.def", std::make_pair("", ""), [&](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL); repeat = std::make_shared<CButton>(Point(24, 505), AnimationPath::builtin("icn6432.def"), std::make_pair("", ""), [&](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL);
repeat->setBorderColor(Colors::METALLIC_GOLD); repeat->setBorderColor(Colors::METALLIC_GOLD);
labels.push_back(std::make_shared<CLabel>(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel"))); labels.push_back(std::make_shared<CLabel>(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel")));
} }
@ -502,17 +503,17 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
for(int i = 0; i < 2; i++) for(int i = 0; i < 2; i++)
{ {
auto heroInfo = owner.cb->battleGetHeroInfo(i); auto heroInfo = owner.cb->getBattle(br.battleID)->battleGetHeroInfo(i);
const int xs[] = {21, 392}; const int xs[] = {21, 392};
if(heroInfo.portrait >= 0) //attacking hero if(heroInfo.portrait >= 0) //attacking hero
{ {
icons.push_back(std::make_shared<CAnimImage>("PortraitsLarge", heroInfo.portrait, 0, xs[i], 38)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), heroInfo.portrait, 0, xs[i], 38));
sideNames[i] = heroInfo.name; sideNames[i] = heroInfo.name;
} }
else else
{ {
auto stacks = owner.cb->battleGetAllStacks(); auto stacks = owner.cb->getBattle(br.battleID)->battleGetAllStacks();
vstd::erase_if(stacks, [i](const CStack * stack) //erase stack of other side and not coming from garrison vstd::erase_if(stacks, [i](const CStack * stack) //erase stack of other side and not coming from garrison
{ {
return stack->unitSide() != i || !stack->base; return stack->unitSide() != i || !stack->base;
@ -525,7 +526,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
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)->unitType()->getIconIndex(), 0, xs[i], 38)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[i], 38));
sideNames[i] = (*best)->unitType()->getNamePluralTranslated(); sideNames[i] = (*best)->unitType()->getNamePluralTranslated();
} }
} }
@ -552,7 +553,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
if (creature->getId() == CreatureID::ARROW_TOWERS ) if (creature->getId() == CreatureID::ARROW_TOWERS )
continue; // do not show destroyed towers in battle results continue; // do not show destroyed towers in battle results
icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", creature->getIconIndex(), 0, xPos, yPos)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), creature->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, ETextAlignment::CENTER, Colors::WHITE, amount.str())); labels.push_back(std::make_shared<CLabel>(xPos + 16, yPos + 42, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, amount.str()));
@ -561,7 +562,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
} }
} }
//printing result description //printing result description
bool weAreAttacker = !(owner.cb->battleGetMySide()); bool weAreAttacker = !(owner.cb->getBattle(br.battleID)->battleGetMySide());
if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
{ {
int text = 304; int text = 304;
@ -580,11 +581,11 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
break; break;
} }
CCS->musich->playMusic("Music/Win Battle", false, true); CCS->musich->playMusic(AudioPath::builtin("Music/Win Battle"), false, true);
CCS->videoh->open("WIN3.BIK"); CCS->videoh->open(VideoPath::builtin("WIN3.BIK"));
std::string str = CGI->generaltexth->allTexts[text]; std::string str = CGI->generaltexth->allTexts[text];
const CGHeroInstance * ourHero = owner.cb->battleGetMyHero(); const CGHeroInstance * ourHero = owner.cb->getBattle(br.battleID)->battleGetMyHero();
if (ourHero) if (ourHero)
{ {
str += CGI->generaltexth->allTexts[305]; str += CGI->generaltexth->allTexts[305];
@ -597,20 +598,20 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
else // we lose else // we lose
{ {
int text = 311; int text = 311;
std::string musicName = "Music/LoseCombat"; AudioPath musicName = AudioPath::builtin("Music/LoseCombat");
std::string videoName = "LBSTART.BIK"; VideoPath videoName = VideoPath::builtin("LBSTART.BIK");
switch(br.result) switch(br.result)
{ {
case EBattleResult::NORMAL: case EBattleResult::NORMAL:
break; break;
case EBattleResult::ESCAPE: case EBattleResult::ESCAPE:
musicName = "Music/Retreat Battle"; musicName = AudioPath::builtin("Music/Retreat Battle");
videoName = "RTSTART.BIK"; videoName = VideoPath::builtin("RTSTART.BIK");
text = 310; text = 310;
break; break;
case EBattleResult::SURRENDER: case EBattleResult::SURRENDER:
musicName = "Music/Surrender Battle"; musicName = AudioPath::builtin("Music/Surrender Battle");
videoName = "SURRENDER.BIK"; videoName = VideoPath::builtin("SURRENDER.BIK");
text = 309; text = 309;
break; break;
default: default:
@ -676,8 +677,8 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
pos.x += parent->pos.w/2 - pos.w/2; pos.x += parent->pos.w/2 - pos.w/2;
pos.y += 10; pos.y += 10;
icons = std::make_shared<CAnimation>("CPRSMALL"); icons = GH.renderHandler().loadAnimation(AnimationPath::builtin("CPRSMALL"));
stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESSMALL"); stateIcons = GH.renderHandler().loadAnimation(AnimationPath::builtin("VCMI/BATTLEQUEUE/STATESSMALL"));
} }
else else
{ {
@ -686,12 +687,12 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
pos.x += 0; pos.x += 0;
pos.y -= pos.h; pos.y -= pos.h;
background = std::make_shared<CFilledTexture>("DIBOXBCK", Rect(0, 0, pos.w, pos.h)); background = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, pos.w, pos.h));
icons = std::make_shared<CAnimation>("TWCRPORT"); icons = GH.renderHandler().loadAnimation(AnimationPath::builtin("TWCRPORT"));
stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESSMALL"); stateIcons = GH.renderHandler().loadAnimation(AnimationPath::builtin("VCMI/BATTLEQUEUE/STATESSMALL"));
//TODO: where use big icons? //TODO: where use big icons?
//stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESBIG"); //stateIcons = GH.renderHandler().loadAnimation("VCMI/BATTLEQUEUE/STATESBIG");
} }
stateIcons->preload(); stateIcons->preload();
@ -714,7 +715,7 @@ void StackQueue::update()
{ {
std::vector<battle::Units> queueData; std::vector<battle::Units> queueData;
owner.getCurrentPlayerInterface()->cb->battleGetTurnOrder(queueData, stackBoxes.size(), 0); owner.getBattle()->battleGetTurnOrder(queueData, stackBoxes.size(), 0);
size_t boxIndex = 0; size_t boxIndex = 0;
@ -750,7 +751,7 @@ StackQueue::StackBox::StackBox(StackQueue * owner):
CIntObject(SHOW_POPUP | HOVER), owner(owner) CIntObject(SHOW_POPUP | HOVER), owner(owner)
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>(owner->embedded ? "StackQueueSmall" : "StackQueueLarge"); background = std::make_shared<CPicture>(ImagePath::builtin(owner->embedded ? "StackQueueSmall" : "StackQueueLarge"));
pos.w = background->pos.w; pos.w = background->pos.w;
pos.h = background->pos.h; pos.h = background->pos.h;

View File

@ -22,6 +22,7 @@
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IRenderHandler.h"
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/battle/CObstacleInstance.h" #include "../../lib/battle/CObstacleInstance.h"
@ -31,7 +32,7 @@ BattleObstacleController::BattleObstacleController(BattleInterface & owner):
owner(owner), owner(owner),
timePassed(0.f) timePassed(0.f)
{ {
auto obst = owner.curInt->cb->battleGetAllObstacles(); auto obst = owner.getBattle()->battleGetAllObstacles();
for(auto & elem : obst) for(auto & elem : obst)
{ {
if ( elem->obstacleType == CObstacleInstance::MOAT ) if ( elem->obstacleType == CObstacleInstance::MOAT )
@ -42,21 +43,21 @@ BattleObstacleController::BattleObstacleController(BattleInterface & owner):
void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi) void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
{ {
std::string animationName = oi.getAnimation(); AnimationPath animationName = oi.getAnimation();
if (animationsCache.count(animationName) == 0) if (animationsCache.count(animationName) == 0)
{ {
if (oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) if (oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
{ {
// obstacle uses single bitmap image for animations // obstacle uses single bitmap image for animations
auto animation = std::make_shared<CAnimation>(); auto animation = GH.renderHandler().createAnimation();
animation->setCustom(animationName, 0, 0); animation->setCustom(animationName.getName(), 0, 0);
animationsCache[animationName] = animation; animationsCache[animationName] = animation;
animation->preload(); animation->preload();
} }
else else
{ {
auto animation = std::make_shared<CAnimation>(animationName); auto animation = GH.renderHandler().loadAnimation(animationName);
animationsCache[animationName] = animation; animationsCache[animationName] = animation;
animation->preload(); animation->preload();
} }
@ -76,7 +77,7 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
continue; continue;
} }
auto animation = std::make_shared<CAnimation>(obstacle["appearAnimation"].String()); auto animation = GH.renderHandler().loadAnimation(AnimationPath::fromJson(obstacle["appearAnimation"]));
animation->preload(); animation->preload();
auto first = animation->getImage(0, 0); auto first = animation->getImage(0, 0);
@ -87,7 +88,7 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
// -> if we know how to blit obstacle, let's blit the effect in the same place // -> if we know how to blit obstacle, let's blit the effect in the same place
Point whereTo = getObstaclePosition(first, obstacle); Point whereTo = getObstaclePosition(first, obstacle);
//AFAIK, in H3 there is no sound of obstacle removal //AFAIK, in H3 there is no sound of obstacle removal
owner.stacksController->addNewAnim(new EffectAnimation(owner, obstacle["appearAnimation"].String(), whereTo, obstacle["position"].Integer(), 0, true)); owner.stacksController->addNewAnim(new EffectAnimation(owner, AnimationPath::fromJson(obstacle["appearAnimation"]), whereTo, obstacle["position"].Integer(), 0, true));
obstacleAnimations.erase(oi.id); obstacleAnimations.erase(oi.id);
//so when multiple obstacles are removed, they show up one after another //so when multiple obstacles are removed, they show up one after another
@ -99,12 +100,12 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
{ {
for(const auto & oi : obstacles) for(const auto & oi : obstacles)
{ {
auto side = owner.curInt->cb->playerToSide(owner.curInt->playerID); auto side = owner.getBattle()->playerToSide(owner.curInt->playerID);
if(!oi->visibleForSide(side.value(), owner.curInt->cb->battleHasNativeStack(side.value()))) if(!oi->visibleForSide(side.value(), owner.getBattle()->battleHasNativeStack(side.value())))
continue; continue;
auto animation = std::make_shared<CAnimation>(oi->getAppearAnimation()); auto animation = GH.renderHandler().loadAnimation(oi->getAppearAnimation());
animation->preload(); animation->preload();
auto first = animation->getImage(0, 0); auto first = animation->getImage(0, 0);
@ -127,7 +128,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
void BattleObstacleController::showAbsoluteObstacles(Canvas & canvas) void BattleObstacleController::showAbsoluteObstacles(Canvas & canvas)
{ {
//Blit absolute obstacles //Blit absolute obstacles
for(auto & obstacle : owner.curInt->cb->battleGetAllObstacles()) for(auto & obstacle : owner.getBattle()->battleGetAllObstacles())
{ {
if(obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) if(obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
{ {
@ -153,7 +154,7 @@ void BattleObstacleController::showAbsoluteObstacles(Canvas & canvas)
void BattleObstacleController::collectRenderableObjects(BattleRenderer & renderer) void BattleObstacleController::collectRenderableObjects(BattleRenderer & renderer)
{ {
for (auto obstacle : owner.curInt->cb->battleGetAllObstacles()) for (auto obstacle : owner.getBattle()->battleGetAllObstacles())
{ {
if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
continue; continue;

View File

@ -9,6 +9,8 @@
*/ */
#pragma once #pragma once
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
struct BattleHex; struct BattleHex;
@ -35,7 +37,7 @@ class BattleObstacleController
float timePassed; float timePassed;
/// cached animations of all obstacles in current battle /// cached animations of all obstacles in current battle
std::map<std::string, std::shared_ptr<CAnimation>> animationsCache; std::map<AnimationPath, std::shared_ptr<CAnimation>> animationsCache;
/// list of all obstacles that are currently being rendered /// list of all obstacles that are currently being rendered
std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations; std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations;

View File

@ -16,6 +16,7 @@
#include "CreatureAnimation.h" #include "CreatureAnimation.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IRenderHandler.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../CGameInfo.h" #include "../CGameInfo.h"
@ -188,9 +189,9 @@ void BattleProjectileController::initStackProjectile(const CStack * stack)
projectilesCache[creature.animation.projectileImageName] = createProjectileImage(creature.animation.projectileImageName); projectilesCache[creature.animation.projectileImageName] = createProjectileImage(creature.animation.projectileImageName);
} }
std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(const std::string & path ) std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(const AnimationPath & path )
{ {
std::shared_ptr<CAnimation> projectile = std::make_shared<CAnimation>(path); std::shared_ptr<CAnimation> projectile = GH.renderHandler().loadAnimation(path);
projectile->preload(); projectile->preload();
if(projectile->size(1) != 0) if(projectile->size(1) != 0)
@ -204,7 +205,7 @@ std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(co
std::shared_ptr<CAnimation> BattleProjectileController::getProjectileImage(const CStack * stack) std::shared_ptr<CAnimation> BattleProjectileController::getProjectileImage(const CStack * stack)
{ {
const CCreature & creature = getShooter(stack); const CCreature & creature = getShooter(stack);
std::string imageName = creature.animation.projectileImageName; AnimationPath imageName = creature.animation.projectileImageName;
if (!projectilesCache.count(imageName)) if (!projectilesCache.count(imageName))
initStackProjectile(stack); initStackProjectile(stack);
@ -361,7 +362,7 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point
void BattleProjectileController::createSpellProjectile(const CStack * shooter, Point from, Point dest, const CSpell * spell) void BattleProjectileController::createSpellProjectile(const CStack * shooter, Point from, Point dest, const CSpell * spell)
{ {
double projectileAngle = std::abs(atan2(dest.x - from.x, dest.y - from.y)); double projectileAngle = std::abs(atan2(dest.x - from.x, dest.y - from.y));
std::string animToDisplay = spell->animationInfo.selectProjectile(projectileAngle); AnimationPath animToDisplay = spell->animationInfo.selectProjectile(projectileAngle);
assert(!animToDisplay.empty()); assert(!animToDisplay.empty());

View File

@ -11,6 +11,7 @@
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
#include "../../lib/Point.h" #include "../../lib/Point.h"
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -83,13 +84,13 @@ class BattleProjectileController
BattleInterface & owner; BattleInterface & owner;
/// all projectiles loaded during current battle /// all projectiles loaded during current battle
std::map<std::string, std::shared_ptr<CAnimation>> projectilesCache; std::map<AnimationPath, std::shared_ptr<CAnimation>> projectilesCache;
/// projectiles currently flying on battlefield /// projectiles currently flying on battlefield
std::vector<std::shared_ptr<ProjectileBase>> projectiles; std::vector<std::shared_ptr<ProjectileBase>> projectiles;
std::shared_ptr<CAnimation> getProjectileImage(const CStack * stack); std::shared_ptr<CAnimation> getProjectileImage(const CStack * stack);
std::shared_ptr<CAnimation> createProjectileImage(const std::string & path ); std::shared_ptr<CAnimation> createProjectileImage(const AnimationPath & path );
void initStackProjectile(const CStack * stack); void initStackProjectile(const CStack * stack);
bool stackUsesRayProjectile(const CStack * stack) const; bool stackUsesRayProjectile(const CStack * stack) const;

View File

@ -20,15 +20,17 @@
#include "../CMusicHandler.h" #include "../CMusicHandler.h"
#include "../CGameInfo.h" #include "../CGameInfo.h"
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IImage.h" #include "../render/IImage.h"
#include "../render/IRenderHandler.h"
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/NetPacks.h" #include "../../lib/NetPacks.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGTownInstance.h"
std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const ImagePath BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const
{ {
auto getImageIndex = [&]() -> int auto getImageIndex = [&]() -> int
{ {
@ -68,44 +70,44 @@ std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisua
auto faction = town->town->faction->getIndex(); auto faction = town->town->faction->getIndex();
if (faction == ETownType::RAMPART || faction == ETownType::NECROPOLIS || faction == ETownType::DUNGEON || faction == ETownType::STRONGHOLD) if (faction == ETownType::RAMPART || faction == ETownType::NECROPOLIS || faction == ETownType::DUNGEON || faction == ETownType::STRONGHOLD)
return prefix + "TPW1.BMP"; return ImagePath::builtinTODO(prefix + "TPW1.BMP");
else else
return prefix + "TPWL.BMP"; return ImagePath::builtinTODO(prefix + "TPWL.BMP");
} }
case EWallVisual::KEEP: case EWallVisual::KEEP:
return prefix + "MAN" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "MAN" + addit + ".BMP");
case EWallVisual::BOTTOM_TOWER: case EWallVisual::BOTTOM_TOWER:
return prefix + "TW1" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "TW1" + addit + ".BMP");
case EWallVisual::BOTTOM_WALL: case EWallVisual::BOTTOM_WALL:
return prefix + "WA1" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "WA1" + addit + ".BMP");
case EWallVisual::WALL_BELLOW_GATE: case EWallVisual::WALL_BELLOW_GATE:
return prefix + "WA3" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "WA3" + addit + ".BMP");
case EWallVisual::WALL_OVER_GATE: case EWallVisual::WALL_OVER_GATE:
return prefix + "WA4" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "WA4" + addit + ".BMP");
case EWallVisual::UPPER_WALL: case EWallVisual::UPPER_WALL:
return prefix + "WA6" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "WA6" + addit + ".BMP");
case EWallVisual::UPPER_TOWER: case EWallVisual::UPPER_TOWER:
return prefix + "TW2" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "TW2" + addit + ".BMP");
case EWallVisual::GATE: case EWallVisual::GATE:
return prefix + "DRW" + addit + ".BMP"; return ImagePath::builtinTODO(prefix + "DRW" + addit + ".BMP");
case EWallVisual::GATE_ARCH: case EWallVisual::GATE_ARCH:
return prefix + "ARCH.BMP"; return ImagePath::builtinTODO(prefix + "ARCH.BMP");
case EWallVisual::BOTTOM_STATIC_WALL: case EWallVisual::BOTTOM_STATIC_WALL:
return prefix + "WA2.BMP"; return ImagePath::builtinTODO(prefix + "WA2.BMP");
case EWallVisual::UPPER_STATIC_WALL: case EWallVisual::UPPER_STATIC_WALL:
return prefix + "WA5.BMP"; return ImagePath::builtinTODO(prefix + "WA5.BMP");
case EWallVisual::MOAT: case EWallVisual::MOAT:
return prefix + "MOAT.BMP"; return ImagePath::builtinTODO(prefix + "MOAT.BMP");
case EWallVisual::MOAT_BANK: case EWallVisual::MOAT_BANK:
return prefix + "MLIP.BMP"; return ImagePath::builtinTODO(prefix + "MLIP.BMP");
case EWallVisual::KEEP_BATTLEMENT: case EWallVisual::KEEP_BATTLEMENT:
return prefix + "MANC.BMP"; return ImagePath::builtinTODO(prefix + "MANC.BMP");
case EWallVisual::BOTTOM_BATTLEMENT: case EWallVisual::BOTTOM_BATTLEMENT:
return prefix + "TW1C.BMP"; return ImagePath::builtinTODO(prefix + "TW1C.BMP");
case EWallVisual::UPPER_BATTLEMENT: case EWallVisual::UPPER_BATTLEMENT:
return prefix + "TW2C.BMP"; return ImagePath::builtinTODO(prefix + "TW2C.BMP");
default: default:
return ""; return ImagePath();
} }
} }
@ -118,10 +120,10 @@ void BattleSiegeController::showWallPiece(Canvas & canvas, EWallVisual::EWallVis
canvas.draw(wallPieceImages[what], Point(pos.x, pos.y)); canvas.draw(wallPieceImages[what], Point(pos.x, pos.y));
} }
std::string BattleSiegeController::getBattleBackgroundName() const ImagePath BattleSiegeController::getBattleBackgroundName() const
{ {
const std::string & prefix = town->town->clientInfo.siegePrefix; const std::string & prefix = town->town->clientInfo.siegePrefix;
return prefix + "BACK.BMP"; return ImagePath::builtinTODO(prefix + "BACK.BMP");
} }
bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what) const bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what) const
@ -133,9 +135,9 @@ bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what)
{ {
case EWallVisual::MOAT: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT).isValid(); case EWallVisual::MOAT: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT).isValid();
case EWallVisual::MOAT_BANK: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT_BANK).isValid(); case EWallVisual::MOAT_BANK: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT_BANK).isValid();
case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && owner.curInt->cb->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED; case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && owner.getBattle()->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED;
case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED; case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.getBattle()->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED;
case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED; case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.getBattle()->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED;
default: return true; default: return true;
} }
} }
@ -180,7 +182,7 @@ BattleSiegeController::BattleSiegeController(BattleInterface & owner, const CGTo
if ( !getWallPieceExistance(EWallVisual::EWallVisual(g)) ) if ( !getWallPieceExistance(EWallVisual::EWallVisual(g)) )
continue; continue;
wallPieceImages[g] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(g), EWallState::REINFORCED)); wallPieceImages[g] = GH.renderHandler().loadImage(getWallPieceImageName(EWallVisual::EWallVisual(g), EWallState::REINFORCED));
} }
} }
@ -220,7 +222,7 @@ Point BattleSiegeController::getTurretCreaturePosition( BattleHex position ) con
void BattleSiegeController::gateStateChanged(const EGateState state) void BattleSiegeController::gateStateChanged(const EGateState state)
{ {
auto oldState = owner.curInt->cb->battleGetGateState(); auto oldState = owner.getBattle()->battleGetGateState();
bool playSound = false; bool playSound = false;
auto stateId = EWallState::NONE; auto stateId = EWallState::NONE;
switch(state) switch(state)
@ -246,7 +248,7 @@ void BattleSiegeController::gateStateChanged(const EGateState state)
wallPieceImages[EWallVisual::GATE] = nullptr; wallPieceImages[EWallVisual::GATE] = nullptr;
if (stateId != EWallState::NONE) if (stateId != EWallState::NONE)
wallPieceImages[EWallVisual::GATE] = IImage::createFromFile(getWallPieceImageName(EWallVisual::GATE, stateId)); wallPieceImages[EWallVisual::GATE] = GH.renderHandler().loadImage(getWallPieceImageName(EWallVisual::GATE, stateId));
if (playSound) if (playSound)
CCS->soundh->playSound(soundBase::DRAWBRG); CCS->soundh->playSound(soundBase::DRAWBRG);
@ -275,7 +277,7 @@ BattleHex BattleSiegeController::getTurretBattleHex(EWallVisual::EWallVisual wal
const CStack * BattleSiegeController::getTurretStack(EWallVisual::EWallVisual wallPiece) const const CStack * BattleSiegeController::getTurretStack(EWallVisual::EWallVisual wallPiece) const
{ {
for (auto & stack : owner.curInt->cb->battleGetAllStacks(true)) for (auto & stack : owner.getBattle()->battleGetAllStacks(true))
{ {
if ( stack->initialPosition == getTurretBattleHex(wallPiece)) if ( stack->initialPosition == getTurretBattleHex(wallPiece))
return stack; return stack;
@ -318,15 +320,15 @@ bool BattleSiegeController::isAttackableByCatapult(BattleHex hex) const
if (owner.tacticsMode) if (owner.tacticsMode)
return false; return false;
auto wallPart = owner.curInt->cb->battleHexToWallPart(hex); auto wallPart = owner.getBattle()->battleHexToWallPart(hex);
return owner.curInt->cb->isWallPartAttackable(wallPart); return owner.getBattle()->isWallPartAttackable(wallPart);
} }
void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca) void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
{ {
if (ca.attacker != -1) if (ca.attacker != -1)
{ {
const CStack *stack = owner.curInt->cb->battleGetStackByID(ca.attacker); const CStack *stack = owner.getBattle()->battleGetStackByID(ca.attacker);
for (auto attackInfo : ca.attackedParts) for (auto attackInfo : ca.attackedParts)
{ {
owner.stacksController->addNewAnim(new CatapultAnimation(owner, stack, attackInfo.destinationTile, nullptr, attackInfo.damageDealt)); owner.stacksController->addNewAnim(new CatapultAnimation(owner, stack, attackInfo.destinationTile, nullptr, attackInfo.damageDealt));
@ -340,8 +342,8 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
for (auto attackInfo : ca.attackedParts) for (auto attackInfo : ca.attackedParts)
positions.push_back(owner.stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120)); positions.push_back(owner.stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120));
CCS->soundh->playSound( "WALLHIT" ); CCS->soundh->playSound( AudioPath::builtin("WALLHIT") );
owner.stacksController->addNewAnim(new EffectAnimation(owner, "SGEXPL.DEF", positions)); owner.stacksController->addNewAnim(new EffectAnimation(owner, AnimationPath::builtin("SGEXPL.DEF"), positions));
} }
owner.waitForAnimations(); owner.waitForAnimations();
@ -353,9 +355,9 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
if (wallId == EWallVisual::GATE) if (wallId == EWallVisual::GATE)
continue; continue;
auto wallState = EWallState(owner.curInt->cb->battleGetWallState(attackInfo.attackedPart)); auto wallState = EWallState(owner.getBattle()->battleGetWallState(attackInfo.attackedPart));
wallPieceImages[wallId] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(wallId), wallState)); wallPieceImages[wallId] = GH.renderHandler().loadImage(getWallPieceImageName(EWallVisual::EWallVisual(wallId), wallState));
} }
} }

View File

@ -11,6 +11,7 @@
#include "../../lib/GameConstants.h" #include "../../lib/GameConstants.h"
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -76,7 +77,7 @@ class BattleSiegeController
std::array<std::shared_ptr<IImage>, EWallVisual::WALL_LAST + 1> wallPieceImages; std::array<std::shared_ptr<IImage>, EWallVisual::WALL_LAST + 1> wallPieceImages;
/// return URI for image for a wall piece /// return URI for image for a wall piece
std::string getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const; ImagePath getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const;
/// returns BattleHex to which chosen wall piece is bound /// returns BattleHex to which chosen wall piece is bound
BattleHex getWallPiecePosition(EWallVisual::EWallVisual what) const; BattleHex getWallPiecePosition(EWallVisual::EWallVisual what) const;
@ -102,7 +103,7 @@ public:
/// queries from other battle controllers /// queries from other battle controllers
bool isAttackableByCatapult(BattleHex hex) const; bool isAttackableByCatapult(BattleHex hex) const;
std::string getBattleBackgroundName() const; ImagePath getBattleBackgroundName() const;
const CCreature *getTurretCreature() const; const CCreature *getTurretCreature() const;
Point getTurretCreaturePosition( BattleHex position ) const; Point getTurretCreaturePosition( BattleHex position ) const;

View File

@ -28,6 +28,7 @@
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../render/Colors.h" #include "../render/Colors.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IRenderHandler.h"
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/spells/ISpellMechanics.h" #include "../../lib/spells/ISpellMechanics.h"
@ -76,10 +77,10 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
animIDhelper(0) animIDhelper(0)
{ {
//preparing graphics for displaying amounts of creatures //preparing graphics for displaying amounts of creatures
amountNormal = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY); amountNormal = GH.renderHandler().loadImage(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
amountPositive = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY); amountPositive = GH.renderHandler().loadImage(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
amountNegative = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY); amountNegative = GH.renderHandler().loadImage(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
amountEffNeutral = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY); amountEffNeutral = GH.renderHandler().loadImage(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
static const auto shifterNormal = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f ); static const auto shifterNormal = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f );
static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f ); static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
@ -94,7 +95,7 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
amountNegative->adjustPalette(shifterNegative, ignoredMask); amountNegative->adjustPalette(shifterNegative, ignoredMask);
amountEffNeutral->adjustPalette(shifterNeutral, ignoredMask); amountEffNeutral->adjustPalette(shifterNeutral, ignoredMask);
std::vector<const CStack*> stacks = owner.curInt->cb->battleGetAllStacks(true); std::vector<const CStack*> stacks = owner.getBattle()->battleGetAllStacks(true);
for(const CStack * s : stacks) for(const CStack * s : stacks)
{ {
stackAdded(s, true); stackAdded(s, true);
@ -126,7 +127,7 @@ BattleHex BattleStacksController::getStackCurrentPosition(const CStack * stack)
void BattleStacksController::collectRenderableObjects(BattleRenderer & renderer) void BattleStacksController::collectRenderableObjects(BattleRenderer & renderer)
{ {
auto stacks = owner.curInt->cb->battleGetAllStacks(false); auto stacks = owner.getBattle()->battleGetAllStacks(false);
for (auto stack : stacks) for (auto stack : stacks)
{ {
@ -359,7 +360,7 @@ void BattleStacksController::initializeBattleAnimations()
void BattleStacksController::tickFrameBattleAnimations(uint32_t msPassed) void BattleStacksController::tickFrameBattleAnimations(uint32_t msPassed)
{ {
for (auto stack : owner.curInt->cb->battleGetAllStacks(true)) for (auto stack : owner.getBattle()->battleGetAllStacks(true))
{ {
if (stackAnimation.find(stack->unitId()) == stackAnimation.end()) //e.g. for summoned but not yet handled stacks if (stackAnimation.find(stack->unitId()) == stackAnimation.end()) //e.g. for summoned but not yet handled stacks
continue; continue;
@ -462,7 +463,7 @@ void BattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> at
addNewAnim(new HittedAnimation(owner, attackedInfo.defender)); addNewAnim(new HittedAnimation(owner, attackedInfo.defender));
if (attackedInfo.fireShield) if (attackedInfo.fireShield)
owner.effectsController->displayEffect(EBattleEffect::FIRE_SHIELD, "FIRESHIE", attackedInfo.attacker->getPosition()); owner.effectsController->displayEffect(EBattleEffect::FIRE_SHIELD, AudioPath::builtin("FIRESHIE"), attackedInfo.attacker->getPosition());
if (attackedInfo.spellEffect != SpellID::NONE) if (attackedInfo.spellEffect != SpellID::NONE)
{ {
@ -481,7 +482,7 @@ void BattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> at
if (attackedInfo.rebirth) if (attackedInfo.rebirth)
{ {
owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){ owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){
owner.effectsController->displayEffect(EBattleEffect::RESURRECT, "RESURECT", attackedInfo.defender->getPosition()); owner.effectsController->displayEffect(EBattleEffect::RESURRECT, AudioPath::builtin("RESURECT"), attackedInfo.defender->getPosition());
addNewAnim(new ResurrectionAnimation(owner, attackedInfo.defender)); addNewAnim(new ResurrectionAnimation(owner, attackedInfo.defender));
}); });
} }
@ -552,9 +553,7 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vector<BattleH
bool BattleStacksController::shouldAttackFacingRight(const CStack * attacker, const CStack * defender) bool BattleStacksController::shouldAttackFacingRight(const CStack * attacker, const CStack * defender)
{ {
bool mustReverse = owner.curInt->cb->isToReverse( bool mustReverse = owner.getBattle()->isToReverse(attacker, defender);
attacker,
defender);
if (attacker->unitSide() == BattleSide::ATTACKER) if (attacker->unitSide() == BattleSide::ATTACKER)
return !mustReverse; return !mustReverse;
@ -594,7 +593,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{ {
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() { owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(-45)); owner.appendBattleLog(info.attacker->formatGeneralMessage(-45));
owner.effectsController->displayEffect(EBattleEffect::GOOD_LUCK, "GOODLUCK", attacker->getPosition()); owner.effectsController->displayEffect(EBattleEffect::GOOD_LUCK, AudioPath::builtin("GOODLUCK"), attacker->getPosition());
}); });
} }
@ -602,7 +601,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{ {
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() { owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(-44)); owner.appendBattleLog(info.attacker->formatGeneralMessage(-44));
owner.effectsController->displayEffect(EBattleEffect::BAD_LUCK, "BADLUCK", attacker->getPosition()); owner.effectsController->displayEffect(EBattleEffect::BAD_LUCK, AudioPath::builtin("BADLUCK"), attacker->getPosition());
}); });
} }
@ -610,7 +609,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{ {
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() { owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(365)); owner.appendBattleLog(info.attacker->formatGeneralMessage(365));
owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, "DEATHBLO", defender->getPosition()); owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, AudioPath::builtin("DEATHBLO"), defender->getPosition());
}); });
for(auto elem : info.secondaryDefender) for(auto elem : info.secondaryDefender)
@ -645,7 +644,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{ {
owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=]() owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=]()
{ {
owner.effectsController->displayEffect(EBattleEffect::DRAIN_LIFE, "DRAINLIF", attacker->getPosition()); owner.effectsController->displayEffect(EBattleEffect::DRAIN_LIFE, AudioPath::builtin("DRAINLIF"), attacker->getPosition());
}); });
} }
@ -670,7 +669,7 @@ void BattleStacksController::endAction(const BattleAction & action)
owner.checkForAnimations(); owner.checkForAnimations();
//check if we should reverse stacks //check if we should reverse stacks
TStacks stacks = owner.curInt->cb->battleGetStacks(CBattleCallback::MINE_AND_ENEMY); TStacks stacks = owner.getBattle()->battleGetStacks(CPlayerBattleCallback::MINE_AND_ENEMY);
for (const CStack *s : stacks) for (const CStack *s : stacks)
{ {
@ -847,7 +846,7 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
auto hoveredQueueUnitId = owner.windowObject->getQueueHoveredUnitId(); auto hoveredQueueUnitId = owner.windowObject->getQueueHoveredUnitId();
if(hoveredQueueUnitId.has_value()) if(hoveredQueueUnitId.has_value())
{ {
return { owner.curInt->cb->battleGetStackByID(hoveredQueueUnitId.value(), true) }; return { owner.getBattle()->battleGetStackByID(hoveredQueueUnitId.value(), true) };
} }
auto hoveredHex = owner.fieldController->getHoveredHex(); auto hoveredHex = owner.fieldController->getHoveredHex();
@ -867,14 +866,14 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
spells::Target target; spells::Target target;
target.emplace_back(hoveredHex); target.emplace_back(hoveredHex);
spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell); spells::BattleCast event(owner.getBattle().get(), caster, mode, spell);
auto mechanics = spell->battleMechanics(&event); auto mechanics = spell->battleMechanics(&event);
return mechanics->getAffectedStacks(target); return mechanics->getAffectedStacks(target);
} }
if(hoveredHex.isValid()) if(hoveredHex.isValid())
{ {
const CStack * const stack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); const CStack * const stack = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
if (stack) if (stack)
return {stack}; return {stack};

View File

@ -29,6 +29,7 @@
#include "../windows/CMessage.h" #include "../windows/CMessage.h"
#include "../render/CAnimation.h" #include "../render/CAnimation.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IRenderHandler.h"
#include "../adventureMap/CInGameConsole.h" #include "../adventureMap/CInGameConsole.h"
#include "../../CCallback.h" #include "../../CCallback.h"
@ -37,7 +38,7 @@
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include "../../lib/filesystem/ResourceID.h" #include "../../lib/filesystem/ResourcePath.h"
#include "../windows/settings/SettingsMainWindow.h" #include "../windows/settings/SettingsMainWindow.h"
BattleWindow::BattleWindow(BattleInterface & owner): BattleWindow::BattleWindow(BattleInterface & owner):
@ -51,7 +52,7 @@ BattleWindow::BattleWindow(BattleInterface & owner):
REGISTER_BUILDER("battleConsole", &BattleWindow::buildBattleConsole); REGISTER_BUILDER("battleConsole", &BattleWindow::buildBattleConsole);
const JsonNode config(ResourceID("config/widgets/BattleWindow2.json")); const JsonNode config(JsonPath::builtin("config/widgets/BattleWindow2.json"));
addShortcut(EShortcut::GLOBAL_OPTIONS, std::bind(&BattleWindow::bOptionsf, this)); addShortcut(EShortcut::GLOBAL_OPTIONS, std::bind(&BattleWindow::bOptionsf, this));
addShortcut(EShortcut::BATTLE_SURRENDER, std::bind(&BattleWindow::bSurrenderf, this)); addShortcut(EShortcut::BATTLE_SURRENDER, std::bind(&BattleWindow::bSurrenderf, this));
@ -367,10 +368,10 @@ void BattleWindow::bSurrenderf()
if (owner.actionsController->spellcastingModeActive()) if (owner.actionsController->spellcastingModeActive())
return; return;
int cost = owner.curInt->cb->battleGetSurrenderCost(); int cost = owner.getBattle()->battleGetSurrenderCost();
if(cost >= 0) if(cost >= 0)
{ {
std::string enemyHeroName = owner.curInt->cb->battleGetEnemyHero().name; std::string enemyHeroName = owner.getBattle()->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!");
@ -387,7 +388,7 @@ void BattleWindow::bFleef()
if (owner.actionsController->spellcastingModeActive()) if (owner.actionsController->spellcastingModeActive())
return; return;
if ( owner.curInt->cb->battleCanFlee() ) if ( owner.getBattle()->battleCanFlee() )
{ {
CFunctionList<void()> ony = std::bind(&BattleWindow::reallyFlee,this); CFunctionList<void()> ony = std::bind(&BattleWindow::reallyFlee,this);
owner.curInt->showYesNoDialog(CGI->generaltexth->allTexts[28], ony, nullptr); //Are you sure you want to retreat? owner.curInt->showYesNoDialog(CGI->generaltexth->allTexts[28], ony, nullptr); //Are you sure you want to retreat?
@ -398,10 +399,10 @@ void BattleWindow::bFleef()
std::string heroName; std::string heroName;
//calculating fleeing hero's name //calculating fleeing hero's name
if (owner.attackingHeroInstance) if (owner.attackingHeroInstance)
if (owner.attackingHeroInstance->tempOwner == owner.curInt->cb->getMyColor()) if (owner.attackingHeroInstance->tempOwner == owner.curInt->cb->getPlayerID())
heroName = owner.attackingHeroInstance->getNameTranslated(); heroName = owner.attackingHeroInstance->getNameTranslated();
if (owner.defendingHeroInstance) if (owner.defendingHeroInstance)
if (owner.defendingHeroInstance->tempOwner == owner.curInt->cb->getMyColor()) if (owner.defendingHeroInstance->tempOwner == owner.curInt->cb->getPlayerID())
heroName = owner.defendingHeroInstance->getNameTranslated(); heroName = owner.defendingHeroInstance->getNameTranslated();
//calculating text //calculating text
auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat! auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat!
@ -419,7 +420,7 @@ void BattleWindow::reallyFlee()
void BattleWindow::reallySurrender() void BattleWindow::reallySurrender()
{ {
if (owner.curInt->cb->getResourceAmount(EGameResID::GOLD) < owner.curInt->cb->battleGetSurrenderCost()) if (owner.curInt->cb->getResourceAmount(EGameResID::GOLD) < owner.getBattle()->battleGetSurrenderCost())
{ {
owner.curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold! owner.curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold!
} }
@ -436,23 +437,23 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
if(!w) if(!w)
return; return;
std::string iconName = variables["actionIconDefault"].String(); AnimationPath iconName = AnimationPath::fromJson(variables["actionIconDefault"]);
switch(action.get()) switch(action.get())
{ {
case PossiblePlayerBattleAction::ATTACK: case PossiblePlayerBattleAction::ATTACK:
iconName = variables["actionIconAttack"].String(); iconName = AnimationPath::fromJson(variables["actionIconAttack"]);
break; break;
case PossiblePlayerBattleAction::SHOOT: case PossiblePlayerBattleAction::SHOOT:
iconName = variables["actionIconShoot"].String(); iconName = AnimationPath::fromJson(variables["actionIconShoot"]);
break; break;
case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE: case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE:
iconName = variables["actionIconSpell"].String(); iconName = AnimationPath::fromJson(variables["actionIconSpell"]);
break; break;
case PossiblePlayerBattleAction::ANY_LOCATION: case PossiblePlayerBattleAction::ANY_LOCATION:
iconName = variables["actionIconSpell"].String(); iconName = AnimationPath::fromJson(variables["actionIconSpell"]);
break; break;
//TODO: figure out purpose of this icon //TODO: figure out purpose of this icon
@ -461,15 +462,15 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
//break; //break;
case PossiblePlayerBattleAction::ATTACK_AND_RETURN: case PossiblePlayerBattleAction::ATTACK_AND_RETURN:
iconName = variables["actionIconReturn"].String(); iconName = AnimationPath::fromJson(variables["actionIconReturn"]);
break; break;
case PossiblePlayerBattleAction::WALK_AND_ATTACK: case PossiblePlayerBattleAction::WALK_AND_ATTACK:
iconName = variables["actionIconNoReturn"].String(); iconName = AnimationPath::fromJson(variables["actionIconNoReturn"]);
break; break;
} }
auto anim = std::make_shared<CAnimation>(iconName); auto anim = GH.renderHandler().loadAnimation(iconName);
w->setImage(anim); w->setImage(anim);
w->redraw(); w->redraw();
} }
@ -509,7 +510,7 @@ void BattleWindow::bAutofightf()
autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool(); autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool();
ai->initBattleInterface(owner.curInt->env, owner.curInt->cb, autocombatPreferences); ai->initBattleInterface(owner.curInt->env, owner.curInt->cb, autocombatPreferences);
ai->battleStart(owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.curInt->cb->battleGetMySide(), false); ai->battleStart(owner.getBattleID(), owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.getBattle()->battleGetMySide(), false);
owner.curInt->autofightingAI = ai; owner.curInt->autofightingAI = ai;
owner.curInt->cb->registerBattleInterface(ai); owner.curInt->cb->registerBattleInterface(ai);
@ -531,7 +532,7 @@ void BattleWindow::bSpellf()
CCS->curh->set(Cursor::Map::POINTER); CCS->curh->set(Cursor::Map::POINTER);
ESpellCastProblem spellCastProblem = owner.curInt->cb->battleCanCastSpell(myHero, spells::Mode::HERO); ESpellCastProblem spellCastProblem = owner.getBattle()->battleCanCastSpell(myHero, spells::Mode::HERO);
if(spellCastProblem == ESpellCastProblem::OK) if(spellCastProblem == ESpellCastProblem::OK)
{ {
@ -633,11 +634,11 @@ void BattleWindow::bTacticPhaseEnd()
void BattleWindow::blockUI(bool on) void BattleWindow::blockUI(bool on)
{ {
bool canCastSpells = false; bool canCastSpells = false;
auto hero = owner.curInt->cb->battleGetMyHero(); auto hero = owner.getBattle()->battleGetMyHero();
if(hero) if(hero)
{ {
ESpellCastProblem spellcastingProblem = owner.curInt->cb->battleCanCastSpell(hero, spells::Mode::HERO); ESpellCastProblem spellcastingProblem = owner.getBattle()->battleCanCastSpell(hero, spells::Mode::HERO);
//if magic is blocked, we leave button active, so the message can be displayed after button click //if magic is blocked, we leave button active, so the message can be displayed after button click
canCastSpells = spellcastingProblem == ESpellCastProblem::OK || spellcastingProblem == ESpellCastProblem::MAGIC_IS_BLOCKED; canCastSpells = spellcastingProblem == ESpellCastProblem::OK || spellcastingProblem == ESpellCastProblem::MAGIC_IS_BLOCKED;
@ -646,8 +647,8 @@ void BattleWindow::blockUI(bool on)
bool canWait = owner.stacksController->getActiveStack() ? !owner.stacksController->getActiveStack()->waitedThisTurn : false; bool canWait = owner.stacksController->getActiveStack() ? !owner.stacksController->getActiveStack()->waitedThisTurn : false;
setShortcutBlocked(EShortcut::GLOBAL_OPTIONS, on); setShortcutBlocked(EShortcut::GLOBAL_OPTIONS, on);
setShortcutBlocked(EShortcut::BATTLE_RETREAT, on || !owner.curInt->cb->battleCanFlee()); setShortcutBlocked(EShortcut::BATTLE_RETREAT, on || !owner.getBattle()->battleCanFlee());
setShortcutBlocked(EShortcut::BATTLE_SURRENDER, on || owner.curInt->cb->battleGetSurrenderCost() < 0); setShortcutBlocked(EShortcut::BATTLE_SURRENDER, on || owner.getBattle()->battleGetSurrenderCost() < 0);
setShortcutBlocked(EShortcut::BATTLE_CAST_SPELL, on || owner.tacticsMode || !canCastSpells); setShortcutBlocked(EShortcut::BATTLE_CAST_SPELL, on || owner.tacticsMode || !canCastSpells);
setShortcutBlocked(EShortcut::BATTLE_WAIT, on || owner.tacticsMode || !canWait); setShortcutBlocked(EShortcut::BATTLE_WAIT, on || owner.tacticsMode || !canWait);
setShortcutBlocked(EShortcut::BATTLE_DEFEND, on || owner.tacticsMode); setShortcutBlocked(EShortcut::BATTLE_DEFEND, on || owner.tacticsMode);

View File

@ -13,8 +13,10 @@
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
#include "../gui/CGuiHandler.h"
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/ColorFilter.h" #include "../render/ColorFilter.h"
#include "../render/IRenderHandler.h"
static const ColorRGBA creatureBlueBorder = { 0, 255, 255, 255 }; static const ColorRGBA creatureBlueBorder = { 0, 255, 255, 255 };
static const ColorRGBA creatureGoldBorder = { 255, 255, 0, 255 }; static const ColorRGBA creatureGoldBorder = { 255, 255, 0, 255 };
@ -185,7 +187,7 @@ void CreatureAnimation::setType(ECreatureAnimType type)
speed = speedController(this, type); speed = speedController(this, type);
} }
CreatureAnimation::CreatureAnimation(const std::string & name_, TSpeedController controller) CreatureAnimation::CreatureAnimation(const AnimationPath & name_, TSpeedController controller)
: name(name_), : name(name_),
speed(0.1f), speed(0.1f),
shadowAlpha(128), shadowAlpha(128),
@ -196,8 +198,8 @@ CreatureAnimation::CreatureAnimation(const std::string & name_, TSpeedController
speedController(controller), speedController(controller),
once(false) once(false)
{ {
forward = std::make_shared<CAnimation>(name_); forward = GH.renderHandler().loadAnimation(name_);
reverse = std::make_shared<CAnimation>(name_); reverse = GH.renderHandler().loadAnimation(name_);
//todo: optimize //todo: optimize
forward->preload(); forward->preload();

View File

@ -70,7 +70,7 @@ public:
using TSpeedController = std::function<float(CreatureAnimation *, ECreatureAnimType)>; using TSpeedController = std::function<float(CreatureAnimation *, ECreatureAnimType)>;
private: private:
std::string name; AnimationPath name;
/// animation for rendering stack in default orientation - facing right /// animation for rendering stack in default orientation - facing right
std::shared_ptr<CAnimation> forward; std::shared_ptr<CAnimation> forward;
@ -122,7 +122,7 @@ public:
/// name - path to .def file, relative to SPRITES/ directory /// name - path to .def file, relative to SPRITES/ directory
/// controller - function that will return for how long *each* frame /// controller - function that will return for how long *each* frame
/// in specified group of animation should be played, measured in seconds /// in specified group of animation should be played, measured in seconds
CreatureAnimation(const std::string & name_, TSpeedController speedController); CreatureAnimation(const AnimationPath & name_, TSpeedController speedController);
/// sets type of animation and resets framecount /// sets type of animation and resets framecount
void setType(ECreatureAnimType type); void setType(ECreatureAnimType type);

View File

@ -25,6 +25,7 @@
#include "../render/IFont.h" #include "../render/IFont.h"
#include "../render/EFont.h" #include "../render/EFont.h"
#include "../renderSDL/ScreenHandler.h" #include "../renderSDL/ScreenHandler.h"
#include "../renderSDL/RenderHandler.h"
#include "../CMT.h" #include "../CMT.h"
#include "../CPlayerInterface.h" #include "../CPlayerInterface.h"
#include "../battle/BattleInterface.h" #include "../battle/BattleInterface.h"
@ -75,6 +76,7 @@ void CGuiHandler::init()
eventDispatcherInstance = std::make_unique<EventDispatcher>(); eventDispatcherInstance = std::make_unique<EventDispatcher>();
windowHandlerInstance = std::make_unique<WindowHandler>(); windowHandlerInstance = std::make_unique<WindowHandler>();
screenHandlerInstance = std::make_unique<ScreenHandler>(); screenHandlerInstance = std::make_unique<ScreenHandler>();
renderHandlerInstance = std::make_unique<RenderHandler>();
shortcutsHandlerInstance = std::make_unique<ShortcutHandler>(); shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
framerateManagerInstance = std::make_unique<FramerateManager>(settings["video"]["targetfps"].Integer()); framerateManagerInstance = std::make_unique<FramerateManager>(settings["video"]["targetfps"].Integer());
} }
@ -206,6 +208,11 @@ IScreenHandler & CGuiHandler::screenHandler()
return *screenHandlerInstance; return *screenHandlerInstance;
} }
IRenderHandler & CGuiHandler::renderHandler()
{
return *renderHandlerInstance;
}
EventDispatcher & CGuiHandler::events() EventDispatcher & CGuiHandler::events()
{ {
return *eventDispatcherInstance; return *eventDispatcherInstance;

View File

@ -22,6 +22,7 @@ class IStatusBar;
class CIntObject; class CIntObject;
class IUpdateable; class IUpdateable;
class IShowActivatable; class IShowActivatable;
class IRenderHandler;
class IScreenHandler; class IScreenHandler;
class WindowHandler; class WindowHandler;
class EventDispatcher; class EventDispatcher;
@ -41,6 +42,7 @@ private:
std::unique_ptr<WindowHandler> windowHandlerInstance; std::unique_ptr<WindowHandler> windowHandlerInstance;
std::unique_ptr<IScreenHandler> screenHandlerInstance; std::unique_ptr<IScreenHandler> screenHandlerInstance;
std::unique_ptr<IRenderHandler> renderHandlerInstance;
std::unique_ptr<FramerateManager> framerateManagerInstance; std::unique_ptr<FramerateManager> framerateManagerInstance;
std::unique_ptr<EventDispatcher> eventDispatcherInstance; std::unique_ptr<EventDispatcher> eventDispatcherInstance;
std::unique_ptr<InputHandler> inputHandlerInstance; std::unique_ptr<InputHandler> inputHandlerInstance;
@ -67,7 +69,7 @@ public:
void stopTextInput(); void stopTextInput();
IScreenHandler & screenHandler(); IScreenHandler & screenHandler();
IRenderHandler & renderHandler();
WindowHandler & windows(); WindowHandler & windows();
/// Returns currently active status bar. Guaranteed to be non-null /// Returns currently active status bar. Guaranteed to be non-null

View File

@ -17,6 +17,7 @@
#include "../renderSDL/CursorHardware.h" #include "../renderSDL/CursorHardware.h"
#include "../render/CAnimation.h" #include "../render/CAnimation.h"
#include "../render/IImage.h" #include "../render/IImage.h"
#include "../render/IRenderHandler.h"
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
@ -46,10 +47,10 @@ CursorHandler::CursorHandler()
cursors = cursors =
{ {
std::make_unique<CAnimation>("CRADVNTR"), GH.renderHandler().loadAnimation(AnimationPath::builtin("CRADVNTR")),
std::make_unique<CAnimation>("CRCOMBAT"), GH.renderHandler().loadAnimation(AnimationPath::builtin("CRCOMBAT")),
std::make_unique<CAnimation>("CRDEFLT"), GH.renderHandler().loadAnimation(AnimationPath::builtin("CRDEFLT")),
std::make_unique<CAnimation>("CRSPELL") GH.renderHandler().loadAnimation(AnimationPath::builtin("CRSPELL"))
}; };
for (auto & cursor : cursors) for (auto & cursor : cursors)
@ -100,11 +101,11 @@ void CursorHandler::dragAndDropCursor(std::shared_ptr<IImage> image)
cursor->setImage(getCurrentImage(), getPivotOffset()); cursor->setImage(getCurrentImage(), getPivotOffset());
} }
void CursorHandler::dragAndDropCursor (std::string path, size_t index) void CursorHandler::dragAndDropCursor (const AnimationPath & path, size_t index)
{ {
CAnimation anim(path); auto anim = GH.renderHandler().loadAnimation(path);
anim.load(index); anim->load(index);
dragAndDropCursor(anim.getImage(index)); dragAndDropCursor(anim->getImage(index));
} }
void CursorHandler::cursorMove(const int & x, const int & y) void CursorHandler::cursorMove(const int & x, const int & y)

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../../lib/Point.h" #include "../../lib/Point.h"
#include "../../lib/filesystem/ResourcePath.h"
class ICursor; class ICursor;
class IImage; class IImage;
@ -113,7 +114,7 @@ class CursorHandler final
{ {
std::shared_ptr<IImage> dndObject; //if set, overrides currentCursor std::shared_ptr<IImage> dndObject; //if set, overrides currentCursor
std::array<std::unique_ptr<CAnimation>, 4> cursors; std::array<std::shared_ptr<CAnimation>, 4> cursors;
bool showing; bool showing;
@ -143,7 +144,7 @@ public:
/// @param image Image to replace cursor with or nullptr to use the normal cursor. /// @param image Image to replace cursor with or nullptr to use the normal cursor.
void dragAndDropCursor(std::shared_ptr<IImage> image); void dragAndDropCursor(std::shared_ptr<IImage> image);
void dragAndDropCursor(std::string path, size_t index); void dragAndDropCursor(const AnimationPath & path, size_t index);
/// Changes cursor to specified index /// Changes cursor to specified index
void set(Cursor::Default index); void set(Cursor::Default index);

View File

@ -31,7 +31,7 @@
#include "../../lib//constants/StringConstants.h" #include "../../lib//constants/StringConstants.h"
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
#include "../../lib/filesystem/ResourceID.h" #include "../../lib/filesystem/ResourcePath.h"
InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config, int used, Point offset): InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config, int used, Point offset):
InterfaceObjectConfigurable(used, offset) InterfaceObjectConfigurable(used, offset)
@ -110,7 +110,7 @@ void InterfaceObjectConfigurable::build(const JsonNode &config)
{ {
if (!config["library"].isNull()) if (!config["library"].isNull())
{ {
const JsonNode library(ResourceID(config["library"].String())); const JsonNode library(JsonPath::fromJson(config["library"]));
loadCustomBuilders(library); loadCustomBuilders(library);
} }
@ -238,7 +238,7 @@ PlayerColor InterfaceObjectConfigurable::readPlayerColor(const JsonNode & config
{ {
logGlobal->debug("Reading PlayerColor"); logGlobal->debug("Reading PlayerColor");
if(!config.isNull() && config.isString()) if(!config.isNull() && config.isString())
return PlayerColor(vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, config.String())); return PlayerColor::decode(config.String());
logGlobal->debug("Unknown PlayerColor attribute"); logGlobal->debug("Unknown PlayerColor attribute");
return PlayerColor::CANNOT_DETERMINE; return PlayerColor::CANNOT_DETERMINE;
@ -305,7 +305,7 @@ EShortcut InterfaceObjectConfigurable::readHotkey(const JsonNode & config) const
std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const
{ {
logGlobal->debug("Building widget CPicture"); logGlobal->debug("Building widget CPicture");
auto image = config["image"].String(); auto image = ImagePath::fromJson(config["image"]);
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto pic = std::make_shared<CPicture>(image, position.x, position.y); auto pic = std::make_shared<CPicture>(image, position.x, position.y);
if(!config["visible"].isNull()) if(!config["visible"].isNull())
@ -369,7 +369,7 @@ std::shared_ptr<CToggleButton> InterfaceObjectConfigurable::buildToggleButton(co
{ {
logGlobal->debug("Building widget CToggleButton"); logGlobal->debug("Building widget CToggleButton");
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto image = config["image"].String(); auto image = AnimationPath::fromJson(config["image"]);
auto help = readHintText(config["help"]); auto help = readHintText(config["help"]);
auto button = std::make_shared<CToggleButton>(position, image, help); auto button = std::make_shared<CToggleButton>(position, image, help);
if(!config["items"].isNull()) if(!config["items"].isNull())
@ -395,7 +395,7 @@ std::shared_ptr<CButton> InterfaceObjectConfigurable::buildButton(const JsonNode
{ {
logGlobal->debug("Building widget CButton"); logGlobal->debug("Building widget CButton");
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto image = config["image"].String(); auto image = AnimationPath::fromJson(config["image"]);
auto help = readHintText(config["help"]); auto help = readHintText(config["help"]);
auto button = std::make_shared<CButton>(position, image, help); auto button = std::make_shared<CButton>(position, image, help);
if(!config["items"].isNull()) if(!config["items"].isNull())
@ -522,7 +522,7 @@ std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNo
{ {
logGlobal->debug("Building widget CAnimImage"); logGlobal->debug("Building widget CAnimImage");
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto image = config["image"].String(); auto image = AnimationPath::fromJson(config["image"]);
int group = config["group"].isNull() ? 0 : config["group"].Integer(); int group = config["group"].isNull() ? 0 : config["group"].Integer();
int frame = config["frame"].isNull() ? 0 : config["frame"].Integer(); int frame = config["frame"].isNull() ? 0 : config["frame"].Integer();
return std::make_shared<CAnimImage>(image, frame, group, position.x, position.y); return std::make_shared<CAnimImage>(image, frame, group, position.x, position.y);
@ -531,7 +531,7 @@ std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNo
std::shared_ptr<CFilledTexture> InterfaceObjectConfigurable::buildTexture(const JsonNode & config) const std::shared_ptr<CFilledTexture> InterfaceObjectConfigurable::buildTexture(const JsonNode & config) const
{ {
logGlobal->debug("Building widget CFilledTexture"); logGlobal->debug("Building widget CFilledTexture");
auto image = config["image"].String(); auto image = ImagePath::fromJson(config["image"]);
auto rect = readRect(config["rect"]); auto rect = readRect(config["rect"]);
auto playerColor = readPlayerColor(config["color"]); auto playerColor = readPlayerColor(config["color"]);
if(playerColor.isValidPlayer()) if(playerColor.isValidPlayer())
@ -546,7 +546,7 @@ std::shared_ptr<ComboBox> InterfaceObjectConfigurable::buildComboBox(const JsonN
{ {
logGlobal->debug("Building widget ComboBox"); logGlobal->debug("Building widget ComboBox");
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto image = config["image"].String(); auto image = AnimationPath::fromJson(config["image"]);
auto help = readHintText(config["help"]); auto help = readHintText(config["help"]);
auto result = std::make_shared<ComboBox>(position, image, help, config["dropDown"]); auto result = std::make_shared<ComboBox>(position, image, help, config["dropDown"]);
if(!config["items"].isNull()) if(!config["items"].isNull())
@ -573,7 +573,7 @@ std::shared_ptr<CTextInput> InterfaceObjectConfigurable::buildTextInput(const Js
logGlobal->debug("Building widget CTextInput"); logGlobal->debug("Building widget CTextInput");
auto rect = readRect(config["rect"]); auto rect = readRect(config["rect"]);
auto offset = readPosition(config["backgroundOffset"]); auto offset = readPosition(config["backgroundOffset"]);
auto bgName = config["background"].String(); auto bgName = ImagePath::fromJson(config["background"]);
auto result = std::make_shared<CTextInput>(rect, offset, bgName, 0); auto result = std::make_shared<CTextInput>(rect, offset, bgName, 0);
if(!config["alignment"].isNull()) if(!config["alignment"].isNull())
result->alignment = readTextAlignment(config["alignment"]); result->alignment = readTextAlignment(config["alignment"]);
@ -664,7 +664,7 @@ std::shared_ptr<CShowableAnim> InterfaceObjectConfigurable::buildAnimation(const
{ {
logGlobal->debug("Building widget CShowableAnim"); logGlobal->debug("Building widget CShowableAnim");
auto position = readPosition(config["position"]); auto position = readPosition(config["position"]);
auto image = config["image"].String(); auto image = AnimationPath::fromJson(config["image"]);
ui8 flags = 0; ui8 flags = 0;
if(!config["repeat"].Bool()) if(!config["repeat"].Bool())
flags |= CShowableAnim::EFlags::PLAY_ONCE; flags |= CShowableAnim::EFlags::PLAY_ONCE;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 907 B

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 444 KiB

View File

@ -1,238 +0,0 @@
/* XPM */
static char *x[] = {
/* columns rows colors chars-per-pixel */
"32 32 200 2 ",
" c gray11",
". c #161616",
"X c #2C0E00",
"o c #2D1003",
"O c #25140C",
"+ c #28130A",
"@ c #311305",
"# c #331609",
"$ c #34190C",
"% c #391C0D",
"& c #241610",
"* c #241A16",
"= c #251E1A",
"- c #2C1C14",
"; c #391E11",
": c #2A241D",
"> c #20201F",
", c #3D2112",
"< c #38231B",
"1 c #3C351E",
"2 c #242323",
"3 c #2C2B2B",
"4 c #282625",
"5 c #332E20",
"6 c #362D29",
"7 c #302620",
"8 c #363122",
"9 c #3C3521",
"0 c #3E352C",
"q c #36302D",
"w c #353433",
"e c #3D3B3B",
"r c #3B3431",
"t c #412516",
"y c #462A1B",
"u c #492E1E",
"i c #45271B",
"p c #443A1B",
"a c #4A3F1C",
"s c #4A2F20",
"d c #4D3323",
"f c #423B24",
"g c #48372E",
"h c #483F25",
"j c #503627",
"k c #513728",
"l c #543B2C",
"z c #593D2F",
"x c #483D37",
"c c #473C37",
"v c #573E30",
"b c #583F31",
"n c #5A4C1D",
"m c #63531C",
"M c #6F5C18",
"N c #725D13",
"B c #7D6515",
"V c #4E4426",
"C c #514623",
"Z c #44423F",
"A c #5C4234",
"S c #5A4438",
"D c #625220",
"F c #6C5A24",
"G c #6B5A29",
"H c #715E26",
"J c #674D3F",
"K c #604537",
"L c #7A6525",
"P c #746129",
"I c #444242",
"U c #494645",
"Y c #4C4B4A",
"T c #4A4845",
"R c #554A46",
"E c #5B4D45",
"W c #514742",
"Q c #555352",
"! c #595757",
"~ c #5D5B5A",
"^ c #694E40",
"/ c #6B5549",
"( c #775D4F",
") c #705648",
"_ c #6B5F58",
"` c #755E52",
"' c #62605E",
"] c #7E6557",
"[ c #7A665A",
"{ c #666564",
"} c #696766",
"| c #6D6B6A",
" . c #6A6865",
".. c #7B6B62",
"X. c #726D69",
"o. c #7A7674",
"O. c #7D7B7B",
"+. c #767471",
"@. c #95750A",
"#. c #98770A",
"$. c #846B1B",
"%. c #876D17",
"&. c #8E731E",
"*. c #93761D",
"=. c #96781C",
"-. c #9B7B10",
";. c #A07F0F",
":. c #A07D10",
">. c #836C22",
",. c #866F29",
"<. c #8C7324",
"1. c #997D22",
"2. c #967A28",
"3. c #826A5D",
"4. c #80675A",
"5. c #856D60",
"6. c #897164",
"7. c #8C7569",
"8. c #8F786C",
"9. c #927C6F",
"0. c #827D79",
"q. c #937E72",
"w. c #A7840F",
"e. c #AE8A16",
"r. c #A5831A",
"t. c #B08C1C",
"y. c #B79015",
"u. c #BD961A",
"i. c #A88825",
"p. c #B08E23",
"a. c #BB9624",
"s. c #BB9626",
"d. c #C69D1B",
"f. c #C29B22",
"g. c #C29C2A",
"h. c #CCA220",
"j. c #CDA42A",
"k. c #D9AD26",
"l. c #D2A726",
"z. c #E6B726",
"x. c #86827D",
"c. c #8A847F",
"v. c #978175",
"b. c #94867D",
"n. c #9B867A",
"m. c #9E897D",
"M. c #998377",
"N. c #848383",
"B. c #8A8680",
"V. c #8F8B86",
"C. c #9B8D85",
"Z. c #938E89",
"A. c #918984",
"S. c #96928E",
"D. c #9A9693",
"F. c #9C9996",
"G. c #9D9B99",
"H. c #939292",
"J. c #A28E82",
"K. c #A69287",
"L. c #A5948A",
"P. c #AC988D",
"I. c #A9958A",
"U. c #A69C96",
"Y. c #AD9C93",
"T. c #A29D99",
"R. c #A89F99",
"E. c #B19E93",
"W. c #A5A29F",
"Q. c #B3A196",
"!. c #B8A69C",
"~. c #B9A69C",
"^. c #A4A3A2",
"/. c #A9A6A3",
"(. c #ADABA9",
"). c #ABA8A5",
"_. c #BCABA1",
"`. c #B2AEAC",
"'. c #B5A9A3",
"]. c #B3B2AF",
"[. c #B3B2B2",
"{. c #B9B5B3",
"}. c #BAB9B9",
"|. c #BBB9B6",
" X c #C0AFA5",
".X c #C4B3AA",
"XX c #C8B8AE",
"oX c #C1BFBE",
"OX c #CDBDB4",
"+X c #CCC9C7",
"@X c #CFCCCB",
"#X c #C5C3C1",
"$X c #D3D1CF",
"%X c #D6D3D2",
"&X c #DDDBDA",
"*X c #EDECEB",
"=X c #E4E3E3",
"-X c #F3F3F3",
";X c #F9F9F9",
":X c None",
/* pixels */
":X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X",
":X:X:XO.V.| Q :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XZ Q ' T :X:X",
":X:XI G.(.}.}.}.(.^.H.N.O.| } ~ ! ' { { } X.o.0.B.x.x.x.x.x.:X:X",
":X:X3 N.H.^.[.}.}.}.}.}.}.}.}.[.`.(./.^.T.T.D.S.Z.V.B.x.x.o.:X:X",
":X:X:X| O. .^ ..b.D./.[.{.}.}.}.{.[.`.(.^.F.S.D.W.'.'.c.c.' :X:X",
":X:X:X! { c % s b ^ ( 5.7.q.b.C.C.L.L.I.Y.E.~. X XXXOXZ.V.~ :X:X",
":X:X:XU ~ c X @ t j K ) [ 3.6.7.q.b.n.J.L.P.E.E.~. XXXZ.D.Y :X:X",
":X:X:Xw Q Z X X X % y v ^ ( ] 5.6.8.q.M.C.J.I.E.Q.~.~.F.F.:X:X:X",
":X:X:X4 Y U X X X X @ t d A ) ] 3.6.7.9.q.n.J.K.P.E.W.W.D.:X:X:X",
":X:X:X:XI U @ X X X X X % i z ^ ( 4.3.6.8.q.M.n.m.I.U.(.x.:X:X:X",
":X . w 3 * + X + O & & & - d K g x Z ^ 7...U E R N.N.e :X:X",
":XG j.9 2 ,.s.* + = s.j.j.j.P * i F j.j.0 [ R i.l.i.' Y g.2.:X:X",
":XH z.f 2 2.k.* * p.f.,.,.2.l.G X L z.z.8 x q p.z.s.{ Y k.i.:X:X",
":Xh i.f.>.d.L : = h.1.O X : L V X H k.p.a.4 <.f.a.p.{ e h.1.:X:X",
":X:XF d.<.d.w k = d.&.+ X X X X o F d.B d.2 <.t.<.r.{ w u.*.:X:X",
":X:XF y.$.y.I ' : e.$.- # & = * X D y.V =.e.e.D %.=.{ 2 e.$.:X:X",
":X:X9 %.w.n Q G.: -.B : : 1 w.n X n w.: M w.-.2 B %.Y > -.B :X:X",
":X:X:Xm #. -X-X6 a @.@.@.#.M 5 o n @.: 1 a a = N B w @.N :X:X",
":X:X:X8 a #X;XC.7 p p p p 8 , # 8 p * X X X + 1 p p 9 :X:X",
":X:X:X:X:X:XO.*X@Xk d h u u u y t % # o X X X < Q Y :X:X:X:X:X:X",
":X:X:X:X:X:X:X&X*X[ d j j d s u u t , % @ o X r Y 3 :X:X:X:X:X:X",
":X:X:X:X:X:X:XF.&XW.z k k j j s d u y , , # - c I :X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X$X%X/ z l k k d d d u u t , 6 w 3 :X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:XF.@XT.v l l l k d d d d u S .Y :X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:XI |.#X..A z l l k j j d v F.F.! :X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:XO.{.]./ A z l z l j z {.=X}.:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:XF.].).` A A z l S `.-X;XO.:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:Xe G.).].V.....b.$X=X*X^.:X:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:X:XT D.W.(.{.}.+X%X&X/.:X:X:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:X:X:Xe x.T./.].|.}.O.:X:X:X:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:X:X:X:X:XY | o. .:X:X:X:X:X:X:X:X:X:X:X:X:X:X",
":X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X"
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

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