Browse Source

- Basic Commander window
- First part of unified quests interface

This graphics package is needed:
http://forum.vcmi.eu/viewtopic.php?p=6943#6943

DjWarmonger 13 years ago
parent
commit
416c08260a

+ 2 - 0
AI/EmptyAI/CEmptyAI.h

@@ -22,6 +22,8 @@ public:
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel){};
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) {};
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
+	void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
+							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) {};
 };
 
 #define NAME "EmptyAI 0.1"

+ 2 - 0
AI/VCAI/VCAI.h

@@ -210,6 +210,8 @@ public:
 	virtual void init(CCallback * CB);
 	virtual void yourTurn();
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
+	virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
+		std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) {};
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void serialize(COSer<CSaveFile> &h, const int version) OVERRIDE; //saving

+ 74 - 6
client/CCreatureWindow.cpp

@@ -120,6 +120,22 @@ CCreatureWindow::CCreatureWindow(const CStackInstance &st, int Type, boost::func
 	}
 }
 
+CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander)
+	:type (COMMANDER), commander (Commander)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
+
+	boost::function<void()> Dsm;
+	CFunctionList<void()> fs[2];
+	//on dismiss confirmed
+	fs[0] += Dsm; //dismiss
+	fs[0] += boost::bind(&CCreatureWindow::close,this);//close this window
+	CFunctionList<void()> cfl;
+	cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
+	dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
+}
+
 void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner)
 {
 	creatureArtifact = NULL; //may be set later
@@ -138,6 +154,9 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
 	else if (Stack->count)
 		count = boost::lexical_cast<std::string>(Stack->count);
 
+	if (type < COMMANDER)
+		commander = NULL;
+
 	//Basic graphics - need to calculate size
 
 	BonusList bl, blTemp;
@@ -185,15 +204,22 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
 	}
 
 	bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (screen->h - 230) / 60);
-	vstd::amin(bonusRows, 4);
+	if (type >= COMMANDER)
+		vstd::amin(bonusRows, 3);
+	else
+		vstd::amin(bonusRows, 4);
 	vstd::amax(bonusRows, 1);
 
-	bitmap = new CPicture("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
+	if (type >= COMMANDER)
+		bitmap = new CPicture("CommWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx");
+	else
+		bitmap = new CPicture("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
 	bitmap->colorizeAndConvert(LOCPLINT->playerID);
 	pos = bitmap->center();
 
 	//Buttons
 	ok = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, boost::bind(&CCreatureWindow::close,this), 489, 148, "hsbtns.def", SDLK_RETURN);
+	ok->assignedKeys.insert(SDLK_ESCAPE);
 
 	if (type <= BATTLE) //in battle or info window
 	{
@@ -271,6 +297,42 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
 			}
 		}
 	}
+	if (commander) //secondary skills
+	{
+		for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i)
+		{
+			auto it = commander->secondarySkills.find(i);
+			if (it != commander->secondarySkills.end())
+			{
+				std::string file = "zvs/Lib1.res/_";
+				switch (i)
+				{
+					case ECommander::ATTACK:
+						file += "AT";
+						break;
+					case ECommander::DEFENSE:
+						file += "DF";
+						break;
+					case ECommander::HEALTH:
+						file += "HP";
+						break;
+					case ECommander::DAMAGE:
+						file += "DM";
+						break;
+					case ECommander::SPEED:
+						file += "SP";
+						break;
+					case ECommander::SPELL_POWER:
+						file += "MP";
+						break;
+				}
+				file += boost::lexical_cast<std::string>(it->second);
+
+				auto skillGraphics = new CPicture(file, 40 + i * 82, 121);
+				blitAtLoc(skillGraphics->bg, 0, 0, bitmap->bg);
+			}
+		}
+	}
 
 	if (battleStack) //only during battle
 	{
@@ -326,6 +388,10 @@ void CCreatureWindow::printLine(int nr, const std::string &text, int baseVal, in
 
 void CCreatureWindow::recreateSkillList(int Pos)
 {
+	int commanderOffset = 0;
+	if (type >= COMMANDER)
+		commanderOffset = 74;
+
 	int n = 0, i = 0, j = 0;
 	int numSkills = std::min ((bonusRows + Pos) << 1, (int)bonusItems.size());
 	std::string gfxName;
@@ -336,7 +402,7 @@ void CCreatureWindow::recreateSkillList(int Pos)
 	for (n = Pos << 1; n < numSkills; ++n)
 	{
 		int offsetx = 257*j - (bonusRows == 4 ? 1 : 0);
-		int offsety = 60*i + (bonusRows > 1 ? 1 : 0); //lack of precision :/
+		int offsety = 60*i + (bonusRows > 1 ? 1 : 0) + commanderOffset; //lack of precision :/
 
 		bonusItems[n]->moveTo (Point(pos.x + offsetx + 10, pos.y + offsety + 230), true);
 		bonusItems[n]->visible = true;
@@ -357,7 +423,7 @@ void CCreatureWindow::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);
 
-	printAtMiddle(c->namePl, 180, 30, FONT_SMALL, Colors::Jasmine,*bitmap); //creature name
+	printAtMiddle ((type >= COMMANDER? c->nameSing : c->namePl), 180, 30, FONT_SMALL, Colors::Jasmine, *bitmap); //creature name
 
 	printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->Attack());
 	printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->Defense());
@@ -371,7 +437,7 @@ void CCreatureWindow::showAll(SDL_Surface * to)
 	}
 	if (stackNode->valOfBonuses(Bonus::CASTS))
 	{
-		printAtMiddle(CGI->generaltexth->allTexts[399], 356, 61, FONT_SMALL, Colors::Cornsilk,*bitmap);
+		printAtMiddle(CGI->generaltexth->allTexts[399], 356, 62, FONT_SMALL, Colors::Cornsilk,*bitmap);
 		std::string casts;
 		if (type == BATTLE)
 			casts = boost::lexical_cast<std::string>((ui16)dynamic_cast<const CStack*>(stackNode)->casts); //ui8 is converted to char :(
@@ -646,6 +712,7 @@ void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *sta
 		abilityText = NULL;
 		ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
 			boost::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
+		ok->assignedKeys.insert(SDLK_ESCAPE);
 	}
 
 	//if we are displying window fo r stack in battle, there are several more things that we need to display
@@ -671,7 +738,8 @@ void CCreInfoWindow::clickRight(tribool down, bool previousState)
 	close();
 }
 
-CIntObject * createCreWindow(const CStack *s, bool lclick/* = false*/)
+CIntObject * createCreWindow(
+	const CStack *s, bool lclick/* = false*/)
 {
 	if(settings["general"]["classicCreatureWindow"].Bool())
 		return new CCreInfoWindow(*s, lclick);

+ 4 - 1
client/CCreatureWindow.h

@@ -17,6 +17,7 @@
 struct Bonus;
 class CCreature;
 class CStackInstance;
+class CCommanderInstance;
 class CStack;
 class ArtifactLocation;
 class CCreatureArtifactInstance;
@@ -39,7 +40,7 @@ class CAnimImage;
 class CCreatureWindow : public CArtifactHolder
 {
 public:
-	enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3}; //only last one should open permanently
+	enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4}; // > 3 are opened permanently
 	//bool active; //TODO: comment me
 	int type;//0 - rclick popup; 1 - normal window
 	int bonusRows; //height of skill window
@@ -48,6 +49,7 @@ public:
 	const CCreature *c; //related creature
 	const CStackInstance *stack;
 	const CBonusSystemNode *stackNode;
+	const CCommanderInstance * commander;
 	const CGHeroInstance *heroOwner;
 	const CArtifactInstance *creatureArtifact; //currently worn artifact
 	std::vector<CComponent*> upgResCost; //cost of upgrade (if not possible then empty)
@@ -77,6 +79,7 @@ public:
 	CCreatureWindow(const CStack & stack, int type); //battle c-tor
 	CCreatureWindow (const CStackInstance &stack, int Type); //pop-up c-tor
 	CCreatureWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
+	CCreatureWindow(const CCommanderInstance * commander); //commander window
 	CCreatureWindow(int Cid, int Type, int creatureCount); //c-tor
 
 	void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);

+ 12 - 0
client/CHeroWindow.cpp

@@ -7,6 +7,7 @@
 #include "CHeroWindow.h"
 #include "CMessage.h"
 #include "CKingdomInterface.h"
+#include "CCreatureWindow.h"
 #include "SDL.h"
 #include "UIFramework/SDL_Extensions.h"
 #include "CBitmapHandler.h"
@@ -116,6 +117,12 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 
 	tacticsButton = new CHighlightableButton(0, 0, map_list_of(0,CGI->generaltexth->heroscrn[26])(3,CGI->generaltexth->heroscrn[25]), CGI->generaltexth->heroscrn[31], false, "hsbtns8.def", NULL, 539, 483, SDLK_b);
 
+	if (hero->commander)
+	{
+		commanderButton = new CAdventureMapButton ("Commander", "Commander info", boost::bind(&CHeroWindow::commanderWindow, this), 317, 18, "chftke.def", SDLK_c, NULL, false);
+	}
+
+
 	//right list of heroes
 	for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++)
 		heroList.push_back(new CHeroSwitcher(Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false)));
@@ -288,6 +295,11 @@ void CHeroWindow::questlog()
 {
 }
 
+void CHeroWindow::commanderWindow()
+{
+	GH.pushInt(new CCreatureWindow (curHero->commander));
+}
+
 void CHeroWindow::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);

+ 2 - 1
client/CHeroWindow.h

@@ -72,7 +72,7 @@ class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts
 	std::vector<CAnimImage *> secSkillImages;
 	CHeroWithMaybePickedArtifact heroWArt;
 
-	CAdventureMapButton * quitButton, * dismissButton, * questlogButton; //general
+	CAdventureMapButton * quitButton, * dismissButton, * questlogButton, * commanderButton; //general
 		
 	CHighlightableButton *tacticsButton; //garrison / formation handling;
 	CHighlightableButtonsGroup *formations;
@@ -88,6 +88,7 @@ public:
 	void quit(); //stops displaying hero window and disposes
 	void dismissCurrent(); //dissmissed currently displayed hero (curHero)
 	void questlog(); //show quest log in hero window
+	void commanderWindow();
 	void switchHero(); //changes displayed hero
 
 	//friends

+ 11 - 0
client/CPlayerInterface.cpp

@@ -9,6 +9,7 @@
 #include "CKingdomInterface.h"
 #include "CGameInfo.h"
 #include "CHeroWindow.h"
+#include "CCreatureWindow.h"
 #include "CMessage.h"
 #include "CPlayerInterface.h"
 //#include "UIFramework/SDL_Extensions.h"
@@ -486,6 +487,16 @@ void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std:
 	CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,callback);
 	GH.pushInt(lw);
 }
+void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
+										std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback)
+{
+	EVENT_HANDLER_CALLED_BY_CLIENT;
+	waitWhileDialog();
+	CCS->soundh->playSound(soundBase::heroNewLevel);
+
+	CCreatureWindow * cw = new CCreatureWindow(commander);
+	GH.pushInt(cw);
+}
 void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;

+ 2 - 0
client/CPlayerInterface.h

@@ -139,6 +139,8 @@ public:
 
 	void heroCreated(const CGHeroInstance* hero) OVERRIDE;
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE;
+	void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
+							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) OVERRIDE;
 	void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;
 	void heroMoved(const TryMoveHero & details) OVERRIDE;
 	void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;

+ 6 - 0
client/NetPacksClient.cpp

@@ -535,6 +535,12 @@ void HeroLevelUp::applyCl( CClient *cl )
 		cl->playerint[h->tempOwner]->heroGotLevel(const_cast<const CGHeroInstance*>(h),static_cast<int>(primskill),skills, callback);
 	}
 }
+void CommanderLevelUp::applyCl( CClient *cl )
+{
+	if (commander->armyObj && vstd::contains(cl->playerint, commander->armyObj->tempOwner)) //is it possible for Commander to exist beyond armed instance?
+	{
+	}
+}
 
 void BlockingDialog::applyCl( CClient *cl )
 {

+ 1 - 1
lib/CCreatureSet.h

@@ -81,7 +81,7 @@ public:
 	//commander class is determined by its base creature
 	ui8 alive;
 	std::string name; // each Commander has different name
-	std::vector <std::pair <ui8, ui8> > secondarySkills; //ID, level
+	std::map <ui8, ui8> secondarySkills; //ID, level
 	//std::vector <CArtifactInstance *> arts;
 	void init() OVERRIDE;
 	CCommanderInstance();

+ 3 - 0
lib/CGameInterface.h

@@ -43,6 +43,7 @@ struct CatapultAttack;
 struct BattleStacksRemoved;
 struct StackLocation;
 class CStackInstance;
+class CCommanderInstance;
 class CStack;
 class CCreature;
 class CLoadFile;
@@ -74,6 +75,8 @@ public:
 	virtual void init(CCallback * CB){};
 	virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
+	virtual	void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
+							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) = 0;
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving

+ 16 - 0
lib/CGameState.h

@@ -34,6 +34,7 @@ class CLuaCallback;
 class CCPPObjectScript;
 class CCreatureSet;
 class CStack;
+class CQuest;
 class CGHeroInstance;
 class CGTownInstance;
 class CArmedInstance;
@@ -58,6 +59,7 @@ class CCampaignState;
 class IModableArt;
 class CGGarrison;
 class CGameInfo;
+struct QuestInfo;
 
 namespace boost
 {
@@ -161,6 +163,7 @@ public:
 	std::vector<ConstTransitivePtr<CGTownInstance> > towns;
 	std::vector<ConstTransitivePtr<CGHeroInstance> > availableHeroes; //heroes available in taverns
 	std::vector<ConstTransitivePtr<CGDwelling> > dwellings; //used for town growth
+	std::vector<QuestInfo> quests; //store info about all received quests
 
 	ui8 enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
 	ui8 status; //0 - in game, 1 - loser, 2 - winner <- uses EStatus enum
@@ -430,3 +433,16 @@ public:
 	friend class CGameHandler;
 };
  
+struct DLL_LINKAGE QuestInfo //universal interface for human and AI
+{
+	CQuest * quest;
+	CGObjectInstance * obj; //related object, most likely Seer Hut
+	int3 tile;
+
+	//std::vector<std::string> > texts //allow additional info for quest log?
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & quest & obj & tile;
+	}
+};

+ 1 - 0
lib/CObjectHandler.h

@@ -26,6 +26,7 @@ class CGameState;
 class CArtifactInstance;
 struct MetaString;
 struct BattleInfo;
+struct QuestInfo;
 class IGameCallback;
 struct BattleResult;
 class CCPPObjectScript;

+ 3 - 0
lib/IGameCallback.h

@@ -56,6 +56,7 @@ class CCreatureSet;
 class CCreature;
 class CStackBasicDescriptor;
 struct TeamState;
+struct QuestInfo;
 class CGCreature;
 
 typedef std::vector<const CStack*> TStacks;
@@ -232,6 +233,7 @@ public:
 	std::vector <const CGHeroInstance *> getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
 	std::vector <const CGDwelling *> getMyDwellings() const; //returns all dwellings that belong to player
 	std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player
+	std::vector <const QuestInfo> getMyQuests() const;
 
 	int getResourceAmount(int type)const;
 	TResources getResourceAmount() const;
@@ -324,6 +326,7 @@ public:
 	virtual void changeObjPos(int objid, int3 newPos, ui8 flags)=0;
 	virtual void sendAndApply(CPackForClient * info)=0;
 	virtual void heroExchange(si32 hero1, si32 hero2)=0; //when two heroes meet on adventure map
+	virtual void addQuest(int player, QuestInfo & quest){};
 };
 
 /// Interface class for handling general game logic and actions

+ 18 - 3
lib/NetPacks.h

@@ -11,6 +11,7 @@
 #include "int3.h"
 #include "ResourceSet.h"
 #include "CObstacleInstance.h"
+#include "CGameState.h"
 
 /*
  * NetPacks.h, part of VCMI engine
@@ -33,6 +34,7 @@ class CGObjectInstance;
 class CArtifactInstance;
 //class CMapInfo;
 struct ArtSlotInfo;
+struct QuestInfo;
 
 struct CPack
 {
@@ -514,7 +516,20 @@ struct SetCommanderproperty : public CPackForClient //120
 	{
 		h & which & alive & accumulatedBonus;
 	}
-}; 
+};
+struct AddQuest : public CPackForClient //121
+{
+	AddQuest(){type = 121;};
+	void applyCl(CClient *cl){};
+
+	ui8 player;
+	QuestInfo quest;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & player & quest;
+	}
+};
 
 struct RemoveObject : public CPackForClient //500
 {
@@ -1141,8 +1156,8 @@ struct HeroLevelUp : public Query//2000
 
 struct CommanderLevelUp : public Query
 {
-	void applyCl(CClient *cl){};
-	DLL_LINKAGE void applyGs(CGameState *gs){};
+	void applyCl(CClient *cl);
+	DLL_LINKAGE void applyGs(CGameState *gs);
 
 	CCommanderInstance * commander;
 	std::vector<std::pair<ui8, ui8> > secondarySkills;

+ 5 - 0
lib/NetPacksLib.cpp

@@ -899,6 +899,11 @@ DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
 	h->UpdateSpeciality();
 }
 
+DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs)
+{
+	commander->levelUp();
+}
+
 DLL_LINKAGE void BattleStart::applyGs( CGameState *gs )
 {
 	gs->curB = info;