Browse Source

* Fixed enchantments (#1265). Their effects were not properly added when reading config. Battle interface will be little less likely to block itself after corrupted spell cast.
* Fail gracefully when the file from which game is started is in invalid version.
* Bumped versions.

Michał W. Urbańczyk 12 years ago
parent
commit
fc6e72dc75

+ 17 - 9
client/CMT.cpp

@@ -97,22 +97,30 @@ void startGame(StartInfo * options, CConnection *serv = NULL);
 
 void startGameFromFile(const std::string &fname)
 {
-	if(fname.size() && boost::filesystem::exists(fname))
+	StartInfo si;
+	try //attempt retrieving start info from given file
 	{
-		StartInfo si;
+		if(!fname.size() || !boost::filesystem::exists(fname))
+			throw std::runtime_error("Startfile \"" + fname + "\" does not exist!");
+
 		CLoadFile out(fname);
 		if(!out.sfile || !*out.sfile)
 		{
-            logGlobal->errorStream() << "Failed to open startfile, falling back to the main menu!";
-			GH.curInt = CGPreGame::create();
-			return;
+			throw std::runtime_error("Cannot read from startfile \"" + fname + "\"!");
 		}
 		out >> si;
-		while(GH.topInt())
-			GH.popIntTotally(GH.topInt());
-
-		startGame(&si);
 	}
+	catch(std::exception &e)
+	{
+		logGlobal->errorStream() << "Failed to start from the file: " + fname << ". Error: " << e.what() 
+			<< " Falling back to main menu.";
+		GH.curInt = CGPreGame::create();
+		return;
+	}
+
+	while(GH.topInt())
+		GH.popIntTotally(GH.topInt());
+	startGame(&si);
 }
 
 void init()

+ 7 - 4
client/battle/CBattleInterface.cpp

@@ -2493,10 +2493,7 @@ void CBattleInterface::projectileShowHelper(SDL_Surface * to)
 void CBattleInterface::endAction(const BattleAction* action)
 {
 	const CStack * stack = curInt->cb->battleGetStackByID(action->stackNumber);
-	//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
-// 	{
-// 		activate();
-// 	}
+
 	if(action->actionType == Battle::HERO_SPELL)
 	{
 		if(action->side)
@@ -2536,6 +2533,12 @@ void CBattleInterface::endAction(const BattleAction* action)
 
 	if( action->actionType == Battle::HERO_SPELL) //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
 		redrawBackgroundWithHexes(activeStack);
+
+	if(activeStack && !animsAreDisplayed.get() && pendingAnims.empty() && !active)
+	{
+		logGlobal->warnStream() << "Something wrong... interface was deactivated but there is no animation. Reactivating...";
+		activate();
+	}
 }
 
 void CBattleInterface::hideQueue()

+ 17 - 4
lib/CSpellHandler.cpp

@@ -248,14 +248,19 @@ CSpell::ETargetType CSpell::getTargetType() const
 
 void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
 {
-	if (level < 0 || level>3)
+	if (level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
 	{
         logGlobal->errorStream() << __FUNCTION__ << " invalid school level " << level;
 		return;
 	}
 	if (effects.empty())
 	{
-        logGlobal->errorStream() << __FUNCTION__ << " This spell has no bonus effects! " << name;
+        logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") has no bonus effects! " << name;
+		return;
+	}
+	if (effects.size() <= level)
+	{
+		logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") is missing entry for level " << level;
 		return;
 	}
 	lst.reserve(lst.size() + effects[level].size());
@@ -440,7 +445,8 @@ CSpellHandler::CSpellHandler()
 	spells.push_back(spells[SpellID::ACID_BREATH_DEFENSE]); //clone Acid Breath attributes for Acid Breath damage effect
 
 	//loading of additional spell traits
-	const JsonNode config(ResourceID("config/spell_info.json"));
+	JsonNode config(ResourceID("config/spell_info.json"));
+	config.setMeta("core");
 
 	BOOST_FOREACH(auto &spell, config["spells"].Struct())
 	{
@@ -493,7 +499,14 @@ CSpellHandler::CSpellHandler()
 			auto v = v_node.convertTo<std::vector<int> >();
 			auto a = a_node.convertTo<std::vector<int> >();
 
-			for (int i=0; i<s->effects.size() ; i++)
+			if(v.size() && v.size() != GameConstants::SPELL_SCHOOL_LEVELS)
+				logGlobal->errorStream() << s->name << " should either have no values or exactly " << GameConstants::SPELL_SCHOOL_LEVELS;
+			if(a.size() && a.size() != GameConstants::SPELL_SCHOOL_LEVELS)
+				logGlobal->errorStream() << s->name << " should either have no ainfos or exactly " << GameConstants::SPELL_SCHOOL_LEVELS;
+			
+			s->effects.resize(GameConstants::SPELL_SCHOOL_LEVELS);
+
+			for (int i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS; i++)
 			{
 				Bonus * b = JsonUtils::parseBonus(bonus_node);
 				b->sid = s->id; //for all

+ 1 - 1
lib/Connection.h

@@ -27,7 +27,7 @@
 #include "mapping/CCampaignHandler.h" //for CCampaignState
 #include "rmg/CMapGenerator.h" // for CMapGenOptions
 
-const ui32 version = 739;
+const ui32 version = 740;
 
 class CConnection;
 class CGObjectInstance;

+ 2 - 1
lib/GameConstants.h

@@ -14,7 +14,7 @@
 
 namespace GameConstants
 {
-	const std::string VCMI_VERSION = "VCMI 0.92";
+	const std::string VCMI_VERSION = "VCMI 0.92b";
 
 	const int BFIELD_WIDTH = 17;
 	const int BFIELD_HEIGHT = 11;
@@ -30,6 +30,7 @@ namespace GameConstants
 	const ui16 BACKPACK_START = 19;
 	const int CREATURES_PER_TOWN = 7; //without upgrades
 	const int SPELL_LEVELS = 5;
+	const int SPELL_SCHOOL_LEVELS = 4;
 	const int CRE_LEVELS = 10; // number of creature experience levels
 
 	const int SPELLBOOK_GOLD_COST = 500;

+ 2 - 0
lib/mapping/MapFormatH3M.cpp

@@ -1538,6 +1538,8 @@ CGObjectInstance * CMapLoaderH3M::readHero(ObjectInstanceID idToBeGiven)
 	PlayerColor owner = PlayerColor(reader.readUInt8());
 	nhi->subID = reader.readUInt8();
 
+	//If hero of this type has been predefined, use that as a base.
+	//Instance data will overwrite the predefined values where appropriate.
 	for(int j = 0; j < map->predefinedHeroes.size(); ++j)
 	{
 		if(map->predefinedHeroes[j]->subID == nhi->subID)