Sfoglia il codice sorgente

A bunch of spellbook-related fixes: #91, #454, #462, #526, #527, #536

Michał W. Urbańczyk 15 anni fa
parent
commit
931949e349

+ 14 - 1
client/CPlayerInterface.cpp

@@ -849,13 +849,14 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	showInfoDialog(text,intComps,soundID);
 }
 
-void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, int soundID)
+void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, int soundID, bool delComps)
 {
 	waitWhileDialog();
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	
 	stopMovement();
 	CInfoWindow *temp = CInfoWindow::create(text, playerID, &components);
+	temp->setDelComps(delComps);
 	if(makingTurn && GH.listInt.size() && LOCPLINT == this)
 	{
 		CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
@@ -1012,6 +1013,7 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
 {
 	h & playerID & serialID;
 	h & sysOpts;
+	h & spellbookSettings;
 }
 
 void CPlayerInterface::serialize( COSer<CSaveFile> &h, const int version )
@@ -1100,6 +1102,11 @@ bool CPlayerInterface::shiftPressed() const
 	return SDL_GetKeyState(NULL)[SDLK_LSHIFT]  ||  SDL_GetKeyState(NULL)[SDLK_RSHIFT];
 }
 
+bool CPlayerInterface::altPressed() const
+{
+	return SDL_GetKeyState(NULL)[SDLK_LALT]  ||  SDL_GetKeyState(NULL)[SDLK_RALT];
+}
+
 void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd )
 {
 	if(stillMoveHero.get() == DURING_MOVE  &&  adventureInt->terrain.currentPath->nodes.size() > 1) //to ignore calls on passing through garrisons
@@ -2052,4 +2059,10 @@ void CPlayerInterface::showShipyardDialogOrProblemPopup(const IShipyard *obj)
 	}
 	else
 		showShipyardDialog(obj);
+}
+
+CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()
+{
+	spellbookLastPageBattle = spellbokLastPageAdvmap = 0;
+	spellbookLastTabBattle = spellbookLastTabAdvmap = 4;
 }

+ 14 - 1
client/CPlayerInterface.h

@@ -137,6 +137,18 @@ public:
 	std::vector<const CGTownInstance *> towns; //our heroes on the adventure map (not the garrisoned ones)
 	std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
 
+	struct SpellbookLastSetting
+	{
+		int spellbookLastPageBattle, spellbokLastPageAdvmap; //on which page we left spellbook
+		int spellbookLastTabBattle, spellbookLastTabAdvmap; //on which page we left spellbook
+
+		SpellbookLastSetting();
+		template <typename Handler> void serialize( Handler &h, const int version )
+		{
+			h & spellbookLastPageBattle & spellbokLastPageAdvmap & spellbookLastTabBattle & spellbookLastTabAdvmap;
+		}
+	} spellbookSettings;
+
 	void update();
 	void recreateHeroTownList();
 	const CGHeroInstance *getWHero(int pos); //returns NULL if position is not valid
@@ -210,6 +222,7 @@ public:
 	void waitWhileDialog();
 	bool shiftPressed() const; //determines if shift key is pressed (left or right or both)
 	bool ctrlPressed() const; //determines if ctrl key is pressed (left or right or both)
+	bool altPressed() const; //determines if alt key is pressed (left or right or both)
 	void redrawHeroWin(const CGHeroInstance * hero);
 	void showComp(SComponent comp); //TODO: comment me
 	void openTownWindow(const CGTownInstance * town); //shows townscreen
@@ -218,7 +231,7 @@ public:
 	void updateInfo(const CGObjectInstance * specific);
 	void init(ICallback * CB);
 	int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
-	void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0);
+	void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0, bool delComps = false);
 	void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
 	void stopMovement();
 	bool moveHero(const CGHeroInstance *h, CGPath path);

+ 204 - 258
client/CSpellWindow.cpp

@@ -33,6 +33,7 @@ extern SDL_Color tytulowy, zwykly, darkTitle;
 SpellbookInteractiveArea::SpellbookInteractiveArea(const SDL_Rect & myRect, boost::function<void()> funcL,
 	const std::string & textR, boost::function<void()> funcHon, boost::function<void()> funcHoff, CPlayerInterface * _myInt)
 {
+	used = LCLICK | RCLICK | HOVER;
 	pos = myRect;
 	onLeft = funcL;
 	textOnRclick = textR;
@@ -67,24 +68,10 @@ void SpellbookInteractiveArea::hover(bool on)
 	}
 }
 
-void SpellbookInteractiveArea::activate()
-{
-	activateLClick();
-	activateRClick();
-	activateHover();
-
-}
-void SpellbookInteractiveArea::deactivate()
-{
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-}
-
 CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells):
 	battleSpellsOnly(openOnBattleSpells),
 	selectedTab(4),
-	spellSite(0),
+	currentPage(0),
 	myHero(_myHero),
 	myInt(_myInt)
 {
@@ -95,87 +82,27 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * _myHe
 			mySpells.insert(v);
 	}
 
-	//initializing schools' levels
-	for(int b=0; b<4; ++b) schoolLvls[b] = 0;
-	for(size_t b=0; b<myHero->secSkills.size(); ++b)
-	{
-		switch(myHero->secSkills[b].first)
-		{
-		case 14: //fire magic
-			schoolLvls[1] = myHero->secSkills[b].second;
-			break;
-		case 15: //air magic
-			schoolLvls[0] = myHero->secSkills[b].second;
-			break;
-		case 16: //water magic
-			schoolLvls[2] = myHero->secSkills[b].second;
-			break;
-		case 17: //earth magic
-			schoolLvls[3] = myHero->secSkills[b].second;
-			break;
-		}
-	}
-
 	//initializing sizes of spellbook's parts
 	for(int b=0; b<5; ++b)
 		sitesPerTabAdv[b] = 0;
 	for(int b=0; b<5; ++b)
 		sitesPerTabBattle[b] = 0;
+
 	for(std::set<ui32>::const_iterator g = mySpells.begin(); g!=mySpells.end(); ++g)
 	{
-		if(CGI->spellh->spells[*g].combatSpell)
-		{
-			++(sitesPerTabBattle[4]);
-		}
-		else
-		{
-			++(sitesPerTabAdv[4]);
-		}
+		const CSpell &s = CGI->spellh->spells[*g];
+		Uint8 *sitesPerOurTab = s.combatSpell ? sitesPerTabBattle : sitesPerTabAdv;
 
-		if(CGI->spellh->spells[*g].air)
-		{
-			if(CGI->spellh->spells[*g].combatSpell)
-			{
-				++(sitesPerTabBattle[0]);
-			}
-			else
-			{
-				++(sitesPerTabAdv[0]);
-			}
-		}
-		if(CGI->spellh->spells[*g].fire)
-		{
-			if(CGI->spellh->spells[*g].combatSpell)
-			{
-				++(sitesPerTabBattle[1]);
-			}
-			else
-			{
-				++(sitesPerTabAdv[1]);
-			}
-		}
-		if(CGI->spellh->spells[*g].water)
-		{
-			if(CGI->spellh->spells[*g].combatSpell)
-			{
-				++(sitesPerTabBattle[2]);
-			}
-			else
-			{
-				++(sitesPerTabAdv[2]);
-			}
-		}
-		if(CGI->spellh->spells[*g].earth)
-		{
-			if(CGI->spellh->spells[*g].combatSpell)
-			{
-				++(sitesPerTabBattle[3]);
-			}
-			else
-			{
-				++(sitesPerTabAdv[3]);
-			}
-		}
+		++sitesPerOurTab[4];
+
+		if(s.air)
+			++sitesPerOurTab[0];
+		if(s.fire)
+			++sitesPerOurTab[1];
+		if(s.water)
+			++sitesPerOurTab[2];
+		if(s.earth)
+			++sitesPerOurTab[3];
 	}
 	if(sitesPerTabAdv[4] % 12 == 0)
 		sitesPerTabAdv[4]/=12;
@@ -243,15 +170,15 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * _myHe
 	manaPoints = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fmanaPtsb, this), CGI->generaltexth->zelp[459].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[459].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 
 	temp_rect = genRect(36, 56, 549 + pos.x, 94 + pos.y);
-	selectSpellsA = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fspellsAb, this), CGI->generaltexth->zelp[454].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[454].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
+	selectSpellsA = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::selectSchool, this, 0), CGI->generaltexth->zelp[454].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[454].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 	temp_rect = genRect(36, 56, 549 + pos.x, 151 + pos.y);
-	selectSpellsE = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fspellsEb, this), CGI->generaltexth->zelp[457].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[457].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
+	selectSpellsE = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::selectSchool, this, 3), CGI->generaltexth->zelp[457].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[457].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 	temp_rect = genRect(36, 56, 549 + pos.x, 210 + pos.y);
-	selectSpellsF = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fspellsFb, this), CGI->generaltexth->zelp[455].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[455].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
+	selectSpellsF = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::selectSchool, this, 1), CGI->generaltexth->zelp[455].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[455].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 	temp_rect = genRect(36, 56, 549 + pos.x, 270 + pos.y);
-	selectSpellsW = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fspellsWb, this), CGI->generaltexth->zelp[456].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[456].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
+	selectSpellsW = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::selectSchool, this, 2), CGI->generaltexth->zelp[456].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[456].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 	temp_rect = genRect(36, 56, 549 + pos.x, 330 + pos.y);
-	selectSpellsAll = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fspellsAllb, this), CGI->generaltexth->zelp[458].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[458].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
+	selectSpellsAll = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::selectSchool, this, 4), CGI->generaltexth->zelp[458].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[458].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
 
 	temp_rect = genRect(leftCorner->h, leftCorner->w, 97 + pos.x, 77 + pos.y);
 	lCorner = new SpellbookInteractiveArea(temp_rect, boost::bind(&CSpellWindow::fLcornerb, this), CGI->generaltexth->zelp[450].second, boost::bind(&CStatusBar::print, statusBar, (CGI->generaltexth->zelp[450].first)), boost::bind(&CStatusBar::clear, statusBar), myInt);
@@ -282,6 +209,10 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * _myHe
 			}
 		}
 	}
+
+	selectedTab = battleSpellsOnly ? LOCPLINT->spellbookSettings.spellbookLastTabBattle : LOCPLINT->spellbookSettings.spellbookLastTabAdvmap;
+	currentPage = battleSpellsOnly ? LOCPLINT->spellbookSettings.spellbookLastPageBattle : LOCPLINT->spellbookSettings.spellbokLastPageAdvmap;
+	abetw(currentPage, 0, pagesWithinCurrentTab());
 	computeSpellsPerArea();
 }
 
@@ -319,25 +250,30 @@ CSpellWindow::~CSpellWindow()
 
 void CSpellWindow::fexitb()
 {
+	(LOCPLINT->battleInt ? LOCPLINT->spellbookSettings.spellbookLastTabBattle : LOCPLINT->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
+	(LOCPLINT->battleInt ? LOCPLINT->spellbookSettings.spellbookLastPageBattle : LOCPLINT->spellbookSettings.spellbokLastPageAdvmap) = currentPage;
+
 	GH.popIntTotally(this);
 }
 
 void CSpellWindow::fadvSpellsb()
 {
-	if (battleSpellsOnly == true) {
+	if (battleSpellsOnly == true) 
+	{
 		turnPageRight();
 		battleSpellsOnly = false;
-		spellSite = 0;
+		currentPage = 0;
 	}
 	computeSpellsPerArea();
 }
 
 void CSpellWindow::fbattleSpellsb()
 {
-	if (battleSpellsOnly == false) {
+	if (battleSpellsOnly == false) 
+	{
 		turnPageLeft();
 		battleSpellsOnly = true;
-		spellSite = 0;
+		currentPage = 0;
 	}
 	computeSpellsPerArea();
 }
@@ -346,75 +282,40 @@ void CSpellWindow::fmanaPtsb()
 {
 }
 
-void CSpellWindow::fspellsAb()
+void CSpellWindow::selectSchool(int school)
 {
-	if (selectedTab != 0) {
-		turnPageRight();
-		selectedTab = 0;
-		spellSite = 0;
-	}
-	computeSpellsPerArea();
-}
-
-void CSpellWindow::fspellsEb()
-{
-	if (selectedTab != 3) {
-		turnPageRight();
-		selectedTab = 3;
-		spellSite = 0;
-	}
-	computeSpellsPerArea();
-}
-
-void CSpellWindow::fspellsFb()
-{
-	if (selectedTab != 1) {
-		turnPageRight();
-		selectedTab = 1;
-		spellSite = 0;
-	}
-	computeSpellsPerArea();
-}
-
-void CSpellWindow::fspellsWb()
-{
-	if (selectedTab != 2) {
-		turnPageRight();
-		selectedTab = 2;
-		spellSite = 0;
-	}
-	computeSpellsPerArea();
-}
-
-void CSpellWindow::fspellsAllb()
-{
-	if (selectedTab != 4) {
+	if (selectedTab != school) 
+	{
 		turnPageRight();
-		selectedTab = 4;
-		spellSite = 0;
+		selectedTab = school;
+		currentPage = 0;
 	}
 	computeSpellsPerArea();
 }
 
 void CSpellWindow::fLcornerb()
 {
-	if(spellSite>0) {
+	if(currentPage>0) 
+	{
 		turnPageLeft();
-		--spellSite;
+		--currentPage;
 	}
 	computeSpellsPerArea();
+	GH.breakEventHandling();
 }
 
 void CSpellWindow::fRcornerb()
 {
-	if((spellSite + 1) < (battleSpellsOnly ? sitesPerTabBattle[selectedTab] : sitesPerTabAdv[selectedTab])) {
+	if((currentPage + 1) < (pagesWithinCurrentTab())) 
+	{
 		turnPageRight();
-		++spellSite;
+		++currentPage;
 	}
 	computeSpellsPerArea();
+	GH.breakEventHandling();
 }
 
-void CSpellWindow::show(SDL_Surface *to)
+void CSpellWindow::showAll(SDL_Surface *to)
 {
 	SDL_BlitSurface(background, NULL, to, &pos);
 	blitAt(spellTab->ourImages[selectedTab].bitmap, 524 + pos.x, 88 + pos.y, to);
@@ -423,20 +324,20 @@ void CSpellWindow::show(SDL_Surface *to)
 	mana<<myHero->mana;
 	CSDL_Ext::printAtMiddle(mana.str(), pos.x+435, pos.y +426, FONT_SMALL, tytulowy, to);
 	
-	statusBar->show(to);
+	statusBar->showAll(to);
 
 	//printing school images
-	if(selectedTab!=4 && spellSite == 0)
+	if(selectedTab!=4 && currentPage == 0)
 	{
 		blitAt(schools->ourImages[selectedTab].bitmap, 117 + pos.x, 74 + pos.y, to);
 	}
 
 	//printing corners
-	if(spellSite!=0)
+	if(currentPage!=0)
 	{
 		blitAt(leftCorner, lCorner->pos.x, lCorner->pos.y, to);
 	}
-	if((spellSite+1) < (battleSpellsOnly ? sitesPerTabBattle[selectedTab] : sitesPerTabAdv[selectedTab]) )
+	if((currentPage+1) < (pagesWithinCurrentTab()) )
 	{
 		blitAt(rightCorner, rCorner->pos.x, rCorner->pos.y, to);
 	}
@@ -444,48 +345,7 @@ void CSpellWindow::show(SDL_Surface *to)
 	//printing spell info
 	for(int b=0; b<12; ++b)
 	{
-		if(spellAreas[b]->mySpell == -1)
-			continue;
-		const CSpell * spell = &CGI->spellh->spells[spellAreas[b]->mySpell];
-		//int b2 = -1; //TODO use me
-
-		blitAt(spells->ourImages[spellAreas[b]->mySpell].bitmap, spellAreas[b]->pos.x, spellAreas[b]->pos.y, to);
-
-		Uint8 bestSchool = -1,
-			bestslvl =  myHero->getSpellSchoolLevel( spell );
-
-		if(spell->air)
-			bestSchool = 0;
-		if(spell->fire)
-			bestSchool = 1;
-		if(spell->water)
-			bestSchool = 2;
-		if(spell->earth)
-			bestSchool = 3;
-
-		//printing border (indicates level of magic school)
-		blitAt(schoolBorders[bestSchool]->ourImages[bestslvl].bitmap, spellAreas[b]->pos.x, spellAreas[b]->pos.y, to);
-
-		SDL_Color firstLineColor, secondLineColor;
-		if(myInt->cb->getSpellCost(spell, myHero) > myHero->mana) //hero cannot cast this spell
-		{
-			firstLineColor = zwykly;
-			secondLineColor = darkTitle;
-		}
-		else
-		{
-			firstLineColor = tytulowy;
-			secondLineColor = zwykly;
-		}
-		//printing spell's name
-		CSDL_Ext::printAtMiddle(spell->name, spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 70, FONT_TINY, firstLineColor, to);
-		//printing lvl
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[171 + spell->level], spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 82, FONT_TINY, secondLineColor, to);
-		//printing  cost
-		std::ostringstream ss;
-		ss<<CGI->generaltexth->allTexts[387]<<": "<<myInt->cb->getSpellCost(spell, myHero);
-
-		CSDL_Ext::printAtMiddle(ss.str(), spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 94, FONT_TINY, secondLineColor, to);
+		spellAreas[b]->showAll(to);
 	}
 }
 
@@ -541,7 +401,7 @@ void CSpellWindow::computeSpellsPerArea()
 	{
 		if(spellsCurSite.size() > 12)
 		{
-			spellsCurSite = std::vector<ui32>(spellsCurSite.begin() + spellSite*12, spellsCurSite.end());
+			spellsCurSite = std::vector<ui32>(spellsCurSite.begin() + currentPage*12, spellsCurSite.end());
 			if(spellsCurSite.size() > 12)
 			{
 				spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end());
@@ -552,13 +412,13 @@ void CSpellWindow::computeSpellsPerArea()
 	{
 		if(spellsCurSite.size() > 10)
 		{
-			if(spellSite == 0)
+			if(currentPage == 0)
 			{
 				spellsCurSite.erase(spellsCurSite.begin()+10, spellsCurSite.end());
 			}
 			else
 			{
-				spellsCurSite = std::vector<ui32>(spellsCurSite.begin() + (spellSite-1)*12 + 10, spellsCurSite.end());
+				spellsCurSite = std::vector<ui32>(spellsCurSite.begin() + (currentPage-1)*12 + 10, spellsCurSite.end());
 				if(spellsCurSite.size() > 12)
 				{
 					spellsCurSite.erase(spellsCurSite.begin()+12, spellsCurSite.end());
@@ -567,33 +427,33 @@ void CSpellWindow::computeSpellsPerArea()
 		}
 	}
 	//applying
-	if(selectedTab == 4 || spellSite != 0)
+	if(selectedTab == 4 || currentPage != 0)
 	{
 		for(size_t c=0; c<12; ++c)
 		{
 			if(c<spellsCurSite.size())
 			{
-				spellAreas[c]->mySpell = spellsCurSite[c];
+				spellAreas[c]->setSpell(spellsCurSite[c]);
 			}
 			else
 			{
-				spellAreas[c]->mySpell = -1;
+				spellAreas[c]->setSpell(-1);
 			}
 		}
 	}
 	else
 	{
-		spellAreas[0]->mySpell = -1;
-		spellAreas[1]->mySpell = -1;
+		spellAreas[0]->setSpell(-1);
+		spellAreas[1]->setSpell(-1);
 		for(size_t c=0; c<10; ++c)
 		{
 			if(c<spellsCurSite.size())
-				spellAreas[c+2]->mySpell = spellsCurSite[c];
+				spellAreas[c+2]->setSpell(spellsCurSite[c]);
 			else
-				spellAreas[c+2]->mySpell = -1;
+				spellAreas[c+2]->setSpell(-1);
 		}
 	}
-
+	redraw();
 }
 
 void CSpellWindow::activate()
@@ -610,13 +470,13 @@ void CSpellWindow::activate()
 	selectSpellsW->activate();
 	selectSpellsAll->activate();
 
-	lCorner->activate();
-	rCorner->activate();
-
 	for(int g=0; g<12; ++g)
 	{
 		spellAreas[g]->activate();
 	}
+
+	lCorner->activate();
+	rCorner->activate();
 }
 
 void CSpellWindow::deactivate()
@@ -632,14 +492,14 @@ void CSpellWindow::deactivate()
 	selectSpellsF->deactivate();
 	selectSpellsW->deactivate();
 	selectSpellsAll->deactivate();
-	
-	lCorner->deactivate();
-	rCorner->deactivate();
 
 	for(int g=0; g<12; ++g)
 	{
 		spellAreas[g]->deactivate();
 	}
+
+	lCorner->deactivate();
+	rCorner->deactivate();
 }
 
 void CSpellWindow::turnPageLeft()
@@ -656,12 +516,62 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
 {
 	if(key.keysym.sym == SDLK_ESCAPE ||  key.keysym.sym == SDLK_RETURN)
 		fexitb();
+
+	if(key.state == SDL_PRESSED)
+	{
+		switch(key.keysym.sym)
+		{
+		case SDLK_LEFT:
+			fLcornerb();
+			break;
+		case SDLK_RIGHT:
+			fRcornerb();
+			break;
+		case SDLK_UP:
+		case SDLK_DOWN:
+			bool down = key.keysym.sym == SDLK_DOWN;
+			static const int schoolsOrder[] = {0, 3, 1, 2, 4};
+			int index = -1;
+			while(schoolsOrder[++index] != selectedTab);
+			index += (down ? 1 : -1);
+			abetw(index, 0, ARRAY_COUNT(schoolsOrder) - 1);
+			if(selectedTab != schoolsOrder[index])
+				selectSchool(schoolsOrder[index]);
+			break;
+		}
+
+		//alt + 1234567890-= casts spell from 1 - 12 slot
+		if(LOCPLINT->altPressed())
+		{
+			SDLKey hlpKey = key.keysym.sym;
+			if(isNumKey(hlpKey, false))
+				hlpKey = numToDigit(hlpKey);
+
+			static const SDLKey spellSelectors[] = {SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, SDLK_7, SDLK_8, SDLK_9, SDLK_0, SDLK_MINUS, SDLK_EQUALS};
+
+			int index = -1;
+			while(++index < ARRAY_COUNT(spellSelectors) && spellSelectors[index] != hlpKey);
+			if(index >= ARRAY_COUNT(spellSelectors))
+				return;
+
+			//try casting spell
+			spellAreas[index]->clickLeft(false, true);
+		}
+	}
+}
+
+Uint8 CSpellWindow::pagesWithinCurrentTab()
+{
+	return battleSpellsOnly ? sitesPerTabBattle[selectedTab] : sitesPerTabAdv[selectedTab];
 }
 
 CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)
 {
 	this->pos = pos;
 	this->owner = owner;
+	used = LCLICK | RCLICK | HOVER;
+
+	spellCost = mySpell = whichSchool = schoolLevel = -1;
 }
 
 void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
@@ -669,9 +579,26 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 	if(!down && mySpell!=-1)
 	{
 		const CSpell *sp = &CGI->spellh->spells[mySpell];
+
 		int spellCost = owner->myInt->cb->getSpellCost(sp, owner->myHero);
+		if(spellCost > owner->myHero->mana) //insufficient mana
+		{
+			char msgBuf[500];
+			sprintf(msgBuf, CGI->generaltexth->allTexts[206].c_str(), spellCost, owner->myHero->mana);
+			owner->myInt->showInfoDialog(std::string(msgBuf));
+		}
+
+		//battle spell on adv map or adventure map spell during combat => display infowindow, not cast
+		if(sp->combatSpell && !owner->myInt->battleInt
+			|| !sp->combatSpell && owner->myInt->battleInt)
+		{
+			std::vector<SComponent*> hlp(1, new SComponent(SComponent::spell, mySpell, 0));
+			LOCPLINT->showInfoDialog(sp->descriptions[schoolLevel], hlp);
+			return;
+		}
+
 		//we will cast a spell
-		if(owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell() && spellCost <= owner->myHero->mana) //if battle window is open
+		if(sp->combatSpell && owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell()) //if battle window is open
 		{
 			int spell = mySpell;
 			owner->fexitb();
@@ -679,50 +606,40 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 		}
 		else //adventure spell
 		{
-			//insufficient mana
-			if(spellCost > owner->myHero->mana)
-			{
-				char msgBuf[500];
-				sprintf(msgBuf, CGI->generaltexth->allTexts[206].c_str(), spellCost, owner->myHero->mana);
-				owner->myInt->showInfoDialog(std::string(msgBuf));
-			}
-			else
-			{
-				using namespace Spells;
-				int spell = mySpell;
-				const CGHeroInstance *h = owner->myHero;
-				owner->fexitb();
+			using namespace Spells;
+			int spell = mySpell;
+			const CGHeroInstance *h = owner->myHero;
+			owner->fexitb();
 
-				switch(spell)
+			switch(spell)
+			{
+			case SUMMON_BOAT:
 				{
-				case SUMMON_BOAT:
+					int3 pos = h->bestLocation();
+					if(pos.x < 0)
 					{
-						int3 pos = h->bestLocation();
-						if(pos.x < 0)
-						{
-							LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[334]); //There is no place to put the boat.
-							return;
-						}
+						LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[334]); //There is no place to put the boat.
+						return;
 					}
-					break;
-				case SCUTTLE_BOAT:
-				case DIMENSION_DOOR:
-					adventureInt->enterCastingMode(sp);
-					return;
-				case VISIONS:
-				case VIEW_EARTH:
-				case DISGUISE:
-				case VIEW_AIR:
-				case FLY:
-				case WATER_WALK:
-				case TOWN_PORTAL:
-					break;
-				default:
-					assert(0);
 				}
-
-				LOCPLINT->cb->castSpell(h, spell);
+				break;
+			case SCUTTLE_BOAT:
+			case DIMENSION_DOOR:
+				adventureInt->enterCastingMode(sp);
+				return;
+			case VISIONS:
+			case VIEW_EARTH:
+			case DISGUISE:
+			case VIEW_AIR:
+			case FLY:
+			case WATER_WALK:
+			case TOWN_PORTAL:
+				break;
+			default:
+				assert(0);
 			}
+
+			LOCPLINT->cb->castSpell(h, spell);
 		}
 	}
 }
@@ -743,7 +660,7 @@ void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState)
 
 		SDL_Surface *spellBox = CMessage::drawBoxTextBitmapSub(
 			owner->myInt->playerID,
-			CGI->spellh->spells[mySpell].descriptions[0] + dmgInfo, this->owner->spells->ourImages[mySpell].bitmap,
+			CGI->spellh->spells[mySpell].descriptions[schoolLevel] + dmgInfo, this->owner->spells->ourImages[mySpell].bitmap,
 			CGI->spellh->spells[mySpell].name,30,30);
 		CInfoPopup *vinya = new CInfoPopup(spellBox, true);
 		GH.pushInt(vinya);
@@ -768,16 +685,45 @@ void CSpellWindow::SpellArea::hover(bool on)
 	}
 }
 
-void CSpellWindow::SpellArea::activate()
+void CSpellWindow::SpellArea::showAll(SDL_Surface *to)
 {
-	activateLClick();
-	activateRClick();
-	activateHover();
+	if(mySpell < 0)
+		return;
+
+	const CSpell * spell = &CGI->spellh->spells[mySpell];
+
+	blitAt(owner->spells->ourImages[mySpell].bitmap, pos.x, pos.y, to);
+	blitAt(owner->schoolBorders[owner->selectedTab >= 4 ? whichSchool : owner->selectedTab]->ourImages[schoolLevel].bitmap, pos.x, pos.y, to); //printing border (indicates level of magic school)
+
+	SDL_Color firstLineColor, secondLineColor;
+	if(spellCost > owner->myHero->mana) //hero cannot cast this spell
+	{
+		static const SDL_Color unavailableSpell = {239, 189, 33, 0};
+		firstLineColor = zwykly;
+		secondLineColor = unavailableSpell;
+	}
+	else
+	{
+		firstLineColor = tytulowy;
+		secondLineColor = zwykly;
+	}
+	//printing spell's name
+	CSDL_Ext::printAtMiddle(spell->name, pos.x + 39, pos.y + 70, FONT_TINY, firstLineColor, to);
+	//printing lvl
+	CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[171 + spell->level], pos.x + 39, pos.y + 82, FONT_TINY, secondLineColor, to);
+	//printing  cost
+	std::ostringstream ss;
+	ss << CGI->generaltexth->allTexts[387] << ": " << spellCost;
+	CSDL_Ext::printAtMiddle(ss.str(), pos.x + 39, pos.y + 94, FONT_TINY, secondLineColor, to);
 }
 
-void CSpellWindow::SpellArea::deactivate()
+void CSpellWindow::SpellArea::setSpell(int spellID)
 {
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-}
+	mySpell = spellID;
+	if(mySpell < 0)
+		return;
+
+	const CSpell * spell = &CGI->spellh->spells[mySpell];
+	schoolLevel = owner->myHero->getSpellSchoolLevel(spell, &whichSchool);
+	spellCost = owner->myInt->cb->getSpellCost(spell, owner->myHero);
+}

+ 11 - 13
client/CSpellWindow.h

@@ -34,8 +34,6 @@ public:
 	void clickLeft(tribool down, bool previousState);
 	void clickRight(tribool down, bool previousState);
 	void hover(bool on);
-	void activate();
-	void deactivate();
 
 	SpellbookInteractiveArea(const SDL_Rect & myRect, boost::function<void()> funcL, const std::string & textR,
 		boost::function<void()> funcHon, boost::function<void()> funcHoff, CPlayerInterface * _myInt);//c-tor
@@ -48,14 +46,19 @@ private:
 	{
 	public:
 		int mySpell;
+		int schoolLevel; //range: 0 none, 3 - expert
+		int whichSchool; //0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
+		int spellCost;
 		CSpellWindow * owner;
 
 		SpellArea(SDL_Rect pos, CSpellWindow * owner);
+
+		void setSpell(int spellID);
+
 		void clickLeft(tribool down, bool previousState);
 		void clickRight(tribool down, bool previousState);
 		void hover(bool on);
-		void activate();
-		void deactivate();
+		void showAll(SDL_Surface *to);
 	};
 
 	SDL_Surface * background, * leftCorner, * rightCorner;
@@ -75,9 +78,8 @@ private:
 
 	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 spellSite; //changes when corners are clicked
+	Uint8 currentPage; //changes when corners are clicked
 	std::set<ui32> mySpells; //all spels in this spellbook
-	Uint8 schoolLvls[4]; //levels of magic for different schools: [0]: air, [1]: fire, [2]: water, [3]: earth; 0 - none, 1 - beginner, 2 - medium, 3 - expert
 
 	const CGHeroInstance * myHero; //hero whose spells are presented
 
@@ -98,19 +100,15 @@ public:
 	void fbattleSpellsb();
 	void fmanaPtsb();
 
-	void fspellsAb();
-	void fspellsEb();
-	void fspellsFb();
-	void fspellsWb();
-	void fspellsAllb();
-
 	void fLcornerb();
 	void fRcornerb();
 
+	void selectSchool(int school); //schools: 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools
+	Uint8 pagesWithinCurrentTab();
 	void keyPressed(const SDL_KeyboardEvent & key);
 	void activate();
 	void deactivate();
-	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
 };
 
 #endif // __CSPELLWINDOW_H__

+ 27 - 1
client/GUIBase.cpp

@@ -362,6 +362,11 @@ CGuiHandler::~CGuiHandler()
 
 }
 
+void CGuiHandler::breakEventHandling()
+{
+	current = NULL;
+}
+
 void CIntObject::activateLClick()
 {
 	GH.lclickable.push_front(this);
@@ -931,7 +936,28 @@ SDLKey arrowToNum( SDLKey key )
 
 SDLKey numToDigit( SDLKey key )
 {
-	return SDLKey(key - SDLK_KP0 + SDLK_0);
+	if(key >= SDLK_KP0 && key <= SDLK_KP9)
+		return SDLKey(key - SDLK_KP0 + SDLK_0);
+
+#define REMOVE_KP(keyName) case SDLK_KP_ ## keyName ## : return SDLK_ ## keyName;
+	switch(key)
+	{
+		REMOVE_KP(PERIOD)
+		REMOVE_KP(MINUS)
+		REMOVE_KP(PLUS)
+		REMOVE_KP(EQUALS)
+			
+	case SDLK_KP_MULTIPLY:
+		return SDLK_ASTERISK;
+	case SDLK_KP_DIVIDE:
+		return SDLK_SLASH;
+	case SDLK_KP_ENTER:
+		return SDLK_RETURN;
+	default:
+		tlog3 << "Illegal numkey conversion!" << std::endl;
+		return SDLK_UNKNOWN;
+	}
+#undef REMOVE_KP
 }
 
 bool isNumKey( SDLKey key, bool number )

+ 1 - 0
client/GUIBase.h

@@ -509,6 +509,7 @@ public:
 	void handleMouseMotion(SDL_Event *sEvent);
 	void handleMoveInterested( const SDL_MouseMotionEvent & motion );
 	void fakeMouseMove();
+	void breakEventHandling(); //current event won't be propagated anymore
 	ui8 defActionsDef; //default auto actions
 	ui8 captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
 	std::list<CIntObject *> createdObj; //stack of objs being created

+ 4 - 3
client/GUIClasses.cpp

@@ -632,6 +632,7 @@ CInfoWindow::CInfoWindow(std::string Text, int player, int charperline, const st
 	{
 		comps[i]->recActions = 0xff;
 		addChild(comps[i]);
+		comps[i]->recActions &= ~(SHOWALL | UPDATE);
 		components.push_back(comps[i]);
 	}
 	setDelComps(delComps);
@@ -1168,7 +1169,7 @@ void CStatusBar::clear()
 	if(LOCPLINT->cingconsole->enteredText == "") //for appropriate support for in-game console
 	{
 		current="";
-		show(screen);
+		redraw();
 	}
 }
 
@@ -1177,7 +1178,7 @@ void CStatusBar::print(const std::string & text)
 	if(LOCPLINT->cingconsole->enteredText == "" || text == LOCPLINT->cingconsole->enteredText) //for appropriate support for in-game console
 	{
 		current=text;
-		show(GH.topInt()==adventureInt ? screen : screen2); //if there are now windows opened, update statusbar on screen, else to cache surface
+		redraw();
 	}
 }
 
@@ -6206,7 +6207,7 @@ void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
 	if(key.keysym.sym == SDLK_TAB)
 	{
 		moveFocus();
-		GH.current = NULL;
+		GH.breakEventHandling();
 		return;
 	}
 

+ 24 - 23
hch/CObjectHandler.cpp

@@ -1221,30 +1221,31 @@ int CGHeroInstance::getTotalStrength() const
 	return (int) ret;
 }
 
-ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell) const
-{
-	ui8 skill = 0; //skill level
-
-	if(spell->fire)
-		skill = std::max(skill,getSecSkillLevel(14));
-	if(spell->air)
-		skill = std::max(skill,getSecSkillLevel(15));
-	if(spell->water)
-		skill = std::max(skill,getSecSkillLevel(16));
-	if(spell->earth)
-		skill = std::max(skill,getSecSkillLevel(17));
-
-	//bonuses (eg. from special terrains)
-	skill = std::max<ui8>(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
-	if(spell->fire)
-		skill = std::max<ui8>(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1));
-	if(spell->air)
-		skill = std::max<ui8>(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 2));
-	if(spell->water)
-		skill = std::max<ui8>(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 4));
-	if(spell->earth)
-		skill = std::max<ui8>(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 8));
+ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool) const
+{
+	si16 skill = -1; //skill level
+
+#define TRY_SCHOOL(schoolName, schoolMechanicsId, schoolOutId)	\
+	if(spell-> ## schoolName)									\
+	{															\
+		int thisSchool = std::max<int>(getSecSkillLevel(14 + (schoolMechanicsId)), valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << (schoolMechanicsId))); \
+		if(thisSchool > skill)									\
+		{														\
+			skill = thisSchool;									\
+			if(outSelectedSchool)								\
+				*outSelectedSchool = schoolOutId;				\
+		}														\
+	}
+	TRY_SCHOOL(fire, 0, 1)
+	TRY_SCHOOL(air, 1, 0)
+	TRY_SCHOOL(water, 2, 2)
+	TRY_SCHOOL(earth, 3, 3)
+#undef TRY_SCHOOL;
+
+
 
+	amax(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
+	assert(skill >= 0 && skill <= 3);
 	return skill;
 }
 

+ 1 - 1
hch/CObjectHandler.h

@@ -366,7 +366,7 @@ public:
 	static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
 	double getHeroStrength() const;
 	int getTotalStrength() const;
-	ui8 getSpellSchoolLevel(const CSpell * spell) const; //returns level on which given spell would be cast by this hero (0 - none, 1 - basic etc)
+	ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = NULL) const; //returns level on which given spell would be cast by this hero (0 - none, 1 - basic etc); optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
 	bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
 	CStackInstance calculateNecromancy (const BattleResult &battleResult) const;
 	void showNecromancyDialog(const CStackInstance &raisedStack) const;