1
0
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:
Ivan Savenko 2013-07-21 10:10:38 +00:00
parent e9d51a2670
commit a148c39e0a
5 changed files with 82 additions and 54 deletions

View File

@ -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);
}
}

View File

@ -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();

View File

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

View File

@ -137,4 +137,6 @@ public:
//helpers. TODO: move them somewhere else
bool isDead() const;
bool isIdle() const;
bool isMoving() const;
bool isShooting() const;
};

View File

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