Răsfoiți Sursa

* blocked map scrolling where dialog window is opened
* it's possible in battles to check remeaining HP of neutral stacks
* function in CGameInterface called when spell is casted. Support for the Magic Arrow from engine side.
* heroes can regain mana
* support for mistycisim and intelligence skills
* fixed leak with creating frameratekeeper every turn
* minor improvements

Michał W. Urbańczyk 17 ani în urmă
părinte
comite
9d099e8c54

+ 2 - 1
CAdvmapInterface.cpp

@@ -26,6 +26,7 @@
 #include <boost/thread.hpp>
 #include "map.h"
 #include "client/CSpellWindow.h"
+#include "lib/CondSh.h"
 #pragma warning (disable : 4355) 
 extern TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX; //fonts
 
@@ -1201,7 +1202,7 @@ void CAdvMapInt::update()
 
 	}
 	++heroAnim;
-	if(animValHitCount % 4)
+	if((animValHitCount % 4) && !LOCPLINT->showingDialog->get())
 	{
 		if(scrollingLeft)
 		{

+ 1 - 1
CBattleInterface.cpp

@@ -1710,8 +1710,8 @@ void CBattleHex::clickRight(boost::logic::tribool down)
 				pom->defenseBonus = h->primSkills[1];
 				pom->luck = h->getCurrentLuck();
 				pom->morale = h->getCurrentMorale();
-				pom->currentHealth = myst.firstHPleft;
 			}
+			pom->currentHealth = myst.firstHPleft;
 			(new CCreInfoWindow(myst.creature->idNumber,0,myst.amount,pom,boost::function<void()>(),boost::function<void()>(),NULL))
 					->activate();
 		}

+ 2 - 0
CGameInterface.h

@@ -22,6 +22,7 @@ class CArmedInstance;
 struct BattleResult;
 struct BattleAttack;
 struct BattleStackAttacked;
+struct SpellCasted;
 class CObstacle
 {
 	int ID;
@@ -74,6 +75,7 @@ public:
 	virtual void battleEnd(BattleResult *br){};
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest){};
+	virtual void battleSpellCasted(SpellCasted *sc){};
 	virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
 	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
 };

+ 9 - 0
CGameState.cpp

@@ -606,6 +606,15 @@ void CGameState::applyNL(IPack * pack)
 			applyNL(&br->bsa);
 			break;
 		}
+	case 3009:
+		{
+			SpellCasted *sc = static_cast<SpellCasted*>(pack);
+			CGHeroInstance *h = (sc->side) ? getHero(curB->hero2) : getHero(curB->hero1);
+			if(h)
+				h->mana -= VLC->spellh->spells[sc->id].costs[sc->skill];
+			//TODO: counter
+			break;
+		}
 	}
 }
 void CGameState::apply(IPack * pack)

+ 4 - 8
CMT.cpp

@@ -140,13 +140,9 @@ int main(int argc, char** argv)
 		CGI->dobjinfo = VLC->dobjinfo;
 		CGI->buildh = VLC->buildh;
 		tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
-		//cgi->curh->initCursor();
-		//cgi->curh->showGraphicCursor();
 		pomtime.getDif();
 		cgi->curh = new CCursorHandler; 
 		cgi->curh->initCursor();
-		//cgi->screenh = new CScreenHandler;
-		//cgi->screenh->initScreen();
 		tlog0<<"\tScreen handler: "<<pomtime.getDif()<<std::endl;
 		CAbilityHandler * abilh = new CAbilityHandler;
 		abilh->loadAbilities();
@@ -187,7 +183,7 @@ int main(int argc, char** argv)
 		cgi->pathf = new CPathfinder();
 		tlog0<<"\tPathfinder: "<<pomtime.getDif()<<std::endl;
 		tlog0<<"Handlers initialization (together): "<<tmh.getDif()<<std::endl;
-		std::ofstream lll("client_log.txt");
+		std::ofstream logs("client_log.txt");
 
 		CConnection *c=NULL;
 		//wait until server is ready
@@ -206,7 +202,7 @@ int main(int argc, char** argv)
 			try
 			{
 				tlog0 << "Establishing connection...\n";
-				c = new CConnection("127.0.0.1",portc,NAME,lll);
+				c = new CConnection("127.0.0.1",portc,NAME,logs);
 			}
 			catch(...)
 			{
@@ -281,10 +277,10 @@ void processCommand(const std::string &message)
 		txth->init(std::string(DATA_DIR "Data" PATHSEPARATOR "H3bitmap.lod"),"data");
 		tlog0<<"done.\nScanning .lod file\n";
 		int curp=0;
-		std::string pattern = ".TXT";
+		std::string pattern = ".TXT", pom;
 		for(int i=0;i<txth->entries.size(); i++)
 		{
-			std::string pom = txth->entries[i].nameStr;
+			pom = txth->entries[i].nameStr;
 			if(boost::algorithm::find_last(pom,pattern))
 			{
 				txth->extractFile(std::string("Extracted_txts\\")+pom,pom);

+ 39 - 35
CPlayerInterface.cpp

@@ -961,6 +961,11 @@ CPlayerInterface::CPlayerInterface(int Player, int serial)
 	pim = new boost::recursive_mutex;
 	showingDialog = new CondSh<bool>(false);
 	heroMoveSpeed = 2;
+	//initializing framerate keeper
+	mainFPSmng = new FPSmanager;
+	SDL_initFramerate(mainFPSmng);
+	SDL_setFramerate(mainFPSmng, 48);
+	//framerate keeper initialized
 }
 CPlayerInterface::~CPlayerInterface()
 {
@@ -972,12 +977,6 @@ void CPlayerInterface::init(ICallback * CB)
 	cb = dynamic_cast<CCallback*>(CB);
 	adventureInt = new CAdvMapInt(playerID);
 	castleInt = NULL;
-	std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
-	for(int i=0;i<hh.size();i++)
-	{
-		SDL_Surface * pom = infoWin(hh[i]);
-		graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
-	}
 	std::vector<const CGTownInstance*> tt = cb->getTownsInfo(false);
 	for(int i=0;i<tt.size();i++)
 	{
@@ -989,19 +988,25 @@ void CPlayerInterface::yourTurn()
 {
 	LOCPLINT = this;
 	makingTurn = true;
+
+	for(std::map<int,SDL_Surface*>::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes
+		SDL_FreeSurface(i->second);
+	graphics->heroWins.clear();
+	std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
+	for(int i=0;i<hh.size();i++)
+	{
+		SDL_Surface * pom = infoWin(hh[i]);
+		graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
+	}
+
 	adventureInt->infoBar.newDay(cb->getDate(1));
+
 	if(adventureInt->heroList.items.size())
 		adventureInt->select(adventureInt->heroList.items[0].first);
 	else
 		adventureInt->select(adventureInt->townList.items[0]);
 	adventureInt->activate();
-	//show rest of things
 
-	//initializing framerate keeper
-	mainFPSmng = new FPSmanager;
-	SDL_initFramerate(mainFPSmng);
-	SDL_setFramerate(mainFPSmng, 48);
-	//framerate keeper initialized
 	timeHandler th;
 	th.getDif();
 	for(;makingTurn;) // main loop
@@ -2046,7 +2051,7 @@ void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	curint->deactivate();
-	curint = new CBattleInterface(army1,army2,hero1,hero2);
+	curint = battleInt = new CBattleInterface(army1,army2,hero1,hero2);
 	curint->activate();
 	LOCPLINT->objsToBlit.push_back(dynamic_cast<IShowable*>(curint));
 }
@@ -2058,20 +2063,20 @@ void CPlayerInterface::battlefieldPrepared(int battlefieldType, std::vector<CObs
 void CPlayerInterface::battleNewRound(int round) //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	dynamic_cast<CBattleInterface*>(curint)->newRound(round);
+	battleInt->newRound(round);
 }
 
 void CPlayerInterface::actionStarted(const BattleAction* action)
 {
 	curAction = action;
 	if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))
-		&& static_cast<CBattleInterface*>(curint)->creAnims[action->stackNumber]->framesInGroup(20)
+		&& battleInt->creAnims[action->stackNumber]->framesInGroup(20)
 		)
 	{
-		static_cast<CBattleInterface*>(curint)->creAnims[action->stackNumber]->setType(20);
+		battleInt->creAnims[action->stackNumber]->setType(20);
 	if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //deactivating interface when move is started
 	{
-		static_cast<CBattleInterface*>(curint)->deactivate();
+		battleInt->deactivate();
 	}
 }
 }
@@ -2081,13 +2086,13 @@ void CPlayerInterface::actionFinished(const BattleAction* action)
 	curAction = NULL;
 	if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
 	{
-		static_cast<CBattleInterface*>(curint)->activate();
+		battleInt->activate();
 	}
 }
 
 BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack
 {
-	CBattleInterface *b = dynamic_cast<CBattleInterface*>(curint);
+	CBattleInterface *b = battleInt;
 	{
 		boost::unique_lock<boost::recursive_mutex> un(*pim);
 		b->stackActivated(stackID);
@@ -2117,7 +2122,8 @@ void CPlayerInterface::battleResultQuited()
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	((CBattleInterface*)curint)->resWindow->deactivate();
 	objsToBlit -= curint;
-	delete curint;
+	delete battleInt;
+	battleInt = 0;
 	curint = adventureInt;
 	adventureInt->activate();
 	LOCPLINT->showingDialog->setn(false);
@@ -2126,30 +2132,28 @@ void CPlayerInterface::battleResultQuited()
 void CPlayerInterface::battleStackMoved(int ID, int dest)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	dynamic_cast<CBattleInterface*>(curint)->stackMoved(ID, dest, dest==curAction->destinationTile);
+	battleInt->stackMoved(ID, dest, dest==curAction->destinationTile);
+}
+void CPlayerInterface::battleSpellCasted(SpellCasted *sc)
+{
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
+}
+void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
+{
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 }
 void CPlayerInterface::battleAttack(BattleAttack *ba)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	if(ba->shot())
-		dynamic_cast<CBattleInterface*>(curint)->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
+		battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
 	else
-		dynamic_cast<CBattleInterface*>(curint)->stackAttacking( ba->stackAttacking, ba->counter() ? curAction->destinationTile : curAction->additionalInfo );
+		battleInt->stackAttacking( ba->stackAttacking, ba->counter() ? curAction->destinationTile : curAction->additionalInfo );
 	if(ba->killed())
-		dynamic_cast<CBattleInterface*>(curint)->stackKilled(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
+		battleInt->stackKilled(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
 	else
-		dynamic_cast<CBattleInterface*>(curint)->stackIsAttacked(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
+		battleInt->stackIsAttacked(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
 }
-//void CPlayerInterface::battleStackKilled(int ID, int dmg, int killed, int IDby, bool byShooting)
-//{
-//	dynamic_cast<CBattleInterface*>(curint)->stackKilled(ID, dmg, killed, IDby, byShooting);
-//}
-
-//void CPlayerInterface::battleStackIsShooting(int ID, int dest)
-//{
-//	dynamic_cast<CBattleInterface*>(curint)->stackIsShooting(ID, dest);
-//}
-
 void CPlayerInterface::showComp(SComponent comp)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);

+ 5 - 1
CPlayerInterface.h

@@ -15,6 +15,7 @@ class CDefEssential;
 class CGHeroInstance;
 class CAdvMapInt;
 class CCastleInterface;
+class CBattleInterface;
 class CStack;
 class SComponent;
 class CCreature;
@@ -326,6 +327,7 @@ public:
 	CMainInterface *curint;
 	CAdvMapInt * adventureInt;
 	CCastleInterface * castleInt;
+	CBattleInterface * battleInt;
 	FPSmanager * mainFPSmng;
 	IStatusBar *statusbar;
 	//to commucate with engine
@@ -369,6 +371,8 @@ public:
 	void battleResultQuited();
 	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	void battleStackMoved(int ID, int dest);
+	void battleSpellCasted(SpellCasted *sc);
+	void battleStackAttacked(BattleStackAttacked * bsa);
 	void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 
@@ -378,7 +382,7 @@ public:
 	void showComp(SComponent comp);
 	void openTownWindow(const CGTownInstance * town); //shows townscreen
 	void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
-	SDL_Surface * infoWin(const CGObjectInstance * specific); //specific=0 => draws info about selected town/hero //TODO - gdy sie dorobi sensowna hierarchie klas ins. to wywalic tego brzydkiego void*
+	SDL_Surface * infoWin(const CGObjectInstance * specific); //specific=0 => draws info about selected town/hero
 	void handleEvent(SDL_Event * sEvent);
 	void handleKeyDown(SDL_Event *sEvent);
 	void handleKeyUp(SDL_Event *sEvent);

+ 25 - 1
client/Client.cpp

@@ -525,6 +525,17 @@ void CClient::process(int what)
 			gs->apply(&br);
 			break;
 		}
+	case 3005:
+		{
+			BattleStackAttacked bsa;
+			*serv >> bsa;
+			gs->apply(&bsa);
+			if(playerint.find(gs->curB->side1) != playerint.end())
+				playerint[gs->curB->side1]->battleStackAttacked(&bsa);
+			if(playerint.find(gs->curB->side2) != playerint.end())
+				playerint[gs->curB->side2]->battleStackAttacked(&bsa);
+			break;
+		}
 	case 3006:
 		{
 			BattleAttack ba;
@@ -544,7 +555,7 @@ void CClient::process(int what)
 	case 3007:
 		{
 			*serv >> curbaction;
-			tlog5 << "Action started. ID: " << curbaction.actionType << ". Destination: "<< curbaction.destinationTile <<std::endl;
+			tlog5 << "Action started. ID: " << (int)curbaction.actionType << ". Destination: "<< curbaction.destinationTile <<std::endl;
 			if(playerint.find(gs->curB->side1) != playerint.end())
 				playerint[gs->curB->side1]->actionStarted(&curbaction);
 			if(playerint.find(gs->curB->side2) != playerint.end())
@@ -565,6 +576,19 @@ void CClient::process(int what)
 				playerint[gs->curB->side2]->actionFinished(&curbaction);
 			break;
 		}
+	case 3009:
+		{
+			tlog5 << "Spell casted!\n";
+			SpellCasted sc;
+			*serv >> sc;
+			gs->apply(&sc);
+			//todo - apply
+			if(playerint.find(gs->curB->side1) != playerint.end())
+				playerint[gs->curB->side1]->battleSpellCasted(&sc);
+			if(playerint.find(gs->curB->side2) != playerint.end())
+				playerint[gs->curB->side2]->battleSpellCasted(&sc);
+			break;
+		}
 	case 9999:
 		break;
 	default:

+ 3 - 6
client/Graphics.cpp

@@ -24,18 +24,17 @@ using namespace CSDL_Ext;
 Graphics * graphics = NULL;
 SDL_Surface * Graphics::drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface *ret, int from, int to)
 {
-	char * buf = new char[10];
+	char buf[10];
 	for (int i=from;i<to;i++)
 	{
 		SDL_itoa(curh->getPrimSkillLevel(i),buf,10);
 		printAtMiddle(buf,84+28*i,68,GEOR13,zwykly,ret);
 	}
-	delete[] buf;
 	return ret;
 }
 SDL_Surface * Graphics::drawHeroInfoWin(const CGHeroInstance * curh)
 {
-	char * buf = new char[10];
+	char buf[10];
 	blueToPlayersAdv(hInfo,curh->tempOwner);
 	SDL_Surface * ret = SDL_DisplayFormat(hInfo);
 	SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format,0,255,255));
@@ -50,14 +49,13 @@ SDL_Surface * Graphics::drawHeroInfoWin(const CGHeroInstance * curh)
 	blitAt(graphics->portraitLarge[curh->portrait],11,12,ret);
 	SDL_itoa(curh->mana,buf,10);
 	printAtMiddle(buf,166,109,GEORM,zwykly,ret); //mana points
-	delete[] buf;
 	blitAt(morale22->ourImages[curh->getCurrentMorale()+3].bitmap,14,84,ret);
 	blitAt(luck22->ourImages[curh->getCurrentLuck()+3].bitmap,14,101,ret);
 	return ret;
 }
 SDL_Surface * Graphics::drawTownInfoWin(const CGTownInstance * curh)
 {
-	char * buf = new char[10];
+	char buf[10];
 	blueToPlayersAdv(tInfo,curh->tempOwner);
 	SDL_Surface * ret = SDL_DisplayFormat(tInfo);
 	SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format,0,255,255));
@@ -87,7 +85,6 @@ SDL_Surface * Graphics::drawTownInfoWin(const CGTownInstance * curh)
 	if(curh->garrisonHero)
 		blitAt(graphics->heroInGarrison,158,87,ret);
 	blitAt(bigTownPic->ourImages[pom].bitmap,13,13,ret);
-	delete[] buf;
 	return ret;
 }
 

+ 1 - 0
client/VCMI_client.vcproj

@@ -65,6 +65,7 @@
 				ShowProgress="0"
 				AdditionalLibraryDirectories="G:\vcmt\repa\libs"
 				GenerateDebugInformation="true"
+				OptimizeReferences="1"
 				TargetMachine="1"
 				Profile="true"
 			/>

+ 3 - 0
global.h

@@ -235,6 +235,9 @@ extern DLL_EXPORT CLogger<5> tlog5; //gray - minor log info
 	{									\
 		tlog1 << e->what()<< std::endl;	\
 		delete e;						\
+	}									\
+	catch (const std::string& e) {		\
+		tlog1 << e << std::endl;	\
 	}
 
 #define HANDLE_EXCEPTIONC(COMMAND)  \

+ 1 - 1
hch/CDefObjInfoHandler.cpp

@@ -27,6 +27,7 @@ void CDefObjInfoHandler::load()
 	std::istringstream inp(bitmaph->getTextFile("ZOBJCTS.TXT"));
 	int objNumber;
 	inp>>objNumber;
+	std::string mapStr;
 	for(int hh=0; hh<objNumber; ++hh)
 	{
 		CGDefInfo* nobj = new CGDefInfo();
@@ -41,7 +42,6 @@ void CDefObjInfoHandler::load()
 			nobj->blockMap[o] = 0xff;
 			nobj->visitMap[o] = 0x00;
 		}
-		std::string mapStr;
 		inp>>mapStr;
 		std::reverse(mapStr.begin(), mapStr.end());
 		for(int v=0; v<mapStr.size(); ++v)

+ 28 - 7
hch/CObjectHandler.cpp

@@ -15,6 +15,7 @@ void CObjectHandler::loadObjects()
 {
 	VLC->objh = this;
 	int ID=0;
+	tlog5 << "\t\tReading OBJNAMES \n";
 	std::string buf = bitmaph->getTextFile("OBJNAMES.TXT");
 	int it=0;
 	while (it<buf.length()-1)
@@ -26,6 +27,7 @@ void CObjectHandler::loadObjects()
 		names.push_back(nobj);
 	}
 
+	tlog5 << "\t\tReading ADVEVENT \n";
 	buf = bitmaph->getTextFile("ADVEVENT.TXT");
 	it=0;
 	std::string temp;
@@ -38,6 +40,7 @@ void CObjectHandler::loadObjects()
 		advobtxt.push_back(temp);
 	}
 
+	tlog5 << "\t\tReading XTRAINFO \n";
 	buf = bitmaph->getTextFile("XTRAINFO.TXT");
 	it=0;
 	while (it<buf.length()-1)
@@ -46,6 +49,7 @@ void CObjectHandler::loadObjects()
 		xtrainfo.push_back(temp);
 	}
 
+	tlog5 << "\t\tReading MINENAME \n";
 	buf = bitmaph->getTextFile("MINENAME.TXT");
 	it=0;
 	while (it<buf.length()-1)
@@ -54,6 +58,7 @@ void CObjectHandler::loadObjects()
 		mines.push_back(std::pair<std::string,std::string>(temp,""));
 	}
 
+	tlog5 << "\t\tReading MINEEVNT \n";
 	buf = bitmaph->getTextFile("MINEEVNT.TXT");
 	it=0;
 	int i=0;
@@ -64,6 +69,7 @@ void CObjectHandler::loadObjects()
 		mines[i++].second = temp;
 	}
 
+	tlog5 << "\t\tReading RESTYPES \n";
 	buf = bitmaph->getTextFile("RESTYPES.TXT");
 	it=0;
 	while (it<buf.length()-1)
@@ -72,6 +78,7 @@ void CObjectHandler::loadObjects()
 		restypes.push_back(temp);
 	}
 
+	tlog5 << "\t\tReading cregens \n";
 	cregens.resize(110); //TODO: hardcoded value - change
 	for(int i=0; i<cregens.size();i++)
 		cregens[i]=-1;
@@ -84,6 +91,8 @@ void CObjectHandler::loadObjects()
 	}
 	ifs.close();
 	ifs.clear();
+
+	tlog5 << "\t\tReading ZCRGN1 \n";
 	buf = bitmaph->getTextFile("ZCRGN1.TXT");
 	it=0;
 	while (it<buf.length()-1)
@@ -91,7 +100,7 @@ void CObjectHandler::loadObjects()
 		loadToIt(temp,buf,it,3);
 		creGens.push_back(temp);
 	}
-
+	tlog5 << "\t\tDone loading objects!\n";
 }
 
 bool CGObjectInstance::isHero() const
@@ -252,13 +261,25 @@ int CGHeroInstance::getSightDistance() const //returns sight distance of this he
 {
 	return 6 + getSecSkillLevel(3); //default + scouting
 }
-void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
+
+int CGHeroInstance::manaLimit() const
 {
-	if (h3m)
-		pos = Pos;
-	else
-		pos = convertPosition(Pos,true);
-}
+	double modifier = 1.0;
+	switch(getSecSkillLevel(24)) //intelligence level
+	{
+	case 1:		modifier+=0.25;		break;
+	case 2:		modifier+=0.5;		break;
+	case 3:		modifier+=1.0;		break;
+	}
+	return 10*primSkills[3]*modifier;
+}
+//void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
+//{
+//	if (h3m)
+//		pos = Pos;
+//	else
+//		pos = convertPosition(Pos,true);
+//}
 
 bool CGHeroInstance::canWalkOnSea() const
 {

+ 2 - 1
hch/CObjectHandler.h

@@ -120,7 +120,8 @@ public:
 	static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
 	int3 getPosition(bool h3m) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
 	int getSightDistance() const; //returns sight distance of this hero
-	void setPosition(int3 Pos, bool h3m); //as above, but sets position
+	int manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
+	//void setPosition(int3 Pos, bool h3m); //as above, but sets position
 
 	bool canWalkOnSea() const;
 	int getCurrentLuck() const;

+ 20 - 2
lib/NetPacks.h

@@ -416,7 +416,8 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
 {
 	ui32 stackAttacked;
 	ui32 newAmount, newHP, killedAmount, damageAmount;
-	ui8 flags; //1 - is stack killed
+	ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown
+	ui32 effect; //set only if flag 2 is present
 
 
 	BattleStackAttacked(){flags = 0; type = 3005;};
@@ -424,9 +425,13 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
 	{
 		return flags & 1;
 	}
+	bool isEffect() //if target stack was killed
+	{
+		return flags & 2;
+	}
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount;
+		h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount & effect;
 	}
 };
 
@@ -468,6 +473,19 @@ struct StartAction : public CPack<StartAction>//3007
 	}
 };
 
+struct SpellCasted : public CPack<SpellCasted>//3009
+{
+	ui8 side; //which hero casted spell: 0 - attacker, 1 - defender
+	ui32 id;
+	ui8 skill;
+	ui16 tile; //destination tile (may not be set in some global/mass spells
+	SpellCasted(){type = 3009;};
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & side & id & skill & tile;
+	}
+};
+
 struct ShowInInfobox : public CPack<ShowInInfobox> //107
 {
 	ShowInInfobox(){type = 107;};

+ 103 - 37
server/CGameHandler.cpp

@@ -349,37 +349,40 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
 	delete battleResult.data;
 
 }
-void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
-{
-	bat.stackAttacking = att->ID;
-	bat.bsa.stackAttacked = def->ID;
-	bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage
-
-	//applying damages
-	bat.bsa.killedAmount = bat.bsa.damageAmount / def->creature->hitPoints;
-	unsigned damageFirst = bat.bsa.damageAmount % def->creature->hitPoints;
+void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)
+{	
+	bsa.killedAmount = bsa.damageAmount / def->creature->hitPoints;
+	unsigned damageFirst = bsa.damageAmount % def->creature->hitPoints;
 
 	if( def->firstHPleft <= damageFirst )
 	{
-		bat.bsa.killedAmount++;
-		bat.bsa.newHP = def->firstHPleft + def->creature->hitPoints - damageFirst;
+		bsa.killedAmount++;
+		bsa.newHP = def->firstHPleft + def->creature->hitPoints - damageFirst;
 	}
 	else
 	{
-		bat.bsa.newHP = def->firstHPleft - damageFirst;
+		bsa.newHP = def->firstHPleft - damageFirst;
 	}
 
-	if(def->amount <= bat.bsa.killedAmount) //stack killed
+	if(def->amount <= bsa.killedAmount) //stack killed
 	{
-		bat.bsa.newAmount = 0;
-		bat.bsa.flags |= 1;
-		bat.bsa.killedAmount = def->amount; //we cannot kill more creatures than we have
+		bsa.newAmount = 0;
+		bsa.flags |= 1;
+		bsa.killedAmount = def->amount; //we cannot kill more creatures than we have
 	}
 	else
 	{
-		bat.bsa.newAmount = def->amount - bat.bsa.killedAmount;
+		bsa.newAmount = def->amount - bsa.killedAmount;
 	}
 }
+
+void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
+{
+	bat.stackAttacking = att->ID;
+	bat.bsa.stackAttacked = def->ID;
+	bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage
+	prepareAttacked(bat.bsa,def);
+}
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
 	try
@@ -427,12 +430,13 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 					tmh.result = 0;
 					tmh.movePoints = h->movement;
 
-					if((h->getOwner() != gs->currentPlayer) || //not turn of that hero
-						(distance(start,end)>=1.5) || //tiles are not neighouring
-						(h->movement < cost) || //lack of movement points
-						(t.tertype == rock) || //rock
-						(!h->canWalkOnSea() && t.tertype == water) ||
-						(t.blocked && !t.visitable) ) //tile is blocked andnot visitable
+					if((h->getOwner() != gs->currentPlayer) //not turn of that hero
+						|| (distance(start,end)>=1.5) //tiles are not neighouring
+						|| (h->movement < cost) //lack of movement points
+						|| (t.tertype == rock)  //rock
+						|| (!h->canWalkOnSea() && t.tertype == water)
+						|| (t.blocked && !t.visitable) //tile is blocked andnot visitable
+						) 
 						goto fail;
 
 					
@@ -1008,8 +1012,19 @@ upgend:
 					case 1: //hero casts spell
 						{
 							CGHeroInstance *h = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
+							if(!h)
+							{
+								tlog2 << "Wrong caster!\n";
+								goto customactionend;
+							}
+							if(ba.additionalInfo >= VLC->spellh->spells.size())
+							{
+								tlog2 << "Wrong spell id (" << ba.additionalInfo << ")!\n";
+								goto customactionend;
+							}
+
 							CSpell *s = &VLC->spellh->spells[ba.additionalInfo];
-							int skill = 0;
+							int skill = 0; //skill level
 
 							if(s->fire)
 								skill = std::max(skill,h->getSecSkillLevel(14));
@@ -1020,15 +1035,66 @@ upgend:
 							if(s->earth)
 								skill = std::max(skill,h->getSecSkillLevel(17));
 
-							if(  !vstd::contains(h->spells,ba.additionalInfo) //hero doesn't know this spell
-								|| (h->mana < s->costs[skill]) //not enough mana
+							//TODO: skill level may be different on special terrain
+
+							if( // !vstd::contains(h->spells,ba.additionalInfo) //hero doesn't know this spell 
+								/*||*/ (h->mana < s->costs[skill]) //not enough mana
+								|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
 								|| 0     )//TODO: hero has already casted a spell in this round
 							{
+								tlog2 << "Spell cannot be casted!\n";
 								goto customactionend;
 							}
 
 							sendAndApply(&StartAction(ba)); //start spell casting
-							//TODO: spell efects
+
+							//TODO: check resistances
+
+							SpellCasted sc;
+							sc.side = ba.side;
+							sc.id = ba.additionalInfo;
+							sc.skill = skill;
+							sc.tile = ba.destinationTile;
+							sendAndApply(&sc);
+							switch(ba.additionalInfo) //spell id
+							{
+							case 15://magic arrow
+								{
+									CStack * attacked = gs->curB->getStackT(ba.destinationTile);
+									if(!attacked) break;
+									BattleStackAttacked bsa;
+									bsa.flags |= 2;
+									bsa.effect = 64;
+									bsa.damageAmount = h->primSkills[2] * 10; //TODO: use skill level
+									bsa.stackAttacked = attacked->ID;
+									prepareAttacked(bsa,attacked);
+									sendAndApply(&bsa);
+									break;
+								}
+							case 53: //haste
+								{
+									break;
+								}
+							}
+
+							//TODO: spells to support possibly soon (list by Zamolxis):
+							/*- Magic Arrow
+							- Haste
+							- Bless
+							- Bloodlust
+							- Curse
+							- Dispel
+							- Shield
+							- Slow
+							- Stone Skin
+							- Lightning Bolt
+							- Ice Bolt
+							- Precision
+							- Blind
+							- Fire Wall
+							- Weakness
+							- Death Ripple */
+
 							sendDataToClients(ui16(3008)); //end casting
 							break;
 						}
@@ -1198,15 +1264,15 @@ void CGameHandler::newTurn()
 		for(int j=0;j<RESOURCE_QUANTITY;j++)
 			r.res[j] = i->second.resources[j];
 		
-		for (unsigned j=0;j<(*i).second.heroes.size();j++) //handle heroes
+		BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes)
 		{
-			NewTurn::Hero h;
-			h.id = (*i).second.heroes[j]->id;
-			h.move = valMovePoints((*i).second.heroes[j], true); //TODO: check if hero is really on the land
-			h.mana = (*i).second.heroes[j]->mana;
-			n.heroes.insert(h);
-			//handle estates
-			switch((*i).second.heroes[j]->getSecSkillLevel(13))
+			NewTurn::Hero hth;
+			hth.id = h->id;
+			hth.move = valMovePoints(h, true); //TODO: check if hero is really on the land
+			hth.mana = std::min(h->mana+1+h->getSecSkillLevel(8), h->manaLimit()); //hero regains 1 mana point + mysticism lvel
+			n.heroes.insert(hth);
+			
+			switch(h->getSecSkillLevel(13)) //handle estates - give gols
 			{
 			case 1: //basic
 				r.res[6] += 125;
@@ -1263,10 +1329,10 @@ void CGameHandler::run()
 		ui8 quantity, pom;
 		//ui32 seed;
 		(*cc) << gs->scenarioOps->mapname << gs->map->checksum << gs->seed;
-		(*cc) >> quantity;
+		(*cc) >> quantity; //how many players will be handled at that client
 		for(int i=0;i<quantity;i++)
 		{
-			(*cc) >> pom;
+			(*cc) >> pom; //read player color
 			gsm.lock();
 			connections[pom] = cc;
 			gsm.unlock();

+ 2 - 0
server/CGameHandler.h

@@ -13,6 +13,7 @@ class CCPPObjectScript;
 class CScriptCallback;
 struct BattleResult;
 struct BattleAttack;
+struct BattleStackAttacked;
 template <typename T> struct CPack;
 template <typename T> struct Query;
 class CGHeroInstance;
@@ -58,6 +59,7 @@ class CGameHandler
 	void moveStack(int stack, int dest);
 	void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
 	void prepareAttack(BattleAttack &bat, CStack *att, CStack *def); //if last parameter is true, attack is by shooting, if false it's a melee attack
+	void prepareAttacked(BattleStackAttacked &bsa, CStack *def);
 
 	void checkForBattleEnd( std::vector<CStack*> &stacks );
 	void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 );