浏览代码

* further changes towards luck/morale support
* partial support for Idol of Fortune, Fountain of Fortune, Faerie Ring, Swan Pond

Michał W. Urbańczyk 17 年之前
父节点
当前提交
218a3beaf6
共有 15 个文件被更改,包括 248 次插入45 次删除
  1. 2 1
      CGameState.cpp
  2. 10 0
      CHeroWindow.cpp
  3. 21 13
      CPlayerInterface.cpp
  4. 2 0
      client/Client.h
  5. 2 0
      hch/CGeneralTextHandler.cpp
  6. 130 7
      hch/CObjectHandler.cpp
  7. 17 19
      hch/CObjectHandler.h
  8. 26 0
      lib/HeroBonus.h
  9. 4 0
      lib/IGameCallback.h
  10. 4 5
      lib/NetPacks.h
  11. 4 0
      lib/VCMI_lib.vcproj
  12. 8 0
      map.cpp
  13. 6 0
      map.h
  14. 10 0
      server/CGameHandler.cpp
  15. 2 0
      server/CGameHandler.h

+ 2 - 1
CGameState.cpp

@@ -587,7 +587,8 @@ void CGameState::applyNL(IPack * pack)
 		{
 			GiveBonus *rh = static_cast<GiveBonus*>(pack);
 			CGHeroInstance *h = getHero(rh->hid);
-			h->bonuses.push_back(CGHeroInstance::Bonus(rh->bduration,rh->btype,rh->bval,rh->bid,toString(rh->bdescr)));
+			h->bonuses.push_back(rh->bonus);
+			h->bonuses.back().description = toString(rh->bdescr);
 			break;
 		}
 	case 500:

+ 10 - 0
CHeroWindow.cpp

@@ -358,6 +358,16 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
 	for(int it=0; it < mrl.size(); it++)
 		morale->text += mrl[it].second;
 
+	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]);
+	for(int it=0; it < mrl.size(); it++)
+		luck->text += mrl[it].second;
 
 	pos.x += 65;
 	pos.y += 8;

+ 21 - 13
CPlayerInterface.cpp

@@ -155,21 +155,24 @@ const CArmedInstance * CGarrisonSlot::getObj()
 	return 	(!upg)?(owner->oup):(owner->odown);
 }
 
+StackState* getStackState(const CGObjectInstance *obj, int pos, bool town)
+{
+	const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(obj);
+	if(!h) return NULL;
+	StackState *pom = new StackState();
+	pom->currentHealth = 0;
+	pom->attackBonus = h->getPrimSkillLevel(0);
+	pom->defenseBonus = h->getPrimSkillLevel(1);
+	pom->luck = h->getCurrentLuck();
+	pom->morale = h->getCurrentMorale(pos,town);
+	return pom;
+}
+
 void CGarrisonSlot::clickRight (tribool down)
 {
-	StackState *pom = NULL;
+	StackState *pom = getStackState(getObj(),ID,LOCPLINT->curint == LOCPLINT->castleInt);
 	if(down && creature)
 	{
-		if(getObj()->ID == 34)
-		{
-			pom = new StackState();
-			const CGHeroInstance *h = static_cast<const CGHeroInstance *>(getObj());
-			pom->currentHealth = 0;
-			pom->attackBonus = h->getPrimSkillLevel(0);
-			pom->defenseBonus = h->getPrimSkillLevel(1);
-			pom->luck = h->getCurrentLuck();
-			pom->morale = h->getCurrentMorale(ID);
-		}
 		(new CCreInfoWindow(creature->idNumber,0,count,pom,boost::function<void()>(),boost::function<void()>(),NULL))
 				->activate();
 		//LOCPLINT->curint->deactivate();
@@ -190,11 +193,12 @@ void CGarrisonSlot::clickLeft(tribool down)
 		{
 			if(owner->highlighted == this) //view info
 			{
+				StackState *pom2 = getStackState(getObj(),ID,LOCPLINT->curint == LOCPLINT->castleInt);
 				UpgradeInfo pom = LOCPLINT->cb->getUpgradeInfo(getObj(),ID);
 				if(pom.oldID>=0)
 				{
 					(new CCreInfoWindow
-						(creature->idNumber,1,count,NULL,
+						(creature->idNumber,1,count,pom2,
 						boost::bind(&CCallback::upgradeCreature,LOCPLINT->cb,getObj(),ID,pom.newID[0]), //if upgrade is possible we'll bind proper function in callback
 						 boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),&pom))
 							->activate();
@@ -202,7 +206,7 @@ void CGarrisonSlot::clickLeft(tribool down)
 				else
 				{
 					(new CCreInfoWindow
-						(creature->idNumber,1,count,NULL,0, boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),NULL) )
+						(creature->idNumber,1,count,pom2,0, boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),NULL) )
 						->activate();
 				}
 				if(LOCPLINT->curint->subInt)
@@ -212,6 +216,7 @@ void CGarrisonSlot::clickLeft(tribool down)
 				owner->highlighted = NULL;
 				show();
 				refr = true;
+				delete pom2;
 			}
 			else if(!creature 
 				&& (owner->splitting 
@@ -726,6 +731,9 @@ SDL_Surface * SComponent::getImg()
 	case morale:
 		return graphics->morale82->ourImages[val+3].bitmap;
 		break;
+	case luck:
+		return graphics->luck82->ourImages[val+3].bitmap;
+		break;
 	}
 	return NULL;
 }

+ 2 - 0
client/Client.h

@@ -85,6 +85,8 @@ public:
 	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb){}; //for hero<=>neutral army
 	void setAmount(int objid, ui32 val){};
 	void moveHero(int hid, int3 pos, bool instant){};
+	void giveHeroBonus(GiveBonus * bonus){};
+	void setMovePoints(SetMovePoints * smp){};
 	//////////////////////////////////////////////////////////////////////////
 	friend class CCallback; //handling players actions
 	friend void processCommand(const std::string &message, CClient *&client); //handling console

+ 2 - 0
hch/CGeneralTextHandler.cpp

@@ -289,6 +289,8 @@ void CGeneralTextHandler::load()
 	while(itr<strs.length()-1)
 	{
 		loadToIt(tmp, strs, itr, 3);
+		if(tmp[0] == '"' && tmp[tmp.size()-1] == '"')
+			tmp = tmp.substr(1,tmp.size()-2);
 		arraytxt.push_back(tmp);
 	}
 

+ 130 - 7
hch/CObjectHandler.cpp

@@ -325,11 +325,6 @@ bool CGHeroInstance::canWalkOnSea() const
 	//TODO: write it - it should check if hero is flying, or something similiar
 	return false;
 }
-int CGHeroInstance::getCurrentLuck() const
-{
-	//TODO: write it
-	return 0;
-}
 int CGHeroInstance::getPrimSkillLevel(int id) const
 {
 	return primSkills[id];
@@ -602,6 +597,10 @@ int CGHeroInstance::getCurrentMorale( int stack, bool town ) const
 	std::vector<std::pair<int,std::string> > mods = getCurrentMoraleModifiers(stack,town);
 	for(int i=0; i < mods.size(); i++)
 		ret += mods[i].first;
+	if(ret > 3)
+		return 3;
+	if(ret < -3)
+		return -3;
 	return ret;
 }
 
@@ -611,21 +610,34 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
 	std::vector<std::pair<int,std::string> > ret;
 
 	//various morale bonuses (from buildings, artifacts, etc)
-	for(std::list<Bonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
-		if(i->type == 2)
+	for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+		if(i->type == HeroBonus::MORALE)
 			ret.push_back(std::make_pair(i->val, i->description));
 
 	//leadership
 	if(getSecSkillLevel(6)) 
 		ret.push_back(std::make_pair(getSecSkillLevel(6),VLC->generaltexth->arraytxt[104+getSecSkillLevel(6)]));
 
+	//town structures
+	if(town && visitedTown)
+	{
+		if(visitedTown->subID == 0  &&  vstd::contains(visitedTown->builtBuildings,22)) //castle, brotherhood of sword built
+			ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[0][22].first + " +2"));
+		else if(vstd::contains(visitedTown->builtBuildings,5)) //tavern is built
+			ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[0][5].first + " +1"));
+	}
 
 	//number of alignments and presence of undead
 	if(stack>=0)
 	{
+		bool archangelInArmy = false;
 		std::set<si8> factions;
 		for(std::map<si32,std::pair<ui32,si32> >::const_iterator i=army.slots.begin(); i!=army.slots.end(); i++)
+		{
 			factions.insert(VLC->creh->creatures[i->second.first].faction);
+			if(i->second.first == 13)
+				archangelInArmy = true;
+		}
 
 		if(factions.size() == 1)
 			ret.push_back(std::pair<int,std::string>(1,VLC->generaltexth->arraytxt[115])); //All troops of one alignment +1
@@ -645,11 +657,55 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
 
 		if(vstd::contains(factions,4))
 			ret.push_back(std::pair<int,std::string>(-1,VLC->generaltexth->arraytxt[116])); //Undead in group -1
+
+		if(archangelInArmy)
+		{
+			char buf[100];
+			sprintf(buf,VLC->generaltexth->arraytxt[117].c_str(),VLC->creh->creatures[13].namePl);
+			ret.push_back(std::pair<int,std::string>(-1,VLC->generaltexth->arraytxt[116])); //%s in group +1
+		}
 	}
 
 	return ret;
 }
 
+int CGHeroInstance::getCurrentLuck( int stack/*=-1*/, bool town/*=false*/ ) const
+{
+	int ret = 0;
+	std::vector<std::pair<int,std::string> > mods = getCurrentLuckModifiers(stack,town);
+	for(int i=0; i < mods.size(); i++)
+		ret += mods[i].first;
+	if(ret > 3)
+		return 3;
+	if(ret < -3)
+		return -3;
+	return ret;
+}
+
+std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers( int stack/*=-1*/, bool town/*=false*/ ) const
+{
+	std::vector<std::pair<int,std::string> > ret;
+
+	//various morale bonuses (from buildings, artifacts, etc)
+	for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+		if(i->type == HeroBonus::LUCK)
+			ret.push_back(std::make_pair(i->val, i->description));
+
+	//luck skill
+	if(getSecSkillLevel(9)) 
+		ret.push_back(std::make_pair(getSecSkillLevel(9),VLC->generaltexth->arraytxt[73+getSecSkillLevel(9)]));
+
+	return ret;
+}
+
+const HeroBonus * CGHeroInstance::getBonus( int from, int id ) const
+{
+	for (std::list<HeroBonus>::const_iterator i=bonuses.begin(); i!=bonuses.end(); i++)
+		if(i->source == from  &&  i->id == id)
+			return &*i;
+	return NULL;
+}
+
 int CGTownInstance::getSightDistance() const //returns sight distance
 {
 	return 10;
@@ -1546,4 +1602,71 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 void CGDwelling::initObj()
 {
 
+}
+
+void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
+{
+	bool visited = h->getBonus(HeroBonus::OBJECT,ID);
+	int messageID, bonusType, bonusVal;
+	InfoWindow iw;
+	iw.player = h->tempOwner;
+
+	switch(ID)
+	{
+	case 14: //swan pond
+		messageID = 29;
+		bonusType = HeroBonus::LUCK;
+		bonusVal = 2;
+	case 28: //Faerie Ring
+		messageID = 49;
+		bonusType = HeroBonus::LUCK;
+		bonusVal = 1;
+		break;
+	case 30: //fountain of fortune
+		messageID = 55;
+		bonusType = HeroBonus::LUCK;
+		bonusVal = rand()%5 - 1;
+		break;
+	case 38: //idol of fortune
+		messageID = 62;
+		bonusType = HeroBonus::IDOL_OF_FORTUNE_BONUS;
+		bonusVal = 1;
+		break;
+	}
+	if(visited)
+	{
+		messageID++;
+	}
+	else
+	{
+		iw.components.push_back(Component(9,0,1,0));
+		GiveBonus gbonus;
+		gbonus.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT, bonusVal, ID,"");
+		gbonus.hid = h->id;
+		gbonus.bdescr <<  std::pair<ui8,ui32>(6,71);
+		cb->giveHeroBonus(&gbonus);
+		if(ID==14) //swan pond - take all move points
+		{
+			SetMovePoints smp;
+			smp.hid = h->id;
+			smp.val = 0;
+			cb->setMovePoints(&smp);
+		}
+	}
+	iw.text << std::pair<ui8,ui32>(11,messageID);
+	cb->showInfoDialog(&iw);
+}
+
+const std::string & CGBonusingObject::getHoverText() const
+{
+	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
+	hoverName = VLC->generaltexth->names[ID];
+	if(h) 
+	{
+		if(!h->getBonus(HeroBonus::OBJECT,ID))
+			hoverName += " " + VLC->generaltexth->allTexts[353]; //not visited
+		else
+			hoverName += " " + VLC->generaltexth->allTexts[352]; //visited
+	}
+	return hoverName;
 }

+ 17 - 19
hch/CObjectHandler.h

@@ -7,6 +7,7 @@
 #include <map>
 #include <list>
 #include "CCreatureHandler.h"
+#include "../lib/HeroBonus.h"
 #ifndef _MSC_VER
 #include "CHeroHandler.h"
 #include "CTownHandler.h"
@@ -183,24 +184,7 @@ public:
 		}
 	} patrol;
 
-	struct DLL_EXPORT Bonus
-	{
-		ui8 duration; //0 - Permanent, 1 - OneBattle, 2 - OneDay, 3 - OneWeek
-		ui8 type; //0 - none, 1 - movement; 2 - morale; 3 - luck
-		si32 val;
-		ui32 id;
-		std::string description;
-
-		Bonus(ui8 Dur, ui8 Type, si32 Val, ui32 ID, std::string Desc)
-			:duration(Dur), type(Type), val(Val), id(ID), description(Desc)
-		{}
-		Bonus(){};
-		template <typename Handler> void serialize(Handler &h, const int version)
-		{
-			h & duration & type & val & id;
-		}
-	};
-	std::list<Bonus> bonuses;
+	std::list<HeroBonus> bonuses;
 	//////////////////////////////////////////////////////////////////////////
 
 
@@ -220,6 +204,7 @@ public:
 	}
 
 	//////////////////////////////////////////////////////////////////////////
+	const HeroBonus *getBonus(int from, int id) const;
 	const std::string &getBiography() const;
 	bool needsLastStack()const;
 	unsigned int getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype) const;
@@ -230,7 +215,8 @@ public:
 	int getSightDistance() const; //returns sight distance of this hero
 	si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
 	bool canWalkOnSea() const;
-	int getCurrentLuck() const;
+	int getCurrentLuck(int stack=-1, bool town=false) const;
+	std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above
 	int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered
 	std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
 	int getPrimSkillLevel(int id) const;
@@ -625,6 +611,18 @@ public:
 	}
 };
 
+class DLL_EXPORT CGBonusingObject : public CGObjectInstance //objects giving bonuses to luck/morale/movement
+{
+public:
+	void onHeroVisit(const CGHeroInstance * h) const;
+	const std::string & getHoverText() const;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CGObjectInstance&>(*this);
+	}
+};
+
 
 
 class DLL_EXPORT CObjectHandler

+ 26 - 0
lib/HeroBonus.h

@@ -0,0 +1,26 @@
+#pragma once
+#include "../global.h"
+#include <string>
+
+struct DLL_EXPORT HeroBonus
+{
+	enum BonusType{NONE, MOVEMENT, MORALE, LUCK, IDOL_OF_FORTUNE_BONUS};
+	enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK};
+	enum BonusSource{ARTIFACT, OBJECT};
+
+	ui8 duration; //uses BonusDuration values
+	ui8 type; //uses BonusType values - says to what is this bonus
+	ui8 source;//uses BonusSource values - what gave that bonus
+	si32 val;//for morale/luck [-3,+3], others any
+	ui32 id; //id of object/artifact
+	std::string description; 
+
+	HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc)
+		:duration(Dur), type(Type), source(Src), val(Val), id(ID), description(Desc)
+	{}
+	HeroBonus(){};
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & duration & type & source & val & id & description;
+	}
+};

+ 4 - 0
lib/IGameCallback.h

@@ -6,6 +6,8 @@
 #include <set>
 #include "../client/FunctionList.h"
 
+struct SetMovePoints;
+struct GiveBonus;
 class CGObjectInstance;
 class CGTownInstance;
 class CGHeroInstance;
@@ -55,5 +57,7 @@ public:
 	virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb)=0; //for hero<=>neutral army
 	virtual void setAmount(int objid, ui32 val)=0;
 	virtual void moveHero(int hid, int3 pos, bool instant)=0;
+	virtual void giveHeroBonus(GiveBonus * bonus)=0;
+	virtual void setMovePoints(SetMovePoints * smp)=0;
 };
 #endif // __IGAMECALLBACK_H__

+ 4 - 5
lib/NetPacks.h

@@ -2,6 +2,8 @@
 #define __NETPACKS_H__
 #include "../global.h"
 #include "BattleAction.h"
+#include "HeroBonus.h"
+
 struct IPack
 {
 	virtual ui16 getType()const = 0 ;
@@ -194,16 +196,13 @@ struct GiveBonus :  public CPack<GiveBonus> //115
 {
 	GiveBonus(){type = 115;};
 
-	ui8 bduration;
-	ui8 btype;
-	si32 bval;
-	ui32 bid;
 	ui32 hid;
+	HeroBonus bonus;
 	MetaString bdescr;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & bduration & btype & bval & bid & hid & bdescr;
+		h & bonus & hid & bdescr;
 	}
 };
 

+ 4 - 0
lib/VCMI_lib.vcproj

@@ -392,6 +392,10 @@
 				RelativePath="..\hch\CTownHandler.h"
 				>
 			</File>
+			<File
+				RelativePath=".\HeroBonus.h"
+				>
+			</File>
 			<File
 				RelativePath=".\IGameCallback.h"
 				>

+ 8 - 0
map.cpp

@@ -1777,6 +1777,14 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 				loadQuest(guard, bufor, i);
 				break;
 			}
+		case 28: //faerie ring
+		case 14: //Swan pond
+		case 38: //idol of fortune
+		case 30: //Fountain of Fortune
+			{
+				nobj = new CGBonusingObject();
+				break;
+			}
 		case 214: //hero placeholder
 			{
 				i+=3; //TODO: handle it more properly

+ 6 - 0
map.h

@@ -495,6 +495,12 @@ struct DLL_EXPORT Mapa : public CMapHeader
 			case 215:
 				SERIALIZE(CGQuestGuard);
 				break;
+			case 28: //faerie ring
+			case 14: //Swan pond
+			case 38: //idol of fortune
+			case 30: //Fountain of Fortune
+				SERIALIZE(CGBonusingObject);
+				break;
 			default:
 				SERIALIZE(CGObjectInstance);
 			}

+ 10 - 0
server/CGameHandler.cpp

@@ -2366,4 +2366,14 @@ void CGameHandler::setObjProperty( int objid, int prop, int val )
 void CGameHandler::sendMessageTo( CConnection &c, std::string message )
 {
 	c << ui16(95) << message;
+}
+
+void CGameHandler::giveHeroBonus( GiveBonus * bonus )
+{
+	sendAndApply(bonus);
+}
+
+void CGameHandler::setMovePoints( SetMovePoints * smp )
+{
+	sendAndApply(smp);
 }

+ 2 - 0
server/CGameHandler.h

@@ -103,6 +103,8 @@ public:
 	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
 	void setAmount(int objid, ui32 val);
 	void moveHero(int hid, int3 pos, bool instant);
+	void giveHeroBonus(GiveBonus * bonus);
+	void setMovePoints(SetMovePoints * smp);
 	//////////////////////////////////////////////////////////////////////////
 
 	void init(StartInfo *si, int Seed);