Bladeren bron

Fixed #484. Preliminary support for bonus limiters/

Michał W. Urbańczyk 15 jaren geleden
bovenliggende
commit
fa4ee94cf9
10 gewijzigde bestanden met toevoegingen van 225 en 47 verwijderingen
  1. 14 0
      client/CMT.cpp
  2. 11 10
      hch/CCreatureHandler.cpp
  3. 2 0
      hch/CCreatureHandler.h
  4. 34 24
      hch/CObjectHandler.cpp
  5. 1 0
      lib/CCreatureSet.cpp
  6. 7 7
      lib/CGameState.cpp
  7. 96 0
      lib/HeroBonus.cpp
  8. 54 4
      lib/HeroBonus.h
  9. 2 2
      lib/NetPacksLib.cpp
  10. 4 0
      lib/RegisterTypes.cpp

+ 14 - 0
client/CMT.cpp

@@ -48,6 +48,7 @@
 #ifdef _WIN32
 #include "SDL_syswm.h"
 #endif
+#include <boost/foreach.hpp>
 
 #if __MINGW32__
 #undef main
@@ -427,6 +428,19 @@ void processCommand(const std::string &message)
 		if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))
 			tlog0 << h->movement << "; max: " << h->maxMovePoints(true) << "/" << h->maxMovePoints(false) << std::endl;
 	}
+	else if(cn == "bonuses")
+	{
+		tlog0 << "Bonuses of " << adventureInt->selection->getHoverText() << std::endl
+			<< adventureInt->selection->bonuses << std::endl;
+
+		tlog0 << "\nInherited bonuses:\n";
+		TCNodes parents;
+		adventureInt->selection->getParents(parents);
+		BOOST_FOREACH(const CBonusSystemNode *parent, parents)
+		{
+			tlog0 << "\nBonuses from " << typeid(*parent).name() << std::endl << parent->bonuses << std::endl;
+		}
+	}
 	else if(client && client->serv && client->serv->connected) //send to server
 	{
 		PlayerMessage pm(LOCPLINT->playerID,message);

+ 11 - 10
hch/CCreatureHandler.cpp

@@ -128,6 +128,12 @@ void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
 	bonuses.push_back(added);
 }
 
+bool CCreature::isMyUpgrade(const CCreature *anotherCre) const
+{
+	//TODO upgrade of upgrade?
+	return vstd::contains(upgrades, anotherCre->idNumber);
+}
+
 int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
 {
 	befi=i;
@@ -337,12 +343,7 @@ void CCreatureHandler::loadCreatures()
 			creatures.push_back(&ncre);
 		}
 	}
-
-	// Map types names
-#define BONUS_NAME(x) ( #x, Bonus::x )
-	static const std::map<std::string, int> type_list = map_list_of BONUS_LIST;
-#undef BONUS_NAME
-
+	
 	////second part of reading cr_abils.txt////
 	bool contReading = true;
 	while(contReading) //main reading loop
@@ -363,10 +364,10 @@ void CCreatureHandler::loadCreatures()
 				reader >> creatureID;
 				reader >> type;
 
-				std::map<std::string, int>::const_iterator it = type_list.find(type);
+				std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
 				CCreature *cre = creatures[creatureID];
 
-				if (it == type_list.end()) 
+				if (it == bonusNameMap.end()) 
 				{
 					if(type == "DOUBLE_WIDE")
 						cre->doubleWide = true;
@@ -403,8 +404,8 @@ void CCreatureHandler::loadCreatures()
 				std::string type;
 				reader >> creatureID;
 				reader >> type;
-				std::map<std::string, int>::const_iterator it = type_list.find(type);
-				if (it == type_list.end())
+				std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
+				if (it == bonusNameMap.end())
 				{
 					if(type == "DOUBLE_WIDE")
 						creatures[creatureID]->doubleWide = false;

+ 2 - 0
hch/CCreatureHandler.h

@@ -55,9 +55,11 @@ public:
 	bool isEvil () const;
 	si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
 	static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
+	bool isMyUpgrade(const CCreature *anotherCre) const;
 
 	void addBonus(int val, int type, int subtype = -1);
 
+
 	template<typename RanGen>
 	int getRandomAmount(RanGen &ranGen)
 	{

+ 34 - 24
hch/CObjectHandler.cpp

@@ -973,50 +973,60 @@ void CGHeroInstance::initObj()
 		{
 			case 1:// creature speciality
 				{
+					speciality.growthsWithLevel = true;
+
 					bonus.type = Bonus::SPECIAL_CREATURE_LEV; // general info to indicate type of growing bonus
 					bonus.additionalInfo = it->additionalinfo; //base creature ID
 					speciality.bonuses.push_back (bonus);
 
-					std::vector<CCreature*>* creatures = &VLC->creh->creatures;
-					int creLevel = (*creatures)[it->additionalinfo]->level;
+					const CCreature &specCreature = *VLC->creh->creatures[it->additionalinfo]; //creature in which we have specialty
+
+					int creLevel = specCreature.level;
 					if(!creLevel) //TODO: set fixed level for War Machines
 					{
 						if(it->additionalinfo == 146)
 							creLevel = 5; //treat ballista as 5-level
 						else
 						{
-							tlog2 << "Warning: unknown level of " << (*creatures)[it->additionalinfo]->namePl << std::endl;
+							tlog2 << "Warning: unknown level of " << specCreature.namePl << std::endl;
 							continue;
 						}
 					}
 
-					speciality.growthsWithLevel = true;
-					bonus.type = Bonus::PRIMARY_SKILL; //TODO: limit to specific creature type
+					int levelFactor = level / creLevel; //round down
+					double primSkillModifier = levelFactor / 20.0;
+
+					bonus.limiter = new CCreatureTypeLimiter(specCreature);
+					bonus.type = Bonus::PRIMARY_SKILL; 
 					bonus.valType = Bonus::ADDITIVE_VALUE;
-					bonus.subtype = 1; //attack
-					bonus.val = level * (*creatures)[it->additionalinfo]->attack / creLevel /20;
+
+					bonus.subtype = PrimarySkill::ATTACK;
+					bonus.val = std::ceil(primSkillModifier * specCreature.attack);
 					speciality.bonuses.push_back (bonus);
-					bonus.subtype = 2; //defense
-					bonus.val = level * (*creatures)[it->additionalinfo]->defence / creLevel /20;
+
+					bonus.subtype = PrimarySkill::DEFENSE;
+					bonus.val = std::ceil(primSkillModifier * specCreature.defence);
 					speciality.bonuses.push_back (bonus);
+
 					bonus.type = Bonus::STACKS_SPEED;
 					bonus.val = 1; //+1 speed
 					speciality.bonuses.push_back (bonus);
-					for (std::set<ui32>::iterator i = (*creatures)[it->additionalinfo]->upgrades.begin();
-						i != VLC->creh->creatures[it->additionalinfo]->upgrades.end(); i++)
-					{
-						bonus.val = (*i); // for all direct upgrades of that creature
-						bonus.type = Bonus::PRIMARY_SKILL;
-						bonus.subtype = 1; //attack
-						bonus.val = level * (*creatures)[*i]->attack / (*creatures)[*i]->level /20;
-						speciality.bonuses.push_back (bonus);
-						bonus.subtype = 2; //defense
-						bonus.val = level * (*creatures)[*i]->defence / (*creatures)[*i]->level /20;
-						speciality.bonuses.push_back (bonus);
-						bonus.type = Bonus::STACKS_SPEED;
-						bonus.val = 1; //+1 speed
-						speciality.bonuses.push_back (bonus);
-					}
+
+// 					for (std::set<ui32>::iterator i = (*creatures)[it->additionalinfo]->upgrades.begin();
+// 						i != VLC->creh->creatures[it->additionalinfo]->upgrades.end(); i++)
+// 					{
+// 						bonus.val = (*i); // for all direct upgrades of that creature
+// 						bonus.type = Bonus::PRIMARY_SKILL;
+// 						bonus.subtype = 1; //attack
+// 						bonus.val = level * (*creatures)[*i]->attack / (*creatures)[*i]->level /20;
+// 						speciality.bonuses.push_back (bonus);
+// 						bonus.subtype = 2; //defense
+// 						bonus.val = level * (*creatures)[*i]->defence / (*creatures)[*i]->level /20;
+// 						speciality.bonuses.push_back (bonus);
+// 						bonus.type = Bonus::STACKS_SPEED;
+// 						bonus.val = 1; //+1 speed
+// 						speciality.bonuses.push_back (bonus);
+// 					}
 				}
 				break;
 			case 2://secondary skill

+ 1 - 0
lib/CCreatureSet.cpp

@@ -252,6 +252,7 @@ void CStackInstance::init()
 	type = NULL;
 	idRand = -1;
 	armyObj = NULL;
+	nodeType = STACK;
 }
 
 int CStackInstance::getQuantityID() const 

+ 7 - 7
lib/CGameState.cpp

@@ -117,11 +117,11 @@ class CObjectCaller : public IObjectCaller
 public:
 	void preInit()
 	{
-		T::preInit();
+		//T::preInit();
 	}
 	void postInit()
 	{
-		T::postInit();
+		//T::postInit();
 	}
 };
 
@@ -148,14 +148,14 @@ public:
 
 	void preInit()
 	{
-		for (size_t i = 0; i < apps.size(); i++)
-			apps[i]->preInit();
+// 		for (size_t i = 0; i < apps.size(); i++)
+// 			apps[i]->preInit();
 	}
 
 	void postInit()
 	{
-		for (size_t i = 0; i < apps.size(); i++)
-			apps[i]->postInit();
+// 		for (size_t i = 0; i < apps.size(); i++)
+// 			apps[i]->postInit();
 	}
 } *objCaller = NULL;
 
@@ -2365,7 +2365,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
 			if (map->isInTheMap(pos)) 
 			{
 				TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
-				if (tile.visitable) 
+				if (tile.visitable && (tile.tertype == TerrainTile::water) == (posTile.tertype == TerrainTile::water)) 
 				{
 					BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) 
 					{

+ 96 - 0
lib/HeroBonus.cpp

@@ -5,10 +5,16 @@
 #include "../hch/CSpellHandler.h"
 #include <sstream>
 #include "../hch/CCreatureHandler.h"
+#include <boost/assign/list_of.hpp>
+#include "CCreatureSet.h"
 
 #define FOREACH_CONST_PARENT(pname, source) 	TCNodes parents; getParents(parents, source); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
 #define FOREACH_PARENT(pname, source) 	TNodes parents; getParents(parents, source); BOOST_FOREACH(CBonusSystemNode *pname, parents)
 
+#define BONUS_NAME(x) ( #x, Bonus::x )
+	DLL_EXPORT const std::map<std::string, int> bonusNameMap = boost::assign::map_list_of BONUS_LIST;
+#undef BONUS_NAME
+
 int DLL_EXPORT BonusList::totalValue() const
 {
 	int base = 0;
@@ -75,6 +81,19 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
 			out.push_back(*i);
 }
 
+void BonusList::limit(const CBonusSystemNode &node)
+{
+	for(const_iterator i = begin(); i != end(); i++)
+	{
+		if(i->limiter && i->limiter->limit(*i, node))
+		{
+			const_iterator toErase = i;
+			i--;
+			erase(toErase);
+		}
+	}
+}
+
 int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
 {
 	CSelector s = Selector::type(type);
@@ -161,6 +180,9 @@ void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, con
 	bonuses.getBonuses(out, selector);
 	FOREACH_CONST_PARENT(p, root ? root : this)
 		p->getBonuses(out, selector, root ? root : this);
+	
+	if(!root)
+		out.limit(*this);
 }
 
 BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
@@ -175,6 +197,9 @@ void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, con
 	bonuses.getBonuses(out, selector, limit);
 	FOREACH_CONST_PARENT(p, root ? root : this)
 		p->getBonuses(out, selector, limit, root ? root : this);
+
+	if(!root)
+		out.limit(*this);
 }
 
 BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
@@ -245,6 +270,16 @@ ui16 CBonusSystemNode::MaxHealth() const
 	return valOfBonuses(Bonus::STACK_HEALTH);
 }
 
+CBonusSystemNode::CBonusSystemNode()
+{
+	nodeType = UNKNOWN;
+}
+
+CBonusSystemNode::~CBonusSystemNode()
+{
+
+}
+
 int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
 {
 	if(obj)
@@ -346,4 +381,65 @@ namespace Selector
 		dummy.subtype = subtype;
 		return sel(dummy);
 	}
+}
+
+DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
+{
+	int i = 0;
+	BOOST_FOREACH(const Bonus &b, bonusList)
+	{
+		out << "Bonus " << i++ << "\n" << b << std::endl;
+	}
+	return out;
+}
+
+DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
+{
+	for(std::map<std::string, int>::const_iterator i = bonusNameMap.begin(); i != bonusNameMap.end(); i++)
+		if(i->second == bonus.type)
+			out << "\tType: " << i->first << " \t";
+
+#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
+	printField(val);
+	printField(subtype);
+	printField(duration);
+	printField(source);
+	printField(id);
+	printField(additionalInfo);
+	printField(turnsRemain);
+	printField(valType);
+	printField(effectRange);
+#undef printField
+
+	return out;
+}
+
+ILimiter::~ILimiter()
+{
+}
+
+bool ILimiter::limit(const Bonus &b, const CBonusSystemNode &node) const /*return true to drop the bonus */
+{
+	return false;
+}
+
+bool CCreatureTypeLimiter::limit(const Bonus &b, const CBonusSystemNode &node) const
+{
+	if(node.nodeType != CBonusSystemNode::STACK)
+		return true;
+
+	const CCreature *c = (static_cast<const CStackInstance *>(&node))->type;
+
+	return c != creature   &&   (!includeUpgrades || !creature->isMyUpgrade(c)); //drop bonus if it's not our creature and (we dont check upgrades or its not our upgrade)
+}
+
+CCreatureTypeLimiter::CCreatureTypeLimiter(const CCreature &Creature, ui8 IncludeUpgrades /*= true*/)
+	:creature(&Creature), includeUpgrades(IncludeUpgrades)
+{
+}
+
+CCreatureTypeLimiter::CCreatureTypeLimiter()
+{
+	creature = NULL;
+	includeUpgrades = false;
 }

+ 54 - 4
lib/HeroBonus.h

@@ -19,17 +19,17 @@
 typedef ui8 TBonusType;
 typedef si32 TBonusSubtype;
 
-
+class CCreature;
 class CSpell;
 struct Bonus;
 class CBonusSystemNode;
+class ILimiter;
 
 typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
 typedef std::set<CBonusSystemNode*> TNodes;
 typedef std::set<const CBonusSystemNode*> TCNodes;
 typedef boost::function<bool(const Bonus&)> CSelector;
 
-
 namespace PrimarySkill
 {
 	enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
@@ -223,6 +223,8 @@ struct DLL_EXPORT Bonus
 	si32 additionalInfo;
 	ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default
 
+	ILimiter *limiter;
+
 	std::string description; 
 
 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1)
@@ -232,6 +234,7 @@ struct DLL_EXPORT Bonus
 		turnsRemain = 0;
 		valType = ADDITIVE_VALUE;
 		effectRange = NO_LIMIT;
+		limiter = NULL;
 	}
 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE)
 		:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), valType(ValType)
@@ -239,6 +242,7 @@ struct DLL_EXPORT Bonus
 		additionalInfo = -1;
 		turnsRemain = 0;
 		effectRange = NO_LIMIT;
+		limiter = NULL;
 	}
 	Bonus()
 	{
@@ -247,6 +251,7 @@ struct DLL_EXPORT Bonus
 		turnsRemain = 0;
 		valType = ADDITIVE_VALUE;
 		effectRange = NO_LIMIT;
+		limiter = NULL;
 	}
 
 // 	//comparison
@@ -263,7 +268,7 @@ struct DLL_EXPORT Bonus
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange;
+		h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange & limiter;
 	}
 
 	static bool OneDay(const Bonus &hb)
@@ -307,6 +312,8 @@ struct DLL_EXPORT Bonus
 	std::string Description() const;
 };
 
+DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
+
 class BonusList : public std::list<Bonus>
 {
 public:
@@ -319,16 +326,35 @@ public:
 	DLL_EXPORT Bonus * getFirst(const CSelector &select);
 	DLL_EXPORT const Bonus * getFirst(const CSelector &select) const;
 
+	void limit(const CBonusSystemNode &node); //erases bonuses using limitor
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & static_cast<std::list<Bonus>&>(*this);
 	}
 };
 
+DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
+
+class DLL_EXPORT ILimiter
+{
+public:
+	virtual ~ILimiter();
+
+	virtual bool limit(const Bonus &b, const CBonusSystemNode &node) const; //return true to drop the bonus
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{}
+};
+
 class DLL_EXPORT CBonusSystemNode
 {
 public:
 	BonusList bonuses;
+	ui8 nodeType;
+
+	CBonusSystemNode();
+	virtual ~CBonusSystemNode();
 
 	//new bonusing node interface
 	// * selector is predicate that tests if HeroBonus matches our criteria
@@ -366,8 +392,13 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & bonuses;
+		h & bonuses & nodeType;
 	}
+
+	enum ENodeTypes
+	{
+		UNKNOWN, STACK
+	};
 };
 
 namespace NBonus
@@ -450,6 +481,23 @@ public:
 	}
 };
 
+class CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
+{
+public:
+	const CCreature *creature;
+	ui8 includeUpgrades;
+
+	CCreatureTypeLimiter();
+	CCreatureTypeLimiter(const CCreature &Creature, ui8 IncludeUpgrades = true);
+
+	bool limit(const Bonus &b, const CBonusSystemNode &node) const;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & creature & includeUpgrades;
+	}
+};
+
 namespace Selector
 {
 	extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;
@@ -466,3 +514,5 @@ namespace Selector
 	bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
 	bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype);
 }
+
+extern DLL_EXPORT const std::map<std::string, int> bonusNameMap;

+ 2 - 2
lib/NetPacksLib.cpp

@@ -737,9 +737,9 @@ DLL_EXPORT void HeroLevelUp::applyGs( CGameState *gs )
 						break;
 						case 2:
 							it->val = (level * (*creatures)[it->additionalInfo]->defence)/creLevel /20;
-						break;
+							break;
 					}
-				break;
+					break;
 			}
 		}
 	}

+ 4 - 0
lib/RegisterTypes.cpp

@@ -20,6 +20,7 @@
 template<typename Serializer> DLL_EXPORT
 void registerTypes1(Serializer &s)
 {
+	//map objects
 	s.template registerType<CGHeroPlaceholder>();
 	s.template registerType<CGHeroInstance>();
 	s.template registerType<CGTownInstance>();
@@ -64,6 +65,9 @@ void registerTypes1(Serializer &s)
 	s.template registerType<CGLighthouse>();
 	s.template registerType<CGMarket>();
 	s.template registerType<CGBlackMarket>();
+	//end of objects
+	s.template registerType<ILimiter>();
+	s.template registerType<CCreatureTypeLimiter>();
 }
 
 template<typename Serializer> DLL_EXPORT