瀏覽代碼

Exposed more of existing limiters for modders (#449)

* Exposed alignment, faction and terrain limiters
* Limiters toString() use now boost:format
godric3 7 年之前
父節點
當前提交
d9d01f0b68
共有 9 個文件被更改,包括 137 次插入22 次删除
  1. 3 0
      AUTHORS
  2. 1 0
      ChangeLog
  3. 10 0
      lib/CStack.cpp
  4. 2 0
      lib/CStack.h
  5. 80 17
      lib/HeroBonus.cpp
  6. 9 3
      lib/HeroBonus.h
  7. 30 0
      lib/JsonNode.cpp
  8. 1 1
      lib/battle/BattleInfo.cpp
  9. 1 1
      lib/registerTypes/RegisterTypes.h

+ 3 - 0
AUTHORS

@@ -69,3 +69,6 @@ Piotr Wójcik aka Chocimier, <[email protected]>
 
 Henning Koehler, <[email protected]>
    * skill modding, bonus updaters
+
+Andrzej Żak aka godric3
+   * minor bug fixes and modding features

+ 1 - 0
ChangeLog

@@ -34,6 +34,7 @@ MODS:
 * Map object sounds can now be configured via json
 * Added bonus updaters for hero specialties
 * Added allOf, anyOf and noneOf qualifiers for bonus limiters
+* Added bonus limiters: alignment, faction and terrain
 
 SOUND:
 * Fixed many mising or wrong pickup and visit sounds for map objects

+ 10 - 0
lib/CStack.cpp

@@ -282,6 +282,16 @@ bool CStack::canBeHealed() const
 		   && !hasBonusOfType(Bonus::SIEGE_WEAPON);
 }
 
+bool CStack::isOnNativeTerrain() const
+{
+	return type->isItNativeTerrain(battle->getTerrainType());
+}
+
+bool CStack::isOnTerrain(int terrain) const
+{
+	return battle->getTerrainType() == terrain;
+}
+
 const CCreature * CStack::unitType() const
 {
 	return type;

+ 2 - 0
lib/CStack.h

@@ -47,6 +47,8 @@ public:
 	std::string getName() const; //plural or singular
 
 	bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines
+	bool isOnNativeTerrain() const;
+	bool isOnTerrain(int terrain) const;
 
 	ui32 level() const;
 	si32 magicResistance() const override; //include aura of resistance

+ 80 - 17
lib/HeroBonus.cpp

@@ -16,11 +16,13 @@
 #include "CCreatureHandler.h"
 #include "CCreatureSet.h"
 #include "CHeroHandler.h"
+#include "CTownHandler.h"
 #include "CGeneralTextHandler.h"
 #include "CSkillHandler.h"
 #include "CStack.h"
 #include "CArtHandler.h"
 #include "StringConstants.h"
+#include "battle/BattleInfo.h"
 
 #define FOREACH_PARENT(pname) 	TNodes lparents; getParents(lparents); for(CBonusSystemNode *pname : lparents)
 #define FOREACH_CPARENT(pname) 	TCNodes lparents; getParents(lparents); for(const CBonusSystemNode *pname : lparents)
@@ -68,7 +70,8 @@ const std::map<std::string, TLimiterPtr> bonusLimiterMap =
 {
 	{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
 	{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
-	{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)}
+	{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
+	{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()}
 };
 
 const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
@@ -1623,11 +1626,9 @@ void CCreatureTypeLimiter::setCreature (CreatureID id)
 
 std::string CCreatureTypeLimiter::toString() const
 {
-	char buf[100];
-	sprintf(buf, "CCreatureTypeLimiter(creature=%s, includeUpgrades=%s)",
-		creature->identifier.c_str(),
-		(includeUpgrades ? "true" : "false"));
-	return std::string(buf);
+	boost::format fmt("CCreatureTypeLimiter(creature=%s, includeUpgrades=%s)");
+	fmt % creature->identifier % (includeUpgrades ? "true" : "false");
+	return fmt.str();
 }
 
 JsonNode CCreatureTypeLimiter::toJsonNode() const
@@ -1671,15 +1672,19 @@ int HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
 
 std::string HasAnotherBonusLimiter::toString() const
 {
-	char buf[100];
-
 	std::string typeName = vstd::findKey(bonusNameMap, type);
 	if(isSubtypeRelevant)
-		sprintf(buf, "HasAnotherBonusLimiter(type=%s, subtype=%d)",	typeName.c_str(), subtype);
+	{
+		boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%d)");
+		fmt % typeName % subtype;
+		return fmt.str();
+	}
 	else
-		sprintf(buf, "HasAnotherBonusLimiter(type=%s)",	typeName.c_str());
-
-	return std::string(buf);
+	{
+		boost::format fmt("HasAnotherBonusLimiter(type=%s)");
+		fmt % typeName;
+		return fmt.str();
+	}
 }
 
 JsonNode HasAnotherBonusLimiter::toJsonNode() const
@@ -1721,24 +1726,48 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
 	return nodeType == dest->getNodeType();
 }
 
-CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType)
+CreatureTerrainLimiter::CreatureTerrainLimiter(int TerrainType)
 	: terrainType(TerrainType)
 {
 }
 
-CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter()
+CreatureTerrainLimiter::CreatureTerrainLimiter()
 	: terrainType(-1)
 {
 
 }
 
-int CreatureNativeTerrainLimiter::limit(const BonusLimitationContext &context) const
+int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
 {
-	const CCreature *c = retrieveCreature(&context.node);
-	return !c || !c->isItNativeTerrain(terrainType); //drop bonus for non-creatures or non-native residents
+	const CStack *stack = retrieveStackBattle(&context.node);
+	if(stack)
+	{
+		if(terrainType == -1)//terrainType not specified = native
+			return !stack->isOnNativeTerrain();
+		return !stack->isOnTerrain(terrainType);
+	}
+	return true;
 	//TODO neutral creatues
 }
 
+std::string CreatureTerrainLimiter::toString() const
+{
+	boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
+	fmt % (terrainType >= 0 ? GameConstants::TERRAIN_NAMES[terrainType] : "native");
+	return fmt.str();
+}
+
+JsonNode CreatureTerrainLimiter::toJsonNode() const
+{
+	JsonNode root(JsonNode::JsonType::DATA_STRUCT);
+
+	root["type"].String() = "CREATURE_TERRAIN_LIMITER";
+	if(terrainType >= 0)
+		root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::TERRAIN_NAMES[terrainType]));
+
+	return root;
+}
+
 CreatureFactionLimiter::CreatureFactionLimiter(int Faction)
 	: faction(Faction)
 {
@@ -1755,6 +1784,23 @@ int CreatureFactionLimiter::limit(const BonusLimitationContext &context) const
 	return !c || c->faction != faction; //drop bonus for non-creatures or non-native residents
 }
 
+std::string CreatureFactionLimiter::toString() const
+{
+	boost::format fmt("CreatureFactionLimiter(faction=%s)");
+	fmt %  VLC->townh->factions[faction]->identifier;
+	return fmt.str();
+}
+
+JsonNode CreatureFactionLimiter::toJsonNode() const
+{
+	JsonNode root(JsonNode::JsonType::DATA_STRUCT);
+
+	root["type"].String() = "CREATURE_FACTION_LIMITER";
+	root["parameters"].Vector().push_back(JsonUtils::stringNode(VLC->townh->factions[faction]->identifier));
+
+	return root;
+}
+
 CreatureAlignmentLimiter::CreatureAlignmentLimiter()
 	: alignment(-1)
 {
@@ -1784,6 +1830,23 @@ int CreatureAlignmentLimiter::limit(const BonusLimitationContext &context) const
 	}
 }
 
+std::string CreatureAlignmentLimiter::toString() const
+{
+	boost::format fmt("CreatureAlignmentLimiter(alignment=%s)");
+	fmt % EAlignment::names[alignment];
+	return fmt.str();
+}
+
+JsonNode CreatureAlignmentLimiter::toJsonNode() const
+{
+	JsonNode root(JsonNode::JsonType::DATA_STRUCT);
+
+	root["type"].String() = "CREATURE_ALIGNMENT_LIMITER";
+	root["parameters"].Vector().push_back(JsonUtils::stringNode(EAlignment::names[alignment]));
+
+	return root;
+}
+
 RankRangeLimiter::RankRangeLimiter(ui8 Min, ui8 Max)
 	:minRank(Min), maxRank(Max)
 {

+ 9 - 3
lib/HeroBonus.h

@@ -965,14 +965,16 @@ public:
 	}
 };
 
-class DLL_LINKAGE CreatureNativeTerrainLimiter : public ILimiter //applies only to creatures that are on their native terrain
+class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain
 {
 public:
 	int terrainType;
-	CreatureNativeTerrainLimiter();
-	CreatureNativeTerrainLimiter(int TerrainType);
+	CreatureTerrainLimiter();
+	CreatureTerrainLimiter(int TerrainType);
 
 	int limit(const BonusLimitationContext &context) const override;
+	virtual std::string toString() const override;
+	virtual JsonNode toJsonNode() const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -989,6 +991,8 @@ public:
 	CreatureFactionLimiter(int TerrainType);
 
 	int limit(const BonusLimitationContext &context) const override;
+	virtual std::string toString() const override;
+	virtual JsonNode toJsonNode() const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -1005,6 +1009,8 @@ public:
 	CreatureAlignmentLimiter(si8 Alignment);
 
 	int limit(const BonusLimitationContext &context) const override;
+	virtual std::string toString() const override;
+	virtual JsonNode toJsonNode() const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 30 - 0
lib/JsonNode.cpp

@@ -19,6 +19,7 @@
 #include "CModHandler.h"
 #include "CGeneralTextHandler.h"
 #include "JsonDetail.h"
+#include "StringConstants.h"
 
 using namespace JsonDetail;
 
@@ -645,6 +646,35 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
 					return bonusLimiter;
 				}
 			}
+			else if(limiterType == "CREATURE_ALIGNMENT_LIMITER")
+			{
+				int alignment = vstd::find_pos(EAlignment::names, parameters[0].String());
+				if(alignment == -1)
+					logMod->error("Error: invalid alignment %s.", parameters[0].String());
+				else
+					return std::make_shared<CreatureAlignmentLimiter>(alignment);
+			}
+			else if(limiterType == "CREATURE_FACTION_LIMITER")
+			{
+				std::shared_ptr<CreatureFactionLimiter> factionLimiter = std::make_shared<CreatureFactionLimiter>();
+				VLC->modh->identifiers.requestIdentifier("faction", parameters[0], [=](si32 faction)
+				{
+					factionLimiter->faction = faction;
+				});
+				return factionLimiter;
+			}
+			else if(limiterType == "CREATURE_TERRAIN_LIMITER")
+			{
+				std::shared_ptr<CreatureTerrainLimiter> terrainLimiter = std::make_shared<CreatureTerrainLimiter>();
+				if(parameters.size())
+				{
+					VLC->modh->identifiers.requestIdentifier("terrain", parameters[0], [=](si32 terrain)
+					{
+						terrainLimiter->terrainType = terrain;
+					});
+				}
+				return terrainLimiter;
+			}
 			else
 			{
 				logMod->error("Error: invalid customizable limiter type %s.", limiterType);

+ 1 - 1
lib/battle/BattleInfo.cpp

@@ -525,7 +525,7 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
 	//overlay premies given
 
 	//native terrain bonuses
-	auto nativeTerrain = std::make_shared<CreatureNativeTerrainLimiter>(curB->terrainType);
+	auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
 
 	curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::STACKS_SPEED, Bonus::TERRAIN_NATIVE, 1, 0, 0)->addLimiter(nativeTerrain));
 	curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::TERRAIN_NATIVE, 1, 0, PrimarySkill::ATTACK)->addLimiter(nativeTerrain));

+ 1 - 1
lib/registerTypes/RegisterTypes.h

@@ -185,7 +185,7 @@ void registerTypesMapObjects2(Serializer &s)
 	s.template registerType<ILimiter, AllOfLimiter>();
 	s.template registerType<ILimiter, CCreatureTypeLimiter>();
 	s.template registerType<ILimiter, HasAnotherBonusLimiter>();
-	s.template registerType<ILimiter, CreatureNativeTerrainLimiter>();
+	s.template registerType<ILimiter, CreatureTerrainLimiter>();
 	s.template registerType<ILimiter, CreatureFactionLimiter>();
 	s.template registerType<ILimiter, CreatureAlignmentLimiter>();
 	s.template registerType<ILimiter, RankRangeLimiter>();