Răsfoiți Sursa

* swapping artifacts (needs testing)
* various improvements and fixes for interface
* put changelog into ChangeLog

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

+ 3 - 0
CAdvmapInterface.cpp

@@ -2,6 +2,7 @@
 #include "CAdvmapInterface.h"
 #include "client/CBitmapHandler.h"
 #include "CPlayerInterface.h"
+#include "CCastleInterface.h"
 #include "hch/CPreGameTextHandler.h"
 #include "hch/CGeneralTextHandler.h"
 #include "hch/CDefHandler.h"
@@ -1098,6 +1099,8 @@ void CAdvMapInt::handleRightClick(std::string text, tribool down, CIntObject * c
 			{
 				LOCPLINT->objsToBlit.erase(LOCPLINT->objsToBlit.begin()+(i));
 				delete pom;
+				if((LOCPLINT->curint == LOCPLINT->castleInt) && !LOCPLINT->castleInt->subInt)
+					LOCPLINT->castleInt->showAll(0,true);
 			}
 		}
 	}

+ 1 - 1
CBattleInterface.cpp

@@ -456,7 +456,7 @@ void CBattleInterface::stackKilled(int ID, int dmg, int killed, int IDby, bool b
 		}
 	}
 	creAnims[ID]->setType(5); //death
-	for(int i=0; i<creAnims[ID]->framesInGroup(5)-1; ++i)
+	for(int i=0; i<creAnims[ID]->framesInGroup(5); ++i)
 	{
 		show();
 		CSDL_Ext::update();

+ 34 - 25
CCallback.cpp

@@ -136,20 +136,24 @@ void CCallback::endTurn()
 }
 UpgradeInfo CCallback::getUpgradeInfo(const CArmedInstance *obj, int stackPos)
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->getUpgradeInfo(const_cast<CArmedInstance*>(obj),stackPos);
 }
 
 const StartInfo * CCallback::getStartInfo()
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->scenarioOps;
 }
 
 int CCallback::howManyTowns()
 {
-	return gs->players[gs->currentPlayer].towns.size();
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
+	return gs->players[player].towns.size();
 }
 const CGTownInstance * CCallback::getTownInfo(int val, bool mode) //mode = 0 -> val = serial; mode = 1 -> val = ID
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	if (!mode)
 		return gs->players[gs->currentPlayer].towns[val];
 	else 
@@ -293,6 +297,7 @@ std::vector < const CGHeroInstance *> CCallback::getHeroesInfo(bool onlyOur)
 
 bool CCallback::isVisible(int3 pos)
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return isVisible(pos,player);
 }
 
@@ -312,6 +317,7 @@ int CCallback::getHeroSerial(const CGHeroInstance * hero)
 }
 const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj)
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	if(!obj)
 		return NULL;
 	if(obj->ID == 34)
@@ -325,7 +331,6 @@ int CCallback::swapCreatures(const CGObjectInstance *s1, const CGObjectInstance
 {
 	if(s1->tempOwner != player   ||   s2->tempOwner != player)
 		return -1;
-
 	*cl->serv << ui16(502) << ui8(1) << s1->id << ui8(p1) << s2->id << ui8(p2);
 	return 0;
 }
@@ -362,31 +367,35 @@ int CCallback::getMySerial()
 	return gs->players[player].serial;
 }
 
-bool CCallback::swapArifacts(const CGHeroInstance * hero1, bool worn1, int pos1, const CGHeroInstance * hero2, bool worn2, int pos2)
+bool CCallback::swapArifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)
 {
-	if(!hero1 || !hero2) //incorrect data
+	if(player!=hero1->tempOwner || player!=hero2->tempOwner)
 		return false;
-	CGHeroInstance * Uhero1 = const_cast<CGHeroInstance *>(hero1);
-	CGHeroInstance * Uhero2 = const_cast<CGHeroInstance *>(hero2);
-
-	if(worn1 && worn2)
-	{
-		std::swap(Uhero1->artifWorn[pos1], Uhero2->artifWorn[pos2]);
-	}
-	else if(worn1 && !worn2)
-	{
-		std::swap(Uhero1->artifWorn[pos1], Uhero2->artifacts[pos2]);
-	}
-	else if(!worn1 && worn2)
-	{
-		std::swap(Uhero1->artifacts[pos1], Uhero2->artifWorn[pos2]);
-	}
-	else
-	{
-		std::swap(Uhero1->artifacts[pos1], Uhero2->artifacts[pos2]);
-	}
-	
+	*cl->serv << ui16(509) << hero1->id << pos1 << hero2->id << pos2;
 	return true;
+	//if(!hero1 || !hero2) //incorrect data
+	//	return false;
+	//CGHeroInstance * Uhero1 = const_cast<CGHeroInstance *>(hero1);
+	//CGHeroInstance * Uhero2 = const_cast<CGHeroInstance *>(hero2);
+
+	//if(worn1 && worn2)
+	//{
+	//	std::swap(Uhero1->artifWorn[pos1], Uhero2->artifWorn[pos2]);
+	//}
+	//else if(worn1 && !worn2)
+	//{
+	//	std::swap(Uhero1->artifWorn[pos1], Uhero2->artifacts[pos2]);
+	//}
+	//else if(!worn1 && worn2)
+	//{
+	//	std::swap(Uhero1->artifacts[pos1], Uhero2->artifWorn[pos2]);
+	//}
+	//else
+	//{
+	//	std::swap(Uhero1->artifacts[pos1], Uhero2->artifacts[pos2]);
+	//}
+	//
+	//return true;
 }
 
 bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
@@ -401,7 +410,6 @@ bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
 			return false; //lack of resources
 
 	*cl->serv << ui16(504) << town->id << buildingID;
-//TODO: check if we are allowed to build
 	return true;
 }
 
@@ -431,6 +439,7 @@ CStack* CCallback::battleGetStackByID(int ID)
 
 CStack* CCallback::battleGetStackByPos(int pos)
 {
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return battleGetStackByID(battleGetStack(pos));
 }
 

+ 2 - 2
CCallback.h

@@ -34,7 +34,7 @@ public:
 	virtual int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//joins first stack tothe second (creatures must be same type)
 	virtual int splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack
 	virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses diven hero; true - successfuly, false - not successfuly
-	virtual bool swapArifacts(const CGHeroInstance * hero1, bool worn1, int pos1, const CGHeroInstance * hero2, bool worn2, int pos2)=0; //swaps artifacts between two given heroes
+	virtual bool swapArifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
 	virtual void recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount)=0;
 	virtual bool dismissCreature(const CArmedInstance *obj, int stackPos)=0;
 	virtual bool upgradeCreature(const CArmedInstance *obj, int stackPos, int newID=-1)=0; //if newID==-1 then best possible upgrade will be made
@@ -106,7 +106,7 @@ public:
 	int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2); //first goes to the second
 	int splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val);
 	bool dismissHero(const CGHeroInstance * hero);
-	bool swapArifacts(const CGHeroInstance * hero1, bool worn1, int pos1, const CGHeroInstance * hero2, bool worn2, int pos2);
+	bool swapArifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2);
 	bool buildBuilding(const CGTownInstance *town, si32 buildingID);
 	void recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount);
 	bool dismissCreature(const CArmedInstance *obj, int stackPos);

+ 14 - 1
CCastleInterface.cpp

@@ -334,6 +334,7 @@ public:
 CCastleInterface::CCastleInterface(const CGTownInstance * Town, bool Activate)
 :hslotup(241,387,0,Town->garrisonHero,this),hslotdown(241,483,1,Town->visitingHero,this)
 {
+	subInt = NULL;
 	hall = NULL;
 	townInt = BitmapHandler::loadBitmap("TOWNSCRN.bmp");
 	cityBg = BitmapHandler::loadBitmap(getBgName(Town->subID));
@@ -623,6 +624,11 @@ void CCastleInterface::show(SDL_Surface * to)
 }
 void CCastleInterface::activate()
 {
+	if(subInt)
+	{
+		subInt->activate();
+		return;
+	}
 	showing = true;
 	townlist->activate();
 	garr->activate();
@@ -637,6 +643,11 @@ void CCastleInterface::activate()
 }
 void CCastleInterface::deactivate()
 {
+	if(subInt)
+	{
+		subInt->deactivate();
+		return;
+	}
 	showing = false;
 	townlist->deactivate();
 	garr->deactivate();
@@ -980,6 +991,7 @@ CHallInterface::~CHallInterface()
 }
 void CHallInterface::close()
 {
+	LOCPLINT->castleInt->subInt = NULL;
 	deactivate();
 	delete this;
 	LOCPLINT->castleInt->activate();
@@ -1392,6 +1404,7 @@ void CMageGuildScreen::close()
 {
 	deactivate();
 	delete this;
+	LOCPLINT->castleInt->subInt = NULL;
 	LOCPLINT->castleInt->activate();
 	LOCPLINT->castleInt->showAll();
 }
@@ -1430,7 +1443,7 @@ void CMageGuildScreen::Scroll::clickRight (tribool down)
 			(LOCPLINT->playerID,
 			spell->descriptions[0],
 			static_cast<CMageGuildScreen*>(LOCPLINT->castleInt->subInt)->scrolls->ourImages[spell->id].bitmap,
-			spell->name);
+			spell->name,30,30);
 		vinya->pos.x = screen->w/2 - vinya->bitmap->w/2;
 		vinya->pos.y = screen->h/2 - vinya->bitmap->h/2;
 		vinya->activate();

+ 8 - 1
CGameState.cpp

@@ -48,7 +48,6 @@ CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)
 			nobj->defInfo->handler=NULL;
 			nobj->defInfo->blockMap[5] = 253;
 			nobj->defInfo->visitMap[5] = 2;
-			nobj->artifacts.resize(20);
 			nobj->artifWorn[16] = 3;
 			nobj->portrait = subid;
 			nobj->primSkills.resize(4);
@@ -463,6 +462,14 @@ void CGameState::applyNL(IPack * pack)
 			}
 			break;
 		}
+	case 509:
+		{
+			SetHeroArtifacts *sha = static_cast<SetHeroArtifacts*>(pack);
+			CGHeroInstance *h = getHero(sha->hid);
+			h->artifacts = sha->artifacts;
+			h->artifWorn = sha->artifWorn;
+			break;
+		}
 	case 1001://set object property
 		{
 			SetObjectProperty *p = static_cast<SetObjectProperty*>(pack);

+ 4 - 14
CHeroWindow.cpp

@@ -458,8 +458,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
 
 	for(int g=0; g<artWorn.size(); ++g)
 	{
-		artWorn[g]->myNumber = g;
-		artWorn[g]->backNumber = -1;
+		artWorn[g]->slotID = g;
 		char * hll = new char[200];
 		sprintf(hll, CGI->generaltexth->heroscrn[1].c_str(), (artWorn[g]->ourArt ? artWorn[g]->ourArt->name.c_str() : ""));
 		artWorn[g]->hoverText = std::string(hll);
@@ -477,7 +476,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
 		add->pos.y = 365;
 		add->pos.h = add->pos.w = 44;
 		if(s<hero->artifacts.size() && hero->artifacts[s])
-			add->text = hero->getArt(s)->description;
+			add->text = hero->getArt(19+s)->description;
 		else
 			add->text = std::string();
 		add->ourWindow = this;
@@ -500,8 +499,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
 		add->neck = true;
 		add->shoulders = true;
 		add->head = true;
-		add->myNumber = -1;
-		add->backNumber = s;
+		add->slotID = 19+s;
 		backpack.push_back(add);
 	}
 	activeArtPlace = NULL;
@@ -890,15 +888,7 @@ void CArtPlace::clickLeft(boost::logic::tribool down)
 			//chceck if swap is possible
 			if(this->fitsHere(ourWindow->activeArtPlace->ourArt) && ourWindow->activeArtPlace->fitsHere(this->ourArt))
 			{
-				//swap artifacts
-
-				LOCPLINT->cb->swapArifacts(
-					ourWindow->curHero,
-					this->myNumber>=0,
-					this->myNumber>=0 ? this->myNumber : (this->backNumber + ourWindow->backpackPos)%ourWindow->curHero->artifacts.size(),
-					ourWindow->curHero,
-					ourWindow->activeArtPlace->myNumber>=0,
-					ourWindow->activeArtPlace->myNumber>=0 ? ourWindow->activeArtPlace->myNumber : (ourWindow->activeArtPlace->backNumber + ourWindow->backpackPos)%ourWindow->curHero->artifacts.size());
+				LOCPLINT->cb->swapArifacts(ourWindow->curHero,slotID,ourWindow->curHero,ourWindow->activeArtPlace->slotID);
 
 				const CArtifact * pmh = ourArt;
 				ourArt = ourWindow->activeArtPlace->ourArt;

+ 1 - 2
CHeroWindow.h

@@ -64,8 +64,7 @@ public:
 	bool spellBook, warMachine1, warMachine2, warMachine3, warMachine4,
 		misc1, misc2, misc3, misc4, misc5, feet, lRing, rRing, torso,
 		lHand, rHand, neck, shoulders, head; //my types
-	int myNumber;
-	int backNumber; //number of artifact if this is backpack artplace
+	ui16 slotID; //0   	head	1 	shoulders		2 	neck		3 	right hand		4 	left hand		5 	torso		6 	right ring		7 	left ring		8 	feet		9 	misc. slot 1		10 	misc. slot 2		11 	misc. slot 3		12 	misc. slot 4		13 	ballista (war machine 1)		14 	ammo cart (war machine 2)		15 	first aid tent (war machine 3)		16 	catapult		17 	spell book		18 	misc. slot 5		19+ 	backpack slots
 
 	bool clicked;
 	CHeroWindow * ourWindow;

+ 7 - 3
CMessage.cpp

@@ -222,6 +222,8 @@ std::pair<int,int> CMessage::getMaxSizes(std::vector<std::vector<SDL_Surface*> >
 			lw+=(*txtg)[i][j]->w;
 			ret.second+=(*txtg)[i][j]->h;
 		}
+		if(!(*txtg)[i].size())
+			ret.second+=19;
 		if (ret.first<lw)
 			ret.first=lw;
 	}
@@ -381,7 +383,7 @@ std::vector< std::vector<SComponent*> > * CMessage::breakComps(std::vector<SComp
 	return ret;
 }
 
-SDL_Surface * CMessage::drawBoxTextBitmapSub(int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline)
+SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline/*=30*/, int imgToBmp/*=55*/ )
 {
 	int curh;
 	std::vector<std::string> * tekst = breakText(text,charperline);
@@ -392,17 +394,19 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub(int player, std::string text, SDL_S
 	boxs.second =
 		(curh=45) //top margin
 		+ txts.second //text total height
-		+ 55 //text <=> img
+		+ imgToBmp //text <=> img
 		+ bitmap->h
 		+ 5 // to sibtitle
 		+ (*txtg)[0][0]->h
 		+ 30;
 	SDL_Surface *ret = drawBox1(boxs.first,boxs.second,player);
 	blitTextOnSur(txtg,curh,ret);
-	curh += 55;
+	curh += imgToBmp;
 	blitAt(bitmap,(ret->w/2)-(bitmap->w/2),curh,ret);
 	curh += bitmap->h + 5;
 	CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+(  ((*txtg)[0][0]->h) / 2  ),GEOR13,zwykly,ret);
+	delete tekst;
+	delete txtg;
 	return ret;
 }
 

+ 1 - 1
CMessage.h

@@ -39,7 +39,7 @@ public:
 	static SDL_Surface * genMessage(std::string title, std::string text, EWindowType type=infoOnly,
 								std::vector<CDefHandler*> *addPics=NULL, void * cb=NULL);
 	static SDL_Surface * drawBox1(int w, int h, int playerColor=1);
-	static SDL_Surface * drawBoxTextBitmapSub(int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline=30);
+	static SDL_Surface * drawBoxTextBitmapSub(int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline=30, int imgToBmp=55);
 	static std::vector<std::string> * breakText(std::string text, int line=30, bool userBreak=true, bool ifor=true); //line - chars per line
 	CMessage();
 	static void init();

+ 25 - 12
CPlayerInterface.cpp

@@ -575,7 +575,7 @@ void CInfoPopup::close()
 	delete this;
 	if(LOCPLINT->curint == LOCPLINT->adventureInt)
 		LOCPLINT->adventureInt->show();
-	else if(LOCPLINT->curint == LOCPLINT->castleInt)
+	else if((LOCPLINT->curint == LOCPLINT->castleInt) && !LOCPLINT->castleInt->subInt)
 		LOCPLINT->castleInt->showAll();
 }
 void CInfoPopup::show(SDL_Surface * to)
@@ -3167,25 +3167,38 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
 	{
 		if(Upg && ui)
 		{
+			bool enough = true;
 			for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost
 			{
+				if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*creatureCount)
+					enough = false;
 				upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*creatureCount)); 
 			}
 
-			CFunctionList<void()> fs[2];
-			fs[0] += Upg;
-			fs[0] += boost::bind(&CCreInfoWindow::close,this);
+			if(enough)
+			{
+				CFunctionList<void()> fs[2];
+				fs[0] += Upg;
+				fs[0] += boost::bind(&CCreInfoWindow::close,this);
 
-			CCastleInterface *pom;
-			if(pom=dynamic_cast<CCastleInterface*>(LOCPLINT->curint)) //if town screen is opened it needs to be redrawn
+				CCastleInterface *pom;
+				if(pom=dynamic_cast<CCastleInterface*>(LOCPLINT->curint)) //if town screen is opened it needs to be redrawn
+				{
+					fs[1] += boost::bind(&CCastleInterface::showAll,pom,screen,true);
+				}
+				fs[1] += boost::bind(&CCreInfoWindow::activate,this);
+				CFunctionList<void()> cfl;
+				cfl = boost::bind(&CCreInfoWindow::deactivate,this);
+				cfl += boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[207],boost::ref(upgResCost),fs[0],fs[1],false,false);
+				upgrade = new AdventureMapButton("",CGI->preth->zelp[446].second,cfl,pos.x+76,pos.y+237,"IVIEWCR.DEF");
+			}
+			else
 			{
-				fs[1] += boost::bind(&CCastleInterface::showAll,pom,screen,true);
+				upgrade = new AdventureMapButton("",CGI->preth->zelp[446].second,boost::function<void()>(),pos.x+76,pos.y+237,"IVIEWCR.DEF");
+				upgrade->callback.funcs.clear();
+				upgrade->bitmapOffset = 2;
 			}
-			fs[1] += boost::bind(&CCreInfoWindow::activate,this);
-			CFunctionList<void()> cfl;
-			cfl = boost::bind(&CCreInfoWindow::deactivate,this);
-			cfl += boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[207],boost::ref(upgResCost),fs[0],fs[1],false,false);
-			upgrade = new AdventureMapButton("",CGI->preth->zelp[446].second,cfl,pos.x+76,pos.y+237,"IVIEWCR.DEF");
+
 		}
 		if(Dsm)
 		{

+ 196 - 0
ChangeLog

@@ -0,0 +1,196 @@
+0.61 -> 0.62
+General:
+* threading and minor changes.
+* support for heroes starting in town garrisons
+* upgrading creatures
+* working gaining levels for heroes (including dialog with skill selection)
+* added fast graphical cursor
+* showing creature amount in the CCreInfoWindow
+
+Castles:
+* icon in infobox showing that there is hero in town garrison
+* fort/citadel/castle screen
+* taking last stack from the heroes army should be impossible (or at least harder)
+* fixed reading forbidden structures
+* randomizing spells in towns
+* viewing hero window in the town screen
+* possibility of moving hero into the garrison
+* partially done mage guild screen 
+
+Adventure Interface:
+* hopefully fixed problems with wrong town defs (village/fort/capitol)
+
+Hero Window:
+* bugfix: splitting stacks works in hero window
+* removed bug causing significant increase of CPU consumption
+
+Battles:
+* shooting
+* removed some displaying problems
+* showing last group of frames in creature animation won't crash
+* added start moving and end moving animations
+* fixed moving two-hex creatures
+* showing/hiding graphic cursor
+* a part of using graphic cursor
+* slightly optimized showing of battle interface
+* animation of getting hit / death by shooting is displayed when it should be
+* improved pathfinding in battles, removed problems with displaying movement, adventure map interface won't be called during battles.
+
+PreGame:
+* updates settings when selecting new map after changing sorting criteria
+* if sorting not by name, name will be used as a secondary criteria
+* when filter is applied a first available map is selected automatically
+* slider position updated after sorting in pregame
+
+0.6 -> 0.61 (Jun 15 2008)
+Improvements:
+* improved attacking in the battles
+* it's possible to kill hostile stack
+* animations won't go in the same phase
+* Better pathfinder
+* "%s" substitutions in Right-click information in town hall
+* windmill won't give wood
+* hover text for heroes
+* support for ZSoft-style PCX files in /Data
+* Splitting: when moving slider to the right so that 0 is left in old slot the army is moved
+* in the townlist in castle selected town will by placed on the 2nd place (not 3rd)
+* stack at the limit of unit's range can now be attacked
+* range of unit is now properly displayed
+* battle log is scrolled down when new event occurs
+* console is closed when application exits
+
+Bugfixes:
+* stack at the limit of unit's range can now be attacked
+* good background for the town hall screen in Stronghold
+* fixed typo in hall.txt
+* VCMI won't crash when r-click neutral stack during the battle
+* water won't blink behind shipyard in the Castle
+* fixed several memory leaks
+* properly displaying two-hex creatures in recruit/split/info window
+* corrupted map file won't cause crash on initializing main menu
+
+0.59 -> 0.6 (Jun 1 2008)
+* partially done attacking in battles
+* screen isn't now refreshed while blitting creature info window
+* r-click creature info windows in battles
+* no more divison by 0 in slider
+* "plural" reference names for Conflux creatures (starting armies of Conflux heroes should now be working)
+* fixed estate problems
+* fixed blinking mana vortex
+* grail increases creature growths
+* new pathfinder
+* several minor improvements
+
+0.58 -> 0.59 (May 24 2008 - closed, test release)
+* fixed memory leak in battles
+* blitting creature animations to rects in the recruitment window
+* fixed wrong creatures def names
+* better battle pathfinder and unit reversing
+* improved slider ( #58 )
+* fixed problems with horde buildings (won't block original dwellings)
+* giving primary skill when hero get level (but there is still no dialog)
+* if an upgraded creature is available it'll be shown as the first in a recruitment window
+* creature levels not messed in Fortress
+* war machines are added to the hero's inventory, not to the garrison
+* support for H3-style PCX graphics in Data/
+* VCMI won't crash when is unable to initialize audio system
+* fixed displaying wrong town defs
+* improvements in recruitment window (slider won't allow to select more creatures than we can afford)
+* creature info window (only r-click)
+* callback for buttons/lists based on boost::function
+* a lot of minor improvements
+
+0.55 -> 0.58 (Apr 20 2008 - closed, test release)
+Towns:
+* recruiting creatures
+* working creature growths (including castle and horde building influences)
+* towns give income
+* town hall screen
+* building buildings (requirements and cost are handled)
+* hints for structures
+* updating town infobox
+Garrisons:
+* merging stacks
+* splitting stacks
+Battles:
+* starting battles
+* displaying terrain, animations of heroes, units, grid, range of units, battle menu with console, amounts of units in stacks
+* leaving battle by pressing flee button
+* moving units in battles and displaying thier ranges
+* defend command for units
+General:
+* a number of minor fixes and improvements
+
+0.54 -> 0.55 (Feb 29 2008)
+* Sprites/ folder works for h3sprite.lod same as Data/ for h3bitmap.lod (but it's still experimental)
+* randomization quantity of creatures on the map
+* fix of Pandora's Box handling
+* reading disposed/predefined heroes
+* new command - "get txt" - VCMI will extract all .txt files from h3bitmap.lod to the Extracted_txts/ folder.
+* more detailed logs
+* reported problems with hero flags resolved
+* heroes cannot occupy the same tile
+* hints for most of creature generators
+* some minor stuff
+
+0.53b -> 0.54 (Feb 23 2008 - first public release)
+* given hero is placed in the town entrance
+* some objects such as river delta won't be blitted "on" hero
+* tiles under FoW are inaccessible
+* giving random hero on RoE maps
+* improved protection against hero duplication
+* fixed starting values of primary abilities of random heroes on RoE/AB maps
+* right click popups with infoboxes for heroes/towns lists
+* new interface coloring (many thanks to GrayFace ;])
+* fixed bug in object flag's coloring
+* added hints in town lists
+* eliminated square from city hints
+
+0.53 - 0.53b (Feb 20 2008)
+* added giving default buildings in towns
+* town infobox won't crash on empty town
+
+0.52 - 0.53 (Feb 18 2008):
+* hopefully the last bugfix of Pandora's Box
+* fixed blockmaps of generated heroes
+* disposed hero cannot be chosen in scenario settings (unless he is in prison)
+* fixed town randomization
+* fixed hero randomization
+* fixed displaying heroes in preGame
+* fixed selecting/deselecting artifact slots in hero window
+* much faster pathfinder
+* memory usage and load time significantly decreased
+* it's impossible to select empty artifact slot in hero window
+* fixed problem with FoW displaying on minimap on L-sized maps
+* fixed crashbug in hero list connected with heroes dismissing
+* mostly done town infobox
+* town daily income is properly calculated
+
+0.51 - 0.52 (Feb 7 2008):
+* [feature] giving starting hero
+* [feature] VCMI will try to use files from /Data folder instead of those from h3bitmap.lod
+* [feature] picked artifacts are added to hero's backpack
+* [feature] possibility of choosing player to play
+* [bugfix] ZELP.TXT file *should* be handled correctly even it is non-english
+* [bugfix] fixed crashbug in reading defs with negativ left/right margins
+* [bugfix] improved randomization
+* [bugfix] pathfinder can't be cheated (what caused errors)
+
+0.5 - 0.51 (Feb 3 2008):
+* close button properly closes (same does 'q' key)
+* two players can't have selected same hero
+* double click on "Show Available Scenarios" won't reset options
+* fixed possible crashbug in town/hero lists
+* fixed crashbug in initializing game caused by wrong prisons handling
+* fixed crashbug on reading hero's custom artifacts in RoE maps
+* fixed crashbug on reading custom Pandora's Box in RoE maps
+* fixed crashbug on reading blank Quest Guards
+* better console messages
+* map reading speed up (though it's still slow, especially on bigger maps)
+
+to 0.5 (Feb 2 2008 - first closed release):
+* Main menu and New game screens
+* Scenario selection, part of advanced options support
+* Partially done adventure map, town and hero interfaces
+* Moving hero
+* Interactions with several objects (mines, resources, mills, and others)

+ 9 - 0
client/Client.cpp

@@ -360,6 +360,15 @@ void CClient::process(int what)
 				playerint[t->tempOwner]->heroInGarrisonChange(t);
 			break;
 		}
+	case 509:
+		{
+			SetHeroArtifacts sha;
+			*serv >> sha;
+			std::cout << "Setting artifacts of hero " << sha.hid << std::endl;
+			gs->apply(&sha);
+			//TODO: inform interfaces
+			break;
+		}
 	case 1001:
 		{
 			SetObjectProperty sop;

+ 9 - 0
config/mageBg.txt

@@ -0,0 +1,9 @@
+TPMAGECS.bmp
+TPMAGERM.bmp
+TPMAGETW.bmp
+TPMAGEIN.bmp
+TPMAGENC.bmp
+TPMAGEDN.bmp
+TPMAGEST.bmp
+TPMAGEFR.bmp
+TPMAGEEL.bmp

+ 37 - 3
hch/CObjectHandler.cpp

@@ -237,11 +237,45 @@ int CGHeroInstance::getSecSkillLevel(const int & ID) const
 			return secSkills[i].second;
 	return -1;
 }
+ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
+{
+	if(pos<19)
+		if(vstd::contains(artifWorn,pos))
+			return artifWorn.find(pos)->second;
+		else
+			return -1;
+	else
+		if(pos-19 < artifacts.size())
+			return artifacts[pos-19];
+		else 
+			return -1;
+}
+void CGHeroInstance::setArtAtPos(ui16 pos, int art)
+{
+	if(art<0)
+	{
+		if(pos<19)
+			artifWorn.erase(pos);
+		else
+			artifacts -= artifacts[pos];
+	}
+	else
+	{
+		if(pos<19)
+			artifWorn[pos] = art;
+		else
+			if(pos-19 < artifacts.size())
+				artifacts[pos-19] = art;
+			else
+				artifacts.push_back(art);
+	}
+}
 const CArtifact * CGHeroInstance::getArt(int pos)
 {
-	if(artifWorn.find(pos)!=artifWorn.end())
-		return &VLC->arth->artifacts[artifWorn[pos]];
-	else 
+	int id = getArtAtPos(pos);
+	if(id>=0)
+		return &VLC->arth->artifacts[id];
+	else
 		return NULL;
 }
 

+ 4 - 2
hch/CObjectHandler.h

@@ -107,8 +107,8 @@ public:
 	bool inTownGarrison; // if hero is in town garrison 
 	CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
 
-	std::vector<int> artifacts; //hero's artifacts from bag
-	std::map<int,int> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+	std::vector<ui32> artifacts; //hero's artifacts from bag
+	std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 	std::set<int> spells; //known spells (spell IDs)
 
 	virtual bool isHero() const;
@@ -125,6 +125,8 @@ public:
 	int getCurrentLuck() const;
 	int getCurrentMorale() const;
 	int getSecSkillLevel(const int & ID) const; //-1 - no skill
+	ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact
+	void setArtAtPos(ui16 pos, int art);
 	const CArtifact * getArt(int pos);
 	CGHeroInstance();
 	virtual ~CGHeroInstance();

+ 12 - 0
lib/NetPacks.h

@@ -164,6 +164,18 @@ struct SetHeroesInTown : public CPack<SetHeroesInTown> //508
 		h & tid & visiting & garrison;
 	}
 };  
+struct SetHeroArtifacts : public CPack<SetHeroArtifacts> //509
+{
+	SetHeroArtifacts(){type = 509;};
+	si32 hid;
+	std::vector<ui32> artifacts; //hero's artifacts from bag
+	std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid & artifacts & artifWorn;
+	}
+};  
 struct NewTurn : public CPack<NewTurn> //101
 {
 	struct Hero

+ 52 - 0
server/CGameHandler.cpp

@@ -501,6 +501,11 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 						if(!S1->slots[p1].second) //if we've moved all creatures
 							S1->slots.erase(p1); 
 					}
+					if((s1->ID==34 && !S1->slots.size()) //it's not allowed to take last stack from hero army!
+						|| (s2->ID==34 && !S2->slots.size()))
+					{
+						break;
+					}
 					SetGarrisons sg;
 					sg.garrs[id1] = *S1;
 					if(s1 != s2)
@@ -732,6 +737,53 @@ upgend:
 					}
 					break;
 				}
+			case 509:
+				{
+					si32 hid1, hid2;
+					ui16 slot1, slot2;
+					c >> hid1 >> slot1 >> hid2 >> slot2;
+					CGHeroInstance *h1 = gs->getHero(hid1), *h2 = gs->getHero(hid2);
+					if((distance(h1->pos,h2->pos) > 1.0)   ||   (h1->tempOwner != h2->tempOwner))
+						break;
+					int a1=h1->getArtAtPos(slot1), a2=h2->getArtAtPos(slot2);
+
+					h2->setArtAtPos(slot2,a1);
+					h1->setArtAtPos(slot1,a2);
+// 					if(std::max(slot1,slot2) < 19)
+// 					{
+// 						if(vstd::contains(h1->artifWorn,slot1) && vstd::contains(h1->artifWorn,slot2))
+// 							std::swap(h1->artifWorn[slot1],h2->artifWorn[slot2]);
+// 						if(vstd::contains(h1->artifWorn,slot1))
+// 						{
+// 							h2->artifWorn[slot2] = h1->artifWorn[slot1];
+// 							h1->artifWorn.erase(slot1);
+// 						}
+// 						else if(vstd::contains(h2->artifWorn,slot2))
+// 						{
+// 							h1->artifWorn[slot1] = h2->artifWorn[slot2];
+// 							h2->artifWorn.erase(slot2);
+// 						}
+// 						else
+// 						{
+// 							std::cout << "Warning, wrong artifact swap command!" << std::endl;
+// 						}
+// 					}
+// 					else
+// 					{
+// 					}
+					SetHeroArtifacts sha;
+					sha.hid = hid1;
+					sha.artifacts = h1->artifacts;
+					sha.artifWorn = h1->artifWorn;
+					sendAndApply(&sha);
+					if(hid1 != hid2)
+					{
+						sha.hid = hid2;
+						sha.artifacts = h2->artifacts;
+						sha.artifWorn = h2->artifWorn;
+						sendAndApply(&sha);
+					}
+				}
 			case 2001:
 				{
 					ui32 qid, answer;