瀏覽代碼

* partial implementation of SRSL parser (although it's enough for almost all Heroes III spells)
* config/spell_info.txt is now less unholy (its size is no more 666 bytes) :)

mateuszb 16 年之前
父節點
當前提交
ece364f735
共有 3 個文件被更改,包括 247 次插入73 次删除
  1. 71 71
      config/spell_info.txt
  2. 172 1
      hch/CSpellHandler.cpp
  3. 4 1
      hch/CSpellHandler.h

+ 71 - 71
config/spell_info.txt

@@ -1,73 +1,73 @@
 //additional spell info, not included in original heroes III files
-//[spellID - -1 is the end of data in file] [-1 -> spell is negative for influenced creatures; 0 - spell is indifferent for them; 1 - spell is poitive for them]
-0 0
-1 0
-2 0
-3 0
-4 0
-5 0
-6 0
-7 0
-8 0
-9 0
-10 0
-11 0
-12 0
-13 0
-14 0
-15 -1
-16 -1
-17 -1
-18 -1
-19 -1
-20 -1
-21 -1
-22 -1
-23 -1
-24 -1
-25 -1
-26 -1
-27 1
-28 1
-29 1
-30 1
-31 1
-32 1
-33 1
-34 1
-35 1
-36 1
-37 1
-38 1
-39 1
-40 1
-41 1
-42 -1
-43 1
-44 1
-45 -1
-46 1
-47 -1
-48 1
-49 1
-50 -1
-51 1
-52 -1
-53 1
-54 -1
-55 1
-56 1
-57 -1
-58 1
-59 -1
-60 -1
-61 -1
-62 -1
-63 1
-64 0
-65 1
-66 0 
-67 0
-68 0
-69 0
+//[spellID - -1 is the end of data in file] [-1 -> spell is negative for influenced creatures; 0 - spell is indifferent for them; 1 - spell is poitive for them] [spell range description in SRSL, none magic] [basic] [advanced] [expert]
+0 0 X X X X
+1 0 X X X X
+2 0 X X X X
+3 0 X X X X
+4 0 X X X X
+5 0 X X X X
+6 0 X X X X
+7 0 X X X X
+8 0 X X X X
+9 0 X X X X
+10 0 X X X X
+11 0 X X X X
+12 0 0 0 0 0
+13 0 0 0 0 0
+14 0 X X X X
+15 -1 0 0 0 0
+16 -1 0 0 0 0
+17 -1 0 0 0 0
+18 -1 0 0 0 0
+19 -1 0 0 0 0
+20 -1 1 1 1 1
+21 -1 0,1 0,1 0,1 0,1
+22 -1 0-2 0-2 0-2 0-2
+23 -1 0,1 0,1 0,1 0,1
+24 -1 X X X X
+25 -1 X X X X
+26 -1 X X X X
+27 1 0 0 0 X
+28 1 0 0 0 X
+29 1 0 0 0 X
+30 1 0 0 0 X
+31 1 0 0 0 X
+32 1 0 0 0 X
+33 1 0 0 0 X
+34 1 0 0 0 X
+35 1 0 0 0 X
+36 1 0 0 0 0
+37 1 0 0 0 0
+38 1 0 0 0 0
+39 1 0 0 0 0
+40 1 0 0 0 0
+41 1 0 0 0 X
+42 -1 0 0 0 X
+43 1 0 0 0 X
+44 1 0 0 0 X
+45 -1 0 0 0 X
+46 1 0 0 0 X
+47 -1 0 0 0 X
+48 1 0 0 0 X
+49 1 0 0 0 X
+50 -1 0 0 0 X
+51 1 0 0 0 X
+52 -1 0 0 0 X
+53 1 0 0 0 X
+54 -1 0 0 0 X
+55 1 0 0 0 0
+56 1 0 0 0 0
+57 -1 0 0 0 0
+58 1 0 0 0 X
+59 -1 0 0 0-1 0-2
+60 -1 0 0 0 0
+61 -1 0 0 0 X
+62 -1 0 0 0 0
+63 1 0 0 0 0
+64 0 X X X X
+65 1 0 0 0 0
+66 0 X X X X
+67 0 X X X X
+68 0 X X X X
+69 0 X X X X
 -1

+ 172 - 1
hch/CSpellHandler.cpp

@@ -4,7 +4,175 @@
 #include "CLodHandler.h"
 #include "../lib/VCMI_Lib.h"
 #include <boost/algorithm/string/replace.hpp>
+#include <cctype>
+
+
 extern CLodHandler *bitmaph;
+
+namespace SRSLPraserHelpers
+{
+	int XYToHex(int x, int y)
+	{
+		return x + 17 * y;
+	}
+
+	int XYToHex(std::pair<int, int> xy)
+	{
+		return XYToHex(xy.first, xy.second);
+	}
+
+	int hexToY(int battleFieldPosition)
+	{
+		return battleFieldPosition/17;
+	}
+
+	int hexToX(int battleFieldPosition)
+	{
+		int pos = battleFieldPosition - hexToY(battleFieldPosition) * 17;
+		return pos;
+	}
+
+	std::pair<int, int> hexToPair(int battleFieldPosition)
+	{
+		return std::make_pair(hexToX(battleFieldPosition), hexToY(battleFieldPosition));
+	}
+
+	//moves hex by one hex in given direction
+	//0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left
+	std::pair<int, int> gotoDir(int x, int y, int direction)
+	{
+		switch(direction)
+		{
+		case 0: //top left
+			return std::make_pair(y%2 ? x-1 : x, y-1);
+		case 1: //top right
+			return std::make_pair(y%2 ? x : x+1, y-1);
+		case 2:  //right
+			return std::make_pair(x+1, y);
+		case 3: //right bottom
+			return std::make_pair(y%2 ? x : x+1, y+1);
+		case 4: //left bottom
+			return std::make_pair(y%2 ? x-1 : x, y+1);
+		case 5: //left
+			return std::make_pair(x-1, y);
+		}
+	}
+
+	std::pair<int, int> gotoDir(std::pair<int, int> xy, int direction)
+	{
+		return gotoDir(xy.first, xy.second, direction);
+	}
+
+	bool isGoodHex(std::pair<int, int> xy)
+	{
+		return xy.first >=0 && xy.first < 17 && xy.second >= 0 && xy.second < 11;
+	}
+
+	//helper fonction for std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const
+	std::set<ui16> getInRange(unsigned int center, int low, int high)
+	{
+		std::set<ui16> ret;
+		if(low == 0)
+		{
+			ret.insert(center);
+		}
+
+		std::pair<int, int> mainPointForLayer[6]; //A, B, C, D, E, F points
+		for(int b=0; b<6; ++b)
+			mainPointForLayer[b] = hexToPair(center);
+
+		for(int it=1; it<=high; ++it) //it - distance to the center
+		{		
+			for(int b=0; b<6; ++b)
+				mainPointForLayer[b] = gotoDir(mainPointForLayer[b], b);
+
+			if(it>=low)
+			{
+				std::pair<int, int> curHex;
+
+				//adding lines (A-b, B-c, C-d, etc)
+				for(int v=0; v<6; ++v)
+				{
+					curHex = mainPointForLayer[v];
+					for(int h=0; h<it; ++h)
+					{
+						if(isGoodHex(curHex))
+							ret.insert(XYToHex(curHex));
+						curHex = gotoDir(curHex, (v+2)%6);
+					}
+				}
+
+			} //if(it>=low)
+		}
+
+		return ret;
+	}
+}
+using namespace SRSLPraserHelpers;
+
+std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const
+{
+	std::set<ui16> ret;
+
+	std::string rng = range[schoolLvl] + ','; //copy + artificial comma for easier handling
+
+	if(rng.size() >= 1 && rng[0] != 'X') //there is at lest one hex in range
+	{
+		std::string number1, number2;
+		int beg, end;
+		bool readingFirst = true;
+		for(int it=0; it<rng.size(); ++it)
+		{
+			if( std::isdigit(rng[it]) ) //reading numer
+			{
+				if(readingFirst)
+					number1 += rng[it];
+				else
+					number2 += rng[it];
+			}
+			else if(rng[it] == ',') //comma
+			{
+				//calculating variables
+				if(readingFirst)
+				{
+					beg = atoi(number1.c_str());
+					number1 = "";
+				}
+				else
+				{
+					end = atoi(number2.c_str());
+					number2 = "";
+				}
+				//obtaining new hexes
+				std::set<ui16> curLayer;
+				if(readingFirst)
+				{
+					curLayer = getInRange(centralHex, beg, beg);
+				}
+				else
+				{
+					curLayer = getInRange(centralHex, beg, end);
+					readingFirst = true;
+				}
+				//adding abtained hexes
+				for(std::set<ui16>::iterator it = curLayer.begin(); it != curLayer.end(); ++it)
+				{
+					ret.insert(*it);
+				}
+
+			}
+			else if(rng[it] == '-') //dash
+			{
+				beg = atoi(number1.c_str());
+				number1 = "";
+				readingFirst = false;
+			}
+		}
+	}
+
+	return ret;
+}
+
 void CSpellHandler::loadSpells()
 {
 	std::string buf = bitmaph->getTextFile("SPTRAITS.TXT"), pom;
@@ -90,7 +258,7 @@ void CSpellHandler::loadSpells()
 	{
 		//reading header
 		std::string dump;
-		for(int i=0; i<42; ++i) ast>>dump;
+		for(int i=0; i<52; ++i) ast>>dump;
 		//reading exact info
 		int spellID;
 		ast>>spellID;
@@ -99,6 +267,9 @@ void CSpellHandler::loadSpells()
 			int buf;
 			ast>>buf;
 			spells[spellID].positiveness = buf;
+			spells[spellID].range.resize(4);
+			for(int g=0; g<4; ++g)
+				ast>>spells[spellID].range[g];
 			ast>>spellID;
 		}
 	}

+ 4 - 1
hch/CSpellHandler.h

@@ -3,6 +3,7 @@
 
 #include <string>
 #include <vector>
+#include <set>
 
 class CSpell
 {
@@ -25,12 +26,14 @@ public:
 	bool combatSpell; //is this spell combat (true) or adventure (false)
 	bool creatureAbility; //if true, only creatures can use this spell
 	si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
+	std::vector<std::string> range; //description of spell's range in SRSL by magic school level
+	std::set<ui16> rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const; //convert range to specific hexes
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs 
-			& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness;
+			& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range;
 	}
 };