Browse Source

- More commanders
- Improved finding closest tiles on battlefield

DjWarmonger 13 years ago
parent
commit
96d198758c
10 changed files with 124 additions and 17 deletions
  1. 36 0
      config/creatures.json
  2. 40 14
      lib/BattleState.cpp
  3. 1 0
      lib/BattleState.h
  4. 28 0
      lib/CCreatureSet.cpp
  5. 8 2
      lib/CCreatureSet.h
  6. 6 0
      lib/CObjectHandler.cpp
  7. 1 1
      lib/CObjectHandler.h
  8. 1 0
      lib/HeroBonus.h
  9. 1 0
      lib/RegisterTypes.h
  10. 2 0
      lib/map.h

+ 36 - 0
config/creatures.json

@@ -1753,6 +1753,10 @@
 				"level": 0,
 				"name": [ "Paladin1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 37, 0 ] ], //expert cure
 				"defname": "ZM174NPC.DEF"
 			},
 
@@ -1761,6 +1765,10 @@
 				"level": 0,
 				"name": [ "Hierophant1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 27, 0 ] ], //expert shield
 				"defname": "ZM175NPC.DEF"
 			},
 
@@ -1769,6 +1777,10 @@
 				"level": 0,
 				"name": [ "TempleGuardian1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 44, 0 ] ], //expert precision
 				"defname": "ZM176NPC.DEF"
 			},
 
@@ -1777,6 +1789,10 @@
 				"level": 0,
 				"name": [ "Succubus1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 29, 0 ] ], //expert fire shield
 				"defname": "ZM177NPC.DEF"
 			},
 
@@ -1785,6 +1801,10 @@
 				"level": 0,
 				"name": [ "SoulEater1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 39, 0 ] ], //expert animate dead
 				"defname": "ZM178NPC.DEF"
 			},
 
@@ -1793,6 +1813,10 @@
 				"level": 0,
 				"name": [ "Brute1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 46, 0 ] ], //expert stone skin
 				"defname": "ZM179NPC.DEF"
 			},
 
@@ -1801,6 +1825,10 @@
 				"level": 0,
 				"name": [ "OgreLeader1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 37, 0 ] ], //expert cure
 				"defname": "ZM180NPC.DEF"
 			},
 
@@ -1809,6 +1837,10 @@
 				"level": 0,
 				"name": [ "Shaman1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 53, 0 ] ], //expert haste
 				"defname": "ZM181NPC.DEF"
 			},
 
@@ -1817,6 +1849,10 @@
 				"level": 0,
 				"name": [ "AstralSpirit1" ],
 				"faction": -1,
+				"ability_add": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
+								[ "CASTS", 1, 0, 0 ] ,
+								[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
+								[ "SPELLCASTER", 3, 58, 0 ] ], //expert counterstrike
 				"defname": "ZM182NPC.DEF"
 			},
 

+ 40 - 14
lib/BattleState.cpp

@@ -376,6 +376,40 @@ std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool
 	return ret;
 }
 
+BattleHex BattleInfo::getClosestTile (bool attackerOwned, int initialPos, std::set<BattleHex> & possibilities) const
+{
+	std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
+
+	BattleHex initialHex = BattleHex(initialPos);
+	auto compareDistance = [initialPos, initialHex](const BattleHex left, const BattleHex right) -> bool
+	{
+		return initialHex.getDistance (initialHex, left) < initialHex.getDistance (initialHex, right);
+	};
+
+	boost::sort (sortedTiles, compareDistance); //closest tiles at front
+
+	int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away
+
+	auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool
+	{
+		return closestDistance < here.getDistance (initialPos, here);
+	};
+
+	boost::remove_if (sortedTiles, notClosest); //only closest tiles are interesting
+
+	auto compareHorizontal = [attackerOwned](const BattleHex left, const BattleHex right) -> bool
+	{
+		if (attackerOwned)
+			return left.getX() > right.getX(); //find furthest right
+		else
+			return left.getX() < right.getX(); //find furthest left
+	};
+
+	boost::sort (sortedTiles, compareHorizontal);
+
+	return sortedTiles.front();
+}
+
 int BattleInfo::getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos) const
 {
 	int pos;
@@ -391,23 +425,15 @@ int BattleInfo::getAvaliableHex(TCreature creID, bool attackerOwned, int initial
 
 	bool ac[GameConstants::BFIELD_SIZE];
 	std::set<BattleHex> occupyable;
+
 	bool twoHex = VLC->creh->creatures[creID]->isDoubleWide();
 	bool flying = VLC->creh->creatures[creID]->isFlying();// vstd::contains(VLC->creh->creatures[creID]->bonuses, Bonus::FLYING);
-	getAccessibilityMap(ac, twoHex, attackerOwned, true, occupyable, flying);
-	for (int g = pos; (-1 < g) && (g < GameConstants::BFIELD_SIZE); )
-	{
-		if ((g % GameConstants::BFIELD_WIDTH != 0) && (g % GameConstants::BFIELD_WIDTH != GameConstants::BFIELD_WIDTH-1) && BattleInfo::isAccessible (g, ac, twoHex, attackerOwned, flying, true))
-		{
-			pos = g;
-			break;
-		}
-		if (attackerOwned)
-			++g; //probably some more sophisticated range-based iteration is needed
-		else
-			--g;
-	}
+	getAccessibilityMap (ac, twoHex, attackerOwned, true, occupyable, flying);
+
+	if (!occupyable.size())
+		return -1; //all tiles are covered
 
-	return pos;
+	return getClosestTile (attackerOwned, initialPos, occupyable);
 }
 
 bool BattleInfo::isStackBlocked(const CStack * stack) const

+ 1 - 0
lib/BattleState.h

@@ -92,6 +92,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
 	const CStack * getStackT(BattleHex tileID, bool onlyAlive = true) const;
 	void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<BattleHex> & occupyable, bool flying, const CStack* stackToOmmit = NULL) const; //send pointer to at least 187 allocated bytes
 	static bool isAccessible(BattleHex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
+	BattleHex getClosestTile (bool attackerOwned, int initialPos, std::set<BattleHex> & possibilities) const; //TODO: vector or set? copying one to another is bad
 	int getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
 	void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
 	std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes

+ 28 - 0
lib/CCreatureSet.cpp

@@ -946,6 +946,34 @@ ui8 CStackInstance::bearerType() const
 	return ArtBearer::CREATURE;
 }
 
+CCommanderInstance::CCommanderInstance()
+{
+	init();
+}
+
+CCommanderInstance::CCommanderInstance (TCreature id)
+{
+	init();
+	CStackInstance (id, 1); //init with single unit
+	name = "Commando"; //TODO - parse them
+}
+
+void CCommanderInstance::init()
+{
+	alive = true;
+	experience = 0;
+	count = 0;
+	type = NULL;
+	idRand = -1;
+	_armyObj = NULL;
+	setNodeType (Bonus::COMMANDER);	
+}
+
+CCommanderInstance::~CCommanderInstance()
+{
+
+}
+
 CStackBasicDescriptor::CStackBasicDescriptor()
 {
 	type = NULL;

+ 8 - 2
lib/CCreatureSet.h

@@ -28,6 +28,7 @@ public:
 
 class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CArtifactSet
 {
+protected:
 	const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
 public:
 	int idRand; //hlp variable used during loading game -> "id" placeholder for randomization
@@ -56,7 +57,7 @@ public:
 	si32 magicResistance() const;
 	int getCreatureID() const; //-1 if not available
 	std::string getName() const; //plural or singular
-	void init();
+	virtual void init();
 	CStackInstance();
 	CStackInstance(TCreature id, TQuantity count);
 	CStackInstance(const CCreature *cre, TQuantity count);
@@ -65,7 +66,7 @@ public:
 	void setType(int creID);
 	void setType(const CCreature *c);
 	void setArmyObj(const CArmedInstance *ArmyObj);
-	void giveStackExp(expType exp);
+	virtual void giveStackExp(expType exp);
 	bool valid(bool allowUnrandomized) const;
 	ui8 bearerType() const OVERRIDE; //from CArtifactSet
 	virtual std::string nodeName() const OVERRIDE; //from CBonusSystemnode
@@ -74,6 +75,7 @@ public:
 
 class DLL_LINKAGE CCommanderInstance : public CStackInstance
 {
+public:
 	//TODO: what if Commander is not a part of creature set?
 
 	//commander class is determined by its base creature
@@ -81,6 +83,10 @@ class DLL_LINKAGE CCommanderInstance : public CStackInstance
 	std::string name; // each Commander has different name
 	std::vector <std::pair <ui8, ui8> > secondarySkills; //ID, level
 	//std::vector <CArtifactInstance *> arts;
+	void init();
+	CCommanderInstance();
+	CCommanderInstance (TCreature id);
+	~CCommanderInstance();
 
 	ui64 getPower() const {return 0;};
 	int getExpRank() const {return 0;};

+ 6 - 0
lib/CObjectHandler.cpp

@@ -711,6 +711,7 @@ CGHeroInstance::CGHeroInstance()
 	visitedTown = NULL;
 	type = NULL;
 	boat = NULL;
+	commander = NULL;
 	sex = 0xff;
 	secSkills.push_back(std::make_pair(-1, -1));
 	speciality.setNodeType(CBonusSystemNode::SPECIALITY);
@@ -773,6 +774,11 @@ void CGHeroInstance::initHero()
 	}
 	assert(validTypes());
 
+	if (GameConstants::COMMANDERS)
+	{
+		commander = new CCommanderInstance (VLC->creh->factionCommanders[type->heroType / 2]); //hopefully it returns town type
+	}
+
 	hoverName = VLC->generaltexth->allTexts[15];
 	boost::algorithm::replace_first(hoverName,"%s",name);
 	boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);

+ 1 - 1
lib/CObjectHandler.h

@@ -327,7 +327,7 @@ public:
 		h & exp & level & name & biography & portrait & mana & secSkills & movement
 			& sex & inTownGarrison & /*artifacts & artifWorn & */spells & patrol & moveDir;
 
-		h & type & speciality;
+		h & type & speciality & commander;
 		BONUS_TREE_DESERIALIZATION_FIX
 		//visitied town pointer will be restored by map serialization method
 	}

+ 1 - 0
lib/HeroBonus.h

@@ -213,6 +213,7 @@ struct DLL_LINKAGE Bonus
 		CAMPAIGN_BONUS,
 		SPECIAL_WEEK,
 		STACK_EXPERIENCE,
+		COMMANDER, //TODO: consider using simply STACK_INSTANCE
 		OTHER /*used for defensive stance and default value of spell level limit*/
 	};
 

+ 1 - 0
lib/RegisterTypes.h

@@ -85,6 +85,7 @@ void registerTypes1(Serializer &s)
 	s.template registerType<CArtifact>();
 	s.template registerType<CCreature>();
 	s.template registerType<CStackInstance>();
+	s.template registerType<CCommanderInstance>();
 	s.template registerType<PlayerState>();
 	s.template registerType<TeamState>();
 	s.template registerType<CGameState>();

+ 2 - 0
lib/map.h

@@ -25,6 +25,7 @@ class CArtifactInstance;
 class CGDefInfo;
 class CGObjectInstance;
 class CGHeroInstance;
+class CCommanderInstance;
 class CGCreature;
 class CQuest;
 class CGTownInstance;
@@ -305,6 +306,7 @@ struct DLL_LINKAGE Mapa : public CMapHeader
 	std::vector< ConstTransitivePtr<CGHeroInstance> > heroes;
 	std::vector< ConstTransitivePtr<CGTownInstance> > towns;
 	std::vector< ConstTransitivePtr<CArtifactInstance> > artInstances; //stores all artifacts
+	//std::vector< ConstTransitivePtr<CCommanderInstance> > commanders;
 	//bmap<ui16, ConstTransitivePtr<CGCreature> > monsters;
 	//bmap<ui16, ConstTransitivePtr<CGHeroInstance> > heroesToBeat;