瀏覽代碼

- fixed crash on opening spellbook during enemy turn
- fixed last known localization issue (bank configs)
- diplomacy and new weeks\month mechanics should be identical to H3
- minor fixes

Ivan Savenko 13 年之前
父節點
當前提交
dbc603b7d7

+ 10 - 7
client/BattleInterface/CBattleInterface.cpp

@@ -1455,13 +1455,16 @@ void CBattleInterface::bSpellf()
 
 	CCS->curh->changeGraphic(0,0);
 
-	const CGHeroInstance * chi = NULL;
-	if(attackingHeroInstance->tempOwner == curInt->playerID)
-		chi = attackingHeroInstance;
-	else
-		chi = defendingHeroInstance;
-	CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), chi, curInt);
-	GH.pushInt(spellWindow);
+	if ( myTurn && curInt->cb->battleCanCastSpell())
+	{
+		const CGHeroInstance * chi = NULL;
+		if(attackingHeroInstance->tempOwner == curInt->playerID)
+			chi = attackingHeroInstance;
+		else
+			chi = defendingHeroInstance;
+		CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), chi, curInt);
+		GH.pushInt(spellWindow);
+	}
 }
 
 void CBattleInterface::bWaitf()

+ 7 - 2
client/CAnimation.cpp

@@ -1168,8 +1168,13 @@ CAnimImage::~CAnimImage()
 
 void CAnimImage::showAll(SDL_Surface * to)
 {
-	IImage *img = anim->getImage(frame, group);
-	if (img)
+	IImage *img;
+
+	if ( flags & CShowableAnim::BASE && frame != 0)
+		if ((img = anim->getImage(0, group)))
+			img->draw(to, pos.x, pos.y);
+
+	if ((img = anim->getImage(frame, group)))
 		img->draw(to, pos.x, pos.y);
 }
 

+ 33 - 32
client/CMusicBase.h

@@ -11,17 +11,9 @@
  */
 
 // Use some magic to keep the list of files and their code name in sync.
+// FIXME: first half of this list should be read from campmusic.txt
 
 #define VCMI_MUSIC_LIST \
-	VCMI_MUSIC_ID(AITheme0) VCMI_MUSIC_FILE("AITheme0.mp3") \
-	VCMI_MUSIC_ID(AITheme1) VCMI_MUSIC_FILE("AITHEME1.MP3") \
-	VCMI_MUSIC_ID(AITheme2) VCMI_MUSIC_FILE("AITHEME2.MP3") \
-	VCMI_MUSIC_ID(bladeABCampaign) VCMI_MUSIC_FILE("BladeABCampaign.mp3") \
-	VCMI_MUSIC_ID(bladeDBCampaign) VCMI_MUSIC_FILE("BladeDBCampaign.mp3") \
-	VCMI_MUSIC_ID(bladeDSCampaign) VCMI_MUSIC_FILE("BladeDSCampaign.mp3") \
-	VCMI_MUSIC_ID(bladeFLCampaign) VCMI_MUSIC_FILE("BladeFLCampaign.mp3") \
-	VCMI_MUSIC_ID(bladeFWCampaign) VCMI_MUSIC_FILE("BladeFWCampaign.mp3") \
-	VCMI_MUSIC_ID(bladePFCampaign) VCMI_MUSIC_FILE("BladePFCampaign.mp3") \
 	VCMI_MUSIC_ID(campainMusic01) VCMI_MUSIC_FILE("CampainMusic01.mp3") \
 	VCMI_MUSIC_ID(campainMusic02) VCMI_MUSIC_FILE("CampainMusic02.mp3") \
 	VCMI_MUSIC_ID(campainMusic03) VCMI_MUSIC_FILE("CampainMusic03.mp3") \
@@ -31,47 +23,56 @@
 	VCMI_MUSIC_ID(campainMusic07) VCMI_MUSIC_FILE("CampainMusic07.mp3") \
 	VCMI_MUSIC_ID(campainMusic08) VCMI_MUSIC_FILE("CampainMusic08.mp3") \
 	VCMI_MUSIC_ID(campainMusic09) VCMI_MUSIC_FILE("CampainMusic09.mp3") \
-	VCMI_MUSIC_ID(campainMusic10) VCMI_MUSIC_FILE("CampainMusic10.mp3") \
-	VCMI_MUSIC_ID(campainMusic11) VCMI_MUSIC_FILE("CampainMusic11.mp3") \
+	VCMI_MUSIC_ID(AITheme0) VCMI_MUSIC_FILE("AITheme0.mp3") \
+	VCMI_MUSIC_ID(AITheme1) VCMI_MUSIC_FILE("AITHEME1.MP3") \
+	VCMI_MUSIC_ID(AITheme2) VCMI_MUSIC_FILE("AITHEME2.MP3") \
 	VCMI_MUSIC_ID(combat1) VCMI_MUSIC_FILE("COMBAT01.MP3") \
 	VCMI_MUSIC_ID(combat2) VCMI_MUSIC_FILE("COMBAT02.MP3") \
 	VCMI_MUSIC_ID(combat3) VCMI_MUSIC_FILE("COMBAT03.MP3") \
 	VCMI_MUSIC_ID(combat4) VCMI_MUSIC_FILE("COMBAT04.MP3") \
 	VCMI_MUSIC_ID(castleTown) VCMI_MUSIC_FILE("CstleTown.mp3") \
-	VCMI_MUSIC_ID(defendCastle) VCMI_MUSIC_FILE("Defend Castle.mp3") \
-	VCMI_MUSIC_ID(dirt) VCMI_MUSIC_FILE("DIRT.MP3") \
+	VCMI_MUSIC_ID(towerTown) VCMI_MUSIC_FILE("TowerTown.mp3") \
+	VCMI_MUSIC_ID(rampartTown) VCMI_MUSIC_FILE("RAMPART.MP3") \
+	VCMI_MUSIC_ID(infernoTown) VCMI_MUSIC_FILE("InfernoTown.mp3") \
+	VCMI_MUSIC_ID(necroTown) VCMI_MUSIC_FILE("necroTown.mp3") \
 	VCMI_MUSIC_ID(dungeonTown) VCMI_MUSIC_FILE("DUNGEON.MP3") \
-	VCMI_MUSIC_ID(elemTown) VCMI_MUSIC_FILE("ElemTown.mp3") \
-	VCMI_MUSIC_ID(evilTheme) VCMI_MUSIC_FILE("EvilTheme.mp3") \
+	VCMI_MUSIC_ID(strongHoldTown) VCMI_MUSIC_FILE("StrongHold.mp3") \
 	VCMI_MUSIC_ID(fortressTown) VCMI_MUSIC_FILE("FortressTown.mp3") \
-	VCMI_MUSIC_ID(goodTheme) VCMI_MUSIC_FILE("GoodTheme.mp3") \
+	VCMI_MUSIC_ID(elemTown) VCMI_MUSIC_FILE("ElemTown.mp3") \
+	VCMI_MUSIC_ID(dirt) VCMI_MUSIC_FILE("DIRT.MP3") \
+	VCMI_MUSIC_ID(sand) VCMI_MUSIC_FILE("SAND.MP3") \
 	VCMI_MUSIC_ID(grass) VCMI_MUSIC_FILE("GRASS.MP3") \
-	VCMI_MUSIC_ID(infernoTown) VCMI_MUSIC_FILE("InfernoTown.mp3") \
+	VCMI_MUSIC_ID(snow) VCMI_MUSIC_FILE("SNOW.MP3") \
+	VCMI_MUSIC_ID(swamp) VCMI_MUSIC_FILE("SWAMP.MP3") \
+	VCMI_MUSIC_ID(rough) VCMI_MUSIC_FILE("ROUGH.MP3") \
+	VCMI_MUSIC_ID(underground) VCMI_MUSIC_FILE("Underground.mp3") \
 	VCMI_MUSIC_ID(lava) VCMI_MUSIC_FILE("LAVA.MP3") \
+	VCMI_MUSIC_ID(water) VCMI_MUSIC_FILE("WATER.MP3") \
+	VCMI_MUSIC_ID(goodTheme) VCMI_MUSIC_FILE("GoodTheme.mp3") \
+	VCMI_MUSIC_ID(neutralTheme) VCMI_MUSIC_FILE("NeutralTheme.mp3") \
+	VCMI_MUSIC_ID(evilTheme) VCMI_MUSIC_FILE("EvilTheme.mp3") \
+	VCMI_MUSIC_ID(secretTheme) VCMI_MUSIC_FILE("SecretTheme.mp3") \
 	VCMI_MUSIC_ID(loopLepr) VCMI_MUSIC_FILE("LoopLepr.mp3") \
+	VCMI_MUSIC_ID(mainMenu) VCMI_MUSIC_FILE("MAINMENU.MP3") \
+	VCMI_MUSIC_ID(winScenario) VCMI_MUSIC_FILE("Win Scenario.mp3" ) \
+	VCMI_MUSIC_ID(campainMusic10) VCMI_MUSIC_FILE("CampainMusic10.mp3") \
+	VCMI_MUSIC_ID(bladeABcampaign) VCMI_MUSIC_FILE("BladeABCampaign.mp3") \
+	VCMI_MUSIC_ID(bladeDBcampaign) VCMI_MUSIC_FILE("BladeDBCampaign.mp3") \
+	VCMI_MUSIC_ID(bladeDScampaign) VCMI_MUSIC_FILE("BladeDSCampaign.mp3") \
+	VCMI_MUSIC_ID(bladeFLcampaign) VCMI_MUSIC_FILE("BladeFLCampaign.mp3") \
+	VCMI_MUSIC_ID(bladeFWcampaign) VCMI_MUSIC_FILE("BladeFWCampaign.mp3") \
+	VCMI_MUSIC_ID(bladePWcampaign) VCMI_MUSIC_FILE("BladePFCampaign.mp3") \
+	VCMI_MUSIC_ID(campainMusic11) VCMI_MUSIC_FILE("CampainMusic11.mp3") \
 	VCMI_MUSIC_ID(loseCampain) VCMI_MUSIC_FILE("Lose Campain.mp3") \
 	VCMI_MUSIC_ID(loseCastle) VCMI_MUSIC_FILE("LoseCastle.mp3") \
 	VCMI_MUSIC_ID(loseCombat) VCMI_MUSIC_FILE("LoseCombat.mp3") \
-	VCMI_MUSIC_ID(mainMenu) VCMI_MUSIC_FILE("MAINMENU.MP3") \
 	VCMI_MUSIC_ID(mainMenuWoG) VCMI_MUSIC_FILE("MainMenuWoG.mp3") \
-	VCMI_MUSIC_ID(necroTown) VCMI_MUSIC_FILE("necroTown.mp3") \
-	VCMI_MUSIC_ID(neutralTheme) VCMI_MUSIC_FILE("NeutralTheme.mp3") \
-	VCMI_MUSIC_ID(rampartTown) VCMI_MUSIC_FILE("RAMPART.MP3") \
 	VCMI_MUSIC_ID(retreatBattle) VCMI_MUSIC_FILE("Retreat Battle.mp3") \
-	VCMI_MUSIC_ID(rough) VCMI_MUSIC_FILE("ROUGH.MP3") \
-	VCMI_MUSIC_ID(sand) VCMI_MUSIC_FILE("SAND.MP3") \
-	VCMI_MUSIC_ID(secretTheme) VCMI_MUSIC_FILE("SecretTheme.mp3") \
-	VCMI_MUSIC_ID(snow) VCMI_MUSIC_FILE("SNOW.MP3") \
-	VCMI_MUSIC_ID(strongHoldTown) VCMI_MUSIC_FILE("StrongHold.mp3") \
 	VCMI_MUSIC_ID(surrenderBattle) VCMI_MUSIC_FILE("Surrender Battle.mp3") \
-	VCMI_MUSIC_ID(swamp) VCMI_MUSIC_FILE("SWAMP.MP3") \
-	VCMI_MUSIC_ID(towerTown) VCMI_MUSIC_FILE("TowerTown.mp3") \
 	VCMI_MUSIC_ID(ultimateLose) VCMI_MUSIC_FILE("UltimateLose.mp3") \
-	VCMI_MUSIC_ID(underground) VCMI_MUSIC_FILE("Underground.mp3") \
-	VCMI_MUSIC_ID(water) VCMI_MUSIC_FILE("WATER.MP3") \
 	VCMI_MUSIC_ID(winBattle) VCMI_MUSIC_FILE("Win Battle.mp3") \
-	VCMI_MUSIC_ID(winScenario) VCMI_MUSIC_FILE("Win Scenario.mp3" )
-
+	VCMI_MUSIC_ID(defendCastle) VCMI_MUSIC_FILE("Defend Castle.mp3") \
+	
 class musicBase
 {
 public:

+ 1 - 3
client/GUIClasses.cpp

@@ -487,7 +487,6 @@ CInfoWindow::CInfoWindow(std::string Text, int player, const TCompsInfo &comps,
 		text->pos.w = text->maxW;
 		text->pos.h = text->maxH;
 	}
-	text->redrawParentOnScrolling = true;
 
 	if(buttons.size())
 	{
@@ -914,7 +913,6 @@ CSelWindow::CSelWindow(const std::string &Text, int player, int charperline, con
 	}
 
 	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::Cornsilk);
-	text->redrawParentOnScrolling = true;
 
 	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
 	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
@@ -3595,7 +3593,7 @@ void CSystemOptionsWindow::setHeroMoveSpeed( int newSpeed )
 
 void CSystemOptionsWindow::setMapScrollingSpeed( int newSpeed )
 {
-	Settings speed = settings.write["adventure"]["mapScrollingSpeed"];
+	Settings speed = settings.write["adventure"]["scrollSpeed"];
 	speed->Float() = newSpeed;
 }
 

+ 21 - 8
client/UIFramework/CIntObject.h

@@ -139,24 +139,35 @@ public:
 
 	void disable(); //deactivates if needed, blocks all automatic activity, allows only disposal
 	void enable(bool activation = true); //activates if needed, all activity enabled (Warning: may not be symetric with disable if recActions was limited!)
-	void defActivate();
-	void defDeactivate();
+
+	// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
+	// usually used automatically by parent
 	void activate();
 	void deactivate();
+
+	//activate or deactivate specific action (LCLICK, RCLICK...)
 	void activate(ui16 what);
 	void deactivate(ui16 what);
+
+	//called each frame to update screen
 	void show(SDL_Surface * to);
+	//called on complete redraw only
 	void showAll(SDL_Surface * to);
+	//request complete redraw
 	void redraw();
 
 	void drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color);
-	void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);
-	void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);
-	void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);
-	void printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color kolor, SDL_Surface * dst);
-	void printAtMiddleWBLoc(const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst);
+	//functions for printing text. Use CLabel where possible instead
+	void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleWBLoc(const std::string & text, int x, int y, EFonts font, int charsPerLine, SDL_Color color, SDL_Surface * dst);
+
+	//image blitting. If possible use CPicture or CAnimImage instead
 	void blitAtLoc(SDL_Surface * src, int x, int y, SDL_Surface * dst);
 	void blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst);
+
 	bool isItInLoc(const SDL_Rect &rect, int x, int y);
 	bool isItInLoc(const SDL_Rect &rect, const Point &p);
 	const Rect & center(const Rect &r, bool propagate = true); //sets pos so that r will be in the center of screen, assigns sizes of r to pos, returns new position
@@ -164,10 +175,12 @@ public:
 	const Rect & center(bool propagate = true); //centers when pos.w and pos.h are set, returns new position
 	void fitToScreen(int borderWidth, bool propagate = true); //moves window to fit into screen
 	void moveBy(const Point &p, bool propagate = true);
-	void moveTo(const Point &p, bool propagate = true);
+	void moveTo(const Point &p, bool propagate = true);//move this to new position, coordinates are absolute (0,0 is topleft screen corner)
 	void changeUsedEvents(ui16 what, bool enable, bool adjust = true);
 
+	//add child without parent to this. Use CGuiHandler::moveChild() if child already have parent
 	void addChild(CIntObject *child, bool adjustPosition = false);
+	//remove child from this without deleting
 	void removeChild(CIntObject *child, bool adjustPosition = false);
 	void delChild(CIntObject *child); //removes from children list, deletes
 	template <typename T> void delChildNUll(T *&child, bool deactivateIfNeeded = false) //removes from children list, deletes and sets pointer to NULL

+ 6 - 5
client/UIFramework/CIntObjectClasses.cpp

@@ -361,14 +361,14 @@ void CAdventureMapButton::setIndex(size_t index, bool playerColoredButton)
 	setImage(new CAnimation(imageNames[index]), playerColoredButton);
 }
 
-void CAdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton)
+void CAdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
 	if (image && active)
 		image->deactivate();
 	delChild(image);
-	image = new CAnimImage(anim, getState());
+	image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
 	if (active)
 		image->activate();
 	if (playerColoredButton)
@@ -1189,6 +1189,9 @@ CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, con
 	pos.w = pos.h = 0;
 	bg = NULL;
 	ignoreLeadingWhitespace = false;
+
+	pos.w = graphics->fonts[font]->getWidth(text.c_str());
+	pos.h = graphics->fonts[font]->height;
 }
 
 void CLabel::setTxt(const std::string &Txt)
@@ -1216,7 +1219,7 @@ void CLabelGroup::add(int x, int y, const std::string &text)
 CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= Colors::Cornsilk*/)
 :CLabel(rect.x, rect.y, Font, Align, Color, Text), sliderStyle(SliderStyle), slider(NULL)
 {
-	redrawParentOnScrolling = false;
+	type |= REDRAW_PARENT;
 	autoRedraw = false;
 	pos.h = rect.h;
 	pos.w = rect.w;
@@ -1270,8 +1273,6 @@ void CTextBox::sliderMoved(int to)
 	if(!slider)
 		return;
 
-	if(redrawParentOnScrolling)
-		parent->redraw();
 	redraw();
 }
 

+ 1 - 2
client/UIFramework/CIntObjectClasses.h

@@ -129,7 +129,7 @@ public:
 	void init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key );
 
 	void setIndex(size_t index, bool playerColoredButton=false);
-	void setImage(CAnimation* anim, bool playerColoredButton=false);
+	void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
 	void setPlayerColor(int player);
 	void showAll(SDL_Surface * to);
 };
@@ -340,7 +340,6 @@ public:
 	int maxH; //total height needed to print all lines
 
 	int sliderStyle;
-	bool redrawParentOnScrolling;
 
 	std::vector<std::string> lines;
 	std::vector<CAnimImage* > effects;

+ 3 - 0
client/UIFramework/SDL_Extensions.cpp

@@ -1119,6 +1119,9 @@ std::string CSDL_Ext::processStr(std::string str, std::vector<std::string> & tor
 
 bool CSDL_Ext::isTransparent( SDL_Surface * srf, int x, int y )
 {
+	if (x < 0 || y < 0 || x >= srf->w || y >= srf->h)
+		return true;
+
 	if(srf->format->BytesPerPixel == 1)
 	{
 		return ((ui8*)srf->pixels)[x + srf->pitch * y]  == 0;

文件差異過大導致無法顯示
+ 111 - 242
config/bankconfig.json


+ 22 - 22
config/campaign_regions.json

@@ -1,16 +1,12 @@
 {
 	"campaign_regions": [
 		{
-			"prefix": "E1",
+			"prefix": "G1",
 			"color_suffix_length": 1,
 			"desc": [
-				{ "infix": "A", "x": 270, "y": 332 },
-				{ "infix": "B", "x": 138, "y": 113 },
-				{ "infix": "C", "x": 26, "y": 70 },
-				{ "infix": "P1", "x": 256, "y": 127 },
-				{ "infix": "P2", "x": 57, "y": 314 },
-				{ "infix": "P3", "x": 137, "y": 310 },
-				{ "infix": "P4", "x": 44, "y": 163 }
+				{ "infix": "A", "x": 57, "y": 314 },
+				{ "infix": "B", "x": 137, "y": 309 },
+				{ "infix": "C", "x": 44, "y": 163 }
 			]
 		},
 
@@ -26,33 +22,37 @@
 		},
 
 		{
-			"prefix": "E2",
+			"prefix": "G3",
 			"color_suffix_length": 1,
 			"desc": [
-				{ "infix": "A", "x": 131, "y": 202 },
-				{ "infix": "B", "x": 60, "y": 145 },
-				{ "infix": "C", "x": 92, "y": 261 },
-				{ "infix": "D", "x": 218, "y": 307 }
+				{ "infix": "A", "x": 289, "y": 376 },
+				{ "infix": "B", "x": 60, "y": 147 },
+				{ "infix": "C", "x": 131, "y": 202 }
 			]
 		},
 
 		{
-			"prefix": "G1",
+			"prefix": "E1",
 			"color_suffix_length": 1,
 			"desc": [
-				{ "infix": "A", "x": 57, "y": 314 },
-				{ "infix": "B", "x": 137, "y": 309 },
-				{ "infix": "C", "x": 44, "y": 163 }
+				{ "infix": "A", "x": 270, "y": 332 },
+				{ "infix": "B", "x": 138, "y": 113 },
+				{ "infix": "C", "x": 26, "y": 70 },
+				{ "infix": "P1", "x": 256, "y": 127 },
+				{ "infix": "P2", "x": 57, "y": 314 },
+				{ "infix": "P3", "x": 137, "y": 310 },
+				{ "infix": "P4", "x": 44, "y": 163 }
 			]
 		},
 
 		{
-			"prefix": "G3",
+			"prefix": "E2",
 			"color_suffix_length": 1,
 			"desc": [
-				{ "infix": "A", "x": 289, "y": 376 },
-				{ "infix": "B", "x": 60, "y": 147 },
-				{ "infix": "C", "x": 131, "y": 202 }
+				{ "infix": "A", "x": 131, "y": 202 },
+				{ "infix": "B", "x": 60, "y": 145 },
+				{ "infix": "C", "x": 92, "y": 261 },
+				{ "infix": "D", "x": 218, "y": 307 }
 			]
 		},
 
@@ -149,7 +149,7 @@
 			"prefix": "HS",
 			"color_suffix_length": 2,
 			"desc": [
-				{ "infix": "A", "x": 140, "y": 326 },
+				{ "infix": "A", "x": 141, "y": 326 },
 				{ "infix": "B", "x": 238, "y": 275 },
 				{ "infix": "C", "x": 22, "y": 161 },
 				{ "infix": "D", "x": 5, "y": 9 }

+ 29 - 12
lib/CCampaignHandler.cpp

@@ -175,11 +175,11 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( const ui8 *buffer, i
 	ret.packedMapSize = read_le_u32(buffer + outIt); outIt += 4;
 	if(mapVersion == 18)//unholy alliance
 	{
-		ret.preconditionRegion = read_le_u16(buffer + outIt); outIt += 2;
+		ret.loadPreconditionRegions(read_le_u16(buffer + outIt)); outIt += 2;
 	}
 	else
 	{
-		ret.preconditionRegion = buffer[outIt++];
+		ret.loadPreconditionRegions(buffer[outIt++]);
 	}
 	ret.regionColor = buffer[outIt++];
 	ret.difficulty = buffer[outIt++];
@@ -192,6 +192,15 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( const ui8 *buffer, i
 	return ret;
 }
 
+void CCampaignScenario::loadPreconditionRegions(ui32 regions)
+{
+	for (int i=0; i<32; i++) //for each bit in region. h3c however can only hold up to 16
+	{
+		if ( (1 << i) & regions)
+			preconditionRegions.insert(i);
+	}
+}
+
 CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version )
 {
 	CScenarioTravel ret;
@@ -444,7 +453,7 @@ bool CCampaign::conquerable( int whichScenario ) const
 	//check preconditioned regions
 	for (int g=0; g<scenarios.size(); ++g)
 	{
-		if(( (1 << g) & scenarios[whichScenario].preconditionRegion ) && !scenarios[g].conquered)
+		if( vstd::contains(scenarios[whichScenario].preconditionRegions, g) && !scenarios[g].conquered)
 			return false; //prerequisite does not met
 			
 	}
@@ -510,17 +519,25 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
 	if (!(travelOptions.whatHeroKeeps & 16))
 	{
 		//trimming artifacts
-		for (int g=0; g<VLC->arth->artifacts.size(); ++g)
+		BOOST_FOREACH(CGHeroInstance * hero, crossoverHeroes)
 		{
-			bool takeable = travelOptions.artifsKeptByHero[g / 8] & ( 1 << (g%8) ) ;
-			if (!takeable)
+			size_t totalArts = GameConstants::BACKPACK_START + hero->artifactsInBackpack.size();
+			for (size_t i=0; i<totalArts; i++ )
 			{
-				//BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
-				{
-					tlog1 << "TODO TODO TODO - take artifacts from hero\n";
-					//TODO how was that supposed to work with worn artifacts?
-					//cgh->artifactsInBackpack -= VLC->arth->artifacts[g];
-				}
+				const ArtSlotInfo *info = hero->getSlot(i);
+				if (!info)
+					continue;
+				
+				const CArtifactInstance *art = info->artifact;
+				if (!art)//FIXME: check spellbook and catapult behaviour
+					continue;
+
+				int id  = art->artType->id;
+				assert( 8*18 > id );//number of arts that fits into h3m format
+				bool takeable = travelOptions.artifsKeptByHero[id / 8] & ( 1 << (id%8) );
+
+				if (takeable)
+					hero->eraseArtSlot(i);
 			}
 		}
 	}

+ 3 - 2
lib/CCampaignHandler.h

@@ -83,7 +83,7 @@ class DLL_LINKAGE CCampaignScenario
 public:
 	std::string mapName;
 	ui32 packedMapSize; //generally not used
-	ui16 preconditionRegion; //what we need to conquer to conquer this one (bitfield!)
+	std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
 	ui8 regionColor;
 	ui8 difficulty;
 	ui8 conquered;
@@ -109,13 +109,14 @@ public:
 
 	std::vector<CGHeroInstance*> crossoverHeroes;
 
+	void loadPreconditionRegions(ui32 regions);
 	void prepareCrossoverHeroes(std::vector<CGHeroInstance *> heroes);
 
 	bool isNotVoid() const;
 
 	template <typename Handler> void serialize(Handler &h, const int formatVersion)
 	{
-		h & mapName & packedMapSize & preconditionRegion & regionColor & difficulty & conquered & regionText & 
+		h & mapName & packedMapSize & preconditionRegions & regionColor & difficulty & conquered & regionText & 
 			prolog & epilog & travelOptions & crossoverHeroes;
 	}
 };

+ 1 - 1
lib/CCreatureHandler.cpp

@@ -38,7 +38,7 @@ CCreatureHandler::CCreatureHandler()
 	// Good: Castle, Rampart, Tower	// Evil: Inferno, Necropolis, Dungeon
 	// Neutral: Stronghold, Fortess, Conflux
 	factionAlignments += 1, 1, 1, -1, -1, -1, 0, 0, 0;
-	doubledCreatures +=  4, 14, 20, 28, 42, 44, 60, 70, 72, 85, 86, 100, 104; //according to Strategija
+	doubledCreatures +=  4, 14, 20, 28, 44, 60, 70, 72, 85, 86, 100, 104; //according to Strategija
 
 	allCreatures.setDescription("All creatures");
 	creaturesOfLevel[0].setDescription("Creatures of unnormalized tier");

+ 1 - 1
lib/CGameState.cpp

@@ -795,7 +795,7 @@ CGameState::CGameState()
 }
 CGameState::~CGameState()
 {
-	delete mx;
+	//delete mx;//TODO: crash on Linux (mutex must be unlocked before destruction)
 	map.dellNull();
 	curB.dellNull();
 	//delete scenarioOps; //TODO: fix for loading ind delete

+ 54 - 80
lib/CObjectHandler.cpp

@@ -93,32 +93,8 @@ static void readCreatures(const JsonNode &creature, std::vector< std::pair <ui16
 	std::pair<si16, si32> creInfo = std::make_pair(-1, 0);
 	std::string creName = creature["name"].String();
 
-	// Look for the best creature that is described by given name
-	if (vstd::contains(VLC->creh->nameToID, creName))
-	{
-		creInfo.first = VLC->creh->nameToID[creName];
-	}
-	else
-	{
-		BOOST_FOREACH(const CCreature *cre, VLC->creh->creatures)
-		{
-			if (cre->namePl == creName || 
-				cre->nameRef == creName ||
-				cre->nameSing == creName)
-				creInfo.first = cre->idNumber;
-		}
-	}
-	if (creInfo.first != -1)
-	{
-		creInfo.second = creature["number"].Float();
-
-		storage.push_back(creInfo);
-	}
-	else
-	{
-		//FIXME: localization issues. switch to numeric ID's in bank config?
-		tlog0<<"Unknown creature in bank config: "<<creName<<"\n";
-	}
+	creInfo.second = creature["number"].Float();
+	creInfo.first = creature["id"].Float();
 }
 
 // Bank helper. Process a bank level.
@@ -2998,7 +2974,7 @@ void CGCreature::initObj()
 	switch(character)
 	{
 	case 0:
-		character = 0;
+		character = -4;
 		break;
 	case 1:
 		character = 1 + ran()%7;
@@ -3059,72 +3035,70 @@ void CGCreature::setPropertyDer(ui8 what, ui32 val)
 
 int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
 {
-	double hlp = h->getTotalStrength() / getArmyStrength();
+	//calculate relative strength of hero and creatures armies
+	double relStrength = double(h->getTotalStrength()) / getArmyStrength();
 
-	if(!character) //compliant creatures will always join
-		return 0;
-	else if(allowJoin)//test for joining
-	{
-		int factor;
-		if(hlp >= 7)
-			factor = 11;
-		else if(hlp >= 1)
-			factor = (int)(2*(hlp-1));
-		else if(hlp >= 0.5)
-			factor = -1;
-		else if(hlp >= 0.333)
-			factor = -2;
-		else
-			factor = -3;
+	int powerFactor;
+	if(relStrength >= 7)
+		powerFactor = 11;
 
-		int sympathy = 0;
+	else if(relStrength >= 1)
+		powerFactor = (int)(2*(relStrength-1));
 
-		std::set<ui32> myKindCres; //what creatures are the same kind as we
-		myKindCres.insert(subID); //we
-		myKindCres.insert(VLC->creh->creatures[subID]->upgrades.begin(),VLC->creh->creatures[subID]->upgrades.end()); //our upgrades
-		for(std::vector<ConstTransitivePtr<CCreature> >::iterator i=VLC->creh->creatures.begin(); i!=VLC->creh->creatures.end(); i++)
-			if(vstd::contains((*i)->upgrades, (ui32) id)) //it's our base creatures
-				myKindCres.insert((*i)->idNumber);
+	else if(relStrength >= 0.5)
+		powerFactor = -1;
 
-		int count = 0, //how many creatures of our kind has hero
-			totalCount = 0;
+	else if(relStrength >= 0.333)
+		powerFactor = -2;
+	else
+		powerFactor = -3;
 
-		for (TSlots::const_iterator i = h->Slots().begin(); i != h->Slots().end(); i++)
-		{
-			if(vstd::contains(myKindCres,i->second->type->idNumber))
-				count += i->second->count;
-			totalCount += i->second->count;
-		}
+	std::set<ui32> myKindCres; //what creatures are the same kind as we
+	myKindCres.insert(subID); //we
+	myKindCres.insert(VLC->creh->creatures[subID]->upgrades.begin(),VLC->creh->creatures[subID]->upgrades.end()); //our upgrades
+	
+	BOOST_FOREACH(ConstTransitivePtr<CCreature> &crea, VLC->creh->creatures)
+	{
+		if(vstd::contains(crea->upgrades, (ui32) id)) //it's our base creatures
+			myKindCres.insert(crea->idNumber);
+	}
 
-		if(count*2 > totalCount)
-			sympathy++;
-		if(count)
-			sympathy++;
-		
+	int count = 0, //how many creatures of similar kind has hero
+		totalCount = 0;
 
-		int charisma = factor + h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy;
-		if(charisma >= character) //creatures might join...
-		{
-			if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy + 1 >= character)
-				return 0; //join for free
-			else if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) * 2  +  sympathy  +  1 >= character)
-				return VLC->creh->creatures[subID]->cost[6] * getStackCount(0); //join for gold
-		}
+	for (TSlots::const_iterator i = h->Slots().begin(); i != h->Slots().end(); i++)
+	{
+		if(vstd::contains(myKindCres,i->second->type->idNumber))
+			count += i->second->count;
+		totalCount += i->second->count;
 	}
 
-	//we are still here - creatures not joined heroes, test for fleeing
+	int sympathy = 0; // 0 if hero have no similar creatures
+	if(count)
+		sympathy++; // 1 - if hero have at least 1 similar creature
+	if(count*2 > totalCount)
+		sympathy++; // 2 - hero have similar creatures more that 50%
 
-	//TODO: it's provisional formula, should be replaced with original one (or something closer to it)
-	//TODO: should be deterministic (will be needed for Vision spell)
-	int hlp2 = (int) (hlp - 2)*1000;
-	if(!neverFlees   
-		&& hlp2 >= 0 
-		&& rand()%2000 < hlp2
-	)
+	int charisma = powerFactor + h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy;
+
+	if(charisma < character) //creatures will fight
+		return -2;
+
+	if (allowJoin)
+	{
+		if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy + 1 >= character)
+			return 0; //join for free
+
+		else if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) * 2  +  sympathy  +  1 >= character)
+			return VLC->creh->creatures[subID]->cost[6] * getStackCount(0); //join for gold
+	}
+
+	//we are still here - creatures have not joined hero, flee or fight
+
+	if (charisma > character)
 		return -1; //flee
 	else
 		return -2; //fight
-
 }
 
 void CGCreature::fleeDecision(const CGHeroInstance *h, ui32 pursue) const

+ 1 - 1
lib/CObjectHandler.h

@@ -688,7 +688,7 @@ class DLL_LINKAGE CGCreature : public CArmedInstance //creatures on map
 {
 public:
 	ui32 identifier; //unique code for this monster (used in missions)
-	si8 character; //character of this set of creatures (0 - the most friendly, 4 - the most hostile) => on init changed to 0 (compliant) - 10 value (savage)
+	si8 character; //character of this set of creatures (0 - the most friendly, 4 - the most hostile) => on init changed to -4 (compliant) ... 10 value (savage)
 	std::string message; //message printed for attacking hero
 	std::vector<ui32> resources; //[res_id], resources given to hero that has won with monsters
 	si32 gainedArtifact; //ID of artifact gained to hero, -1 if none

+ 1 - 1
lib/Connection.h

@@ -754,7 +754,7 @@ public:
 #define READ_CHECK_U32(x)			\
 	ui32 length;			\
 	*this >> length;				\
-	if(length > 50000)				\
+	if(length > 500000)				\
 	{								\
 		tlog2 << "Warning: very big length: " << length << "\n" ;\
 		reportState(tlog2);			\

+ 6 - 1
lib/StartInfo.h

@@ -21,6 +21,7 @@ struct PlayerSettings
 	si8 bonus; //usees enum type Ebonus
 	ui8 color; //from 0 - 
 	ui8 handicap;//0-no, 1-mild, 2-severe
+	ui8 team;
 
 	std::string name;
 	ui8 human; //0 - AI, non-0 serves as player id
@@ -35,6 +36,7 @@ struct PlayerSettings
 		h & handicap;
 		h & name;
 		h & human;
+		h & team;
 	}
 
 	PlayerSettings()
@@ -52,7 +54,10 @@ struct StartInfo
 
 	ui8 mode; //uses EMode enum
 	ui8 difficulty; //0=easy; 4=impossible
-	bmap<int, PlayerSettings> playerInfos; //color indexed
+
+	typedef bmap<int, PlayerSettings> TPlayerInfos;
+	TPlayerInfos playerInfos; //color indexed
+
 	ui8 turnTime; //in minutes, 0=unlimited
 	std::string mapname;
 	ui8 whichMapInCampaign; //used only for mode CAMPAIGN

+ 17 - 8
server/CGameHandler.cpp

@@ -1031,15 +1031,16 @@ void CGameHandler::newTurn()
 						else
 							availableCount += t->creatureGrowth(k);
 
-						if( vstd::contains(t->creatures[k].second, n.creatureid)
-							|| (n.specialWeek == NewTurn::DEITYOFFIRE && (cre->idNumber == 42 || cre->idNumber == 43)))
+						//Deity of fire week - upgrade both imps and upgrades
+						if (n.specialWeek == NewTurn::DEITYOFFIRE && vstd::contains(t->creatures[k].second, n.creatureid))
+							availableCount += 15;
+
+						if( cre->idNumber == n.creatureid ) //bonus week, effect applies only to identical creatures
 						{
 							if(n.specialWeek == NewTurn::DOUBLE_GROWTH)
 								availableCount *= 2;
 							else if(n.specialWeek == NewTurn::BONUS_GROWTH)
 								availableCount += 5;
-							else if(n.specialWeek == NewTurn::DEITYOFFIRE)
-								availableCount += 15;
 						}
 					}
 				}
@@ -1130,8 +1131,16 @@ void CGameHandler::newTurn()
 					iw.text.addReplacement2(15);							//%+d 15
 					break;
 				default:
-					iw.text.addTxt(MetaString::ARRAY_TXT, (newMonth ? 130 : 133));
-					iw.text.addReplacement(MetaString::ARRAY_TXT, 43 + rand()%15);
+					if (newMonth)
+					{
+						iw.text.addTxt(MetaString::ARRAY_TXT, (130));
+						iw.text.addReplacement(MetaString::ARRAY_TXT, 32 + rand()%10);
+					}
+					else
+					{
+						iw.text.addTxt(MetaString::ARRAY_TXT, (133));
+						iw.text.addReplacement(MetaString::ARRAY_TXT, 43 + rand()%15);
+					}
 			}
 			for (std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end(); i++)
 			{
@@ -4486,7 +4495,7 @@ void CGameHandler::checkLossVictory( ui8 player )
 			std::vector<CGHeroInstance *> hes;
 			BOOST_FOREACH(CGHeroInstance * ghi, gs->map->heroes)
 			{
-				if (ghi->tempOwner == 0 /*TODO: insert human player's color*/)
+				if (ghi->tempOwner == vic)
 				{
 					hes.push_back(ghi);
 				}
@@ -5530,7 +5539,7 @@ void CGameHandler::spawnWanderingMonsters(int creatureID)
 	std::vector<int3>::iterator tile;
 	std::vector<int3> tiles;
 	getFreeTiles(tiles);
-	ui32 amount = (tiles.size()) >> 6;
+	ui32 amount = tiles.size() / 200; //Chance is 0.5% for each tile
 	std::random_shuffle(tiles.begin(), tiles.end(), p_myrandom);
 	tlog5 << "Spawning wandering monsters. Found " << tiles.size() << " free tiles. Creature type: " << creatureID << std::endl;
 	const CCreature *cre = VLC->creh->creatures[creatureID];

部分文件因文件數量過多而無法顯示