浏览代码

- Full support for scholar skill
- Some code for #366
- Fixed R-click issue from rev 1516

Ivan Savenko 15 年之前
父节点
当前提交
32b6b9cb17
共有 7 个文件被更改,包括 130 次插入110 次删除
  1. 7 4
      client/CCastleInterface.cpp
  2. 2 1
      client/CCastleInterface.h
  3. 22 40
      client/CKingdomInterface.cpp
  4. 4 5
      client/CKingdomInterface.h
  5. 17 38
      client/GUIClasses.cpp
  6. 1 1
      client/GUIClasses.h
  7. 77 21
      server/CGameHandler.cpp

+ 7 - 4
client/CCastleInterface.cpp

@@ -429,6 +429,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
 	count=0;
 	town = Town;
 	animval = 0;
+	winMode = 1;
 
 	//garrison
 	garr = new CGarrisonInt(pos.x+305,pos.y+387,4,Point(0,96),townInt,Point(62,374),town,town->visitingHero);
@@ -789,7 +790,7 @@ void CCastleInterface::showAll( SDL_Surface * to/*=NULL*/)
 		creainfo[i]->show(to);
 
 	//print name
-	CSDL_Ext::printAt(town->name,pos.x+85,pos.y+389,FONT_SMALL,zwykly,to);
+	CSDL_Ext::printAt(town->name,pos.x+85,pos.y+387,FONT_MEDIUM,zwykly,to);
 	//blit town icon
 	int pom = town->subID*2;
 	if (!town->hasFort())
@@ -895,6 +896,8 @@ void CCastleInterface::deactivate()
 void CCastleInterface::addBuilding(int bid)
 {
 	//TODO: lepiej by bylo tylko dodawac co trzeba pamietajac o grupach
+	if ( winMode == 2 )//we will only build buildings, no need to update interface - it will be closed in a moment
+		return;
 	deactivate();
 	recreateBuildings();
 	recreateIcons();
@@ -1537,7 +1540,7 @@ CHallInterface::~CHallInterface()
 }
 void CHallInterface::close()
 {
-	GH.popIntTotally(this);
+	GH.popInts(LOCPLINT->castleInt->winMode == 2? 2 : 1 );
 }
 void CHallInterface::show(SDL_Surface * to)
 {
@@ -1598,8 +1601,8 @@ void CHallInterface::CBuildWindow::deactivate()
 void CHallInterface::CBuildWindow::Buy()
 {
 	int building = bid;
-	GH.popInts(2); //we - build window and hall screen
 	LOCPLINT->cb->buildBuilding(LOCPLINT->castleInt->town,building);
+	GH.popInts(LOCPLINT->castleInt->winMode == 2? 3 : 2 ); //we - build window and hall screen
 }
 
 void CHallInterface::CBuildWindow::close()
@@ -1770,7 +1773,7 @@ void CFortScreen::deactivate()
 
 void CFortScreen::close()
 {
-	GH.popIntTotally(this);
+	GH.popInts(LOCPLINT->castleInt->winMode == 3? 2 : 1 );
 }
 
 CFortScreen::CFortScreen( CCastleInterface * owner )

+ 2 - 1
client/CCastleInterface.h

@@ -106,6 +106,7 @@ public:
 	CStatusBar * statusbar;
 	CResDataBar *resdatabar;
 	unsigned char animval, count;
+	int winMode;//0=right-click popup, 1 = normal, 2 = town hall only, 3 = fort only;
 
 	CDefEssential *bars, //0 - yellow, 1 - green, 2 - red, 3 - gray
 		*status; //0 - already, 1 - can't, 2 - lack of resources
@@ -231,7 +232,7 @@ public:
 
 class CMageGuildScreen : public CIntObject
 {
-public:	
+public:
 	class Scroll : public CIntObject
 	{
 	public:

+ 22 - 40
client/CKingdomInterface.cpp

@@ -488,14 +488,17 @@ CKingdomInterface::CTownItem::CTownItem(int num, CKingdomInterface * Owner)
 		creaCount[i]->pos = genRect(32, 32, pos.x+409+i*37, pos.y + 78);
 		creaCount[i]->type = i;
 	}
-	hallArea = new HoverableArea();
+	hallArea = new LRClickableAreaOpenTown();
 	hallArea->pos = genRect(38, 38, pos.x+69, pos.y + 31);
+	hallArea->type = 2;
 
-	fortArea = new HoverableArea();
+	fortArea = new LRClickableAreaOpenTown();
 	fortArea->pos = genRect(38, 38, pos.x+111, pos.y + 31);
+	fortArea->type = 3;
 
 	townImage = new LRClickableAreaOpenTown();
 	townImage->pos = genRect(64, 58, pos.x+5, pos.y + 6);
+	townImage->type = 1;
 
 	incomeArea = new HoverableArea();
 	incomeArea->pos = genRect(42, 64, pos.x+154, pos.y + 31);
@@ -560,10 +563,14 @@ void CKingdomInterface::CTownItem::setTown(const CGTownInstance * newTown)
 
 	townImage->hoverText = town->name;
 	townImage->town = town;
+	hallArea->town = town;
 
 	hallArea->hoverText = CGI->buildh->buildings[town->subID][10+town->hallLevel()]->Name();
 	if (town->hasFort())
+	{
 		fortArea->hoverText = CGI->buildh->buildings[town->subID][6+town->fortLevel()]->Name();
+		fortArea->town = town;
+	}
 	else
 		fortArea->hoverText = "";
 }
@@ -609,11 +616,12 @@ void CKingdomInterface::CTownItem::deactivate()
 		visitHero->deactivate();
 
 	for (int i=0; i<CREATURES_PER_TOWN;i++)
-		if (vstd::contains(town->builtBuildings,30+i))
+		if (creaCount[i]->active)
 		{
 			creaGrowth[i]->deactivate();
 			creaCount [i]->deactivate();
-		}	garr->deactivate();
+		}
+	garr->deactivate();
 }
 
 void CKingdomInterface::CTownItem::showAll(SDL_Surface * to)
@@ -741,10 +749,10 @@ CKingdomInterface::CHeroItem::CHeroItem(int num, CKingdomInterface * Owner)
 	experience->pos = genRect(33, 49, pos.x+322, pos.y+5);
 	experience->hoverText = CGI->generaltexth->heroscrn[9];
 
-	morale = new LRClickableAreaWTextComp();
+	morale = new MoraleLuckBox();
 	morale->pos = genRect(20,32,pos.x+221,pos.y+52);
 
-	luck = new LRClickableAreaWTextComp();
+	luck = new MoraleLuckBox();
 	luck->pos = genRect(20,32,pos.x+221,pos.y+28);
 
 	spellPoints = new LRClickableAreaWText();
@@ -807,7 +815,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 	for (int i=0; i<artifacts.size(); i++)
 	{
 		artifacts[i]->type = hero->getArtAtPos(i);
-		if (artifacts[i]->type<0)
+		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
 			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
 		else
 		{
@@ -841,7 +849,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 	//secondary skills
 	for(size_t g=0; g<std::min(secondarySkills.size(),hero->secSkills.size()); ++g)
 	{
-		int skill = hero->secSkills[g].first, 
+		int skill = hero->secSkills[g].first,
 		    level = hero->secSkills[g].second;
 		secondarySkills[g]->type = skill;
 		secondarySkills[g]->bonus = level;
@@ -859,35 +867,9 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 	sprintf(bufor, CGI->generaltexth->allTexts[205].c_str(), hero->name.c_str(), hero->mana, hero->manaLimit());
 	spellPoints->text = std::string(bufor);
 
-	//setting morale
-	std::vector<std::pair<int,std::string> > mrl = hero->getCurrentMoraleModifiers();
-	int mrlv = hero->getCurrentMorale();
-	int mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale, 0 - neutral, 1 - good
-	morale->hoverText = CGI->generaltexth->heroscrn[4 - mrlt];
-	morale->baseType = SComponent::morale;
-	morale->bonus = mrlv;
-	morale->text = CGI->generaltexth->arraytxt[88];
-	boost::algorithm::replace_first(morale->text,"%s",CGI->generaltexth->arraytxt[86-mrlt]);
-	if (!mrl.size())
-		morale->text += CGI->generaltexth->arraytxt[108];
-	else
-		for(int it=0; it < mrl.size(); it++)
-			morale->text += "\n" + mrl[it].second;
-
-	//setting luck
-	mrl = hero->getCurrentLuckModifiers();
-	mrlv = hero->getCurrentLuck();
-	mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck, 0 - neutral, 1 - good
-	luck->hoverText = CGI->generaltexth->heroscrn[7 - mrlt];
-	luck->baseType = SComponent::luck;
-	luck->bonus = mrlv;
-	luck->text = CGI->generaltexth->arraytxt[62];
-	boost::algorithm::replace_first(luck->text,"%s",CGI->generaltexth->arraytxt[60-mrlt]);
-	if (!mrl.size())
-		luck->text += CGI->generaltexth->arraytxt[77];
-	else
-		for(int it=0; it < mrl.size(); it++)
-			luck->text += "\n" + mrl[it].second;
+	//setting morale and luck
+	morale->set(true,hero);
+	luck->set(false,hero);
 }
 
 void CKingdomInterface::CHeroItem::scrollArts(int move)
@@ -1065,8 +1047,8 @@ void CKingdomInterface::CHeroItem::CArtPlace::activate()
 
 void CKingdomInterface::CHeroItem::CArtPlace::clickLeft(tribool down, bool previousState)
 {
-	if (!down && previousState && type>=0)
-	{
+	if (!down && previousState && type>=0 && type < 145)
+	{tlog1<<type;
 		if(type == 0)
 		{
 			CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), hero->hero, LOCPLINT);
@@ -1079,7 +1061,7 @@ void CKingdomInterface::CHeroItem::CArtPlace::clickLeft(tribool down, bool previ
 
 void CKingdomInterface::CHeroItem::CArtPlace::clickRight(tribool down, bool previousState)
 {
-	if (type>=0)
+	if (type>=0 && type < 145)
 		LRClickableAreaWTextComp::clickRight(down, previousState);
 }
 

+ 4 - 5
client/CKingdomInterface.h

@@ -13,8 +13,7 @@ class CStatusBar;
 class CSlider;
 class CMinorResDataBar;
 class HoverableArea;
-/*class LRClickableAreaWText
-class LRClickableAreaWTextComp*/
+class MoraleLuckBox;
 
 /*
  * CKingdomInterface.h, part of VCMI engine
@@ -44,9 +43,9 @@ class CKingdomInterface : public CIntObject
 		const CGTownInstance * town;
 		CKingdomInterface * owner;
 		int numb;//position on screen (1..size)
-		HoverableArea *hallArea, *fortArea, *incomeArea;//hoverable text for town hall, fort, income
+		HoverableArea *incomeArea;//hoverable text for town hall, fort, income
 		LRClickableAreaOpenHero * garrHero, *visitHero;//portraits of heroes
-		LRClickableAreaOpenTown * townImage;//town image
+		LRClickableAreaOpenTown *hallArea, *fortArea,  * townImage;//town image
 		std::vector < HoverableArea * > creaGrowth;
 		std::vector < CCreaPlace * > creaCount;
 		void setTown(const CGTownInstance * newTown);//change town and update info
@@ -77,7 +76,7 @@ class CKingdomInterface : public CIntObject
 		AdventureMapButton * artLeft, * artRight;//buttons for backpack
 		LRClickableAreaOpenHero * portrait;
 		LRClickableAreaWText * experience;
-		LRClickableAreaWTextComp * morale, * luck;
+		MoraleLuckBox * morale, * luck;
 		LRClickableAreaWText * spellPoints;
 		LRClickableAreaWText * speciality;
 		std::vector<LRClickableAreaWTextComp *> primarySkills;

+ 17 - 38
client/GUIClasses.cpp

@@ -1204,7 +1204,6 @@ CList::CList(int Size)
 
 void CList::fixPos()
 {
-	int oldFrom = from;
 	if(selected < 0) //no selection, do nothing
 		return;
 	if(selected < from) //scroll up
@@ -3691,7 +3690,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 
 void CArtPlace::clickRight(tribool down, bool previousState)
 {
-	if(ourArt && !locked() && text.size()) { //if there is no description or it's a lock, do nothing ;]
+	if(down && ourArt && !locked() && text.size()) { //if there is no description or it's a lock, do nothing ;]
 		if (slotID < 19) {
 			selectedNo = false;
 
@@ -3975,13 +3974,20 @@ void LRClickableAreaOpenHero::clickRight(tribool down, bool previousState)
 void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
 {
 	if((!down) && previousState && town)
+		{
 		LOCPLINT->openTownWindow(town);
+		LOCPLINT->castleInt->winMode = type;
+		if ( type == 2 )
+			LOCPLINT->castleInt->buildingClicked(10);
+		else if ( type == 3 && town->fortLevel() )
+			LOCPLINT->castleInt->buildingClicked(7);
+		}
 }
 
 void LRClickableAreaOpenTown::clickRight(tribool down, bool previousState)
 {
 	if((!down) && previousState && town)
-		LOCPLINT->openTownWindow(town);
+		LOCPLINT->openTownWindow(town);//TODO: popup?
 }
 
 void CArtifactsOfHero::activate()
@@ -4577,40 +4583,13 @@ CExchangeWindow::CExchangeWindow(si32 hero1, si32 hero2) : bg(NULL)
 		spellPoints[b]->text = std::string(bufor);
 
 		//setting morale
-		morale[b] = new LRClickableAreaWTextComp();
+		morale[b] = new MoraleLuckBox();
 		morale[b]->pos = genRect(32, 32, pos.x + 177 + 490*b, pos.y + 45);
-
-		std::vector<std::pair<int,std::string> > mrl = heroInst[b]->getCurrentMoraleModifiers();
-		int mrlv = heroInst[b]->getCurrentMorale();
-		int mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale[b], 0 - neutral, 1 - good
-		morale[b]->hoverText = CGI->generaltexth->heroscrn[4 - mrlt];
-		morale[b]->baseType = SComponent::morale;
-		morale[b]->bonus = mrlv;
-		morale[b]->text = CGI->generaltexth->arraytxt[88];
-		boost::algorithm::replace_first(morale[b]->text,"%s",CGI->generaltexth->arraytxt[86-mrlt]);
-		if (!mrl.size())
-			morale[b]->text += CGI->generaltexth->arraytxt[108];
-		else
-			for(int it=0; it < mrl.size(); it++)
-				morale[b]->text += "\n" + mrl[it].second;
-
+		morale[b]->set(true,heroInst[b]);
 		//setting luck
-		luck[b] = new LRClickableAreaWTextComp();
+		luck[b] = new MoraleLuckBox();
 		luck[b]->pos = genRect(32, 32, pos.x + 213 + 490*b, pos.y + 45);
-
-		mrl = heroInst[b]->getCurrentLuckModifiers();
-		mrlv = heroInst[b]->getCurrentLuck();
-		mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck[b], 0 - neutral, 1 - good
-		luck[b]->hoverText = CGI->generaltexth->heroscrn[7 - mrlt];
-		luck[b]->baseType = SComponent::luck;
-		luck[b]->bonus = mrlv;
-		luck[b]->text = CGI->generaltexth->arraytxt[62];
-		boost::algorithm::replace_first(luck[b]->text,"%s",CGI->generaltexth->arraytxt[60-mrlt]);
-		if (!mrl.size())
-			luck[b]->text += CGI->generaltexth->arraytxt[77];
-		else
-			for(int it=0; it < mrl.size(); it++)
-				luck[b]->text += "\n" + mrl[it].second;
+		luck[b]->set(false,heroInst[b]);
 	}
 
 	//buttons
@@ -5098,8 +5077,8 @@ void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= -
 	if(morale)
 	{
 		//setting morale
-		mrl = hero->getCurrentMoraleModifiers();
-		mrlv = hero->getCurrentMorale();
+		mrl = hero->getCurrentMoraleModifiers(slot);
+		mrlv = hero->getCurrentMorale(slot);
 		mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale, 0 - neutral, 1 - good
 		hoverText = CGI->generaltexth->heroscrn[4 - mrlt];
 		baseType = SComponent::morale;
@@ -5115,8 +5094,8 @@ void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= -
 	else
 	{
 		//setting luck
-		mrl = hero->getCurrentLuckModifiers();
-		mrlv = hero->getCurrentLuck();
+		mrl = hero->getCurrentLuckModifiers(slot);
+		mrlv = hero->getCurrentLuck(slot);
 		mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck, 0 - neutral, 1 - good
 		hoverText = CGI->generaltexth->heroscrn[7 - mrlt];
 		baseType = SComponent::luck;

+ 1 - 1
client/GUIClasses.h

@@ -838,7 +838,7 @@ class CExchangeWindow : public CWindowWithGarrison
 
 	std::vector<LRClickableAreaWTextComp *> secSkillAreas[2], primSkillAreas;
 
-	LRClickableAreaWTextComp *morale[2], *luck[2];
+	MoraleLuckBox *morale[2], *luck[2];
 
 	LRClickableAreaWText *speciality[2];
 	LRClickableAreaWText *experience[2];

+ 77 - 21
server/CGameHandler.cpp

@@ -1976,36 +1976,92 @@ void CGameHandler::changeObjPos( int objid, int3 newPos, ui8 flags )
 }
 
 void CGameHandler::useScholarSkill(si32 fromHero, si32 toHero)
-{//TODO: dialog window;
+{
 	const CGHeroInstance * h1 = getHero(fromHero);
 	const CGHeroInstance * h2 = getHero(toHero);
 
-	int ScholarLevel = std::max( h1->getSecSkillLevel(18), h2->getSecSkillLevel(18));//heroes can trade with this levels
-	if ( ScholarLevel == 0 )
-		return;
+	if ( h1->getSecSkillLevel(18) < h2->getSecSkillLevel(18) )
+	{
+		std::swap (h1,h2);//1st hero need to have higher scholar level for correct message
+		std::swap(fromHero, toHero);
+	}
 
-	ScholarLevel++;
-	int h1Lvl = std::min(ScholarLevel, h1->getSecSkillLevel(7)+2),
-	    h2Lvl = std::min(ScholarLevel, h2->getSecSkillLevel(7)+2);//heroes can receive this levels
-	ChangeSpells cs;
-	cs.learn = true;
-	cs.hid = toHero;//giving spells to first hero
+	int ScholarLevel = h1->getSecSkillLevel(18);//heroes can trade up to this level
+	if (!ScholarLevel || !vstd::contains(h1->artifWorn,17) || !vstd::contains(h2->artifWorn,17) )
+		return;//no scholar skill or no spellbook
 
-	for(std::set<ui32>::const_iterator it=h1->spells.begin(); it!=h1->spells.end();it++)
-		if ( h2Lvl >= VLC->spellh->spells[*it].level && !vstd::contains(h2->spells, *it))//hero can learn it and don't have it yet
-			cs.spells.insert(*it);//spell to learn
+	int h1Lvl = std::min(ScholarLevel+1, h1->getSecSkillLevel(7)+2),
+	    h2Lvl = std::min(ScholarLevel+1, h2->getSecSkillLevel(7)+2);//heroes can receive this levels
 
-	if (cs.spells.size())//if found new spell - apply
-		sendAndApply(&cs);
+	ChangeSpells cs1;
+	cs1.learn = true;
+	cs1.hid = toHero;//giving spells to first hero
+		for(std::set<ui32>::const_iterator it=h1->spells.begin(); it!=h1->spells.end();it++)
+			if ( h2Lvl >= VLC->spellh->spells[*it].level && !vstd::contains(h2->spells, *it))//hero can learn it and don't have it yet
+				cs1.spells.insert(*it);//spell to learn
 
-	cs.hid = fromHero;
-	cs.spells.clear();
+	ChangeSpells cs2;
+	cs2.learn = true;
+	cs2.hid = fromHero;
 
 	for(std::set<ui32>::const_iterator it=h2->spells.begin(); it!=h2->spells.end();it++)
 		if ( h1Lvl >= VLC->spellh->spells[*it].level && !vstd::contains(h1->spells, *it))
-			cs.spells.insert(*it);
-	if (cs.spells.size())
-		sendAndApply(&cs);
+			cs2.spells.insert(*it);
+			
+	if (cs1.spells.size() || cs2.spells.size())//create a message
+	{		
+		InfoWindow iw;
+		iw.player = h1->tempOwner;
+		iw.components.push_back(Component(Component::SEC_SKILL, 18, ScholarLevel, 0));
+
+		iw.text.addTxt(MetaString::GENERAL_TXT, 139);//"%s, who has studied magic extensively,
+		iw.text.addReplacement(h1->name);
+		
+		if (cs2.spells.size())//if found new spell - apply
+		{
+			iw.text.addTxt(MetaString::GENERAL_TXT, 140);//learns
+			int size = cs2.spells.size();
+			for(std::set<ui32>::const_iterator it=cs2.spells.begin(); it!=cs2.spells.end();it++)
+			{
+				iw.components.push_back(Component(Component::SPELL, (*it), 1, 0));
+				iw.text.addTxt(MetaString::SPELL_NAME, (*it));
+				switch (size--)
+				{
+					case 2:	iw.text.addTxt(MetaString::GENERAL_TXT, 141);
+					case 1:	break;
+					default:	iw.text << ", ";
+				}
+			}
+			iw.text.addTxt(MetaString::GENERAL_TXT, 142);//from %s
+			iw.text.addReplacement(h2->name);
+			sendAndApply(&cs2);
+		}
+
+		if (cs1.spells.size() && cs2.spells.size() )
+		{
+			iw.text.addTxt(MetaString::GENERAL_TXT, 141);//and
+		}
+
+		if (cs1.spells.size())
+		{
+			iw.text.addTxt(MetaString::GENERAL_TXT, 147);//teaches
+			int size = cs1.spells.size();
+			for(std::set<ui32>::const_iterator it=cs1.spells.begin(); it!=cs1.spells.end();it++)
+			{
+				iw.components.push_back(Component(Component::SPELL, (*it), 1, 0));
+				iw.text.addTxt(MetaString::SPELL_NAME, (*it));
+				switch (size--)
+				{
+					case 2:	iw.text.addTxt(MetaString::GENERAL_TXT, 141);
+					case 1:	break;
+					default:	iw.text << ", ";
+				}			}
+			iw.text.addTxt(MetaString::GENERAL_TXT, 148);//from %s
+			iw.text.addReplacement(h2->name);
+			sendAndApply(&cs1);
+		}
+		sendAndApply(&iw);
+	}
 }
 
 void CGameHandler::heroExchange(si32 hero1, si32 hero2)
@@ -2015,12 +2071,12 @@ void CGameHandler::heroExchange(si32 hero1, si32 hero2)
 
 	if(player1 == player2)//TODO: allies
 	{
-		useScholarSkill(hero1,hero2);
 		OpenWindow hex;
 		hex.window = OpenWindow::EXCHANGE_WINDOW;
 		hex.id1 = hero1;
 		hex.id2 = hero2;
 		sendAndApply(&hex);
+		useScholarSkill(hero1,hero2);
 	}
 }