Prechádzať zdrojové kódy

changes in hero class format:
- new property: affinity (might/magic) since in mods it is impossible to
rely on odd/even numeric indexes
- property commander is now part of hero class

Ivan Savenko 12 rokov pred
rodič
commit
7d7e65a316

+ 0 - 38
Mods/WoG/config/wog/factions.json

@@ -1,38 +0,0 @@
-{
-	"core:castle" :
-	{
-		"commander" : "paladin1"
-	},
-	"core:conflux" :
-	{
-		"commander" : "astralSpirit1"
-	},
-	"core:dungeon" :
-	{
-		"commander" : "brute1"
-	},
-	"core:fortress" :
-	{
-		"commander" : "shaman1"
-	},
-	"core:inferno" :
-	{
-		"commander" : "succubus1"
-	},
-	"core:necropolis" :
-	{
-		"commander" : "soulEater1"
-	},
-	"core:rampart" :
-	{
-		"commander" : "hierophant1"
-	},
-	"core:stronghold" :
-	{
-		"commander" : "ogreLeader1"
-	},
-	"core:tower" :
-	{
-		"commander" : "templeGuardian1"
-	}
-}

+ 74 - 0
Mods/WoG/config/wog/heroClasses.json

@@ -0,0 +1,74 @@
+{
+        "core:knight" :
+        {
+                "commander" : "paladin1"
+        },
+        "core:cleric" :
+        {
+                "commander" : "paladin1"
+        },
+        "core:planeswalker" :
+        {
+                "commander" : "astralSpirit1"
+        },
+        "core:elementalist" :
+        {
+                "commander" : "astralSpirit1"
+        },
+        "core:warlock" :
+        {
+                "commander" : "brute1"
+        },
+        "core:overlord" :
+        {
+                "commander" : "brute1"
+        },
+        "core:beastmaster" :
+        {
+                "commander" : "shaman1"
+        },
+        "core:witch" :
+        {
+                "commander" : "shaman1"
+        },
+        "core:demoniac" :
+        {
+                "commander" : "succubus1"
+        },
+        "core:heretic" :
+        {
+                "commander" : "succubus1"
+        },
+        "core:deathknight" :
+        {
+                "commander" : "soulEater1"
+        },
+        "core:necromancer" :
+        {
+                "commander" : "soulEater1"
+        },
+        "core:ranger" :
+        {
+                "commander" : "hierophant1"
+        },
+        "core:druid" :
+        {
+                "commander" : "hierophant1"
+        },
+        "core:barbarian" :
+        {
+                "commander" : "ogreLeader1"
+        },
+        "core:battlemage" :
+        {
+                "commander" : "ogreLeader1"
+        },
+        "core:alchemist" :
+        {
+                "commander" : "templeGuardian1"
+        },
+        "core:wizard" :
+        {
+                "commander" : "templeGuardian1"
+        }
+}

+ 2 - 2
Mods/WoG/mod.json

@@ -17,9 +17,9 @@
 		"config/wog/creatures.json"
 	],
 
-	"factions" : 
+	"heroClasses" : 
 	[
-		"config/wog/factions.json"
+		"config/wog/heroClasses.json"
 	],
 
 	"filesystem":

+ 0 - 1
config/factions/castle.json

@@ -4,7 +4,6 @@
 		"index" : 0,
 		"nativeTerrain": "grass",
 		"alignment" : "good",
-		"commander" : "zealot",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASCAS",

+ 0 - 1
config/factions/conflux.json

@@ -4,7 +4,6 @@
 		"index" : 8,
 		"nativeTerrain": "grass",
 		"alignment" : "neutral",
-		"commander" : "iceElemental",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASELE",

+ 0 - 1
config/factions/dungeon.json

@@ -4,7 +4,6 @@
 		"index" : 5,
 		"nativeTerrain": "subterra",
 		"alignment" : "evil",
-		"commander" : "medusaQueen",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASDUN",

+ 0 - 1
config/factions/fortress.json

@@ -4,7 +4,6 @@
 		"index" : 7,
 		"nativeTerrain": "swamp",
 		"alignment" : "neutral",
-		"commander" : "lizardWarrior",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASFOR",

+ 0 - 1
config/factions/inferno.json

@@ -4,7 +4,6 @@
 		"index" : 3,
 		"nativeTerrain": "lava",
 		"alignment" : "evil",
-		"commander" : "magog",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASINF",

+ 0 - 1
config/factions/necropolis.json

@@ -4,7 +4,6 @@
 		"index" : 4,
 		"nativeTerrain": "dirt",
 		"alignment" : "evil",
-		"commander" : "powerLich",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASNEC",

+ 1 - 2
config/factions/neutral.json

@@ -8,7 +8,6 @@
 		{
 			"120px" : "TPCASNEU",
 			"130px" : "CRBKGNEU"
-		},
-		"commander" : "enchanter" //just in case
+		}
 	}
 }

+ 0 - 1
config/factions/rampart.json

@@ -4,7 +4,6 @@
 		"index" : 1,
 		"nativeTerrain": "grass",
 		"alignment" : "good",
-		"commander" : "grandElf",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASRAM",

+ 0 - 1
config/factions/stronghold.json

@@ -4,7 +4,6 @@
 		"index" : 6,
 		"nativeTerrain": "rough",
 		"alignment" : "neutral",
-		"commander" : "orcChieftain",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASSTR",

+ 0 - 1
config/factions/tower.json

@@ -4,7 +4,6 @@
 		"index" : 2,
 		"nativeTerrain" : "snow",
 		"alignment" : "good",
-		"commander" : "archMage",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASTOW",

+ 38 - 2
config/heroClasses.json

@@ -4,6 +4,8 @@
 		"index": 0,
 		"faction" : "castle",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "zealot",
 		"animation":
 		{
 			"battle" : { "male" : "CH00.DEF",  "female" : "CH01.DEF" },
@@ -15,6 +17,8 @@
 		"index": 1,
 		"faction" : "castle",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "zealot",
 		"animation":
 		{
 			"battle" : { "male" : "CH00.DEF",  "female" : "CH01.DEF" },
@@ -26,6 +30,8 @@
 		"index": 2,
 		"faction" : "rampart",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "grandElf",
 		"animation":
 		{
 			"battle" : { "male" : "CH02.DEF",  "female" : "CH03.DEF" },
@@ -37,6 +43,8 @@
 		"index": 3,
 		"faction" : "rampart",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "grandElf",
 		"animation":
 		{
 			"battle" : { "male" : "CH02.DEF",  "female" : "CH03.DEF" },
@@ -48,6 +56,8 @@
 		"index": 4,
 		"faction" : "tower",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "archMage",
 		"animation":
 		{
 			"battle" : { "male" : "CH05.DEF",  "female" : "CH04.DEF" },
@@ -59,6 +69,8 @@
 		"index": 5,
 		"faction" : "tower",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "archMage",
 		"animation":
 		{
 			"battle" : { "male" : "CH05.DEF",  "female" : "CH04.DEF" },
@@ -70,6 +82,8 @@
 		"index": 6,
 		"faction" : "inferno",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "magog",
 		"animation":
 		{
 			"battle" : { "male" : "CH06.DEF",  "female" : "CH07.DEF" },
@@ -81,6 +95,8 @@
 		"index": 7,
 		"faction" : "inferno",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "magog",
 		"animation":
 		{
 			"battle" : { "male" : "CH06.DEF",  "female" : "CH07.DEF" },
@@ -92,6 +108,8 @@
 		"index": 8,
 		"faction" : "necropolis",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "powerLich",
 		"animation":
 		{
 			"battle" : { "male" : "CH08.DEF",  "female" : "CH09.DEF" },
@@ -103,6 +121,8 @@
 		"index": 9,
 		"faction" : "necropolis",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "powerLich",
 		"animation":
 		{
 			"battle" : { "male" : "CH08.DEF",  "female" : "CH09.DEF" },
@@ -114,6 +134,8 @@
 		"index": 10,
 		"faction" : "dungeon",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "medusaQueen",
 		"animation":
 		{
 			"battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" },
@@ -125,6 +147,8 @@
 		"index": 11,
 		"faction" : "dungeon",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "medusaQueen",
 		"animation":
 		{
 			"battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" },
@@ -136,6 +160,8 @@
 		"index": 12,
 		"faction" : "stronghold",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "orcChieftain",
 		"animation":
 		{
 			"battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" },
@@ -147,6 +173,8 @@
 		"index": 13,
 		"faction" : "stronghold",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "orcChieftain",
 		"animation":
 		{
 			"battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" },
@@ -158,6 +186,8 @@
 		"index": 14,
 		"faction" : "fortress",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "lizardWarrior",
 		"animation":
 		{
 			"battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" },
@@ -169,6 +199,8 @@
 		"index": 15,
 		"faction" : "fortress",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "lizardWarrior",
 		"animation":
 		{
 			"battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" },
@@ -180,9 +212,11 @@
 		"index": 16,
 		"faction" : "conflux",
 		"defaultTavern" : 5,
+		"affinity" : "might",
+		"commander" : "iceElemental",
 		"animation":
 		{
-			"battle" : { "male" : "CH16.DEF",  "female" : "CH17.DEF" },
+			"battle" : { "male" : "CH16.DEF",  "female" : "CH16.DEF" },
 			"map":     { "male" : "AH16_.def", "female" : "AH16_.def" }
 		}
 	},
@@ -191,9 +225,11 @@
 		"index": 17,
 		"faction" : "conflux",
 		"defaultTavern" : 5,
+		"affinity" : "magic",
+		"commander" : "iceElemental",
 		"animation":
 		{
-			"battle" : { "male" : "CH16.DEF",  "female" : "CH17.DEF" },
+			"battle" : { "male" : "CH17.DEF",  "female" : "CH17.DEF" },
 			"map":     { "male" : "AH17_.def", "female" : "AH17_.def" }
 		}
 	}

+ 1 - 5
config/schemas/faction.json

@@ -33,7 +33,7 @@
 	"description": "Json format for defining new faction (aka towns) in VCMI",
 	"required" : [ "name", "alignment", "creatureBackground" ],
 	"dependencies" : {
-		"town" : [ "puzzleMap", "commander" ]
+		"town" : [ "puzzleMap" ]
 	},
 	
 	"additionalProperties" : false,
@@ -51,10 +51,6 @@
 			"enum" : [ "good", "neutral", "evil" ],
 			"description": "Town alignment, good, neutral or evil"
 		},
-		"commander": {
-			"type":"string",
-			"description": "Identifier of creature that is used as commander by heroes"
-		},
 		"creatureBackground": {
 			"type":"object",
 			"additionalProperties" : false,

+ 11 - 1
config/schemas/heroClass.json

@@ -5,7 +5,8 @@
 	"description" : "Format used to define classes of heroes in VCMI",
 	"required" : [
 		"animation", "faction", "highLevelChance", "lowLevelChance",
-		"name", "primarySkills", "secondarySkills", "tavern", "defaultTavern"
+		"name", "primarySkills", "secondarySkills", "tavern", "defaultTavern",
+		"affinity", "commander"
 	],
 
 	"additionalProperties" : false,
@@ -62,6 +63,15 @@
 			"type":"string",
 			"description": "Faction this hero class belongs to"
 		},
+		"affinity" : {
+			"type" : "string",
+			"description" : "Affinity of hero class, might or magic",
+			"enum" : [ "might", "magic"]
+		},
+		"commander": {
+			"type":"string",
+			"description": "Identifier of creature that is used as commander by heroes"
+		},
 		"highLevelChance": {
 			"type":"object",
 			"description": "Chance to get specific primary skill on level-up, applicable for levels starting from 10",

+ 17 - 1
lib/CHeroHandler.cpp

@@ -7,6 +7,7 @@
 #include "JsonNode.h"
 #include "StringConstants.h"
 #include "BattleHex.h"
+#include "CCreatureHandler.h"
 #include "CModHandler.h"
 #include "CTownHandler.h"
 #include "CObjectHandler.h" //for hero specialty
@@ -45,7 +46,7 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
 
 bool CHeroClass::isMagicHero() const
 {
-	return id % 2; // 0 - might, 1 - magic
+	return affinity == MAGIC;
 }
 
 EAlignment::EAlignment CHeroClass::getAlignment() const
@@ -88,6 +89,8 @@ bool CObstacleInfo::isAppropriate(ETerrainType terrainType, int specialBattlefie
 
 CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
 {
+	std::string affinityStr[2] = { "might", "magic" };
+
 	auto  heroClass = new CHeroClass();
 
 	heroClass->imageBattleFemale = node["animation"]["battle"]["female"].String();
@@ -96,6 +99,9 @@ CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
 	heroClass->imageMapMale      = node["animation"]["map"]["male"].String();
 
 	heroClass->name = node["name"].String();
+	heroClass->affinity = vstd::find_pos(affinityStr, node["affinity"].String());
+	if (heroClass->affinity >= 2) //FIXME: MODS COMPATIBILITY
+		heroClass->affinity = 0;
 
 	for(const std::string & pSkill : PrimarySkill::names)
 	{
@@ -109,6 +115,16 @@ CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
 		heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
 	}
 
+	//FIXME: MODS COMPATIBILITY
+	if (!node["commander"].isNull())
+	{
+		VLC->modh->identifiers.requestIdentifier ("creature", node["commander"],
+		[=](si32 commanderID)
+		{
+			heroClass->commander = VLC->creh->creatures[commanderID];
+		});
+	}
+
 	heroClass->defaultTavernChance = node["defaultTavern"].Float();
 	for(auto & tavern : node["tavern"].Struct())
 	{

+ 10 - 1
lib/CHeroHandler.h

@@ -97,16 +97,25 @@ public:
 class DLL_LINKAGE CHeroClass
 {
 public:
+	enum EClassAffinity
+	{
+		MIGHT,
+		MAGIC
+	};
+
 	std::string identifier;
 	std::string name; // translatable
 	//double aggression; // not used in vcmi.
 	TFaction faction;
 	ui8 id;
+	ui8 affinity; // affility, using EClassAffinity enum
 
 	// default chance for hero of specific class to appear in tavern, if field "tavern" was not set
 	// resulting chance = sqrt(town.chance * heroClass.chance)
 	ui32 defaultTavernChance;
 
+	CCreature * commander;
+
 	std::vector<int> primarySkillInitial;  // initial primary skills
 	std::vector<int> primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level
 	std::vector<int> primarySkillHighLevel;// same for high levels (> 10)
@@ -128,7 +137,7 @@ public:
 		h & identifier & name & faction & id & defaultTavernChance;// & aggression;
 		h & primarySkillInitial   & primarySkillLowLevel;
 		h & primarySkillHighLevel & secSkillProbability;
-		h & selectionProbability;
+		h & selectionProbability & affinity & commander;
 		h & imageBattleMale & imageBattleFemale & imageMapMale & imageMapFemale;
 	}
 	EAlignment::EAlignment getAlignment() const;

+ 1 - 1
lib/CObjectHandler.cpp

@@ -824,7 +824,7 @@ void CGHeroInstance::initHero()
 
 	if (VLC->modh->modules.COMMANDERS && !commander)
 	{
-		commander = new CCommanderInstance (VLC->townh->factions[type->heroClass->faction]->commander);
+		commander = new CCommanderInstance(type->heroClass->commander->idNumber);
 		commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
 		commander->giveStackExp (exp); //after our exp is set
 	}

+ 11 - 2
lib/CTownHandler.cpp

@@ -5,6 +5,7 @@
 #include "CGeneralTextHandler.h"
 #include "JsonNode.h"
 #include "StringConstants.h"
+#include "CCreatureHandler.h"
 #include "CModHandler.h"
 #include "CHeroHandler.h"
 #include "CArtHandler.h"
@@ -628,11 +629,19 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, std::string identi
 	faction->name = source["name"].String();
 	faction->identifier = identifier;
 
-	VLC->modh->identifiers.requestIdentifier ("creature", source["commander"],
+	//FIXME: MODS COMPATIBILITY
+	if (!source["commander"].isNull())
+	{
+		VLC->modh->identifiers.requestIdentifier ("creature", source["commander"],
 		[=](si32 commanderID)
 		{
-			faction->commander = CreatureID(commanderID);
+			for (auto ptr : VLC->heroh->classes.heroClasses)
+			{
+				if (ptr->commander == nullptr && ptr->faction == faction->index)
+					ptr->commander = VLC->creh->creatures[commanderID];
+			}
 		});
+	}
 
 	faction->creatureBg120 = source["creatureBackground"]["120px"].String();
 	faction->creatureBg130 = source["creatureBackground"]["130px"].String();

+ 1 - 3
lib/CTownHandler.h

@@ -112,8 +112,6 @@ public:
 	ETerrainType nativeTerrain;
 	EAlignment::EAlignment alignment;
 
-	CreatureID commander;
-
 	CTown * town; //NOTE: can be null
 
 	std::string creatureBg120;
@@ -123,7 +121,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & name & identifier & index & nativeTerrain & alignment & commander & town & creatureBg120 & creatureBg130 & puzzleMap;
+		h & name & identifier & index & nativeTerrain & alignment & town & creatureBg120 & creatureBg130 & puzzleMap;
 	}
 };