mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-13 22:06:58 +02:00
more battles animations:
- UI will be correctly greyed-out during opponent turn - fixed remaining issues with blit order - a bit better handling of catapult attack - fixes #1362
This commit is contained in:
parent
e9d51a2670
commit
a148c39e0a
@ -230,11 +230,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o);
|
||||
bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s);
|
||||
bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r);
|
||||
bFlee->block(!curInt->cb->getMyColor() || !curInt->cb->battleCanFlee());
|
||||
bSurrender->block(!curInt->cb->getMyColor() || curInt->cb->battleGetSurrenderCost() < 0);
|
||||
bAutofight = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
|
||||
bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c);
|
||||
bSpell->block(true);
|
||||
bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, boost::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", SDLK_w);
|
||||
bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, boost::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", SDLK_d);
|
||||
bDefence->assignedKeys.insert(SDLK_SPACE);
|
||||
@ -250,8 +247,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
{
|
||||
btactNext = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)nullptr), 213, 560, "icm011.def", SDLK_SPACE);
|
||||
btactEnd = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN);
|
||||
bDefence->block(true);
|
||||
bWait->block(true);
|
||||
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
|
||||
}
|
||||
else
|
||||
@ -884,8 +879,7 @@ void CBattleInterface::bAutofightf()
|
||||
else
|
||||
{
|
||||
curInt->isAutoFightOn = true;
|
||||
deactivate();
|
||||
bAutofight->activate();
|
||||
blockUI(true);
|
||||
|
||||
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
|
||||
ai->init(curInt->cb);
|
||||
@ -1201,12 +1195,16 @@ void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca)
|
||||
{
|
||||
const CStack * stack = curInt->cb->battleGetStackByID(ca.attacker);
|
||||
addNewAnim(new CShootingAnimation(this, stack, it->first.second, nullptr, true, it->second));
|
||||
}
|
||||
|
||||
waitForAnims();
|
||||
|
||||
for(auto it = ca.attackedParts.begin(); it != ca.attackedParts.end(); ++it)
|
||||
{
|
||||
SDL_FreeSurface(siegeH->walls[it->first.first + 2]);
|
||||
siegeH->walls[it->first.first + 2] = BitmapHandler::loadBitmap(
|
||||
siegeH->getSiegeName(it->first.first + 2, curInt->cb->battleGetWallState(it->first.first)) );
|
||||
}
|
||||
waitForAnims();
|
||||
}
|
||||
|
||||
void CBattleInterface::battleFinished(const BattleResult& br)
|
||||
@ -1233,10 +1231,6 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
{
|
||||
const CSpell &spell = *CGI->spellh->spells[sc->id];
|
||||
|
||||
//spell opening battle is cast when no stack is active
|
||||
if(sc->castedByHero && ( activeStack == nullptr || sc->side == !activeStack->attackerOwned) )
|
||||
bSpell->block(true);
|
||||
|
||||
std::vector< std::string > anims; //for magic arrow and ice bolt
|
||||
|
||||
if (vstd::contains(CCS->soundh->spellSounds, &spell))
|
||||
@ -1658,6 +1652,8 @@ void CBattleInterface::setActiveStack(const CStack * stack)
|
||||
|
||||
if (activeStack) // update UI
|
||||
creAnims[activeStack->ID]->setBorderColor(AnimationControls::getGoldBorder());
|
||||
|
||||
blockUI(activeStack == nullptr);
|
||||
}
|
||||
|
||||
void CBattleInterface::setHoveredStack(const CStack * stack)
|
||||
@ -1693,16 +1689,6 @@ void CBattleInterface::activateStack()
|
||||
|
||||
queue->update();
|
||||
redrawBackgroundWithHexes(activeStack);
|
||||
bWait->block(s->waited() || tacticsMode); //block waiting button if stack has been already waiting
|
||||
|
||||
//block cast spell button if hero doesn't have a spellbook
|
||||
ESpellCastProblem::ESpellCastProblem spellcastingProblem;
|
||||
bool canCastSpells = curInt->cb->battleCanCastSpell(&spellcastingProblem);
|
||||
bSpell->block(!canCastSpells && spellcastingProblem != ESpellCastProblem::MAGIC_IS_BLOCKED); //if magic is blocked, we leave button active, so the message can be displayed (cf bug #97)
|
||||
bSurrender->block((curInt == attackerInt ? defendingHeroInstance : attackingHeroInstance) == nullptr);
|
||||
bFlee->block(!curInt->cb->battleCanFlee());
|
||||
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
|
||||
|
||||
|
||||
//set casting flag to true if creature can use it to not check it every time
|
||||
const Bonus *spellcaster = s->getBonusLocalFirst(Selector::type(Bonus::SPELLCASTER)),
|
||||
@ -1724,9 +1710,6 @@ void CBattleInterface::activateStack()
|
||||
|
||||
getPossibleActionsForStack (s);
|
||||
|
||||
if(!pendingAnims.size() && !active)
|
||||
activate();
|
||||
|
||||
GH.fakeMouseMove();
|
||||
}
|
||||
|
||||
@ -1886,7 +1869,12 @@ void CBattleInterface::endAction(const BattleAction* action)
|
||||
if(activeStack && !animsAreDisplayed.get() && pendingAnims.empty() && !active)
|
||||
{
|
||||
logGlobal->warnStream() << "Something wrong... interface was deactivated but there is no animation. Reactivating...";
|
||||
activate();
|
||||
blockUI(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// block UI if no active stack (e.g. enemy turn);
|
||||
blockUI(activeStack == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1918,10 +1906,42 @@ void CBattleInterface::showQueue()
|
||||
}
|
||||
}
|
||||
|
||||
void CBattleInterface::blockUI(bool on)
|
||||
{
|
||||
ESpellCastProblem::ESpellCastProblem spellcastingProblem;
|
||||
bool canCastSpells = curInt->cb->battleCanCastSpell(&spellcastingProblem);
|
||||
bool canWait = activeStack ? !activeStack->waited() : false;
|
||||
|
||||
bOptions->block(on);
|
||||
bFlee->block(on || !curInt->cb->battleCanFlee());
|
||||
bSurrender->block(on || curInt->cb->battleGetSurrenderCost() < 0);
|
||||
|
||||
// never block autofight button
|
||||
//FIXME: is that correct?
|
||||
bAutofight->block(false); //curInt->isAutoFightOn
|
||||
|
||||
if(tacticsMode && btactEnd && btactNext)
|
||||
{
|
||||
btactNext->block(on);
|
||||
btactEnd->block(on);
|
||||
}
|
||||
else
|
||||
{
|
||||
bConsoleUp->block(on);
|
||||
bConsoleDown->block(on);
|
||||
}
|
||||
|
||||
//if magic is blocked, we leave button active, so the message can be displayed (cf bug #97)
|
||||
bSpell->block(on || (!canCastSpells && spellcastingProblem != ESpellCastProblem::MAGIC_IS_BLOCKED));
|
||||
bWait->block(on || tacticsMode || !canWait);
|
||||
bDefence->block(on || tacticsMode);
|
||||
}
|
||||
|
||||
void CBattleInterface::startAction(const BattleAction* action)
|
||||
{
|
||||
//setActiveStack(nullptr);
|
||||
setHoveredStack(nullptr);
|
||||
blockUI(true);
|
||||
|
||||
if(action->actionType == Battle::END_TACTIC_PHASE)
|
||||
{
|
||||
@ -1929,19 +1949,6 @@ void CBattleInterface::startAction(const BattleAction* action)
|
||||
menu = BitmapHandler::loadBitmap("CBAR.bmp");
|
||||
|
||||
graphics->blueToPlayersAdv(menu, curInt->playerID);
|
||||
bDefence->block(false);
|
||||
bWait->block(false);
|
||||
if(active)
|
||||
{
|
||||
if(btactEnd && btactNext) //if the other side had tactics, there are no buttons
|
||||
{
|
||||
btactEnd->deactivate();
|
||||
btactNext->deactivate();
|
||||
bConsoleDown->activate();
|
||||
bConsoleUp->activate();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1967,8 +1974,6 @@ void CBattleInterface::startAction(const BattleAction* action)
|
||||
}
|
||||
}
|
||||
|
||||
if(active)
|
||||
deactivate();
|
||||
redraw(); // redraw after deactivation, including proper handling of hovered hexes
|
||||
|
||||
char txt[400];
|
||||
@ -2030,7 +2035,7 @@ void CBattleInterface::waitForAnims()
|
||||
void CBattleInterface::bEndTacticPhase()
|
||||
{
|
||||
setActiveStack(nullptr);
|
||||
btactEnd->block(true);
|
||||
blockUI(true);
|
||||
tacticsMode = false;
|
||||
}
|
||||
|
||||
@ -3128,7 +3133,9 @@ void CBattleInterface::showProjectiles(SDL_Surface * to)
|
||||
// Check if projectile is already visible (shooter animation did the shot)
|
||||
if (!it->shotDone)
|
||||
{
|
||||
if (creAnims[it->stackID]->getCurrentFrame() >= it->animStartDelay)
|
||||
// frame we're waiting for is reached OR animation has already finished
|
||||
if (creAnims[it->stackID]->getCurrentFrame() >= it->animStartDelay ||
|
||||
creAnims[it->stackID]->isShooting() == false)
|
||||
{
|
||||
//at this point projectile should become visible
|
||||
creAnims[it->stackID]->pause(); // pause animation
|
||||
@ -3197,27 +3204,29 @@ void CBattleInterface::showBattlefieldObjects(SDL_Surface * to)
|
||||
{
|
||||
showPiecesOfWall(to, hex.walls);
|
||||
showObstacles(to, hex.obstacles);
|
||||
showStacks(to, hex.dead);
|
||||
showAliveStacks(to, hex.alive);
|
||||
showBattleEffects(to, hex.effects);
|
||||
};
|
||||
|
||||
if(attackingHero)
|
||||
attackingHero->show(to);
|
||||
|
||||
if(defendingHero)
|
||||
defendingHero->show(to);
|
||||
|
||||
BattleObjectsByHex objects = sortObjectsByHex();
|
||||
|
||||
// dead stacks should be blit first
|
||||
showStacks(to, objects.beforeAll.dead);
|
||||
for( auto & data : objects.hex )
|
||||
showStacks(to, data.dead);
|
||||
showStacks(to, objects.afterAll.dead);
|
||||
|
||||
// display objects that must be blit before anything else (e.g. topmost walls)
|
||||
showHexEntry(objects.beforeAll);
|
||||
|
||||
// actual blit of most of objects, hex by hex
|
||||
// NOTE: row-by-row blitting may be a better approach
|
||||
for( auto & data : objects.hex )
|
||||
showHexEntry(data);
|
||||
|
||||
// objects that must be blit *after* everything else - e.g. bottom tower or some spell effects
|
||||
showHexEntry(objects.afterAll);
|
||||
}
|
||||
@ -3412,7 +3421,7 @@ BattleObjectsByHex CBattleInterface::sortObjectsByHex()
|
||||
|
||||
if(!creAnims[stack->ID]->isDead())
|
||||
{
|
||||
if (creAnims[stack->ID]->getType() != CCreatureAnim::MOVING)
|
||||
if (!creAnims[stack->ID]->isMoving())
|
||||
sorted.hex[stack->position].alive.push_back(stack);
|
||||
else
|
||||
{
|
||||
@ -3500,11 +3509,9 @@ void CBattleInterface::updateBattleAnimations()
|
||||
|
||||
if(preSize > 0 && pendingAnims.size() == 0)
|
||||
{
|
||||
//action finished, restore the interface
|
||||
if(!active)
|
||||
activate();
|
||||
|
||||
//anims ended
|
||||
blockUI(activeStack == nullptr);
|
||||
|
||||
animsAreDisplayed.setn(false);
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,6 @@ private:
|
||||
void showHighlightedHex(SDL_Surface * to, BattleHex hex);
|
||||
void showInterface(SDL_Surface * to);
|
||||
|
||||
|
||||
void showBattlefieldObjects(SDL_Surface * to);
|
||||
|
||||
void showAliveStacks(SDL_Surface * to, std::vector<const CStack *> stacks);
|
||||
@ -265,6 +264,10 @@ public:
|
||||
|
||||
const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
|
||||
|
||||
// block all UI elements, e.g. during enemy turn
|
||||
// unlike activate/deactivate this method will correctly grey-out all elements
|
||||
void blockUI(bool on);
|
||||
|
||||
//button handle funcs:
|
||||
void bOptionsf();
|
||||
void bSurrenderf();
|
||||
|
@ -429,6 +429,20 @@ bool CCreatureAnimation::isIdle() const
|
||||
|| getType() == CCreatureAnim::MOUSEON;
|
||||
}
|
||||
|
||||
bool CCreatureAnimation::isMoving() const
|
||||
{
|
||||
return getType() == CCreatureAnim::MOVE_START
|
||||
|| getType() == CCreatureAnim::MOVING
|
||||
|| getType() == CCreatureAnim::MOVE_END;
|
||||
}
|
||||
|
||||
bool CCreatureAnimation::isShooting() const
|
||||
{
|
||||
return getType() == CCreatureAnim::SHOOT_UP
|
||||
|| getType() == CCreatureAnim::SHOOT_FRONT
|
||||
|| getType() == CCreatureAnim::SHOOT_DOWN;
|
||||
}
|
||||
|
||||
void CCreatureAnimation::pause()
|
||||
{
|
||||
speed = 0;
|
||||
|
@ -137,4 +137,6 @@ public:
|
||||
//helpers. TODO: move them somewhere else
|
||||
bool isDead() const;
|
||||
bool isIdle() const;
|
||||
bool isMoving() const;
|
||||
bool isShooting() const;
|
||||
};
|
||||
|
@ -1931,8 +1931,10 @@ std::set<const CStack*> CBattleInfoCallback::getAffectedCreatures(const CSpell *
|
||||
}
|
||||
}
|
||||
}
|
||||
int targetsOnLevel[4] = {4, 4, 5, 5};
|
||||
|
||||
BattleHex lightningHex = destinationTile;
|
||||
for (int i = 0; i < 5; ++i) //TODO: depends on spell school level
|
||||
for (int i = 0; i < targetsOnLevel[skillLevel]; ++i)
|
||||
{
|
||||
auto stack = battleGetStackByPos (lightningHex, true);
|
||||
if (!stack)
|
||||
|
Loading…
x
Reference in New Issue
Block a user