mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-23 22:37:55 +02:00
Merge pull request #1108 from Nordsoft91/battle-dialog
[HDMod features] Quick combat
This commit is contained in:
@@ -585,44 +585,57 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
if(heroDefender)
|
||||
battleResult.data->exp[1] = heroDefender->calculateXp(battleResult.data->exp[1]);
|
||||
|
||||
const CArmedInstance *bEndArmy1 = gs->curB->sides.at(0).armyObject;
|
||||
const CArmedInstance *bEndArmy2 = gs->curB->sides.at(1).armyObject;
|
||||
const BattleResult::EResult result = battleResult.get()->result;
|
||||
|
||||
auto findBattleQuery = [this]() -> std::shared_ptr<CBattleQuery>
|
||||
{
|
||||
for (auto &q : queries.allQueries())
|
||||
{
|
||||
if (auto bq = std::dynamic_pointer_cast<CBattleQuery>(q))
|
||||
if (bq->bi == gs->curB)
|
||||
return bq;
|
||||
}
|
||||
return std::shared_ptr<CBattleQuery>();
|
||||
};
|
||||
|
||||
auto battleQuery = findBattleQuery();
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
|
||||
if (!battleQuery)
|
||||
{
|
||||
logGlobal->error("Cannot find battle query!");
|
||||
complain("Player " + boost::lexical_cast<std::string>(gs->curB->sides[0].color) + " has no battle query at the top!");
|
||||
return;
|
||||
}
|
||||
if (battleQuery != queries.topQuery(gs->curB->sides[0].color))
|
||||
complain("Player " + boost::lexical_cast<std::string>(gs->curB->sides[0].color) + " although in battle has no battle query at the top!");
|
||||
|
||||
battleQuery->result = boost::make_optional(*battleResult.data);
|
||||
|
||||
//Check how many battle queries were created (number of players blocked by battle)
|
||||
const int queriedPlayers = battleQuery ? (int)boost::count(queries.allQueries(), battleQuery) : 0;
|
||||
finishingBattle = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
||||
|
||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(this, gs->curB);
|
||||
battleResult.data->queryID = battleDialogQuery->queryID;
|
||||
queries.addQuery(battleDialogQuery);
|
||||
|
||||
//set same battle result for all queries
|
||||
for(auto q : queries.allQueries())
|
||||
{
|
||||
auto otherBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(q);
|
||||
if(otherBattleQuery)
|
||||
otherBattleQuery->result = battleQuery->result;
|
||||
}
|
||||
|
||||
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
||||
}
|
||||
|
||||
CasualtiesAfterBattle cab1(bEndArmy1, gs->curB), cab2(bEndArmy2, gs->curB); //calculate casualties before deleting battle
|
||||
void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
|
||||
{
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(battleInfo->sides.at(0).color));
|
||||
if(!battleQuery)
|
||||
{
|
||||
logGlobal->trace("No battle query, battle end was confirmed by another player");
|
||||
return;
|
||||
}
|
||||
|
||||
const CArmedInstance *bEndArmy1 = battleInfo->sides.at(0).armyObject;
|
||||
const CArmedInstance *bEndArmy2 = battleInfo->sides.at(1).armyObject;
|
||||
const BattleResult::EResult result = battleResult.get()->result;
|
||||
|
||||
CasualtiesAfterBattle cab1(bEndArmy1, battleInfo), cab2(bEndArmy2, battleInfo); //calculate casualties before deleting battle
|
||||
ChangeSpells cs; //for Eagle Eye
|
||||
|
||||
if (finishingBattle->winnerHero)
|
||||
if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
|
||||
{
|
||||
if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(Bonus::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
|
||||
{
|
||||
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::LEARN_BATTLE_SPELL_CHANCE, 0);
|
||||
for(auto & spellId : gs->curB->sides.at(!battleResult.data->winner).usedSpellsHistory)
|
||||
for(auto & spellId : battleInfo->sides.at(!battleResult.data->winner).usedSpellsHistory)
|
||||
{
|
||||
auto spell = spellId.toSpell(VLC->spells());
|
||||
if(spell && spell->getLevel() <= eagleEyeLevel && !finishingBattle->winnerHero->spellbookContainsSpell(spell->getId()) && getRandomGenerator().nextInt(99) < eagleEyeChance)
|
||||
@@ -632,7 +645,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
}
|
||||
std::vector<const CArtifactInstance *> arts; //display them in window
|
||||
|
||||
if (result == BattleResult::NORMAL && finishingBattle->winnerHero)
|
||||
if(result == BattleResult::NORMAL && !finishingBattle->isDraw() && finishingBattle->winnerHero)
|
||||
{
|
||||
auto sendMoveArtifact = [&](const CArtifactInstance *art, MoveArtifact *ma)
|
||||
{
|
||||
@@ -668,7 +681,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
//we assume that no big artifacts can be found
|
||||
MoveArtifact ma;
|
||||
ma.src = ArtifactLocation(finishingBattle->loserHero,
|
||||
ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
|
||||
ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
|
||||
const CArtifactInstance * art = ma.src.getArt();
|
||||
if (art->artType->getId() != ArtifactID::GRAIL) //grail may not be won
|
||||
{
|
||||
@@ -690,7 +703,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto armySlot : gs->curB->battleGetArmyObject(!battleResult.data->winner)->stacks)
|
||||
for (auto armySlot : battleInfo->sides.at(!battleResult.data->winner).armyObject->stacks)
|
||||
{
|
||||
auto artifactsWorn = armySlot.second->artifactsWorn;
|
||||
for (auto artSlot : artifactsWorn)
|
||||
@@ -705,8 +718,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
}
|
||||
}
|
||||
}
|
||||
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
||||
|
||||
|
||||
if (arts.size()) //display loot
|
||||
{
|
||||
InfoWindow iw;
|
||||
@@ -767,42 +779,49 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
}
|
||||
cab1.updateArmy(this);
|
||||
cab2.updateArmy(this); //take casualties after battle is deleted
|
||||
|
||||
if(battleResult.data->winner != BattleSide::ATTACKER && heroAttacker) //remove beaten Attacker
|
||||
|
||||
if(finishingBattle->loserHero) //remove beaten hero
|
||||
{
|
||||
RemoveObject ro(heroAttacker->id);
|
||||
RemoveObject ro(finishingBattle->loserHero->id);
|
||||
sendAndApply(&ro);
|
||||
}
|
||||
|
||||
if(battleResult.data->winner != BattleSide::DEFENDER && heroDefender) //remove beaten Defender
|
||||
if(finishingBattle->isDraw() && finishingBattle->winnerHero) //for draw case both heroes should be removed
|
||||
{
|
||||
RemoveObject ro(heroDefender->id);
|
||||
RemoveObject ro(finishingBattle->winnerHero->id);
|
||||
sendAndApply(&ro);
|
||||
}
|
||||
|
||||
if(battleResult.data->winner == BattleSide::DEFENDER
|
||||
&& heroDefender
|
||||
&& heroDefender->visitedTown
|
||||
&& !heroDefender->inTownGarrison
|
||||
&& heroDefender->visitedTown->garrisonHero == heroDefender)
|
||||
|
||||
if(battleResult.data->winner == BattleSide::DEFENDER
|
||||
&& finishingBattle->winnerHero
|
||||
&& finishingBattle->winnerHero->visitedTown
|
||||
&& !finishingBattle->winnerHero->inTownGarrison
|
||||
&& finishingBattle->winnerHero->visitedTown->garrisonHero == finishingBattle->winnerHero)
|
||||
{
|
||||
swapGarrisonOnSiege(heroDefender->visitedTown->id); //return defending visitor from garrison to its rightful place
|
||||
swapGarrisonOnSiege(finishingBattle->winnerHero->visitedTown->id); //return defending visitor from garrison to its rightful place
|
||||
}
|
||||
//give exp
|
||||
if(battleResult.data->exp[0] && heroAttacker && battleResult.get()->winner == BattleSide::ATTACKER)
|
||||
changePrimSkill(heroAttacker, PrimarySkill::EXPERIENCE, battleResult.data->exp[0]);
|
||||
else if(battleResult.data->exp[1] && heroDefender && battleResult.get()->winner == BattleSide::DEFENDER)
|
||||
changePrimSkill(heroDefender, PrimarySkill::EXPERIENCE, battleResult.data->exp[1]);
|
||||
if(!finishingBattle->isDraw() && battleResult.data->exp[finishingBattle->winnerSide] && finishingBattle->winnerHero)
|
||||
changePrimSkill(finishingBattle->winnerHero, PrimarySkill::EXPERIENCE, battleResult.data->exp[finishingBattle->winnerSide]);
|
||||
|
||||
BattleResultAccepted raccepted;
|
||||
raccepted.army1 = const_cast<CArmedInstance*>(bEndArmy1);
|
||||
raccepted.army2 = const_cast<CArmedInstance*>(bEndArmy2);
|
||||
raccepted.hero1 = const_cast<CGHeroInstance*>(battleInfo->sides.at(0).hero);
|
||||
raccepted.hero2 = const_cast<CGHeroInstance*>(battleInfo->sides.at(1).hero);
|
||||
raccepted.exp[0] = battleResult.data->exp[0];
|
||||
raccepted.exp[1] = battleResult.data->exp[1];
|
||||
sendAndApply(&raccepted);
|
||||
|
||||
queries.popIfTop(battleQuery);
|
||||
|
||||
//--> continuation (battleAfterLevelUp) occurs after level-up queries are handled or on removing query (above)
|
||||
//--> continuation (battleAfterLevelUp) occurs after level-up queries are handled or on removing query
|
||||
}
|
||||
|
||||
void CGameHandler::battleAfterLevelUp(const BattleResult &result)
|
||||
{
|
||||
LOG_TRACE(logGlobal);
|
||||
|
||||
if(!finishingBattle)
|
||||
return;
|
||||
|
||||
finishingBattle->remainingBattleQueriesCount--;
|
||||
logGlobal->trace("Decremented queries count to %d", finishingBattle->remainingBattleQueriesCount);
|
||||
@@ -885,6 +904,8 @@ void CGameHandler::battleAfterLevelUp(const BattleResult &result)
|
||||
sendAndApply(&sah);
|
||||
}
|
||||
}
|
||||
|
||||
finishingBattle.reset();
|
||||
}
|
||||
|
||||
void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter)
|
||||
@@ -2598,6 +2619,9 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
|
||||
const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank,
|
||||
const CGTownInstance *town) //use hero=nullptr for no hero
|
||||
{
|
||||
if(gs->curB)
|
||||
gs->curB.dellNull();
|
||||
|
||||
engageIntoBattle(army1->tempOwner);
|
||||
engageIntoBattle(army2->tempOwner);
|
||||
|
||||
@@ -2611,7 +2635,35 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
|
||||
|
||||
setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
||||
|
||||
auto battleQuery = std::make_shared<CBattleQuery>(this, gs->curB);
|
||||
//existing battle query for retying auto-combat
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
|
||||
if(battleQuery)
|
||||
{
|
||||
for(int i : {0, 1})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
SetMana restoreInitialMana;
|
||||
restoreInitialMana.val = battleQuery->initialHeroMana[i];
|
||||
restoreInitialMana.hid = heroes[i]->id;
|
||||
sendAndApply(&restoreInitialMana);
|
||||
}
|
||||
}
|
||||
|
||||
battleQuery->bi = gs->curB;
|
||||
battleQuery->result = boost::none;
|
||||
battleQuery->belligerents[0] = gs->curB->sides[0].armyObject;
|
||||
battleQuery->belligerents[1] = gs->curB->sides[1].armyObject;
|
||||
}
|
||||
|
||||
battleQuery = std::make_shared<CBattleQuery>(this, gs->curB);
|
||||
for(int i : {0, 1})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
battleQuery->initialHeroMana[i] = heroes[i]->mana;
|
||||
}
|
||||
}
|
||||
queries.addQuery(battleQuery);
|
||||
|
||||
this->battleThread = std::make_unique<boost::thread>(boost::thread(&CGameHandler::runBattle, this));
|
||||
@@ -7188,7 +7240,7 @@ void CGameHandler::showInfoDialog(const std::string & msg, PlayerColor player)
|
||||
showInfoDialog(&iw);
|
||||
}
|
||||
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, BattleInfo *bat):
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, const BattleInfo * bat):
|
||||
army(_army)
|
||||
{
|
||||
heroWithDeadCommander = ObjectInstanceID();
|
||||
@@ -7340,12 +7392,14 @@ CGameHandler::FinishingBattleHelper::FinishingBattleHelper(std::shared_ptr<const
|
||||
loserHero = result.winner != 0 ? info.sides[0].hero : info.sides[1].hero;
|
||||
victor = info.sides[result.winner].color;
|
||||
loser = info.sides[!result.winner].color;
|
||||
winnerSide = result.winner;
|
||||
remainingBattleQueriesCount = RemainingBattleQueriesCount;
|
||||
}
|
||||
|
||||
CGameHandler::FinishingBattleHelper::FinishingBattleHelper()
|
||||
{
|
||||
winnerHero = loserHero = nullptr;
|
||||
winnerSide = 0;
|
||||
remainingBattleQueriesCount = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user