Jelajahi Sumber

- town events implemented
- merged CustomImagecComponent into SComponent
- moved some subID-related code from CastleInterface

Ivan Savenko 15 tahun lalu
induk
melakukan
8319e5e703

+ 6 - 79
client/CCastleInterface.cpp

@@ -392,36 +392,6 @@ void CHeroGSlot::setHighlight( bool on )
 	}
 }
 
-static std::string getBgName(int type) //TODO - co z tym zrobi�?
-{
-	switch (type)
-	{
-	case 0:
-		return "TBCSBACK.bmp";
-	case 1:
-		return "TBRMBACK.bmp";
-	case 2:
-		return "TBTWBACK.bmp";
-	case 3:
-		return "TBINBACK.bmp";
-	case 4:
-		return "TBNCBACK.bmp";
-	case 5:
-		return "TBDNBACK.bmp";
-	case 6:
-		return "TBSTBACK.bmp";
-	case 7:
-		return "TBFRBACK.bmp";
-	case 8:
-		return "TBELBACK.bmp";
-	default:
-#ifndef __GNUC__
-		throw new std::exception("std::string getBgName(int type): invalid type");
-#else
-		throw new std::exception();
-#endif
-	}
-}
 class SORTHELP
 {
 public:
@@ -444,7 +414,6 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
 	fort = NULL;
 	market = NULL;
 	townInt = BitmapHandler::loadBitmap("TOWNSCRN.bmp");
-	cityBg = BitmapHandler::loadBitmap(getBgName(Town->subID));
 	pos.x = screen->w/2 - 400;
 	pos.y = screen->h/2 - 300;
 	hslotup.pos.x += pos.x;
@@ -483,51 +452,9 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
 	//growth icons and buildings
 	recreateBuildings();
 	recreateIcons();
-
-	std::string defname;
-	switch (town->subID)
-	{
-	case 0:
-		defname = "HALLCSTL.DEF";
-		musicID = musicBase::castleTown;
-		break;
-	case 1:
-		defname = "HALLRAMP.DEF";
-		musicID = musicBase::rampartTown;
-		break;
-	case 2:
-		defname = "HALLTOWR.DEF";
-		musicID = musicBase::towerTown;
-		break;
-	case 3:
-		defname = "HALLINFR.DEF";
-		musicID = musicBase::infernoTown;
-		break;
-	case 4:
-		defname = "HALLNECR.DEF";
-		musicID = musicBase::necroTown;
-		break;
-	case 5:
-		defname = "HALLDUNG.DEF";
-		musicID = musicBase::dungeonTown;
-		break;
-	case 6:
-		defname = "HALLSTRN.DEF";
-		musicID = musicBase::strongHoldTown;
-		break;
-	case 7:
-		defname = "HALLFORT.DEF";
-		musicID = musicBase::fortressTown;
-		break;
-	case 8:
-		defname = "HALLELEM.DEF";
-		musicID = musicBase::elemTown;
-		break;
-	default:
-		throw new std::string("Wrong town subID");
-	}
-	bicons = CDefHandler::giveDefEss(defname);
-	CGI->musich->playMusic(musicID, -1);
+	cityBg = BitmapHandler::loadBitmap(graphics->townBgs[town->subID]);
+	bicons = CDefHandler::giveDefEss(graphics->buildingPics[town->subID]);
+	CGI->musich->playMusic(CGI->musich->townMusics[town->subID], -1);
 }
 
 CCastleInterface::~CCastleInterface()
@@ -796,7 +723,7 @@ void CCastleInterface::castleTeleport(int where)
 void CCastleInterface::defaultBuildingClicked(int building)
 {
 	std::vector<SComponent*> comps(1,
-		new CCustomImgComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
+		new SComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
 
 	LOCPLINT->showInfoDialog(
 		CGI->buildh->buildings[town->subID].find(building)->second->Description(),
@@ -806,7 +733,7 @@ void CCastleInterface::defaultBuildingClicked(int building)
 void CCastleInterface::enterFountain(int building)
 {
 	std::vector<SComponent*> comps(1,
-		new CCustomImgComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
+		new SComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
 
 	std::string descr = CGI->buildh->buildings[town->subID].find(building)->second->Description();
 	if ( building == 21)//we need description for mystic pond as well
@@ -2051,7 +1978,7 @@ void CMageGuildScreen::Scroll::clickLeft(tribool down, bool previousState)
 	if(down)
 	{
 		std::vector<SComponent*> comps(1,
-			new CCustomImgComponent(SComponent::spell,spell->id,0,graphics->spellscr->ourImages[spell->id].bitmap,false)
+			new SComponent(SComponent::spell,spell->id,0)
 		);
 		LOCPLINT->showInfoDialog(spell->descriptions[0],comps, soundBase::sound_todo);
 	}

+ 1 - 1
client/CPreGame.cpp

@@ -2329,7 +2329,7 @@ void CBonusSelection::showAll( SDL_Surface * to )
 
 void CBonusSelection::loadPositionsOfGraphics()
 {
-	std::ifstream is((GVCMIDirs.UserPath + "/config/campaign_regions.txt").c_str(), std::ios_base::binary | std::ios_base::in);
+	std::ifstream is(DATA_DIR "/config/campaign_regions.txt", std::ios_base::binary | std::ios_base::in);
 
 	assert(is.is_open());
 

+ 27 - 28
client/GUIClasses.cpp

@@ -896,6 +896,8 @@ void SComponent::init(Etype Type, int Subtype, int Val)
 		subtitle = CGI->generaltexth->capColors[Subtype];
 		break;
 	}
+	img = NULL;
+	free = false;
 	type = Type;
 	subtype = Subtype;
 	val = Val;
@@ -908,7 +910,7 @@ void SComponent::init(Etype Type, int Subtype, int Val)
 	pos.w = temp->w;
 	pos.h = temp->h;
 }
-SComponent::SComponent(Etype Type, int Subtype, int Val)
+SComponent::SComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur):img(sur),free(freeSur)
 {
 	init(Type,Subtype,Val);
 }
@@ -925,44 +927,58 @@ SComponent::SComponent(const Component &c)
 	if(c.id==2 && c.when==-1)
 		subtitle += CGI->generaltexth->allTexts[3].substr(2,CGI->generaltexth->allTexts[3].length()-2);
 }
+
+SComponent::~SComponent()
+{
+	if (free && img)
+		SDL_FreeSurface(img);
+}
+
+SDL_Surface * SComponent::setSurface(std:: string defname, int imagepos)
+{
+	if (img)
+		tlog1<<"SComponent::setSurface: Warning - surface is already set!\n";
+	CDefEssential * def = CDefHandler::giveDefEss(defname);
+	
+	free = true;
+	img = def->ourImages[imagepos].bitmap;
+	img->refcount++;//to preserve surface whed def is deleted
+	delete def;
+}
+
 void SComponent::show(SDL_Surface * to)
 {
 	blitAt(getImg(),pos.x,pos.y,to);
 }
+
 SDL_Surface * SComponent::getImg()
 {
+	if (img)
+		return img;
 	switch (type)
 	{
 	case artifact:
 		return graphics->artDefs->ourImages[subtype].bitmap;
-		break;
 	case primskill:
 		return graphics->pskillsb->ourImages[subtype].bitmap;
-		break;
 	case secskill44:
 		return graphics->abils44->ourImages[subtype*3 + 3 + val - 1].bitmap;
-		break;
 	case secskill:
 		return graphics->abils82->ourImages[subtype*3 + 3 + val - 1].bitmap;
-		break;
 	case resource:
 		return graphics->resources->ourImages[subtype].bitmap;
-		break;
 	case experience:
 		return graphics->pskillsb->ourImages[4].bitmap;
-		break;
 	case morale:
 		return graphics->morale82->ourImages[val+3].bitmap;
-		break;
 	case luck:
 		return graphics->luck82->ourImages[val+3].bitmap;
-		break;
 	case spell:
 		return graphics->spellscr->ourImages[subtype].bitmap;
-		break;
+	case building:
+		return setSurface(graphics->buildingPics[subtype],val);
 	case creature:
 		return graphics->bigImgs[subtype];
-		break;
 	case hero:
 		return graphics->portraitLarge[subtype];
 	case flag:
@@ -2544,23 +2560,6 @@ CMinorResDataBar::~CMinorResDataBar()
 	SDL_FreeSurface(bg);
 }
 
-SDL_Surface * CCustomImgComponent::getImg()
-{
-	return bmp;
-}
-
-CCustomImgComponent::CCustomImgComponent( Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur )
-:bmp(sur), free(freeSur)
-{
-	init(Type,Subtype,Val);
-}
-
-CCustomImgComponent::~CCustomImgComponent()
-{
-	if(free)
-		SDL_FreeSurface(bmp);
-}
-
 CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CPicture * titlePic, std::string _title, std::string _descr,
 				boost::function<void(int)> Callback, int initState):items(_items), title(_title), descr(_descr),selected(initState)
 {

+ 7 - 12
client/GUIClasses.h

@@ -159,11 +159,16 @@ public:
 	std::string description; //r-click
 	std::string subtitle; //TODO: comment me
 
+	SDL_Surface *img; //our image
+	bool free; //should surface be freed on delete
+	
+	SDL_Surface * setSurface(std::string defName, int imgPos);
+
 	void init(Etype Type, int Subtype, int Val);
-	SComponent(Etype Type, int Subtype, int Val); //c-tor
+	SComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur=NULL, bool freeSur=false); //c-tor
 	SComponent(const Component &c); //c-tor
 	SComponent(){}; //c-tor
-	virtual ~SComponent(){}; //d-tor
+	virtual ~SComponent(); //d-tor
 
 	void clickRight(tribool down, bool previousState); //call-in
 	SDL_Surface * getImg();
@@ -172,16 +177,6 @@ public:
 	virtual void deactivate();
 };
 
-class CCustomImgComponent :  public SComponent
-{
-public:
-	SDL_Surface *bmp; //our image
-	bool free; //should surface be freed on delete
-	SDL_Surface * getImg();
-	CCustomImgComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur); //c-tor
-	~CCustomImgComponent(); //d-tor
-};
-
 class CSelectableComponent : public SComponent, public KeyShortcut
 {
 public:

+ 9 - 4
client/Graphics.cpp

@@ -198,13 +198,18 @@ void Graphics::loadPaletteAndColors()
 	}
 	neutralColor->r = 0x84; neutralColor->g = 0x84; neutralColor->b = 0x84; neutralColor->unused = 0x0;//gray
 
-	std::ifstream bback(DATA_DIR "/config/mageBg.txt");
-	while(!bback.eof())
+	std::ifstream tpics(DATA_DIR "/config/townPics.txt");
+	assert(tpics.is_open());
+	while(!tpics.eof())
 	{
-		bback >> pals;
+		tpics >> pals;
+		townBgs.push_back(pals);
+		tpics >> pals;
 		guildBgs.push_back(pals);
+		tpics >> pals;
+		buildingPics.push_back(pals);
 	}
-	bback.close();
+	tpics.close();
 }
 
 void Graphics::initializeBattleGraphics()

+ 4 - 1
client/Graphics.h

@@ -67,12 +67,15 @@ public:
 	std::map<int,SDL_Surface*> bigImgs; //creature ID -> big 58x64 img of creature; //ID=-2 is for blank (black) img; -1 for the border
 	std::map<int,SDL_Surface*> backgrounds; //castle ID -> 100x130 background creature image // -1 is for neutral
 	std::map<int,SDL_Surface*> backgroundsm; //castle ID -> 100x120 background creature image // -1 is for neutral
+	//towns
+	std::vector< std::string > buildingPics;//filenames of def with building images (used rarely, too big to keep them loaded)
+	std::vector< std::string > townBgs;//backgrounds of town
+	std::vector< std::string > guildBgs;// name of bitmaps with imgs for mage guild screen
 	//for battles
 	std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type
 	std::vector< std::string > battleHeroes; //battleHeroes[hero type] - name of def that has hero animation for battle
 	std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
 	CDefEssential * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
-	std::vector<std::string> guildBgs;// name of bitmaps with imgs for mage guild screen
 	std::vector< Point > wallPositions[F_NUMBER]; //positions of different pieces of wall <x, y>
 	//abilities
 	CDefEssential * abils32, * abils44, * abils82;

+ 0 - 9
config/mageBg.txt

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

+ 10 - 0
config/townPics.txt

@@ -0,0 +1,10 @@
+TBCSBACK.bmp	TPMAGECS.bmp	HALLCSTL.DEF
+TBRMBACK.bmp	TPMAGERM.bmp	HALLRAMP.DEF
+TBTWBACK.bmp	TPMAGETW.bmp	HALLTOWR.DEF
+TBINBACK.bmp	TPMAGEIN.bmp	HALLINFR.DEF
+TBNCBACK.bmp	TPMAGENC.bmp	HALLNECR.DEF
+TBDNBACK.bmp	TPMAGEDN.bmp	HALLDUNG.DEF
+TBSTBACK.bmp	TPMAGEST.bmp	HALLSTRN.DEF
+TPMAGEFR.bmp	TBFRBACK.bmp	HALLFORT.DEF	
+TBELBACK.bmp	TPMAGEEL.bmp	HALLELEM.DEF
+

+ 7 - 1
hch/CMusicHandler.cpp

@@ -303,9 +303,15 @@ CMusicHandler::CMusicHandler(): currentMusic(NULL), nextMusic(NULL)
 #undef VCMI_MUSIC_NAME
 #undef VCMI_MUSIC_FILE
 
-	// Vector for helper
+	// Vectors for helper
 	battleMusics += musicBase::combat1, musicBase::combat2, 
 		musicBase::combat3, musicBase::combat4;
+	
+	townMusics += musicBase::castleTown,     musicBase::rampartTown,
+	              musicBase::towerTown,      musicBase::infernoTown,
+	              musicBase::necroTown,      musicBase::dungeonTown,
+				  musicBase::strongHoldTown, musicBase::fortressTown,
+	              musicBase::elemTown;
 }
 
 void CMusicHandler::init()

+ 1 - 0
hch/CMusicHandler.h

@@ -120,6 +120,7 @@ public:
 	// Musics
 	std::map<musicBase::musicID, std::string> musics;
 	std::vector<musicBase::musicID> battleMusics;
+	std::vector<musicBase::musicID> townMusics;
 
 	void playMusic(musicBase::musicID musicID, int loop=1);
 	void playMusicFromSet(std::vector<musicBase::musicID> &music_vec, int loop=1);

+ 2 - 25
hch/CObjectHandler.h

@@ -41,6 +41,7 @@ class CGTownBuilding;
 class CArtifact;
 class CGDefInfo;
 class CSpecObjInfo;
+class CCastleEvent;
 struct TerrainTile;
 struct InfoWindow;
 struct Component;
@@ -48,30 +49,6 @@ struct BankConfig;
 struct UpdateHeroSpeciality;
 class CGBoat;
 
-class DLL_EXPORT CCastleEvent
-{
-public:
-	std::string name, message;
-	std::vector<si32> resources;  //gain / loss of resources
-	ui8 players; //players for whom this event can be applied
-	ui8 forHuman, forComputer;
-	ui32 firstShow; //postpone of first encounter time in days
-	ui32 forEvery; //every n days this event will occure
-	ui8 bytes[6]; //build specific buildings (raw format, similar to town's)
-	si32 gen[7]; //additional creatures in i-th level dwelling
-
-	bool operator<(const CCastleEvent &drugie) const
-	{
-		return firstShow<drugie.firstShow;
-	}
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & name & message & resources & players & forHuman & forComputer & firstShow 
-			& forEvery & bytes & gen;
-	}
-};
-
 class DLL_EXPORT CQuest
 {
 public:
@@ -527,7 +504,7 @@ public:
 	std::vector<CGTownBuilding*> bonusingBuildings;
 	std::vector<ui32> possibleSpells, obligatorySpells;
 	std::vector<std::vector<ui32> > spells; //spells[level] -> vector of spells, first will be available in guild
-	std::set<CCastleEvent> events;
+	std::list<CCastleEvent*> events;
 	std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond);
 
 	//////////////////////////////////////////////////////////////////////////

+ 23 - 16
lib/map.cpp

@@ -721,41 +721,48 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int
 
 	for(int gh = 0; gh<numberOfEvent; ++gh)
 	{
-		CCastleEvent nce;
-		nce.name = readString(bufor,i);
-		nce.message = readString(bufor,i);
-		nce.resources.resize(RESOURCE_QUANTITY);
+		CCastleEvent *nce = new CCastleEvent();
+		nce->town = nt;
+		nce->name = readString(bufor,i);
+		nce->message = readString(bufor,i);
+		nce->resources.resize(RESOURCE_QUANTITY);
 		for(int x=0; x < 7; x++)
 		{
-			nce.resources[x] = readNormalNr(bufor,i); 
+			nce->resources[x] = readNormalNr(bufor,i); 
 			i+=4;
 		}
 
-		nce.players = bufor[i]; ++i;
+		nce->players = bufor[i]; ++i;
 		if(version > AB)
 		{
-			nce.forHuman = bufor[i]; ++i;
+			nce->humanAffected = bufor[i]; ++i;
 		}
 		else
-			nce.forHuman = true;
+			nce->humanAffected = true;
 
-		nce.forComputer = bufor[i]; ++i;
-		nce.firstShow = readNormalNr(bufor,i, 2); i+=2;
-		nce.forEvery = bufor[i]; ++i;
+		nce->computerAffected = bufor[i]; ++i;
+		nce->firstOccurence = readNormalNr(bufor,i, 2); i+=2;
+		nce->nextOccurence = bufor[i]; ++i;
 
 		i+=17;
 
-		for(int kk=0; kk<6; ++kk)
+		//new buildings
+		for(int byte=0;byte<6;byte++)
 		{
-			nce.bytes[kk] = bufor[i]; ++i;
+			for(int bit=0;bit<8;bit++)
+				if(bufor[i] & (1<<bit))
+					nce->buildings.insert(byte*8+bit);
+			i++;
 		}
-
+		nce->buildings = convertBuildings(nce->buildings,subid);
+		
+		nce->creatures.resize(7);
 		for(int vv=0; vv<7; ++vv)
 		{
-			nce.gen[vv] = readNormalNr(bufor,i, 2); i+=2;
+			nce->creatures[vv] = readNormalNr(bufor,i, 2);i+=2;
 		}
 		i+=4;
-		nt->events.insert(nce);
+		nt->events.push_back(nce);
 	}//castle events have been read 
 
 	if(version > AB)

+ 16 - 0
lib/map.h

@@ -177,6 +177,7 @@ public:
 	ui8 computerAffected;
 	ui32 firstOccurence;
 	ui32 nextOccurence; //after nextOccurance day event will occur; if it it 0, event occures only one time;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & name & message & resources
@@ -187,6 +188,21 @@ public:
 		return firstOccurence < b.firstOccurence;
 	}
 };
+
+class DLL_EXPORT CCastleEvent: public CMapEvent
+{
+public:
+	std::set<si32> buildings;//build specific buildings
+	std::vector<si32> creatures;//additional creatures in i-th level dwelling
+	CGTownInstance * town;//owner of this event
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CMapEvent&>(*this);
+		h & buildings & creatures;
+	}
+};
+
 class DLL_EXPORT CMapHeader
 {
 public:

+ 88 - 9
server/CGameHandler.cpp

@@ -1123,6 +1123,7 @@ void CGameHandler::newTurn()
 			}
 			n.res[player][6] += (**j).dailyIncome();
 		}
+		handleTownEvents(*j, n);
 		if ((**j).subID == 2 && vstd::contains((**j).builtBuildings, 26)) // Skyship, probably easier to handle same as Veil of darkness
 		{ //do it every new day after veils apply
 			FoWChange fw;
@@ -2604,18 +2605,18 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos )
 	return true;
 }
 
-bool CGameHandler::buildStructure( si32 tid, si32 bid )
+bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 {
 	CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[tid]);
 	CBuilding * b = VLC->buildh->buildings[t->subID][bid];
 
-	if(gs->canBuildStructure(t,bid) != 7)
+	if( !force && gs->canBuildStructure(t,bid) != 7)
 	{
 		complain("Cannot build that building!");
 		return false;
 	}
 	
-	if(bid == 26) //grail
+	if( !force && bid == 26) //grail
 	{
 		if(!t->visitingHero || !t->visitingHero->hasArt(2))
 		{
@@ -2688,12 +2689,15 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
 	getTilesInRange(fw.tiles,t->pos,t->getSightRadious(),t->tempOwner,1);
 	sendAndApply(&fw);
 
-	SetResources sr;
-	sr.player = t->tempOwner;
-	sr.res = gs->getPlayer(t->tempOwner)->resources;
-	for(int i=0;i<b->resources.size();i++)
-		sr.res[i]-=b->resources[i];
-	sendAndApply(&sr);
+	if (!force)
+	{
+		SetResources sr;
+		sr.player = t->tempOwner;
+		sr.res = gs->getPlayer(t->tempOwner)->resources;
+		for(int i=0;i<b->resources.size();i++)
+			sr.res[i]-=b->resources[i];
+		sendAndApply(&sr);
+	}
 
 	if(bid<5) //it's mage guild
 	{
@@ -4380,6 +4384,81 @@ void CGameHandler::handleTimeEvents()
 	}
 }
 
+void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
+{
+	town->events.sort(evntCmp);
+	while(town->events.size() && town->events.front()->firstOccurence == gs->day)
+	{
+		ui8 player = town->tempOwner;
+		CCastleEvent *ev = town->events.front();
+		PlayerState *pinfo = gs->getPlayer(player);
+
+		if( pinfo  //player exists
+			&& (ev->players & 1<<player) //event is enabled to this player
+			&& ((ev->computerAffected && !pinfo->human) 
+				|| (ev->humanAffected && pinfo->human) ) )
+		{
+
+			// dialog
+			InfoWindow iw;
+			iw.player = player;
+			iw.text << ev->message;
+
+			for (int i=0; i<ev->resources.size(); i++)
+				if(ev->resources[i]) //if resource had changed, we add it to the dialog
+				{
+					int was = n.res[player][i];
+					n.res[player][i] += ev->resources[i];
+					n.res[player][i] = std::max(n.res[player][i], 0);
+
+					if(pinfo->resources[i] != n.res[player][i]) //if non-zero res change
+						iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was,0));
+				}
+			for(std::set<si32>::iterator i = ev->buildings.begin(); i!=ev->buildings.end();i++)
+				if ( !vstd::contains(town->builtBuildings, *i))
+				{
+					buildStructure(town->id, *i, true);
+					iw.components.push_back(Component(Component::BUILDING, town->subID, *i, 0));
+				}
+
+			SetAvailableCreatures sac;
+			if (n.cres.empty() || n.cres.back().tid != town->id)
+			{
+				sac.tid = town->id;
+				sac.creatures = town->creatures;
+			}
+			else
+			{
+				sac = n.cres.back();
+				n.cres.pop_back();
+			}
+			
+			for(int i=0;i<ev->creatures.size();i++) //creature growths
+			{
+				if(town->creatureDwelling(i) && ev->creatures[i])//there is dwelling
+				{
+					sac.creatures[i].first += ev->creatures[i];
+					iw.components.push_back(Component(Component::CREATURE, 
+							town->creatures[i].second.back(), ev->creatures[i], 0));
+				}
+			}
+			n.cres.push_back(sac);
+			sendAndApply(&iw); //show dialog
+		}
+
+		if(ev->nextOccurence)
+		{
+			ev->firstOccurence += ev->nextOccurence;
+			town->events.sort(evntCmp);
+		}
+		else
+		{
+			delete ev;
+			town->events.pop_front();
+		}
+	}
+}
+
 bool CGameHandler::complain( const std::string &problem )
 {
 	sendMessageToAll("Server encountered a problem: " + problem);

+ 3 - 1
server/CGameHandler.h

@@ -8,6 +8,7 @@
 #include "../lib/Connection.h"
 #include "../lib/IGameCallback.h"
 #include "../lib/BattleAction.h"
+#include "../lib/NetPacks.h"
 #include <boost/function.hpp>
 #include <boost/thread.hpp>
 
@@ -186,13 +187,14 @@ public:
 	bool garrisonSwap(si32 tid);
 	bool upgradeCreature( ui32 objid, ui8 pos, ui32 upgID );
 	bool recruitCreatures(si32 objid, ui32 crid, ui32 cram, si32 level);
-	bool buildStructure(si32 tid, si32 bid);
+	bool buildStructure(si32 tid, si32 bid, bool force=false);//force - for events: no cost, no checkings
 	bool razeStructure(si32 tid, si32 bid);
 	bool disbandCreature( si32 id, ui8 pos );
 	bool arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val, ui8 player);
 	void save(const std::string &fname);
 	void close();
 	void handleTimeEvents();
+	void handleTownEvents(CGTownInstance *town, NewTurn &n);
 	bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
 	void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
 	void engageIntoBattle( ui8 player );