Server:
authorsmxx
Thu, 04 Feb 2010 20:45:03 +0000
changeset 2747 7889a3a9724f
parent 2746 55593f8a490b
child 2748 63e5a31c016c
Server: * Added support for flags (this still needs further adjustments to restore compatibility with older versions (team datasets)!) Engine: * Added support for flags * Added weapon tooltips * Moved SplitBySpace to uMisc * Set file operations to readonly to avoid conflicts running multiple copies networked and synced on one (fast) machine * Flash active team while green arrow is shown (waiting for input or camera centered on active hog) * Updated English locale Frontend: * Added support for flags * Added flag selection to edit team page * Added checkbox for weapon tooltips in options * "Random team" button may now be translated * Disabled "official server" button till protocol is handled for all versions (see above; nemo's server is updated to new protocol) Graphics: * Added basic set of example flags
QTfrontend/game.cpp
QTfrontend/gameuiconfig.cpp
QTfrontend/gameuiconfig.h
QTfrontend/newnetclient.cpp
QTfrontend/pages.cpp
QTfrontend/pages.h
QTfrontend/team.cpp
QTfrontend/team.h
gameServer/CoreTypes.hs
gameServer/HWProtoInRoomState.hs
gameServer/HWProtoNEState.hs
gameServer/Utils.hs
hedgewars/CCHandlers.inc
hedgewars/hwengine.pas
hedgewars/uConsole.pas
hedgewars/uConsts.pas
hedgewars/uLand.pas
hedgewars/uLandObjects.pas
hedgewars/uLocale.pas
hedgewars/uMisc.pas
hedgewars/uStore.pas
hedgewars/uTeams.pas
hedgewars/uWorld.pas
share/hedgewars/Data/Graphics/CMakeLists.txt
share/hedgewars/Data/Graphics/Flags/CMakeLists.txt
share/hedgewars/Data/Graphics/Flags/france.png
share/hedgewars/Data/Graphics/Flags/germany.png
share/hedgewars/Data/Graphics/Flags/hedgewars.png
share/hedgewars/Data/Graphics/Flags/italy.png
share/hedgewars/Data/Graphics/Flags/united_kingdom.png
share/hedgewars/Data/Graphics/Flags/united_states.png
share/hedgewars/Data/Locale/en.txt
--- a/QTfrontend/game.cpp	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/game.cpp	Thu Feb 04 20:45:03 2010 +0000
@@ -290,6 +290,7 @@
 #else
 	arguments << "0";
 #endif
+	arguments << (config->isWeaponTooltip() ? "1" : "0");
 	arguments << tr("en.txt");
 	arguments << QString::number(config->volume()); // sound volume
 	arguments << QString::number(config->timerInterval());
--- a/QTfrontend/gameuiconfig.cpp	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/gameuiconfig.cpp	Thu Feb 04 20:45:03 2010 +0000
@@ -39,6 +39,8 @@
 	//Form->resize(value("window/width", 640).toUInt(), value("window/height", 450).toUInt());
 	resizeToConfigValues();
 
+	Form->ui.pageOptions->WeaponTooltip->setChecked(value("misc/WeaponTooltip", true).toBool());
+
 	int t = Form->ui.pageOptions->CBResolution->findText(value("video/resolution").toString());
 	Form->ui.pageOptions->CBResolution->setCurrentIndex((t < 0) ? 0 : t);
 	Form->ui.pageOptions->CBFullscreen->setChecked(value("video/fullscreen", false).toBool());
@@ -111,6 +113,8 @@
 
 	setValue("video/frontendeffects", isFrontendEffects());
 
+	setValue("misc/WeaponTooltip", isWeaponTooltip());
+
 	bool ffscr = isFrontendFullscreen();
 	setValue("video/frontendfullscreen", ffscr);
 	emit frontendFullscreen(ffscr);
@@ -171,6 +175,11 @@
   return Form->ui.pageOptions->CBFrontendEffects->isChecked();
 }
 
+bool GameUIConfig::isWeaponTooltip() const
+{
+  return Form->ui.pageOptions->WeaponTooltip->isChecked();
+}
+
 bool GameUIConfig::isFrontendFullscreen() const
 {
   return Form->ui.pageOptions->CBFrontendFullscreen->isChecked();
--- a/QTfrontend/gameuiconfig.h	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/gameuiconfig.h	Thu Feb 04 20:45:03 2010 +0000
@@ -50,6 +50,7 @@
 	bool isReducedQuality() const;
 	bool isFrontendEffects() const;
 	bool isFrontendFullscreen() const;
+	bool isWeaponTooltip() const;
 	void resizeToConfigValues();
 
 #ifdef __APPLE__
--- a/QTfrontend/newnetclient.cpp	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/newnetclient.cpp	Thu Feb 04 20:45:03 2010 +0000
@@ -111,6 +111,7 @@
 	     team.Grave + delimeter +
 	     team.Fort + delimeter +
 	     team.Voicepack + delimeter +
+		 team.Flag + delimeter +
 	     QString::number(team.difficulty);
 
 	for(int i = 0; i < 8; ++i)
@@ -322,7 +323,7 @@
 	}
 
 	if (lst[0] == "ADD_TEAM") {
-		if(lst.size() != 23)
+		if(lst.size() != 24)
 		{
 			qWarning("Net: Bad ADDTEAM message");
 			return;
--- a/QTfrontend/pages.cpp	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/pages.cpp	Thu Feb 04 20:45:03 2010 +0000
@@ -155,7 +155,7 @@
 
 	}
 
-	randTeamButton = addButton("Random Team", GBHLayout, 9, false);
+	randTeamButton = addButton(QPushButton::tr("Random Team"), GBHLayout, 9, false);
 
 	vbox1->addWidget(GBoxHedgehogs);
 
@@ -184,6 +184,11 @@
 	CBGrave->setIconSize(QSize(32, 32));
 	GBTLayout->addWidget(CBGrave);
 
+	CBFlag = new QComboBox(GBoxTeam);
+	CBFlag->setMaxCount(65535);
+	CBFlag->setIconSize(QSize(22, 15));
+	GBTLayout->addWidget(CBFlag);
+
 	{
 		QHBoxLayout * hbox = new QHBoxLayout();
 		CBVoicepack = new QComboBox(GBoxTeam);
@@ -232,6 +237,16 @@
 		CBGrave->addItem(icon, (*it).replace(QRegExp("^(.*)\\.png"), "\\1"));
 	}
 
+	tmpdir.cd(datadir->absolutePath());
+	tmpdir.cd("Graphics/Flags");
+	list = tmpdir.entryList(QStringList("*.png"));
+	for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+	{
+		QPixmap pix(datadir->absolutePath() + "/Graphics/Flags/" + *it);
+		QIcon icon(pix.copy(0, 0, 22, 15));
+		CBFlag->addItem(icon, (*it).replace(QRegExp("^(.*)\\.png"), "\\1"));
+	}
+
 	vbox1->addStretch();
 	vbox2->addStretch();
 //	vbox3->addStretch();
@@ -388,6 +403,11 @@
             WeaponsName = new QComboBox(this);
             WeaponsLayout->addWidget(WeaponsName, 0, 0, 1, 2);
             WeaponEdit = addButton(tr("Edit"), WeaponsLayout, 1, 1);
+
+            WeaponTooltip = new QCheckBox(this);
+            WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips"));
+            WeaponsLayout->addWidget(WeaponTooltip, 2, 0, 1, 2);
+
             gbTBLayout->addWidget(groupWeapons, 1, 0);
         }
 
@@ -1293,5 +1313,8 @@
 	BtnLAN = addButton(tr("LAN game"), pageLayout, 1, 2);
 	BtnOfficialServer = addButton(tr("Official server"), pageLayout, 2, 2);
 
+	// hack: temporary deactivated - requires server modifications that aren't backward compatible (yet)
+	BtnOfficialServer->setEnabled(false);
+
 	BtnBack = addButton(":/res/Exit.png", pageLayout, 4, 0, true);
 }
--- a/QTfrontend/pages.h	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/pages.h	Thu Feb 04 20:45:03 2010 +0000
@@ -156,6 +156,7 @@
 	QComboBox *CBFort;
 	SquareLabel *FortPreview;
 	QComboBox *CBGrave;
+	QComboBox *CBFlag;
 	QComboBox *CBTeamLvl;
 	QComboBox *CBVoicepack;
 	QGroupBox *GBoxBinds;
@@ -200,9 +201,10 @@
 public:
 	PageOptions(QWidget* parent = 0);
 
-	QPushButton* WeaponsButt;
-	QPushButton* WeaponEdit;
-	QComboBox* WeaponsName;
+	QPushButton *WeaponsButt;
+	QPushButton *WeaponEdit;
+	QComboBox *WeaponsName;
+	QCheckBox *WeaponTooltip;
 
 	QPushButton *BtnBack;
 	IconedGroupBox *teamsBox;
--- a/QTfrontend/team.cpp	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/team.cpp	Thu Feb 04 20:45:03 2010 +0000
@@ -42,6 +42,7 @@
 	Grave = "Statue";
 	Fort = "Plane";
 	Voicepack = "Default";
+	Flag = "hedgewars";
 	for(int i = 0; i < BINDS_NUMBER; i++)
 	{
 		binds[i].action = cbinds[i].action;
@@ -54,17 +55,18 @@
   m_isNetTeam(true)
 {
 	// net teams are configured from QStringList
-	if(strLst.size() != 22) throw HWTeamConstructException();
+	if(strLst.size() != 23) throw HWTeamConstructException();
 	TeamName = strLst[0];
 	Grave = strLst[1];
 	Fort = strLst[2];
 	Voicepack = strLst[3];
-	Owner = strLst[4];
-	difficulty = strLst[5].toUInt();
+	Flag = strLst[4];
+	Owner = strLst[5];
+	difficulty = strLst[6].toUInt();
 	for(int i = 0; i < 8; i++)
 	{
-		HHName[i]=strLst[i * 2 + 6];
-		HHHat[i]=strLst[i * 2 + 7];
+		HHName[i]=strLst[i * 2 + 7];
+		HHHat[i]=strLst[i * 2 + 8];
 	}
 }
 
@@ -83,6 +85,7 @@
 	Grave = QString("Simple"); // default
 	Fort = QString("Island"); // default
 	Voicepack = "Default";
+	Flag = "hedgewars";
 
 	for(int i = 0; i < BINDS_NUMBER; i++)
 	{
@@ -137,6 +140,11 @@
 			str.remove(0, 5);
 			Fort = str;
 		} else
+		if (str.startsWith("flag "))
+		{
+			str.remove(0, 5);
+			Flag = str;
+		} else
 		if (str.startsWith("voicepack "))
 		{
 			str.remove(0, 10);
@@ -188,6 +196,7 @@
 	stream << "grave " << Grave << endl;
 	stream << "fort " << Fort << endl;
 	stream << "voicepack " << Voicepack << endl;
+	stream << "flag " << Flag << endl;
 	for(int i = 0; i < BINDS_NUMBER; i++)
 	{
 		stream << "bind " << binds[i].strbind << " " << binds[i].action << endl;
@@ -207,6 +216,7 @@
 		hwform->ui.pageEditTeam->HHHats[i]->setCurrentIndex(hwform->ui.pageEditTeam->HHHats[i]->findData(HHHat[i], Qt::DisplayRole));
 	}
 	hwform->ui.pageEditTeam->CBGrave->setCurrentIndex(hwform->ui.pageEditTeam->CBGrave->findText(Grave));
+	hwform->ui.pageEditTeam->CBFlag->setCurrentIndex(hwform->ui.pageEditTeam->CBFlag->findText(Flag));
 
 	hwform->ui.pageEditTeam->CBFort->setCurrentIndex(hwform->ui.pageEditTeam->CBFort->findText(Fort));
 	hwform->ui.pageEditTeam->CBVoicepack->setCurrentIndex(hwform->ui.pageEditTeam->CBVoicepack->findText(Voicepack));
@@ -231,6 +241,7 @@
 	Grave = hwform->ui.pageEditTeam->CBGrave->currentText();
 	Fort = hwform->ui.pageEditTeam->CBFort->currentText();
 	Voicepack = hwform->ui.pageEditTeam->CBVoicepack->currentText();
+	Flag = hwform->ui.pageEditTeam->CBFlag->currentText();
 	for(int i = 0; i < BINDS_NUMBER; i++)
 	{
 		binds[i].strbind = hwform->ui.pageEditTeam->CBBind[i]->itemData(hwform->ui.pageEditTeam->CBBind[i]->currentIndex()).toString();
@@ -248,6 +259,7 @@
 	sl.push_back(QString("egrave " + Grave));
 	sl.push_back(QString("efort " + Fort));
 	sl.push_back(QString("evoicepack " + Voicepack));
+	sl.push_back(QString("eflag " + Flag));
 
 	if (!m_isNetTeam)
 		for(int i = 0; i < BINDS_NUMBER; i++)
--- a/QTfrontend/team.h	Thu Feb 04 18:46:49 2010 +0000
+++ b/QTfrontend/team.h	Thu Feb 04 20:45:03 2010 +0000
@@ -45,6 +45,7 @@
 		QString HHHat[8];
 		QString Grave;
 		QString Fort;
+		QString Flag;
 		QString Voicepack;
 		QString Owner;
 		unsigned int difficulty;
--- a/gameServer/CoreTypes.hs	Thu Feb 04 18:46:49 2010 +0000
+++ b/gameServer/CoreTypes.hs	Thu Feb 04 20:45:03 2010 +0000
@@ -55,6 +55,7 @@
 		teamgrave :: String,
 		teamfort :: String,
 		teamvoicepack :: String,
+		teamflag :: String,
 		difficulty :: Int,
 		hhnum :: Int,
 		hedgehogs :: [HedgehogInfo]
--- a/gameServer/HWProtoInRoomState.hs	Thu Feb 04 18:46:49 2010 +0000
+++ b/gameServer/HWProtoInRoomState.hs	Thu Feb 04 20:45:03 2010 +0000
@@ -42,7 +42,7 @@
 	where
 		client = clients IntMap.! clID
 
-handleCmd_inRoom clID clients rooms ("ADD_TEAM" : name : color : grave : fort : voicepack : difStr : hhsInfo)
+handleCmd_inRoom clID clients rooms ("ADD_TEAM" : name : color : grave : fort : voicepack : flag : difStr : hhsInfo)
 	| length hhsInfo /= 16 = []
 	| length (teams room) == 6 = [Warning "too many teams"]
 	| canAddNumber <= 0 = [Warning "too many hedgehogs"]
@@ -61,7 +61,7 @@
 		room = rooms IntMap.! (roomID client)
 		canAddNumber = 48 - (sum . map hhnum $ teams room)
 		findTeam = find (\t -> name == teamname t) $ teams room
-		newTeam = (TeamInfo clID (nick client) name color grave fort voicepack difficulty newTeamHHNum (hhsList hhsInfo))
+		newTeam = (TeamInfo clID (nick client) name color grave fort voicepack flag difficulty newTeamHHNum (hhsList hhsInfo))
 		difficulty = fromMaybe 0 (maybeRead difStr :: Maybe Int)
 		hhsList [] = []
 		hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs
--- a/gameServer/HWProtoNEState.hs	Thu Feb 04 18:46:49 2010 +0000
+++ b/gameServer/HWProtoNEState.hs	Thu Feb 04 20:45:03 2010 +0000
@@ -13,7 +13,7 @@
 
 handleCmd_NotEntered clID clients _ ["NICK", newNick]
 	| not . null $ nick client = [ProtocolError "Nickname already chosen"]
-	| haveSameNick = [AnswerThisClient ["WARNING", "Nickname collision"], ByeClient ""]
+	| haveSameNick = [AnswerThisClient ["WARNING", "Nickname already in use"], ByeClient ""]
 	| illegalName newNick = [ByeClient "Illegal nickname"]
 	| otherwise =
 		ModifyClient (\c -> c{nick = newNick}) :
--- a/gameServer/Utils.hs	Thu Feb 04 18:46:49 2010 +0000
+++ b/gameServer/Utils.hs	Thu Feb 04 20:45:03 2010 +0000
@@ -59,6 +59,7 @@
 		teamgrave team,
 		teamfort team,
 		teamvoicepack team,
+		teamflag team,
 		teamowner team,
 		show $ difficulty team
 		]
--- a/hedgewars/CCHandlers.inc	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/CCHandlers.inc	Thu Feb 04 20:45:03 2010 +0000
@@ -123,6 +123,14 @@
 CurrentTeam^.voicepack:= AskForVoicepack(s)
 end;
 
+procedure chFlag(var s: shortstring);
+begin
+if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/flag"', true);
+if s[1]='"' then Delete(s, 1, 1);
+if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1);
+CurrentTeam^.flag:= s
+end;
+
 procedure chAddHH(var id: shortstring);
 var s: shortstring;
     Gear: PGear;
--- a/hedgewars/hwengine.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/hwengine.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -440,7 +440,7 @@
 begin
 
 	case ParamCount of
-		17: begin
+		18: begin
 			val(ParamStr(2), cScreenWidth);
 			val(ParamStr(3), cScreenHeight);
 			cInitWidth:= cScreenWidth;
@@ -451,15 +451,16 @@
 			cFullScreen:= ParamStr(6) = '1';
 			isSoundEnabled:= ParamStr(7) = '1';
 			cVSyncInUse:= ParamStr(8) = '1';
-			cLocaleFName:= ParamStr(9);
-			val(ParamStr(10), cInitVolume);
-			val(ParamStr(11), cTimerInterval);
-			PathPrefix:= ParamStr(12);
-			cShowFPS:= ParamStr(13) = '1';
-			cAltDamage:= ParamStr(14) = '1';
-			UserNick:= DecodeBase64(ParamStr(15));
-			isMusicEnabled:= ParamStr(16) = '1';
-			cReducedQuality:= ParamStr(17) = '1';
+			cWeaponTooltips:= ParamStr(9) = '1';
+			cLocaleFName:= ParamStr(10);
+			val(ParamStr(11), cInitVolume);
+			val(ParamStr(12), cTimerInterval);
+			PathPrefix:= ParamStr(13);
+			cShowFPS:= ParamStr(14) = '1';
+			cAltDamage:= ParamStr(15) = '1';
+			UserNick:= DecodeBase64(ParamStr(16));
+			isMusicEnabled:= ParamStr(17) = '1';
+			cReducedQuality:= ParamStr(18) = '1';
 		end;
 		3: begin
 			val(ParamStr(2), ipcPort);
--- a/hedgewars/uConsole.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uConsole.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -33,7 +33,6 @@
 procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean);
 procedure StopMessages(Message: Longword);
 function  GetLastConsoleLine: shortstring;
-procedure SplitBySpace(var a, b: shortstring);
 
 procedure doPut(putX, putY: LongInt; fromAI: boolean);
 
@@ -99,19 +98,6 @@
       end;
 end;
 
-procedure SplitBySpace(var a, b: shortstring);
-var i, t: LongInt;
-begin
-i:= Pos(' ', a);
-if i > 0 then
-	begin
-	for t:= 1 to Pred(i) do
-		if (a[t] >= 'A')and(a[t] <= 'Z') then Inc(a[t], 32);
-	b:= copy(a, i + 1, Length(a) - i);
-	byte(a[0]):= Pred(i)
-	end else b:= '';
-end;
-
 procedure WriteToConsole(s: shortstring);
 var Len: LongInt;
     done: boolean;
@@ -318,6 +304,7 @@
 	RegisterVariable('-cur_l'  , vtCommand, @chCurL_m       , true );
 	RegisterVariable('+cur_r'  , vtCommand, @chCurR_p       , true );
 	RegisterVariable('-cur_r'  , vtCommand, @chCurR_m       , true );
+	RegisterVariable('flag'    , vtCommand, @chFlag         , false);
 end;
 
 procedure free_uConsole;
--- a/hedgewars/uConsts.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uConsts.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -45,7 +45,7 @@
 
 	TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps,
 			ptMapCurrent, ptDemos, ptSounds, ptGraves, ptFonts, ptForts,
-			ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats);
+			ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags);
 
 	TSprite = (sprWater, sprCloud, sprBomb, sprBigDigit, sprFrame,
 			sprLag, sprArrow, sprGrenade, sprTargetP, sprUFO,
@@ -182,9 +182,10 @@
 	cWhiteColorChannels	: TSDL_Color = (r:$FF; g:$FF; b:$FF; unused:$FF);
 	cNearBlackColorChannels	: TSDL_Color = (r:$00; g:$00; b:$10; unused:$FF);
 
-	cWhiteColor		: Longword = $FFFFFFFF;
-	cYellowColor		: Longword = $FFFFFF00;
-	cExplosionBorderColor	: LongWord = $FF808080;
+	cWhiteColor		      : Longword = $FFFFFFFF;
+	cYellowColor		  : Longword = $FFFFFF00;
+	cNearBlackColor       : Longword = $FF000010;
+	cExplosionBorderColor : LongWord = $FF808080;
 
 {$WARNINGS OFF}
 	cAirPlaneSpeed: hwFloat = (isNegative: false; QWordValue:   3006477107); // 1.4
@@ -352,7 +353,8 @@
 	ammoprop_AltUse       = $00000400;
 	ammoprop_NotBorder    = $00000800;
 	ammoprop_Utility      = $00001000;
-
+	ammoprop_NoRoundEndHint=$10000000;
+	
 	AMMO_INFINITE = 100;
 
 	EXPLAllDamageInRadius = $00000001;
@@ -493,7 +495,7 @@
 			(FileName:   'AmmoName'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil;
 			Width: 202; Height: 33; imageWidth: 0; imageHeight: 0; saveSurf: false),// sprAMSlotName
 			(FileName:      'Ammos'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil;
-			Width:  32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false),// sprAMAmmos
+			Width:  32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: true),// sprAMAmmos
 			(FileName:   'SlotKeys'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil;
 			Width:  32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false),// sprAMSlotKeys
 			(FileName:  'Selection'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil;
@@ -918,13 +920,16 @@
 			NameTex: nil;
 			Probability: 100;
 			NumberInCase: 3;
-			Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_AttackInMove or ammoprop_AltAttack;
-				Count: 5;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amRope;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_ForwMsgs or
+							ammoprop_AttackInMove or
+							ammoprop_AltAttack;
+					Count: 5;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amRope;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1051,7 +1056,8 @@
 			NameTex: nil;
 			Probability: 100;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_ForwMsgs or
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_ForwMsgs or
 							ammoprop_AttackInMove or
 							ammoprop_NoCrosshair or
 							ammoprop_DontHold or
@@ -1139,13 +1145,16 @@
 			NameTex: nil;
 			Probability: 150;
 			NumberInCase: 3;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_NeedTarget or ammoprop_AttackingPut;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amGirder;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+							ammoprop_NeedTarget or
+							ammoprop_AttackingPut;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amGirder;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1181,13 +1190,16 @@
 			NameTex: nil;
 			Probability: 100;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_NoCrosshair or ammoprop_DontHold;
-				Count: 3;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amSwitch;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_ForwMsgs or
+							ammoprop_NoCrosshair or
+							ammoprop_DontHold;
+					Count: 3;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amSwitch;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1396,13 +1408,17 @@
 			NameTex: nil;
 			Probability: 20;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amLowGravity;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amLowGravity;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1415,13 +1431,17 @@
 			NameTex: nil;
 			Probability: 15;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amExtraDamage;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amExtraDamage;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1434,13 +1454,17 @@
 			NameTex: nil;
 			Probability: 20;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amInvulnerable;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amInvulnerable;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1453,13 +1477,17 @@
 			NameTex: nil;
 			Probability: 30;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amExtraTime;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amExtraTime;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1472,13 +1500,17 @@
 			NameTex: nil;
 			Probability: 15;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amLaserSight;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amLaserSight;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1491,13 +1523,17 @@
 			NameTex: nil;
 			Probability: 15;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_NoCrosshair or  ammoprop_DontHold or  ammoprop_AltUse or ammoprop_Utility;
-				Count: 1;
-				NumPerTurn: 0;
-				Timer: 0;
-				Pos: 0;
-				AmmoType: amVampiric;
-				AttackVoice: sndNone);
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_NoCrosshair or
+						  ammoprop_DontHold or
+						  ammoprop_AltUse or
+                          ammoprop_Utility;
+					Count: 1;
+					NumPerTurn: 0;
+					Timer: 0;
+					Pos: 0;
+					AmmoType: amVampiric;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1529,7 +1565,8 @@
 			NameTex: nil;
 			Probability: 20;
 			NumberInCase: 1;
-			Ammo: (Propz: ammoprop_ForwMsgs or
+			Ammo: (Propz: ammoprop_NoRoundEndHint or
+						  ammoprop_ForwMsgs or
 							ammoprop_AttackInMove or
 							ammoprop_NoCrosshair or
 							ammoprop_DontHold or
@@ -1548,7 +1585,6 @@
 			SkipTurns: 0;
 			PosCount: 1;
 			PosSprite: sprWater),
-
 			(NameId: sidMolotov;
 			NameTex: nil;
 			Probability: 0;
@@ -1623,7 +1659,8 @@
 		'Graphics/AmmoMenu',             // ptAmmoMenu
 		'Graphics/Hedgehog',             // ptHedgehog
 		'Sounds/voices',                 // ptVoices
-		'Graphics/Hats'                  // ptHats
+		'Graphics/Hats',                 // ptHats
+		'Graphics/Flags'                 // ptFlags
 	);
 begin
 	PathPrefix := './';
--- a/hedgewars/uLand.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uLand.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -730,6 +730,7 @@
 s:= Pathz[ptMapCurrent] + '/map.cfg';
 WriteLnToConsole('Fetching map HH limit');
 Assign(f, s);
+filemode:= 0; // readonly
 Reset(f);
 Readln(f);
 if not eof(f) then Readln(f, MaxHedgehogs);
--- a/hedgewars/uLandObjects.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uLandObjects.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -371,6 +371,7 @@
 WriteLnToConsole('Reading objects info...');
 Assign(f, s);
 {$I-}
+filemode:= 0; // readonly
 Reset(f);
 
 // read sky and explosion border colors
--- a/hedgewars/uLocale.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uLocale.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -31,14 +31,17 @@
             sidLaserSight, sidVampiric, sidSniperRifle, sidJetpack, sidMolotov);
 
 	TMsgStrId = (sidStartFight, sidDraw, sidWinner, sidVolume, sidPaused,
-			sidConfirm, sidSuddenDeath, sidRemaining, sidFuel, sidSync);
+			sidConfirm, sidSuddenDeath, sidRemaining, sidFuel, sidSync,
+			sidNoEndTurn, sidNotYetAvailable);
 
 	TEventId = (eidDied, eidDrowned, eidRoundStart, eidRoundWin, eidRoundDraw,
 			eidNewHealthPack, eidNewAmmoPack, eidNewUtilityPack, eidTurnSkipped, eidHurtSelf,
-			eidHomerun);
+			eidHomerun, eidFrozen);
 
 const MAX_EVENT_STRINGS = 100;
 var trammo: array[TAmmoStrId] of string;
+    trammoc: array[TAmmoStrId] of string;
+    trammod: array[TAmmoStrId] of string;
     trmsg: array[TMsgStrId] of string;
 
 procedure LoadLocale(FileName: string);
@@ -65,9 +68,9 @@
 for e:= Low(TEventId) to High(TEventId) do first[e]:= true;
 
 {$I-} // iochecks off
+Assign(f, FileName);
 filemode:= 0; // readonly
-Assign(f, FileName);
-reset(f);
+Reset(f);
 if IOResult = 0 then loaded:= true;
 TryDo(loaded, 'Cannot load locale "' + FileName + '"', false);
 if loaded then
@@ -98,6 +101,8 @@
                trevt[TEventId(b)][trevt_n[TEventId(b)]]:= s;
                inc(trevt_n[TEventId(b)]);
                end;
+           3: if (b >=0) and (b <= ord(High(TAmmoStrId))) then trammoc[TAmmoStrId(b+1)]:= s;
+           4: if (b >=0) and (b <= ord(High(TAmmoStrId))) then trammod[TAmmoStrId(b+1)]:= s;
            end;
        end;
    Close(f)
--- a/hedgewars/uMisc.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uMisc.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -108,6 +108,8 @@
 	cLaserSighting	: boolean;
 	cVampiric	: boolean;
 	cArtillery	: boolean;
+	WeaponTooltipTex : PTexture;
+	cWeaponTooltips: boolean;
 
 	flagMakeCapture	: boolean;
 
@@ -125,6 +127,8 @@
 
 procedure init_uMisc;
 procedure free_uMisc;
+procedure SplitBySpace(var a, b: shortstring);
+procedure SplitByChar(var a, b: string; c: char);
 procedure movecursor(dx, dy: Integer);
 function  hwSign(r: hwFloat): LongInt;
 function  Min(a, b: LongInt): LongInt;
@@ -166,6 +170,31 @@
     f: textfile;
 {$ENDIF}
 
+// should this include "strtolower()" for the split string?
+procedure SplitBySpace(var a, b: shortstring);
+var i, t: LongInt;
+begin
+i:= Pos(' ', a);
+if i > 0 then
+	begin
+	for t:= 1 to Pred(i) do
+		if (a[t] >= 'A')and(a[t] <= 'Z') then Inc(a[t], 32);
+	b:= copy(a, i + 1, Length(a) - i);
+	byte(a[0]):= Pred(i)
+	end else b:= '';
+end;
+
+procedure SplitByChar(var a, b: string; c: char);
+var i: LongInt;
+begin
+i:= Pos(c, a);
+if i > 0 then
+	begin
+	b:= copy(a, i + 1, Length(a) - i);
+	byte(a[0]):= Pred(i)
+	end else b:= '';
+end;
+
 procedure movecursor(dx, dy: Integer);
 var x, y: LongInt;
 begin
--- a/hedgewars/uStore.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uStore.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -77,7 +77,9 @@
 function  LoadImage(const filename: string; imageFlags: LongInt): PSDL_Surface;
 procedure SetupOpenGL;
 procedure SetScale(f: GLfloat);
-
+procedure RenderWeaponTooltip(atype: TAmmoType);
+procedure ShowWeaponTooltip(x, y: LongInt);
+procedure FreeWeaponTooltip;
 
 implementation
 uses uMisc, uConsole, uLand, uLocale, uWorld{$IFDEF IPHONEOS}, PascalExports{$ENDIF};
@@ -145,6 +147,32 @@
 WriteInRoundRect:= finalRect;
 end;
 
+function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: string): TSDL_Rect;
+var w, h: LongInt;
+    tmpsurf: PSDL_Surface;
+    clr: TSDL_Color;
+    finalRect: TSDL_Rect;
+begin
+TTF_SizeUTF8(Fontz[Font].Handle, Str2PChar(s), w, h);
+finalRect.x:= X + FontBorder + 2;
+finalRect.y:= Y + FontBorder;
+finalRect.w:= w + FontBorder * 2 + 4;
+finalRect.h:= h + FontBorder * 2;
+clr.r:= Color shr 16;
+clr.g:= (Color shr 8) and $FF;
+clr.b:= Color and $FF;
+tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(s), clr);
+tmpsurf:= doSurfaceConversion(tmpsurf);
+SDLTry(tmpsurf <> nil, true);
+SDL_UpperBlit(tmpsurf, nil, Surface, @finalRect);
+SDL_FreeSurface(tmpsurf);
+finalRect.x:= X;
+finalRect.y:= Y;
+finalRect.w:= w + FontBorder * 2 + 4;
+finalRect.h:= h + FontBorder * 2;
+WriteInRect:= finalRect
+end;
+
 procedure StoreLoad;
 var s: string;
 
@@ -153,7 +181,7 @@
 		i: LongInt;
 		r, rr: TSDL_Rect;
 		drY: LongInt;
-		texsurf: PSDL_Surface;
+		texsurf, flagsurf: PSDL_Surface;
 	begin
 	r.x:= 0;
 	r.y:= 0;
@@ -177,6 +205,34 @@
 		HealthTex:= Surface2Tex(texsurf, false);
 		SDL_FreeSurface(texsurf);
 
+		r.x:= 0;
+		r.y:= 0;
+		r.w:= 32;
+		r.h:= 32;
+		texsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 32, RMask, GMask, BMask, AMask);
+		TryDo(texsurf <> nil, errmsgCreateSurface, true);
+		TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
+
+		r.w:= 26;
+		r.h:= 19;
+
+		DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true);
+
+		flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone);
+		if flagsurf = nil then
+			flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone);
+		TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true);
+		copyToXY(flagsurf, texsurf, 2, 2);
+		SDL_FreeSurface(flagsurf);
+		
+		// restore black border pixels inside the flag
+		PLongwordArray(texsurf^.pixels)^[32 * 2 +  2]:= cNearBlackColor;
+		PLongwordArray(texsurf^.pixels)^[32 * 2 + 23]:= cNearBlackColor;
+		PLongwordArray(texsurf^.pixels)^[32 * 16 +  2]:= cNearBlackColor;
+		PLongwordArray(texsurf^.pixels)^[32 * 16 + 23]:= cNearBlackColor;
+
+		FlagTex:= Surface2Tex(texsurf, false);
+		
 		dec(drY, r.h + 2);
 		DrawHealthY:= drY;
 		for i:= 0 to 7 do
@@ -1316,6 +1372,183 @@
         end;
 end;
 
+function RenderHelpWindow(caption, subcaption, description, extra: shortstring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
+var tmpsurf: PSDL_SURFACE;
+	w, h, i, j: LongInt;
+	font: THWFont;
+	r, r2: TSDL_Rect;
+	wa, ha: LongInt;
+	tmpline, tmpline2, tmpdesc: shortstring;
+begin
+font:= fnt16;
+
+// make sure there is a caption as well as a sub caption - description is optional
+if caption = '' then caption:= '???';
+if subcaption = '' then subcaption:= ' ';
+
+w:= 0;
+h:= 0;
+wa:= FontBorder * 2 + 4;
+ha:= FontBorder * 2;
+
+// TODO: Recheck height/position calculation
+
+// get caption's dimensions
+TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(caption), i, j);
+// width adds 36 px (image + space)
+w:= i + 36 + wa;
+h:= j + ha;
+
+// get sub caption's dimensions
+TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(subcaption), i, j);
+// width adds 36 px (image + space)
+if w < (i + 36 + wa) then w:= i + 36 + wa;
+inc(h, j + ha);
+
+// get description's dimensions
+tmpdesc:= description;
+while tmpdesc <> '' do
+	begin
+	tmpline:= tmpdesc;
+	SplitByChar(tmpline, tmpdesc, '|');
+	if tmpline <> '' then
+		begin
+		TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(tmpline), i, j);
+		if w < (i + wa) then w:= i + wa;
+		inc(h, j + ha)
+		end
+	end;
+
+if extra <> '' then
+	begin
+	// get extra label's dimensions
+	TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(extra), i, j);
+	if w < (i + wa) then w:= i + wa;
+	inc(h, j + ha);
+	end;
+	
+// add borders space
+inc(w, wa);
+inc(h, ha + 8);
+
+tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
+TryDo(tmpsurf <> nil, 'RenderHelpWindow: fail to create surface', true);
+
+// render border and background
+r.x:= 0;
+r.y:= 0;
+r.w:= w;
+r.h:= h;
+DrawRoundRect(@r, cWhiteColor, cNearBlackColor, tmpsurf, true);
+
+// render caption
+r:= WriteInRect(tmpsurf, 36 + FontBorder + 2, ha, $ffffffff, font, caption);
+// render sub caption
+r:= WriteInRect(tmpsurf, 36 + FontBorder + 2, r.y + r.h, $ffc7c7c7, font, subcaption);
+
+// render all description lines
+tmpdesc:= description;
+while tmpdesc <> '' do
+	begin
+	tmpline:= tmpdesc;
+	SplitByChar(tmpline, tmpdesc, '|');
+	r2:= r;
+	if tmpline <> '' then
+		begin
+		r:= WriteInRect(tmpsurf, FontBorder + 2, r.y + r.h, $ff707070, font, tmpline);
+		
+		// render highlighted caption (if there's a ':')
+		SplitByChar(tmpline, tmpline2, ':');
+		if tmpline2 <> '' then
+			WriteInRect(tmpsurf, FontBorder + 2, r2.y + r2.h, $ffc7c7c7, font, tmpline + ':');
+		end
+	end;
+
+if extra <> '' then
+	r:= WriteInRect(tmpsurf, FontBorder + 2, r.y + r.h, extracolor, font, extra);
+
+r.x:= FontBorder + 6;
+r.y:= FontBorder + 4;
+r.w:= 32;
+r.h:= 32;
+SDL_FillRect(tmpsurf, @r, $ffffffff);
+SDL_UpperBlit(iconsurf, iconrect, tmpsurf, @r);
+	
+RenderHelpWindow:=  Surface2Tex(tmpsurf, true);
+SDL_FreeSurface(tmpsurf)
+end;
+
+procedure RenderWeaponTooltip(atype: TAmmoType);
+var r: TSDL_Rect;
+	i: LongInt;
+	extra: string;
+	extracolor: LongInt;
+begin
+{$IFNDEF IPHONEOS}
+// don't do anything if the window shouldn't be shown
+if not cWeaponTooltips then
+	begin
+{$ENDIF}
+	WeaponTooltipTex:= nil;
+{$IFNDEF IPHONEOS}
+	exit
+	end;
+
+// free old texture
+FreeWeaponTooltip;
+
+// image region
+i:= LongInt(atype) - 1;
+r.x:= (i shr 5) * 32;
+r.y:= (i mod 32) * 32;
+r.w:= 32;
+r.h:= 32;
+
+// default (no extra text)
+extra:= '';
+extracolor:= 0;
+
+if (CurrentTeam <> nil) and (Ammoz[atype].SkipTurns >= CurrentTeam^.Clan^.TurnNumber) then // weapon or utility is not yet available
+	begin
+	extra:= trmsg[sidNotYetAvailable];
+	extracolor:= LongInt($ffc77070);
+	end
+else if (Ammoz[atype].Ammo.Propz and ammoprop_NoRoundEndHint) <> 0 then // weapon or utility won't end your turn
+	begin
+	extra:= trmsg[sidNoEndTurn];
+	extracolor:= LongInt($ff70c770);
+	end
+else 
+	begin
+	extra:= '';
+	extracolor:= 0;
+	end;
+
+// render window and return the texture
+WeaponTooltipTex:= RenderHelpWindow(trammo[Ammoz[atype].NameId], trammoc[Ammoz[atype].NameId], trammod[Ammoz[atype].NameId], extra, extracolor, SpritesData[sprAMAmmos].Surface, @r)
+{$ENDIF}
+end;
+
+procedure ShowWeaponTooltip(x, y: LongInt);
+begin
+{$IFNDEF IPHONEOS}
+// draw the texture if it exists
+if WeaponTooltipTex <> nil then
+	DrawTexture(x, y, WeaponTooltipTex)
+{$ENDIF}
+end;
+
+procedure FreeWeaponTooltip;
+begin
+{$IFNDEF IPHONEOS}
+// free the existing texture (if there's any)
+if WeaponTooltipTex = nil then
+	exit;
+FreeTexture(WeaponTooltipTex);
+WeaponTooltipTex:= nil
+{$ENDIF}
+end;
+
 procedure init_uStore;
 begin
 	PixelFormat:= nil;
--- a/hedgewars/uTeams.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uTeams.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -65,7 +65,9 @@
 			NameTagTex: PTexture;
 			CrosshairTex,
 			GraveTex,
-			HealthTex: PTexture;
+			HealthTex,
+			FlagTex: PTexture;
+			Flag: string;
 			GraveName: string;
 			FortName: string;
 			TeamHealth: LongInt;
@@ -259,6 +261,7 @@
 FillChar(team^, sizeof(TTeam), 0);
 team^.AttackBar:= 2;
 team^.CurrHedgehog:= cMaxHHIndex;
+team^.Flag:= 'hedgewars';
 
 TeamsArray[TeamsCount]:= team;
 inc(TeamsCount);
--- a/hedgewars/uWorld.pas	Thu Feb 04 18:46:49 2010 +0000
+++ b/hedgewars/uWorld.pas	Thu Feb 04 20:45:03 2010 +0000
@@ -65,6 +65,7 @@
     CountTicks: Longword;
     SoundTimerTicks: Longword;
     prevPoint: TPoint;
+	amSel: TAmmoType = amNothing;
 
 procedure InitWorld;
 var i, t: LongInt;
@@ -183,21 +184,33 @@
 	DrawSprite(sprAMBorders, x, y, 0);
 
 	if (Pos >= 0) then
+		begin
 		if (Ammo^[Slot, Pos].Count > 0) and (Ammo^[Slot, Pos].AmmoType <> amNothing) then
-		begin
-		DrawTexture(cScreenWidth div 2 - 200 + AMxShift, cScreenHeight - 68, Ammoz[Ammo^[Slot, Pos].AmmoType].NameTex);
+			if (amSel <> Ammo^[Slot, Pos].AmmoType) or (WeaponTooltipTex = nil) then
+				begin
+				amSel:= Ammo^[Slot, Pos].AmmoType;
+				RenderWeaponTooltip(amSel)
+				end;
+			
+			DrawTexture(cScreenWidth div 2 - 200 + AMxShift, cScreenHeight - 68, Ammoz[Ammo^[Slot, Pos].AmmoType].NameTex);
 
-		if Ammo^[Slot, Pos].Count < AMMO_INFINITE then
-			DrawTexture(cScreenWidth div 2 + AMxShift - 35, cScreenHeight - 68, CountTexz[Ammo^[Slot, Pos].Count]);
+			if Ammo^[Slot, Pos].Count < AMMO_INFINITE then
+				DrawTexture(cScreenWidth div 2 + AMxShift - 35, cScreenHeight - 68, CountTexz[Ammo^[Slot, Pos].Count]);
 
-		if bSelected and (Ammoz[Ammo^[Slot, Pos].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber < 0) then
-			begin
-			bShowAmmoMenu:= false;
-			SetWeapon(Ammo^[Slot, Pos].AmmoType);
-			bSelected:= false;
-			exit
-			end;
-		end;
+			if bSelected and (Ammoz[Ammo^[Slot, Pos].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber < 0) then
+				begin
+				bShowAmmoMenu:= false;
+				SetWeapon(Ammo^[Slot, Pos].AmmoType);
+				bSelected:= false;
+				FreeWeaponTooltip;
+				exit
+				end;
+		end
+	else
+		FreeWeaponTooltip;
+	
+	if (WeaponTooltipTex <> nil) and (AMxShift = 0) then
+		ShowWeaponTooltip(x - WeaponTooltipTex^.w - 3, y);
 	end;
 
 bSelected:= false;
@@ -341,6 +354,7 @@
     tdx, tdy: Double;
     grp: TCapGroup;
     s: string[15];
+	highlight: Boolean;
     offset: LongInt;
     scale: GLfloat;
 begin
@@ -518,22 +532,40 @@
 			end;
 
 // Teams Healths
+
 for t:= 0 to Pred(TeamsCount) do
    with TeamsArray[t]^ do
       begin
-      DrawTexture(- NameTagTex^.w - 3, cScreenHeight + DrawHealthY, NameTagTex);
-
+	  highlight:= bShowFinger and (CurrentTeam = TeamsArray[t]) and ((RealTicks mod 1000) < 500);
+	  
+      if highlight then
+         glColor4f(((Clan^.Color shr 16) and $ff) / $ff, ((Clan^.Color shr 8) and $ff) / $ff, (Clan^.Color and $ff) / $ff, 1);
+      DrawTexture(- NameTagTex^.w - 16, cScreenHeight + DrawHealthY, NameTagTex);
+  
       r.x:= 0;
       r.y:= 0;
+	  
+	  r.w:= 26;
+	  r.h:= 19;
+	  DrawFromRect(-14, cScreenHeight + DrawHealthY, @r, FlagTex);
+	   
       r.w:= 2 + TeamHealthBarWidth;
       r.h:= HealthTex^.h;
-
-      DrawFromRect(0, cScreenHeight + DrawHealthY, @r, HealthTex);
+      DrawFromRect(14, cScreenHeight + DrawHealthY, @r, HealthTex);
 
       inc(r.x, cTeamHealthWidth + 2);
       r.w:= 3;
 
-      DrawFromRect(TeamHealthBarWidth + 2, cScreenHeight + DrawHealthY, @r, HealthTex);
+      DrawFromRect(TeamHealthBarWidth + 16, cScreenHeight + DrawHealthY, @r, HealthTex);
+      if highlight then // if highlighted, draw flag again to keep its colors
+         begin
+         r.x:= 2;
+         r.y:= 2;
+         r.w:= 22;
+         r.h:= 15;
+         glColor4f(1, 1, 1, 1);
+         DrawFromRect(-12, cScreenHeight + DrawHealthY + 2, @r, FlagTex);
+         end;
       end;
 
 // Lag alert
--- a/share/hedgewars/Data/Graphics/CMakeLists.txt	Thu Feb 04 18:46:49 2010 +0000
+++ b/share/hedgewars/Data/Graphics/CMakeLists.txt	Thu Feb 04 20:45:03 2010 +0000
@@ -1,4 +1,5 @@
 add_subdirectory(AmmoMenu)
+add_subdirectory(Flags)
 add_subdirectory(Graves)
 add_subdirectory(Hats)
 add_subdirectory(Hedgehog)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Graphics/Flags/CMakeLists.txt	Thu Feb 04 20:45:03 2010 +0000
@@ -0,0 +1,5 @@
+file(GLOB FlagTemplates *.png) 
+
+install(FILES
+	${FlagTemplates}
+	DESTINATION ${SHAREPATH}Data/Graphics/Flags)
Binary file share/hedgewars/Data/Graphics/Flags/france.png has changed
Binary file share/hedgewars/Data/Graphics/Flags/germany.png has changed
Binary file share/hedgewars/Data/Graphics/Flags/hedgewars.png has changed
Binary file share/hedgewars/Data/Graphics/Flags/italy.png has changed
Binary file share/hedgewars/Data/Graphics/Flags/united_kingdom.png has changed
Binary file share/hedgewars/Data/Graphics/Flags/united_states.png has changed
--- a/share/hedgewars/Data/Locale/en.txt	Thu Feb 04 18:46:49 2010 +0000
+++ b/share/hedgewars/Data/Locale/en.txt	Thu Feb 04 20:45:03 2010 +0000
@@ -52,6 +52,10 @@
 01:07=%1 remaining
 01:08=Fuel
 01:09=Synchronizing...
+01:10=Using this utility won't end your turn!
+01:11=This weapon or utility is not yet available!
+01:10=Using this utility won't end your turn!
+01:11=This weapon or utility is not yet available!
 
 ; Event messages
 ; Hog (%1) died
@@ -348,3 +352,179 @@
 02:10=Home Run!
 02:10=A bird, a plane, ...
 02:10=That one is out!
+; Hog (%1) is frozen and misses his turn
+02:11=%1 is cool as ice!
+
+; Weapon Categories
+03:00=Timed Grenade
+03:01=Timed Grenade
+03:02=Ballistic Weapon
+03:03=Guided Weapon
+03:04=Gun (multiple shots)
+03:05=Digging Tool
+03:06=Action
+03:07=Transport Utility
+03:08=Proximity Bomb
+03:09=Gun (multiple shots)
+03:10=BOOM!
+03:11=Bonk!
+03:12=Martial Arts
+03:13=UNUSED
+03:14=Transport Utility
+03:15=Airborne Attack
+03:16=Airborne Attack
+03:17=Digging Utility
+03:18=Utility
+03:19=Transport Utility
+03:20=Action
+03:21=Ballistic Weapon
+03:22=Call me Indiana!
+03:23=(Really) Martial Arts
+03:24=The cake is NOT a lie!
+03:25=Costume Kit
+03:26=Juicy Grenade
+03:27=Fiery Grenade
+03:28=Ballistic Weapon
+03:29=Ballistic Weapon
+03:30=Airborne Attack
+03:31=Remote Controlled Bomb
+03:32=Temporary Effect
+03:33=Temporary Effect
+03:34=Temporary Effect
+03:35=Temporary Effect
+03:36=Temporary Effect
+03:37=Temporary Effect
+03:38=Gun (one shot)
+03:39=Transport Utility
+03:40=Incinerating Grenade
+
+; Weapon Descriptions (use | as line breaks)
+04:00=Attack your enemies using a simple grenade.|It will explode once its timer reaches zero.|1-5: Set grenade's timer|Attack: Hold to throw with more power
+04:01=Attack your enemies using a cluster bomb.|It will split into smaller bombs once its timer|reaches zero.|1-5: Set grenade's timer|Attack: Hold to throw with more power
+04:02=Attack your enemies using a ballistic projectile|that might be influenced by wind.|Attack: Hold to shoot with more power
+04:03=Launch a guided bomb that while home into|the selected target. Don't shoot with full power|to improve its precision.|Cursor: Pick target|Attack: Hold to shoot with more power
+04:04=Attack your enemy using a shotgun with two shots.|Thanks to its spread you don't need direct hits|to harm your opponents.|Attack: Shoot (multiple times)
+04:05=Move underground! Use the pickhammer to drill|a hole into the ground and reach other areas.|Attack: Start or stop digging
+04:06=Bored? No way to attack? Save your ammo?|No problem! Just skip your turn, coward!|Attack: Skip your turn without fighting
+04:07=Bridge huge distances using timed shots with the|rope. Use your momentum to slide into other hogs|or drop grenades and other weapons on them.|Attack: Shoot or release the rope|Long Jump: Drop grenades or similar weapons
+04:08=Keep your enemies away by dropping a mine in|narrow passages or right below their feet. Be|sure to retreat before you trigger it yourself!|Attack: Drop mine next to your feet
+04:09=Not sure about your aiming? Use the Desert|Eagle to attack using up to five shots.|Attack: Shoot (multiple times)
+04:10=Brute force is always an option. Drop this classic|explosive next to your enemies and retreat.|Attack: Drop dynamite next to your feet
+04:11=Get rid of enemy hogs by batting them over|the map borders or into water. Or how about|knocking some mines to your friends?|Attack: Bat everything in front of you
+04:12=Get close and personal to unleash the power of|this almost deadly martial arts technique.|Attack: Perform the Fire Punch
+04:13=UNUSED
+04:14=Fear of heights? Better grab a parachute.|It will unfold once|you fall too far and|save your hog from taking fall damage.|Attack: Unfold the parachute
+04:15=Call in an airplane to attack your enemies|using a bombing run.|Left/Right: Determine attack direction|Cursor: Select target region
+04:16=Call in an airplane to drop several mines|in the target area.|Left/Right: Determine attack direction|Cursor: Select target region
+04:17=Need shelter? Use the blow torch to dig|a tunnel into solid ground granting you|cover.|Attack: Start or stop digging
+04:18=Need additional protection or want to pass|unpassable ground? Place some girders as you|like.|Left/Right: Select girder to place|Cursor: Place girder in a valid position
+04:19=Used at the right moment teleportation can|be more powerful than almost all weapons as|it allows you to save hogs from dangerous|situations within seconds.|Cursor: Select target region
+04:20=Allows you to play the current turn with|a different hog.|Attack: Enable switching hogs
+04:21=Shoot a grenade-like projectile that will|release multiple bombs upon impact.|Attack: Shoot at full power
+04:22=Not just for Indiana Jones! The whip is an|useful weapon in many situations. Especially|when you'd like to shove someone off a cliff.|Attack: Strike everything in front of you
+04:23=If you have nothing to lose, this might be|quite handy. Sacrifice your hog by launching|it into a specific direction hurting everything|on his way and exploding at the end.|Attack: Launch the devastating and deadly attack
+04:24=Happy Birthday! Launch this cake, let it walk right|next to your enemies and let them have an explosive|party. The cake is able to pass almost all terrain|but he might detonate earlier this way.|Attack: Start the cake or let it stop and explode
+04:25=Use this disguise kit to get your enemies to jump|towards your hog (and into some gap or hole).|Attack: Use the kit and try to seduce another hog
+04:26=Throw this juicy water melon at your enemies. Once|the timer expires, it will split into several|explosive pieces.|Attack: Hold to shoot with more power
+04:27=Let hellfire rain onto your opponents by using|this fiendish explosive. Don't get too close to|the explosion as smaller fires might last longer.|Attack: Hold to shoot with more power
+04:28=Short time after launching this rocket, it will|start drilling through solid ground and explode|once its fuse is triggered or it resurfaces again.|Attack: Hold to shoot with more power
+04:29=This is nothing for small kids! The ball gun fires|tons of small colored balls filled with explosives.|Attack: Shoot at full power|Up/Down: Continue aiming
+04:30=Call in an airplane to launch a powerful napalm|strike. With proper aiming this attack can eradicate|huge parts of landscape including unlucky hogs|sitting there.|Left/Right: Determine attack direction|Cursor: Select target region
+04:31=The RC plane is the ideal weapon to collect crates or|attack far away hogs. Either steer it into enemies or|drop some bombs first.|Attack: Launch the plane or drop bombs|Long Jump: Let the valkyries ride into battle|Up/Down: Steer the plane
+04:32=Low gravity is more effective than any diet! Jump|higher and over greater distances or let your enemies|fly even further.|Attack: Activate
+04:33=Sometimes you just need that little extra boost to|deal some more damage.|Attack: Activate
+04:34=Can't touch me!|Attack: Activate
+04:35=Sometimes time's running too fast. Grab some extra|seconds to finish your attack.|Attack: Activate
+04:36=Well, sometimes you're just too bad in aiming. Get|some assistance using modern day technology.|Attack: Activate
+04:37=Don't fear the daylight. It will just last one turn|but will enable you to absorb the damage you do to|other hogs.|Attack: Activate
+04:38=The sniper rifle can be the most devastating weapon|in your whole arsenal, however it's very ineffective|at close quarters. The damage dealt increases with|the distance to its target.|Attack: Shoot (once)
+04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility is able to|bring you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force into one direction
+04:40=Set some ground on fire using this bottle filled|with (soon to be) burning liquid.|Attack: Hold to shoot with more power
+; Hog (%1) is frozen and misses his turn
+02:11=%1 is cool as ice!
+
+; Weapon Categories
+03:00=Timed Grenade
+03:01=Timed Grenade
+03:02=Ballistic Weapon
+03:03=Guided Weapon
+03:04=Gun (multiple shots)
+03:05=Digging Tool
+03:06=Action
+03:07=Transport Utility
+03:08=Proximity Bomb
+03:09=Gun (multiple shots)
+03:10=BOOM!
+03:11=Bonk!
+03:12=Martial Arts
+03:13=UNUSED
+03:14=Transport Utility
+03:15=Airborne Attack
+03:16=Airborne Attack
+03:17=Digging Utility
+03:18=Utility
+03:19=Transport Utility
+03:20=Action
+03:21=Ballistic Weapon
+03:22=Call me Indiana!
+03:23=(Really) Martial Arts
+03:24=The cake is NOT a lie!
+03:25=Costume Kit
+03:26=Juicy Grenade
+03:27=Fiery Grenade
+03:28=Ballistic Weapon
+03:29=Ballistic Weapon
+03:30=Airborne Attack
+03:31=Remote Controlled Bomb
+03:32=Temporary Effect
+03:33=Temporary Effect
+03:34=Temporary Effect
+03:35=Temporary Effect
+03:36=Temporary Effect
+03:37=Temporary Effect
+03:38=Gun (one shot)
+03:39=Transport Utility
+03:40=Incinerating Grenade
+
+; Weapon Descriptions (use | as line breaks)
+04:00=Attack your enemies using a simple grenade.|It will explode once its timer reaches zero.|1-5: Set grenade's timer|Attack: Hold to throw with more power
+04:01=Attack your enemies using a cluster bomb.|It will split into smaller bombs once its timer|reaches zero.|1-5: Set grenade's timer|Attack: Hold to throw with more power
+04:02=Attack your enemies using a ballistic projectile|that might be influenced by wind.|Attack: Hold to shoot with more power
+04:03=Launch a guided bomb that while home into|the selected target. Don't shoot with full power|to improve its precision.|Cursor: Pick target|Attack: Hold to shoot with more power
+04:04=Attack your enemy using a shotgun with two shots.|Thanks to its spread you don't need direct hits|to harm your opponents.|Attack: Shoot (multiple times)
+04:05=Move underground! Use the pickhammer to drill|a hole into the ground and reach other areas.|Attack: Start or stop digging
+04:06=Bored? No way to attack? Save your ammo?|No problem! Just skip your turn, coward!|Attack: Skip your turn without fighting
+04:07=Bridge huge distances using timed shots with the|rope. Use your momentum to slide into other hogs|or drop grenades and other weapons on them.|Attack: Shoot or release the rope|Long Jump: Drop grenades or similar weapons
+04:08=Keep your enemies away by dropping a mine in|narrow passages or right below their feet. Be|sure to retreat before you trigger it yourself!|Attack: Drop mine next to your feet
+04:09=Not sure about your aiming? Use the Desert|Eagle to attack using up to five shots.|Attack: Shoot (multiple times)
+04:10=Brute force is always an option. Drop this classic|explosive next to your enemies and retreat.|Attack: Drop dynamite next to your feet
+04:11=Get rid of enemy hogs by batting them over|the map borders or into water. Or how about|knocking some mines to your friends?|Attack: Bat everything in front of you
+04:12=Get close and personal to unleash the power of|this almost deadly martial arts technique.|Attack: Perform the Fire Punch
+04:13=UNUSED
+04:14=Fear of heights? Better grab a parachute.|It will unfold once|you fall too far and|save your hog from taking fall damage.|Attack: Unfold the parachute
+04:15=Call in an airplane to attack your enemies|using a bombing run.|Left/Right: Determine attack direction|Cursor: Select target region
+04:16=Call in an airplane to drop several mines|in the target area.|Left/Right: Determine attack direction|Cursor: Select target region
+04:17=Need shelter? Use the blow torch to dig|a tunnel into solid ground granting you|cover.|Attack: Start or stop digging
+04:18=Need additional protection or want to pass|unpassable ground? Place some girders as you|like.|Left/Right: Select girder to place|Cursor: Place girder in a valid position
+04:19=Used at the right moment teleportation can|be more powerful than almost all weapons as|it allows you to save hogs from dangerous|situations within seconds.|Cursor: Select target region
+04:20=Allows you to play the current turn with|a different hog.|Attack: Enable switching hogs
+04:21=Shoot a grenade-like projectile that will|release multiple bombs upon impact.|Attack: Shoot at full power
+04:22=Not just for Indiana Jones! The whip is an|useful weapon in many situations. Especially|when you'd like to shove someone off a cliff.|Attack: Strike everything in front of you
+04:23=If you have nothing to lose, this might be|quite handy. Sacrifice your hog by launching|it into a specific direction hurting everything|on his way and exploding at the end.|Attack: Launch the devastating and deadly attack
+04:24=Happy Birthday! Launch this cake, let it walk right|next to your enemies and let them have an explosive|party. The cake is able to pass almost all terrain|but he might detonate earlier this way.|Attack: Start the cake or let it stop and explode
+04:25=Use this disguise kit to get your enemies to jump|towards your hog (and into some gap or hole).|Attack: Use the kit and try to seduce another hog
+04:26=Throw this juicy water melon at your enemies. Once|the timer expires, it will split into several|explosive pieces.|Attack: Hold to shoot with more power
+04:27=Let hellfire rain onto your opponents by using|this fiendish explosive. Don't get too close to|the explosion as smaller fires might last longer.|Attack: Hold to shoot with more power
+04:28=Short time after launching this rocket, it will|start drilling through solid ground and explode|once its fuse is triggered or it resurfaces again.|Attack: Hold to shoot with more power
+04:29=This is nothing for small kids! The ball gun fires|tons of small colored balls filled with explosives.|Attack: Shoot at full power|Up/Down: Continue aiming
+04:30=Call in an airplane to launch a powerful napalm|strike. With proper aiming this attack can eradicate|huge parts of landscape including unlucky hogs|sitting there.|Left/Right: Determine attack direction|Cursor: Select target region
+04:31=The RC plane is the ideal weapon to collect crates or|attack far away hogs. Either steer it into enemies or|drop some bombs first.|Attack: Launch the plane or drop bombs|Long Jump: Let the valkyries ride into battle|Up/Down: Steer the plane
+04:32=Low gravity is more effective than any diet! Jump|higher and over greater distances or let your enemies|fly even further.|Attack: Activate
+04:33=Sometimes you just need that little extra boost to|deal some more damage.|Attack: Activate
+04:34=Can't touch me!|Attack: Activate
+04:35=Sometimes time's running too fast. Grab some extra|seconds to finish your attack.|Attack: Activate
+04:36=Well, sometimes you're just too bad in aiming. Get|some assistance using modern day technology.|Attack: Activate
+04:37=Don't fear the daylight. It will just last one turn|but will enable you to absorb the damage you do to|other hogs.|Attack: Activate
+04:38=The sniper rifle can be the most devastating weapon|in your whole arsenal, however it's very ineffective|at close quarters. The damage dealt increases with|the distance to its target.|Attack: Shoot (once)
+04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility is able to|bring you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force into one direction
+04:40=Set some ground on fire using this bottle filled|with (soon to be) burning liquid.|Attack: Hold to shoot with more power