2
0
Эх сурвалжийг харах

* fixed project files for RD configuration
* fixed crash when creature is casting Hypnosis (ie. exped Vampire Lords)
* fixed crash when creature is casting Cure before attack (ie. exped Unicorns)
* fixed crash when creature is summoning elemental (TODO fix it)
* fixed crash when doing a bonus system operation with a hero liberated from prison (ie. entering town or battle)
* fixed deadlock when StupidAI tried to assault the turrets
* fixed never ending siege when StupidAI has to use catapult (no more deadlocks on AI-AI siege)
* fixed deadlock when a hero received a level during another player's turn (ie. when he successfully defended)
* AI can win the game by defeating all enemies if there is a specific victory condition applying only to human players
* added options to help testing adventure map AI (--onlyAI, --autoSkip and --oneGoodAI).
* many minor changes

Michał W. Urbańczyk 14 жил өмнө
parent
commit
046e54563c

+ 5 - 11
AI/GeniusAI/CGeniusAI.cpp

@@ -1353,14 +1353,6 @@ void CGeniusAI::battleSpellCast(const BattleSpellCast *sc)
 // }
 
 
-/**
- *
- */
-void CGeniusAI::battleStackAttacking(int ID, int dest)
-{
-	DbgBox("\t\t\tCGeniusAI::battleStackAttacking");
-}
-
 
 /**
  *
@@ -1386,9 +1378,11 @@ BattleAction CGeniusAI::activeStack(const CStack * stack)
 	message += ")";
 	DbgBox(message.c_str());
 
-	BattleAction bact = m_battleLogic->MakeDecision(stack->ID);
-	assert(m_cb->battleGetStackByID(bact.stackNumber));
-	return bact;
+ 	return BattleAction::makeDefend(stack);
+// 
+// 	BattleAction bact = m_battleLogic->MakeDecision(stack->ID);
+// 	assert(m_cb->battleGetStackByID(bact.stackNumber));
+// 	return bact;
 }
 
 

+ 0 - 1
AI/GeniusAI/CGeniusAI.h

@@ -207,7 +207,6 @@ public:
 	//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 	//
 	//virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);
-	virtual void battleStackAttacking(int ID, int dest);
 	virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting);
 	virtual BattleAction activeStack(const CStack * stack);
 	void battleResultsApplied();

+ 14 - 1
AI/StupidAI/StupidAI.cpp

@@ -102,6 +102,19 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 	std::vector<int> dists = cb->battleGetDistances(stack);
 	std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
 
+	if(stack->type->idNumber == 145) //catapult
+	{
+		BattleAction attack;
+		static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
+		attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
+		attack.actionType = BattleAction::CATAPULT;
+		attack.additionalInfo = 0;
+		attack.side = side;
+		attack.stackNumber = stack->ID;
+
+		return attack;
+	}
+
 	BOOST_FOREACH(const CStack *s, cb->battleGetStacks(CBattleCallback::ONLY_ENEMY))
 	{
 		if(cb->battleCanShoot(stack, s->position))
@@ -125,7 +138,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 				}
 			}
 
-			if(!vstd::contains(enemiesReachable, s))
+			if(!vstd::contains(enemiesReachable, s) && s->position.isValid())
 				enemiesUnreachable.push_back(s);
 		}
 	}

+ 7 - 4
AI/StupidAI/StupidAI.vcxproj

@@ -107,7 +107,7 @@
       <Optimization>Disabled</Optimization>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -124,7 +124,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -143,7 +143,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -160,13 +160,16 @@
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdInc.h</PrecompiledHeaderFile>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="StupidAI.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="StdInc.h" />
     <ClInclude Include="StupidAI.h" />
-	<ClInclude Include="..\..\Global.h" />
+    <ClInclude Include="..\..\Global.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 2 - 4
CCallback.cpp

@@ -58,9 +58,7 @@ void CCallback::selectionMade(int selection, int asker)
 {
 	QueryReply pack(asker,selection);
 	pack.player = player;
-
-	boost::unique_lock<boost::mutex> lock(*cl->serv->wmx);
-	*cl->serv << &pack;
+	cl->serv->sendPackToServer(pack, player);
 }
 void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount, si32 level/*=-1*/)
 {
@@ -192,7 +190,7 @@ void CBattleCallback::sendRequest(const CPack* request)
 	if(waitTillRealize)
 		cl->waitingRequest.set(typeList.getTypeID(request));
 
-	cl->serv->sendPack(*request);
+	cl->serv->sendPackToServer(*request, player);
 
 	if(waitTillRealize)
 	{

+ 4 - 2
client/CConfigHandler.cpp

@@ -172,7 +172,8 @@ void config::CConfigHandler::init()
 	const JsonNode config(GameConstants::DATA_DIR + "/config/resolutions.json");
 	const JsonVector &guisettings_vec = config["GUISettings"].Vector();
 
-	BOOST_FOREACH(const JsonNode &g, guisettings_vec) {
+	BOOST_FOREACH(const JsonNode &g, guisettings_vec) 
+	{
 		std::pair<int,int> curRes(g["resolution"]["x"].Float(), g["resolution"]["y"].Float());
 		GUIOptions *current = &conf.guiOptions[curRes];
 		
@@ -249,6 +250,7 @@ void config::CConfigHandler::init()
 		cc.screenx = cc.resx;
 		cc.screeny = cc.resy;
 	}
-
+	cc.autoSkip = false;
+	cc.oneGoodAI = false;
 	SetResolution(cc.resx, cc.resy);
 }

+ 1 - 0
client/CConfigHandler.h

@@ -27,6 +27,7 @@ namespace config
 			defaultPlayerAI, defaultBattleAI; //dll names
 		bool showFPS; //show/hide FPS counter
 		bool classicCreatureWindow;
+		bool autoSkip, oneGoodAI; //for AI testing purposes
 	};
 	
 	struct ButtonInfo

+ 49 - 7
client/CMT.cpp

@@ -93,6 +93,20 @@ void startGame(StartInfo * options, CConnection *serv = NULL);
 #include <getopt.h>
 #endif
 
+void startGameFromFile(const std::string &fname)
+{
+	if(fname.size() && boost::filesystem::exists(fname))
+	{
+		StartInfo si;
+		CLoadFile out(fname);
+		out >> si;
+		while(GH.topInt())
+			GH.popIntTotally(GH.topInt());
+
+		startGame(&si);
+	}
+}
+
 void init()
 {
 	CStopWatch tmh, pomtime;
@@ -164,16 +178,17 @@ static void prog_version(void)
 	printf("  binary directory:  %s\n", GameConstants::BIN_DIR.c_str());
 }
 
-static void prog_help(const char *progname)
+static void prog_help(const po::options_description &opts)
 {
 	printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str());
-    printf("Copyright (C) 2007-2010 VCMI dev team - see AUTHORS file\n");
+    printf("Copyright (C) 2007-2012 VCMI dev team - see AUTHORS file\n");
     printf("This is free software; see the source for copying conditions. There is NO\n");
     printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
 	printf("\n");
 	printf("Usage:\n");
-	printf("  -h, --help        display this help and exit\n");
-	printf("  -v, --version     display version information and exit\n");
+	std::cout << opts;
+// 	printf("  -h, --help        display this help and exit\n");
+// 	printf("  -v, --version     display version information and exit\n");
 }
 
 
@@ -189,6 +204,10 @@ int main(int argc, char** argv)
 		("help,h", "display help and exit")
 		("version,v", "display version information and exit")
 		("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
+		("start", po::value<std::string>(), "starts game from saved StartInfo file")
+		("onlyAI", "runs without GUI, all players will be default AI")
+		("oneGoodAI", "puts one default AI and the rest will be GeniusAI")
+		("autoSkip", "automatically skip turns in GUI")
 		("nointro,i", "skips intro movies");
 
 	po::variables_map vm;
@@ -207,7 +226,7 @@ int main(int argc, char** argv)
 	po::notify(vm);
 	if(vm.count("help"))
 	{
-		prog_help(0);
+		prog_help(opts);
 		return 0;
 	}
 	if(vm.count("version"))
@@ -269,8 +288,15 @@ int main(int argc, char** argv)
 
 	if(!vm.count("battle"))
 	{
-		//CCS->musich->playMusic(musicBase::mainMenu, -1);
-		GH.curInt = new CGPreGame; //will set CGP pointer to itself
+		gOnlyAI = vm.count("onlyAI");
+		conf.cc.autoSkip = vm.count("autoSkip");
+		conf.cc.oneGoodAI = vm.count("oneGoodAI");
+
+
+		if(!vm.count("start"))
+			GH.curInt = new CGPreGame; //will set CGP pointer to itself
+		else
+			startGameFromFile(vm["start"].as<std::string>());
 	}
 	else
 	{
@@ -508,6 +534,22 @@ void processCommand(const std::string &message)
 	{
 		conf.cc.classicCreatureWindow = !conf.cc.classicCreatureWindow;
 	}
+	else if(cn == "sinfo")
+	{
+		std::string fname;
+		readed >> fname;
+		if(fname.size() && SEL)
+		{
+			CSaveFile out(fname);
+			out << SEL->sInfo;
+		}
+	}
+	else if(cn == "start")
+	{
+		std::string fname;
+		readed >> fname;
+		startGameFromFile(fname);
+	}
 	else if(client && client->serv && client->serv->connected) //send to server
 	{
 		PlayerMessage pm(LOCPLINT->playerID,message);

+ 39 - 11
client/CPlayerInterface.cpp

@@ -2140,6 +2140,11 @@ CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h)
 
 void CPlayerInterface::acceptTurn()
 {
+	if(conf.cc.autoSkip)
+	{
+		while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
+			iw->close();
+	}
 	waitWhileDialog();
 
 	if(howManyPeople > 1)
@@ -2171,24 +2176,47 @@ void CPlayerInterface::acceptTurn()
 		adventureInt->select(towns.front());
 
 	adventureInt->showAll(screen);
+
+	if(conf.cc.autoSkip && !LOCPLINT->shiftPressed())
+	{
+		if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
+			iw->close();
+
+		adventureInt->endTurn.callback();
+	}
 }
 
 void CPlayerInterface::tryDiggging(const CGHeroInstance *h)
 {
 	std::string hlp;
-	if(h->movement < h->maxMovePoints(true))
-		showInfoDialog(CGI->generaltexth->allTexts[56]); //"Digging for artifacts requires a whole day, try again tomorrow."
-	else if(cb->getTile(h->getPosition(false))->tertype == TerrainTile::water)
-		showInfoDialog(CGI->generaltexth->allTexts[60]); //Try looking on land!
-	else
+	CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
+
+	int msgToShow = -1;
+	CGHeroInstance::ECanDig isDiggingPossible = h->diggingStatus();
+	if(hlp.length())
+		isDiggingPossible = CGHeroInstance::TILE_OCCUPIED; //TODO integrate with canDig
+
+	switch(isDiggingPossible)
 	{
-		const TerrainTile *t = cb->getTile(h->getPosition());
-		CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
-		if(hlp.length() || t->blockingObjects.size() > 1)
-			showInfoDialog(CGI->generaltexth->allTexts[97]); //Try searching on clear ground.
-		else
-			cb->dig(h);
+	case CGHeroInstance::CAN_DIG:
+		break;
+	case CGHeroInstance::LACK_OF_MOVEMENT:
+		msgToShow = 56; //"Digging for artifacts requires a whole day, try again tomorrow."
+		break;
+	case CGHeroInstance::TILE_OCCUPIED:
+		msgToShow = 97; //Try searching on clear ground.
+		break;
+	case CGHeroInstance::WRONG_TERRAIN:
+		msgToShow = 60; ////Try looking on land!
+		break;
+	default:
+		assert(0);
 	}
+
+	if(msgToShow < 0)
+		cb->dig(h);
+	else
+		showInfoDialog(CGI->generaltexth->allTexts[msgToShow]);
 }
 
 void CPlayerInterface::updateInfo(const CGObjectInstance * specific)

+ 1 - 0
client/CPreGame.h

@@ -503,4 +503,5 @@ public:
 	void openCampaignScreen(std::string name);
 };
 
+extern ISelectionScreenInfo *SEL;
 extern CGPreGame *CGP;

+ 13 - 6
client/Client.cpp

@@ -121,7 +121,7 @@ void CClient::waitForMoveAndSend(int color)
 		assert(vstd::contains(battleints, color));
 		BattleAction ba = battleints[color]->activeStack(gs->curB->getStack(gs->curB->activeStack, false));
 		MakeAction temp_action(ba);
-		*serv << &temp_action;
+		serv->sendPackToServer(temp_action, color);
 		return;
 	}HANDLE_EXCEPTION
 	tlog1 << "We should not be here!" << std::endl;
@@ -169,7 +169,7 @@ void CClient::save(const std::string & fname)
 	}
 
 	SaveGame save_game(fname);
-	*serv << &save_game;
+	serv->sendPackToServer((CPackForClient&)save_game, getCurrentPlayer());
 }
 
 void CClient::endGame( bool closeConnection /*= true*/ )
@@ -348,6 +348,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	}
 
 	int humanPlayers = 0;
+	int sensibleAILimit = conf.cc.oneGoodAI ? 1 : GameConstants::PLAYER_LIMIT;
 	for(std::map<int, PlayerSettings>::iterator it = gs->scenarioOps->playerInfos.begin(); 
 		it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players
 	{ 
@@ -361,7 +362,13 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 			CCallback *cb = new CCallback(gs,color,this);
 			if(!it->second.human) 
 			{
-				playerint[color] = static_cast<CGameInterface*>(CDynLibHandler::getNewAI(conf.cc.defaultPlayerAI));
+				std::string AItoGive = conf.cc.defaultPlayerAI;
+				if(!sensibleAILimit)
+					AItoGive = "GeniusAI";
+				else
+					sensibleAILimit--;
+				playerint[color] = static_cast<CGameInterface*>(CDynLibHandler::getNewAI(AItoGive));
+				tlog1 << "Player " << (int)color << " will be lead by " << AItoGive << std::endl;
 			}
 			else 
 			{
@@ -515,7 +522,7 @@ void CClient::stopConnection()
 		tlog0 << "Connection has been requested to be closed.\n";
 		boost::unique_lock<boost::mutex>(*serv->wmx);
 		CloseServer close_server;
-		*serv << &close_server;
+		serv->sendPackToServer(close_server, 255);
 		tlog0 << "Sent closing signal to the server\n";
 	}
 
@@ -579,7 +586,7 @@ void CClient::commitPackage( CPackForClient *pack )
 	CommitPackage cp;
 	cp.freePack = false;
 	cp.packToCommit = pack;
-	*serv << &cp;
+	serv->sendPackToServer(cp, 255);
 }
 
 int CClient::getLocalPlayer() const
@@ -605,7 +612,7 @@ void CClient::commenceTacticPhaseForInt(CBattleGameInterface *battleInt)
 		if(gs && !!gs->curB && gs->curB->tacticDistance) //while awaiting for end of tactics phase, many things can happen (end of battle... or game)
 		{
 			MakeAction ma(BattleAction::makeEndOFTacticPhase(battleInt->playerID));
-			serv->sendPack(ma);
+			serv->sendPackToServer(ma, battleInt->playerID);
 		}
 	} HANDLE_EXCEPTION
 }

+ 2 - 1
client/NetPacksClient.cpp

@@ -710,7 +710,6 @@ void EndAction::applyCl( CClient *cl )
 
 void PackageApplied::applyCl( CClient *cl )
 {
-	ui8 player = GS(cl)->currentPlayer;
 	INTERFACE_CALL_IF_PRESENT(player, requestRealized, this);
 	if(cl->waitingRequest.get() == packType)
 		cl->waitingRequest.setn(false);
@@ -811,6 +810,8 @@ void OpenWindow::applyCl(CClient *cl)
 	case THIEVES_GUILD:
 		{
 			//displays Thieves' Guild window (when hero enters Den of Thieves)
+			if(!LOCPLINT)
+				return;
 			const CGObjectInstance *obj = cl->getObj(id1);
 			GH.pushInt( new CThievesGuildWindow(obj) );
 		}

+ 10 - 0
client/VCMI_client.vcxproj

@@ -136,6 +136,8 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <AssemblerOutput>NoListing</AssemblerOutput>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -168,6 +170,8 @@
       <AssemblerListingLocation>$(SolutionDir)$(Configuration)\</AssemblerListingLocation>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -203,6 +207,8 @@
       <AssemblerListingLocation>$(SolutionDir)$(Configuration)\</AssemblerListingLocation>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -250,6 +256,9 @@
     <ClCompile Include="StdInc.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdInc.h</PrecompiledHeaderFile>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="UIFramework\CCursorHandler.cpp" />
     <ClCompile Include="UIFramework\CGuiHandler.cpp" />
@@ -301,6 +310,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="..\ChangeLog" />
+    <None Include="ClassDiagram21.cd" />
     <None Include="vcmi.ico" />
   </ItemGroup>
   <ItemGroup>

+ 2 - 2
lib/BattleState.cpp

@@ -2203,7 +2203,7 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInst
 	return ESpellCastProblem::OK;
 }
 
-std::vector<ui32> BattleInfo::calculateResistedStacks( const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode ) const
+std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const
 {
 	std::vector<ui32> ret;
 	for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
@@ -2241,7 +2241,7 @@ std::vector<ui32> BattleInfo::calculateResistedStacks( const CSpell * sp, const
 			if( (*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
 				|| ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft 
 		> 
-		caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)]
+		usedSpellPower * 25 + sp->powers[spellLevel]
 			)
 			{
 				ret.push_back((*it)->ID);

+ 1 - 1
lib/BattleState.h

@@ -135,7 +135,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
 	TSpell getRandomBeneficialSpell(const CStack * subject) const;
 	TSpell getRandomCastedSpell(const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
 
-	std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode) const;
+	std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const;
 
 
 	bool battleCanFlee(int player) const; //returns true if player can flee from the battle

+ 8 - 2
lib/CCreatureSet.cpp

@@ -210,13 +210,13 @@ ui64 CCreatureSet::getArmyStrength() const
 {
 	ui64 ret = 0;
 	for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); i++)
-		ret += i->second->type->AIValue * i->second->count;
+		ret += i->second->getPower();
 	return ret;
 }
 
 ui64 CCreatureSet::getPower (TSlot slot) const
 {
-	return getCreature(slot)->AIValue * getStackCount(slot);
+	return getStack(slot).getPower();
 }
 std::string CCreatureSet::getRoughAmount (TSlot slot) const
 {
@@ -942,6 +942,12 @@ std::string CStackInstance::getName() const
 	return (count > 1) ? type->namePl : type->nameSing;
 }
 
+ui64 CStackInstance::getPower() const
+{
+	assert(type);
+	return type->AIValue * count;
+}
+
 CStackBasicDescriptor::CStackBasicDescriptor()
 {
 	type = NULL;

+ 1 - 0
lib/CCreatureSet.h

@@ -48,6 +48,7 @@ public:
 	std::string bonusToString(Bonus *bonus, bool description) const; // how would bonus description look for this particular type of node
 	std::string bonusToGraphics(Bonus *bonus) const; //file name of graphics from StackSkills , in future possibly others
 
+	ui64 getPower() const;
 	int getQuantityID() const;
 	std::string getQuantityTXT(bool capitalized = true) const;
 	int getExpRank() const;

+ 0 - 6
lib/CGameInterface.h

@@ -92,12 +92,6 @@ class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate)
 {
 public:
 	CGlobalAI();
-	virtual void yourTurn() OVERRIDE{};
-	virtual void heroKilled(const CGHeroInstance*){};
-	virtual void heroCreated(const CGHeroInstance*) OVERRIDE{};
-	virtual void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) OVERRIDE{};
-	virtual void battleStackAttacking(int ID, int dest) {};
-	virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) OVERRIDE{};
 	virtual BattleAction activeStack(const CStack * stack) OVERRIDE;
 };
 

+ 14 - 2
lib/CGameState.cpp

@@ -1720,6 +1720,9 @@ int CGameState::getPlayerRelations( ui8 color1, ui8 color2 )
 {
 	if ( color1 == color2 )
 		return 2;
+	if(color1 == 255 || color2 == 255) //neutral player has no friends
+		return  0; 
+
 	const TeamState * ts = getPlayerTeam(color1);
 	if (ts && vstd::contains(ts->players, color2))
 		return 1;
@@ -2007,9 +2010,12 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
 int CGameState::victoryCheck( ui8 player ) const
 {
 	const PlayerState *p = CGameInfoCallback::getPlayer(player);
-	if(map->victoryCondition.condition == EVictoryConditionType::WINSTANDARD  ||  map->victoryCondition.allowNormalVictory)
+	if(map->victoryCondition.condition == EVictoryConditionType::WINSTANDARD  ||  map->victoryCondition.allowNormalVictory
+		|| (!p->human && !map->victoryCondition.appliesToAI)) //if the special victory condition applies only to human, AI has the standard)
+	{
 		if(player == checkForStandardWin())
 			return -1;
+	}
 
 	if (p->enteredWinningCheatCode)
 	{ //cheater or tester, but has entered the code...
@@ -2477,6 +2483,11 @@ CGPathNode::CGPathNode()
 	theNodeBefore = NULL;
 }
 
+bool CGPathNode::reachable() const
+{
+	return turns < 255;
+}
+
 bool CPathsInfo::getPath( const int3 &dst, CGPath &out )
 {
 	assert(isValid);
@@ -2940,7 +2951,8 @@ bool CPathfinder::goodForLandSeaTransition()
 				return false;
 
 			//tile must be accessible -> exception: unblocked blockvis tiles -> clear but guarded by nearby monster coast
-			if(dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked)) 
+			if(dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked)
+				|| dt->visitable)  //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
 				return false;;
 
 			useEmbarkCost = 2;

+ 9 - 8
lib/CGameState.h

@@ -217,7 +217,7 @@ struct CPathNode
 	bool visited;
 };
 
-struct CGPathNode
+struct DLL_LINKAGE CGPathNode
 {
 	enum EAccessibility
 	{
@@ -233,7 +233,9 @@ struct CGPathNode
 	ui32 moveRemains;
 	CGPathNode * theNodeBefore;
 	int3 coord; //coordinates
+
 	CGPathNode();
+	bool reachable() const;
 };
 
 
@@ -306,7 +308,7 @@ struct DLL_LINKAGE DuelParameters
 
 class CPathfinder : private CGameInfoCallback
 {
-public:
+private:
 	bool useSubterraneanGates;
 	bool allowEmbarkAndDisembark;
 	CPathsInfo &out;
@@ -323,19 +325,18 @@ public:
 	ui8 useEmbarkCost; //0 - usual movement; 1 - embark; 2 - disembark
 	int destTopVisObjID;
 
-	CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero);;
 
 	CGPathNode *getNode(const int3 &coord);
-
 	void initializeGraph();
-	CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const;
-
-	void calculatePaths(int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or NULL if path does not exists
+	bool goodForLandSeaTransition(); //checks if current move will be between sea<->land. If so, checks it legality (returns false if movement is not possible) and sets useEmbarkCost
 
+	CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const;
 	bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
 	bool canStepOntoDst() const;
-	bool goodForLandSeaTransition(); //checks if current move will be between sea<->land. If so, checks it legality (returns false if movement is not possible) and sets useEmbarkCost
 
+public:
+	CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero);
+	void calculatePaths(int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or NULL if path does not exists
 };
 
 

+ 24 - 0
lib/CObjectHandler.cpp

@@ -1486,6 +1486,25 @@ int CGHeroInstance::movementPointsAfterEmbark(int MPsBefore, int basicCost, bool
 	return 0; //take all MPs otherwise
 }
 
+CGHeroInstance::ECanDig CGHeroInstance::diggingStatus() const
+{
+	std::string hlp;
+	if(movement < maxMovePoints(true))
+		return LACK_OF_MOVEMENT;
+	else if(cb->getTile(getPosition(false))->tertype == TerrainTile::water)
+		return WRONG_TERRAIN;
+	else
+	{
+		const TerrainTile *t = cb->getTile(getPosition());
+		//TODO look for hole
+		//CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
+		if(/*hlp.length() || */t->blockingObjects.size() > 1)
+			return TILE_OCCUPIED;
+		else
+			return CAN_DIG;
+	}
+}
+
 void CGDwelling::initObj()
 {
 	switch(ID)
@@ -2392,6 +2411,11 @@ const CArmedInstance * CGTownInstance::getUpperArmy() const
 	return this;
 }
 
+bool CGTownInstance::hasBuilt(int buildingID) const
+{
+	return vstd::contains(builtBuildings, buildingID);
+}
+
 void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
 {
 	if(visitors.find(h->id)==visitors.end())

+ 7 - 1
lib/CObjectHandler.h

@@ -123,11 +123,11 @@ public:
 
 class DLL_LINKAGE IMarket
 {
-	virtual int getMarketEfficiency() const =0;
 public:
 	const CGObjectInstance *o;
 
 	IMarket(const CGObjectInstance *O);
+	virtual int getMarketEfficiency() const =0;
 	virtual bool allowsTrade(EMarketMode::EMarketMode mode) const;
 	virtual int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
 	virtual std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
@@ -256,6 +256,10 @@ public:
 		SCHOLAR, TACTICS, ARTILLERY, LEARNING, OFFENCE, ARMORER, INTELLIGENCE, SORCERY, RESISTANCE,
 		FIRST_AID
 	};
+	enum ECanDig
+	{
+		CAN_DIG, LACK_OF_MOVEMENT, WRONG_TERRAIN, TILE_OCCUPIED
+	};
 	//////////////////////////////////////////////////////////////////////////
 
 	ui8 moveDir; //format:	123
@@ -366,6 +370,7 @@ public:
 	bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
 	CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
 	void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
+	ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 - 
 
 	//////////////////////////////////////////////////////////////////////////
 
@@ -607,6 +612,7 @@ public:
 	GrowthInfo getGrowthInfo(int level) const;
 	bool hasFort() const;
 	bool hasCapitol() const;
+	bool hasBuilt(int buildingID) const;
 	int dailyIncome() const; //calculates daily income of this town
 	int spellsAtLevel(int level, bool checkGuild) const; //levels are counted from 1 (1 - 5)
 	void removeCapitols (ui8 owner) const;

+ 3 - 2
lib/Connection.cpp

@@ -240,10 +240,11 @@ CPack * CConnection::retreivePack()
 	return ret;
 }
 
-void CConnection::sendPack(const CPack &pack)
+void CConnection::sendPackToServer(const CPack &pack, ui8 player)
 {
 	boost::unique_lock<boost::mutex> lock(*wmx);
-	*this << &pack; //packs has to be sent as polymorphic pointers!
+	tlog5 << "Sending to server a pack of type " << typeid(pack).name() << std::endl;
+	*this << player << &pack; //packs has to be sent as polymorphic pointers!
 }
 
 CSaveFile::CSaveFile( const std::string &fname )

+ 1 - 1
lib/Connection.h

@@ -916,7 +916,7 @@ public:
 	~CConnection(void);
 
 	CPack *retreivePack(); //gets from server next pack (allocates it with new)
-	void sendPack(const CPack &pack);
+	void sendPackToServer(const CPack &pack, ui8 player);
 };
 
 DLL_LINKAGE std::ostream &operator<<(std::ostream &str, const CConnection &cpc);

+ 5 - 0
lib/IGameCallback.cpp

@@ -1253,6 +1253,11 @@ int CGameInfoCallback::getLocalPlayer() const
 	return getCurrentPlayer();
 }
 
+bool CGameInfoCallback::isInTheMap(const int3 &pos) const
+{
+	return gs->map->isInTheMap(pos);
+}
+
 void IGameEventRealizer::showInfoDialog( InfoWindow *iw )
 {
 	commitPackage(iw);

+ 2 - 1
lib/IGameCallback.h

@@ -189,7 +189,8 @@ public:
 	int3 guardingCreaturePosition (int3 pos) const;
 	const CMapHeader * getMapHeader()const;
 	int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
-	const TerrainTile * getTile(int3 tile, bool verbose = true) const;	
+	const TerrainTile * getTile(int3 tile, bool verbose = true) const;
+	bool isInTheMap(const int3 &pos) const;
 
 	//town
 	const CGTownInstance* getTown(int objid) const;

+ 4 - 1
lib/NetPacks.h

@@ -60,12 +60,14 @@ struct CPackForClient : public CPack
 
 struct CPackForServer : public CPack
 {
+	ui8 player;
 	CConnection *c;
 	CGameState* GS(CGameHandler *gh);
 	CPackForServer()
 	{
 		type = 2; 
 		c = NULL;
+		player = 255;
 	};
 
 	bool applyGh(CGameHandler *gh);//called after applying to gs
@@ -170,10 +172,11 @@ struct PackageApplied : public CPackForClient //94
 
 	ui8 result; //0 - something went wrong, request hasn't been realized; 1 - OK
 	ui32 packType; //type id of applied package
+	ui8 player;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & result & packType;
+		h & result & packType & player;
 	}
 };
 

+ 5 - 0
lib/NetPacksLib.cpp

@@ -449,6 +449,11 @@ DLL_LINKAGE void HeroRecruited::applyGs( CGameState *gs )
 DLL_LINKAGE void GiveHero::applyGs( CGameState *gs )
 {
 	CGHeroInstance *h = gs->getHero(id);
+
+	//bonus system
+	h->detachFrom(&gs->globalEffects);
+	h->attachTo(gs->getPlayer(player));
+
 	gs->map->removeBlockVisTiles(h,true);
 	h->setOwner(player);
 	h->movement =  h->maxMovePoints(true);

+ 8 - 0
lib/ResourceSet.h

@@ -78,6 +78,14 @@ namespace Res
 			return ret;
 		}
 
+		DLL_LINKAGE ResourceSet & operator=(const TResource &rhs)
+		{
+			for(int i = 0; i < size(); i++)
+				at(i) = rhs;
+
+			return *this;
+		}
+
 	// WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i] 
 	// that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a
 // 		bool operator<(const ResourceSet &rhs)

+ 11 - 0
lib/VCMI_lib.vcxproj

@@ -134,6 +134,7 @@
       <ExpandAttributedSource>false</ExpandAttributedSource>
       <AssemblerOutput>NoListing</AssemblerOutput>
       <PreprocessToFile>false</PreprocessToFile>
+      <PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -161,6 +162,9 @@
       <AssemblerListingLocation>$(SolutionDir)$(Configuration)\</AssemblerListingLocation>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
     </ClCompile>
     <Link>
       <AdditionalDependencies>zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -197,6 +201,9 @@
       <AssemblerListingLocation>$(SolutionDir)$(Configuration)\</AssemblerListingLocation>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -246,6 +253,10 @@
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdInc.h</PrecompiledHeaderFile>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <ClCompile Include="VCMI_Lib.cpp" />
   </ItemGroup>

+ 5 - 0
lib/map.cpp

@@ -2222,3 +2222,8 @@ bool TerrainTile::hasFavourableWinds() const
 {
 	return siodmyTajemniczyBajt & 128;
 }
+
+bool TerrainTile::isWater() const
+{
+	return tertype == water;
+}

+ 2 - 0
lib/map.h

@@ -67,6 +67,8 @@ struct DLL_LINKAGE TerrainTile
 	bool isClear(const TerrainTile *from = NULL) const; //checks for blocking objs and terraint type (water / land)
 	int topVisitableID() const; //returns ID of the top visitable ovject or -1 if there is none
 
+	bool isWater() const;
+
 	bool isCoastal() const;
 	bool hasFavourableWinds() const;
 };

+ 37 - 26
server/CGameHandler.cpp

@@ -53,6 +53,7 @@ extern bool end2;
 
 #define COMPLAIN_RET_IF(cond, txt) do {if(cond){complain(txt); return;}} while(0)
 #define COMPLAIN_RET(txt) {complain(txt); return false;}
+#define COMPLAIN_RETF(txt, FORMAT) {complain(boost::str(boost::format(txt) % FORMAT)); return false;}
 #define NEW_ROUND 		BattleNextRound bnr;\
 		bnr.round = gs->curB->round + 1;\
 		sendAndApply(&bnr);
@@ -67,7 +68,7 @@ template <typename T> class CApplyOnGH;
 class CBaseForGHApply
 {
 public:
-	virtual bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0; 
+	virtual bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack, ui8 player) const =0; 
 	virtual ~CBaseForGHApply(){}
 	template<typename U> static CBaseForGHApply *getApplier(const U * t=NULL)
 	{
@@ -78,10 +79,11 @@ public:
 template <typename T> class CApplyOnGH : public CBaseForGHApply
 {
 public:
-	bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const
+	bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack, ui8 player) const
 	{
 		T *ptr = static_cast<T*>(pack);
 		ptr->c = c;
+		ptr->player = player;
 		return ptr->applyGh(gh);
 	}
 };
@@ -121,7 +123,8 @@ void PlayerStatuses::addPlayer(ui8 player)
 	boost::unique_lock<boost::mutex> l(mx);
 	players[player];
 }
-bool PlayerStatuses::hasQueries(ui8 player)
+
+int PlayerStatuses::getQueriesCount(ui8 player)
 {
 	boost::unique_lock<boost::mutex> l(mx);
 	if(players.find(player) != players.end())
@@ -130,9 +133,10 @@ bool PlayerStatuses::hasQueries(ui8 player)
 	}
 	else
 	{
-		throw std::string("No such player!");
+		return 0;
 	}
 }
+
 bool PlayerStatuses::checkFlag(ui8 player, bool PlayerStatus::*flag)
 {
 	boost::unique_lock<boost::mutex> l(mx);
@@ -624,24 +628,26 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 	setThreadName(-1, "CGameHandler::handleConnection");
 	srand(time(NULL));
 	CPack *pack = NULL;
+	ui8 player = 255;
 	try
 	{
 		while(1)//server should never shut connection first //was: while(!end2)
 		{
 			{
 				boost::unique_lock<boost::mutex> lock(*c.rmx);
-				c >> pack; //get the package
+				c >> player >> pack; //get the package
 				tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
 			}
 
 			int packType = typeList.getTypeID(pack); //get the id of type
 			CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
-			if(packType != typeList.getTypeID<QueryReply>() &&
-			   (packType != typeList.getTypeID<ArrangeStacks>() || !isAllowedArrangePack((ArrangeStacks*)pack)) && // for dialogs like garrison
-			   states[getCurrentPlayer()].queries.size())
+			if(packType != typeList.getTypeID<QueryReply>() 
+				&&   (packType != typeList.getTypeID<ArrangeStacks>() || !isAllowedArrangePack((ArrangeStacks*)pack)) // for dialogs like garrison
+				&&   states.getQueriesCount(player))
 			{
-				complain("Answer the query before attempting any further actions!");
+				complain(boost::str(boost::format("Player %d has to answer queries  before attempting any further actions (count=%d)!") % (int)player % states.getQueriesCount(player)));
 				PackageApplied applied;
+				applied.player = player;
 				applied.result = false;
 				applied.packType = packType;
 				{
@@ -651,11 +657,12 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 			}
 			else if(apply)
 			{
-				bool result = apply->applyOnGH(this,&c,pack);
+				bool result = apply->applyOnGH(this,&c,pack, player);
 				tlog5 << "Message successfully applied (result=" << result << ")!\n";
 
 				//send confirmation that we've applied the package
 				PackageApplied applied;
+				applied.player = player;
 				applied.result = result;
 				applied.packType = packType;
 				{
@@ -669,6 +676,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 			}
 			delete pack;
 			pack = NULL;
+			player = 255;
 		}
 	}
 	catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
@@ -3544,7 +3552,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 	}
 
 	//checking if creatures resist
-	sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode);
+	sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode, usedSpellPower, spellLvl);
 
 	//calculating dmg to display
 	for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
@@ -3775,7 +3783,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 						hi.healedHP = gs->curB->calculateHealedHP(hpGained, spell, *it);
 					}
 					else
-						hi.healedHP = gs->curB->calculateHealedHP(spell, usedSpellPower, stack->getBonus(Selector::typeSubtype(Bonus::SPELLCASTER, spell->id))->additionalInfo, *it);
+						hi.healedHP = gs->curB->calculateHealedHP(spell, usedSpellPower, spellLvl, *it);
 				}
 				else
 					hi.healedHP = gs->curB->calculateHealedHP(caster, spell, *it);
@@ -3809,16 +3817,20 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 			}
 
 			BattleStackAdded bsa;
-
-			bsa.pos = gs->curB->getAvaliableHex(creID, !(bool)casterSide); //TODO: unify it
-
-			bsa.amount = caster->getPrimSkillLevel(2) * VLC->spellh->spells[spellID]->powers[spellLvl] *
-				(100 + caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, spellID)) / 100.0; //new feature - percentage bonus
-
 			bsa.creID = creID;
 			bsa.attacker = !(bool)casterSide;
 			bsa.summoned = true;
-			sendAndApply(&bsa);
+			bsa.pos = gs->curB->getAvaliableHex(creID, !(bool)casterSide); //TODO: unify it
+
+			//TODO stack casting -> probably power will be zero; set the proper number of creatures manually
+			int percentBonus = caster ? caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, spellID) : 0;
+
+			bsa.amount = usedSpellPower * VLC->spellh->spells[spellID]->powers[spellLvl] *
+				(100 + percentBonus) / 100.0; //new feature - percentage bonus
+			if(bsa.amount)
+				sendAndApply(&bsa);
+			else
+				complain("Summoning elementals didn't summon any!");
 		}
 		break;
 	case Spells::REMOVE_OBSTACLE:
@@ -4605,18 +4617,17 @@ bool CGameHandler::dig( const CGHeroInstance *h )
 		}
 	}
 
+	if(h->diggingStatus() != CGHeroInstance::CAN_DIG) //checks for terrain and movement
+		COMPLAIN_RETF("Hero cannot dig (error code %d)!", h->diggingStatus());
+
+	//create a hole
 	NewObject no;
 	no.ID = 124;
 	no.pos = h->getPosition();
 	no.subID = getTile(no.pos)->tertype;
-
-	if(no.subID >= 8) //no digging on water / rock
-	{
-		complain("Cannot dig - wrong terrain type!");
-		return false;
-	}
 	sendAndApply(&no);
-
+	
+	//take MPs
 	SetMovePoints smp;
 	smp.hid = h->id;
 	smp.val = 0;

+ 1 - 1
server/CGameHandler.h

@@ -59,7 +59,7 @@ public:
 
 	void addPlayer(ui8 player);
 	PlayerStatus operator[](ui8 player);
-	bool hasQueries(ui8 player);
+	int getQueriesCount(ui8 player); //returns 0 if there is no such player
 	bool checkFlag(ui8 player, bool PlayerStatus::*flag);
 	void setFlag(ui8 player, bool PlayerStatus::*flag, bool val);
 	void addQuery(ui8 player, ui32 id);

+ 6 - 3
server/VCMI_server.vcxproj

@@ -125,7 +125,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -151,7 +151,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -182,7 +182,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -201,6 +201,9 @@
     <ClCompile Include="StdInc.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdInc.h</PrecompiledHeaderFile>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Create</PrecompiledHeader>
     </ClCompile>
   </ItemGroup>
   <ItemGroup>