1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

use only CSpell in CSpellWindow

This commit is contained in:
AlexVinS
2016-10-16 10:32:12 +03:00
parent 63cbf960df
commit 2eb61533fa
2 changed files with 90 additions and 103 deletions

View File

@ -74,6 +74,29 @@ void CSpellWindow::InteractiveArea::hover(bool on)
owner->statusBar->clear(); owner->statusBar->clear();
} }
class SpellbookSpellSorter
{
public:
bool operator()(const CSpell * A, const CSpell * B)
{
if(A->level < B->level)
return true;
if(A->level > B->level)
return false;
for(ui8 schoolId = 0; schoolId < 4; schoolId++)
{
if(A->school.at((ESpellSchool)schoolId) && !B->school.at((ESpellSchool)schoolId))
return true;
if(!A->school.at((ESpellSchool)schoolId) && B->school.at((ESpellSchool)schoolId))
return false;
}
return A->name < B->name;
}
} spellsorter;
CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells): CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells):
CWindowObject(PLAYER_COLORED, "SpelBack"), CWindowObject(PLAYER_COLORED, "SpelBack"),
battleSpellsOnly(openOnBattleSpells), battleSpellsOnly(openOnBattleSpells),
@ -83,11 +106,13 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
myInt(_myInt) myInt(_myInt)
{ {
//initializing castable spells //initializing castable spells
for(const auto & spell : CGI->spellh->objects) mySpells.reserve(CGI->spellh->objects.size());
for(const CSpell * spell : CGI->spellh->objects)
{ {
if(!spell->isCreatureAbility() && myHero->canCastThisSpell(spell.get())) if(!spell->isCreatureAbility() && myHero->canCastThisSpell(spell))
mySpells.insert(spell->id); mySpells.push_back(spell);
} }
std::sort(mySpells.begin(), mySpells.end(), spellsorter);
//initializing sizes of spellbook's parts //initializing sizes of spellbook's parts
for(auto & elem : sitesPerTabAdv) for(auto & elem : sitesPerTabAdv)
@ -95,9 +120,8 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
for(auto & elem : sitesPerTabBattle) for(auto & elem : sitesPerTabBattle)
elem = 0; elem = 0;
for(const auto & g : mySpells) for(const auto spell : mySpells)
{ {
const CSpell * spell = g.toSpell();
int * sitesPerOurTab = spell->isCombatSpell() ? sitesPerTabBattle : sitesPerTabAdv; int * sitesPerOurTab = spell->isCombatSpell() ? sitesPerTabBattle : sitesPerTabAdv;
++sitesPerOurTab[4]; ++sitesPerOurTab[4];
@ -361,51 +385,25 @@ void CSpellWindow::show(SDL_Surface * to)
statusBar->show(to); statusBar->show(to);
} }
class SpellbookSpellSorter
{
public:
bool operator()(const SpellID & a, const SpellID & b)
{
const CSpell & A = *(a.toSpell());
const CSpell & B = *(b.toSpell());
if(A.level<B.level)
return true;
if(A.level>B.level)
return false;
for(ui8 schoolId = 0; schoolId < 4; schoolId++)
{
if(A.school.at((ESpellSchool)schoolId) && !B.school.at((ESpellSchool)schoolId))
return true;
if(!A.school.at((ESpellSchool)schoolId) && B.school.at((ESpellSchool)schoolId))
return false;
}
return A.name < B.name;
}
} spellsorter;
void CSpellWindow::computeSpellsPerArea() void CSpellWindow::computeSpellsPerArea()
{ {
std::vector<SpellID> spellsCurSite; std::vector<const CSpell *> spellsCurSite;
for(const SpellID & spellID : mySpells) spellsCurSite.reserve(mySpells.size());
for(const CSpell * spell : mySpells)
{ {
const CSpell * s = spellID.toSpell(); if(spell->combatSpell ^ !battleSpellsOnly
&& ((selectedTab == 4) || spell->school.at((ESpellSchool)selectedTab))
if(s->combatSpell ^ !battleSpellsOnly
&& ((selectedTab == 4) || s->school.at((ESpellSchool)selectedTab))
) )
{ {
spellsCurSite.push_back(spellID); spellsCurSite.push_back(spell);
} }
} }
std::sort(spellsCurSite.begin(), spellsCurSite.end(), spellsorter);
if(selectedTab == 4) if(selectedTab == 4)
{ {
if(spellsCurSite.size() > 12) if(spellsCurSite.size() > 12)
{ {
spellsCurSite = std::vector<SpellID>(spellsCurSite.begin() + currentPage*12, spellsCurSite.end()); spellsCurSite = std::vector<const CSpell *>(spellsCurSite.begin() + currentPage*12, spellsCurSite.end());
if(spellsCurSite.size() > 12) if(spellsCurSite.size() > 12)
{ {
spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end()); spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end());
@ -422,7 +420,7 @@ void CSpellWindow::computeSpellsPerArea()
} }
else else
{ {
spellsCurSite = std::vector<SpellID>(spellsCurSite.begin() + (currentPage-1)*12 + 10, spellsCurSite.end()); spellsCurSite = std::vector<const CSpell *>(spellsCurSite.begin() + (currentPage-1)*12 + 10, spellsCurSite.end());
if(spellsCurSite.size() > 12) if(spellsCurSite.size() > 12)
{ {
spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end()); spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end());
@ -435,26 +433,26 @@ void CSpellWindow::computeSpellsPerArea()
{ {
for(size_t c=0; c<12; ++c) for(size_t c=0; c<12; ++c)
{ {
if(c<spellsCurSite.size()) if(c < spellsCurSite.size())
{ {
spellAreas[c]->setSpell(spellsCurSite[c]); spellAreas[c]->setSpell(spellsCurSite[c]);
} }
else else
{ {
spellAreas[c]->setSpell(SpellID::NONE); spellAreas[c]->setSpell(nullptr);
} }
} }
} }
else else
{ {
spellAreas[0]->setSpell(SpellID::NONE); spellAreas[0]->setSpell(nullptr);
spellAreas[1]->setSpell(SpellID::NONE); spellAreas[1]->setSpell(nullptr);
for(size_t c=0; c<10; ++c) for(size_t c=0; c<10; ++c)
{ {
if(c<spellsCurSite.size()) if(c < spellsCurSite.size())
spellAreas[c+2]->setSpell(spellsCurSite[c]); spellAreas[c+2]->setSpell(spellsCurSite[c]);
else else
spellAreas[c+2]->setSpell(SpellID::NONE); spellAreas[c+2]->setSpell(nullptr);
} }
} }
redraw(); redraw();
@ -596,39 +594,37 @@ CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)
addUsedEvents(LCLICK | RCLICK | HOVER); addUsedEvents(LCLICK | RCLICK | HOVER);
spellCost = whichSchool = schoolLevel = -1; spellCost = whichSchool = schoolLevel = -1;
mySpell = SpellID::NONE; mySpell = nullptr;
} }
void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
{ {
if(!down && mySpell != SpellID::NONE) if(!down && mySpell)
{ {
const CSpell * sp = mySpell.toSpell(); int spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero);
int spellCost = owner->myInt->cb->getSpellCost(sp, owner->myHero);
if(spellCost > owner->myHero->mana) //insufficient mana if(spellCost > owner->myHero->mana) //insufficient mana
{ {
owner->myInt->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana)); owner->myInt->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana));
return; return;
} }
//battle spell on adv map or adventure map spell during combat => display infowindow, not cast //battle spell on adv map or adventure map spell during combat => display infowindow, not cast
if((sp->isCombatSpell() && !owner->myInt->battleInt) if((mySpell->isCombatSpell() && !owner->myInt->battleInt)
|| (sp->isAdventureSpell() && (owner->myInt->battleInt || owner->myInt->castleInt))) || (mySpell->isAdventureSpell() && (owner->myInt->battleInt || owner->myInt->castleInt)))
{ {
std::vector<CComponent*> hlp(1, new CComponent(CComponent::spell, mySpell, 0)); std::vector<CComponent*> hlp(1, new CComponent(CComponent::spell, mySpell->id, 0));
LOCPLINT->showInfoDialog(sp->getLevelInfo(schoolLevel).description, hlp); LOCPLINT->showInfoDialog(mySpell->getLevelInfo(schoolLevel).description, hlp);
return; return;
} }
//we will cast a spell //we will cast a spell
if(sp->combatSpell && owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell()) //if battle window is open if(mySpell->combatSpell && owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell()) //if battle window is open
{ {
ESpellCastProblem::ESpellCastProblem problem = owner->myInt->cb->battleCanCastThisSpell(sp); ESpellCastProblem::ESpellCastProblem problem = owner->myInt->cb->battleCanCastThisSpell(mySpell);
switch (problem) switch (problem)
{ {
case ESpellCastProblem::OK: case ESpellCastProblem::OK:
{ {
owner->myInt->battleInt->castThisSpell(mySpell); owner->myInt->battleInt->castThisSpell(mySpell->id);
owner->fexitb(); owner->fexitb();
return; return;
} }
@ -703,7 +699,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
} }
} }
} }
else if(sp->isAdventureSpell() && !owner->myInt->battleInt) //adventure spell and not in battle else if(mySpell->isAdventureSpell() && !owner->myInt->battleInt) //adventure spell and not in battle
{ {
const CGHeroInstance *h = owner->myHero; const CGHeroInstance *h = owner->myHero;
GH.popInt(owner); GH.popInt(owner);
@ -715,7 +711,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
delete owner; delete owner;
}); });
if(mySpell == SpellID::TOWN_PORTAL) if(mySpell->id == SpellID::TOWN_PORTAL)
{ {
//special case //special case
//todo: move to mechanics //todo: move to mechanics
@ -735,7 +731,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
return; return;
} }
const int movementCost = (h->getSpellSchoolLevel(sp) >= 3) ? 200 : 300; const int movementCost = (h->getSpellSchoolLevel(mySpell) >= 3) ? 200 : 300;
if(h->movement < movementCost) if(h->movement < movementCost)
{ {
@ -743,7 +739,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
return; return;
} }
if (h->getSpellSchoolLevel(sp) < 2) //not advanced or expert - teleport to nearest available city if (h->getSpellSchoolLevel(mySpell) < 2) //not advanced or expert - teleport to nearest available city
{ {
auto nearest = Towns.cbegin(); //nearest town's iterator auto nearest = Towns.cbegin(); //nearest town's iterator
si32 dist = LOCPLINT->cb->getTown((*nearest)->id)->pos.dist2dSQ(h->pos); si32 dist = LOCPLINT->cb->getTown((*nearest)->id)->pos.dist2dSQ(h->pos);
@ -765,7 +761,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
else else
{ {
const CGTownInstance * town = LOCPLINT->cb->getTown((*nearest)->id); const CGTownInstance * town = LOCPLINT->cb->getTown((*nearest)->id);
LOCPLINT->cb->castSpell(h, mySpell, town->visitablePos());// - town->getVisitableOffset()); LOCPLINT->cb->castSpell(h, mySpell->id, town->visitablePos());// - town->getVisitableOffset());
} }
} }
else else
@ -789,14 +785,14 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]); LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]);
else else
GH.pushInt (new CObjectListWindow(availableTowns, GH.pushInt (new CObjectListWindow(availableTowns,
new CAnimImage("SPELLSCR",mySpell), new CAnimImage("SPELLSCR",mySpell->id),
CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41], CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41],
castTownPortal)); castTownPortal));
} }
return; return;
} }
if(mySpell == SpellID::SUMMON_BOAT) if(mySpell->id == SpellID::SUMMON_BOAT)
{ {
//special case //special case
//todo: move to mechanics //todo: move to mechanics
@ -808,13 +804,13 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
} }
} }
if(sp->getTargetType() == CSpell::LOCATION) if(mySpell->getTargetType() == CSpell::LOCATION)
{ {
adventureInt->enterCastingMode(sp); adventureInt->enterCastingMode(mySpell);
} }
else if(sp->getTargetType() == CSpell::NO_TARGET) else if(mySpell->getTargetType() == CSpell::NO_TARGET)
{ {
LOCPLINT->cb->castSpell(h, mySpell); LOCPLINT->cb->castSpell(h, mySpell->id);
} }
else else
{ {
@ -826,12 +822,11 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState) void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState)
{ {
if(down && mySpell != -1) if(down && mySpell)
{ {
std::string dmgInfo; std::string dmgInfo;
const CGHeroInstance * hero = owner->myHero; int causedDmg = owner->myInt->cb->estimateSpellDamage(mySpell, owner->myHero);
int causedDmg = owner->myInt->cb->estimateSpellDamage( CGI->spellh->objects[mySpell], (hero ? hero : nullptr)); if(causedDmg == 0 || mySpell->id == SpellID::TITANS_LIGHTNING_BOLT) //Titan's Lightning Bolt already has damage info included
if(causedDmg == 0 || mySpell == SpellID::TITANS_LIGHTNING_BOLT) //Titan's Lightning Bolt already has damage info included
dmgInfo = ""; dmgInfo = "";
else else
{ {
@ -839,43 +834,35 @@ void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState)
boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(causedDmg)); boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(causedDmg));
} }
CRClickPopup::createAndPush(CGI->spellh->objects[mySpell]->getLevelInfo(schoolLevel).description + dmgInfo, CRClickPopup::createAndPush(mySpell->getLevelInfo(schoolLevel).description + dmgInfo,
new CComponent(CComponent::spell, mySpell)); new CComponent(CComponent::spell, mySpell->id));
} }
} }
void CSpellWindow::SpellArea::hover(bool on) void CSpellWindow::SpellArea::hover(bool on)
{ {
//Hoverable::hover(on); if(mySpell)
if(mySpell != -1)
{ {
if(on) if(on)
{ owner->statusBar->setText(boost::to_string(boost::format("%s (%s)") % mySpell->name % CGI->generaltexth->allTexts[171+mySpell->level]));
std::ostringstream ss;
ss<<CGI->spellh->objects[mySpell]->name<<" ("<<CGI->generaltexth->allTexts[171+CGI->spellh->objects[mySpell]->level]<<")";
owner->statusBar->setText(ss.str());
}
else else
{
owner->statusBar->clear(); owner->statusBar->clear();
}
} }
} }
void CSpellWindow::SpellArea::showAll(SDL_Surface * to) void CSpellWindow::SpellArea::showAll(SDL_Surface * to)
{ {
if(mySpell < 0) if(!mySpell)
return; return;
const CSpell * spell = mySpell.toSpell(); owner->spells->load(mySpell->id);
owner->spells->load(mySpell);
IImage * icon = owner->spells->getImage(mySpell,0,false); IImage * icon = owner->spells->getImage(mySpell->id,0,false);
if(icon != nullptr) if(icon != nullptr)
icon->draw(to, pos.x, pos.y); icon->draw(to, pos.x, pos.y);
else else
logGlobal->errorStream() << __FUNCTION__ << ": failed to load spell icon for spell with id " << mySpell; logGlobal->errorStream() << __FUNCTION__ << ": failed to load icon for spell " << mySpell->name;
blitAt(owner->schoolBorders[owner->selectedTab >= 4 ? whichSchool : owner->selectedTab]->ourImages[schoolLevel].bitmap, pos.x, pos.y, to); //printing border (indicates level of magic school) blitAt(owner->schoolBorders[owner->selectedTab >= 4 ? whichSchool : owner->selectedTab]->ourImages[schoolLevel].bitmap, pos.x, pos.y, to); //printing border (indicates level of magic school)
@ -892,30 +879,29 @@ void CSpellWindow::SpellArea::showAll(SDL_Surface * to)
secondLineColor = Colors::WHITE; secondLineColor = Colors::WHITE;
} }
//printing spell's name //printing spell's name
printAtMiddleLoc(spell->name, 39, 70, FONT_TINY, firstLineColor, to); printAtMiddleLoc(mySpell->name, 39, 70, FONT_TINY, firstLineColor, to);
//printing lvl //printing lvl
if(schoolLevel > 0) if(schoolLevel > 0)
{ {
boost::format fmt("%s/%s"); boost::format fmt("%s/%s");
fmt % CGI->generaltexth->allTexts[171 + spell->level]; fmt % CGI->generaltexth->allTexts[171 + mySpell->level];
fmt % CGI->generaltexth->levels.at(3+(schoolLevel-1));//lines 4-6 fmt % CGI->generaltexth->levels.at(3+(schoolLevel-1));//lines 4-6
printAtMiddleLoc(fmt.str(), 39, 82, FONT_TINY, secondLineColor, to); printAtMiddleLoc(fmt.str(), 39, 82, FONT_TINY, secondLineColor, to);
} }
else else
printAtMiddleLoc(CGI->generaltexth->allTexts[171 + spell->level], 39, 82, FONT_TINY, secondLineColor, to); printAtMiddleLoc(CGI->generaltexth->allTexts[171 + mySpell->level], 39, 82, FONT_TINY, secondLineColor, to);
//printing cost //printing cost
std::ostringstream ss; std::ostringstream ss;
ss << CGI->generaltexth->allTexts[387] << ": " << spellCost; ss << CGI->generaltexth->allTexts[387] << ": " << spellCost;
printAtMiddleLoc(ss.str(), 39, 94, FONT_TINY, secondLineColor, to); printAtMiddleLoc(ss.str(), 39, 94, FONT_TINY, secondLineColor, to);
} }
void CSpellWindow::SpellArea::setSpell(SpellID spellID) void CSpellWindow::SpellArea::setSpell(const CSpell * spell)
{ {
mySpell = spellID; mySpell = spell;
if(mySpell < 0) if(mySpell)
return; {
schoolLevel = owner->myHero->getSpellSchoolLevel(mySpell, &whichSchool);
const CSpell * spell = CGI->spellh->objects[mySpell]; spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero);
schoolLevel = owner->myHero->getSpellSchoolLevel(spell, &whichSchool); }
spellCost = owner->myInt->cb->getSpellCost(spell, owner->myHero);
} }

View File

@ -19,6 +19,7 @@ class CGHeroInstance;
class CGStatusBar; class CGStatusBar;
class CPlayerInterface; class CPlayerInterface;
class CSpellWindow; class CSpellWindow;
class CSpell;
/// The spell window /// The spell window
class CSpellWindow : public CWindowObject class CSpellWindow : public CWindowObject
@ -27,7 +28,7 @@ private:
class SpellArea : public CIntObject class SpellArea : public CIntObject
{ {
public: public:
SpellID mySpell; const CSpell * mySpell;
int schoolLevel; //range: 0 none, 3 - expert int schoolLevel; //range: 0 none, 3 - expert
int whichSchool; //0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, int whichSchool; //0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
int spellCost; int spellCost;
@ -35,7 +36,7 @@ private:
SpellArea(SDL_Rect pos, CSpellWindow * owner); SpellArea(SDL_Rect pos, CSpellWindow * owner);
void setSpell(SpellID spellID); void setSpell(const CSpell * spell);
void clickLeft(tribool down, bool previousState) override; void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override;
@ -79,7 +80,7 @@ private:
bool battleSpellsOnly; //if true, only battle spells are displayed; if false, only adventure map spells are displayed bool battleSpellsOnly; //if true, only battle spells are displayed; if false, only adventure map spells are displayed
Uint8 selectedTab; // 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools Uint8 selectedTab; // 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools
int currentPage; //changes when corners are clicked int currentPage; //changes when corners are clicked
std::set<SpellID> mySpells; //all spels in this spellbook std::vector<const CSpell *> mySpells; //all spels in this spellbook
const CGHeroInstance * myHero; //hero whose spells are presented const CGHeroInstance * myHero; //hero whose spells are presented