diff --git a/data/countryflags/default.png b/data/countryflags/default.png
new file mode 100644
index 000000000..15b40c627
Binary files /dev/null and b/data/countryflags/default.png differ
diff --git a/data/countryflags/index.txt b/data/countryflags/index.txt
new file mode 100644
index 000000000..9e4de5e58
--- /dev/null
+++ b/data/countryflags/index.txt
@@ -0,0 +1,10 @@
+
+##### country codes #####
+
+##### custom #####
+
+default
+== -1
+
+##### ISO 3166-1 based #####
+
diff --git a/src/game/client/components/countryflags.cpp b/src/game/client/components/countryflags.cpp
new file mode 100644
index 000000000..fd6e31d16
--- /dev/null
+++ b/src/game/client/components/countryflags.cpp
@@ -0,0 +1,105 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com. */
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "countryflags.h"
+
+
+void CCountryFlags::LoadCountryflagsIndexfile()
+{
+ IOHANDLE File = Storage()->OpenFile("countryflags/index.txt", IOFLAG_READ, IStorage::TYPE_ALL);
+ if(!File)
+ {
+ Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "couldn't open index file");
+ return;
+ }
+
+ char aOrigin[128];
+ CLineReader LineReader;
+ LineReader.Init(File);
+ char *pLine;
+ while((pLine = LineReader.Get()))
+ {
+ if(!str_length(pLine) || pLine[0] == '#') // skip empty lines and comments
+ continue;
+
+ str_copy(aOrigin, pLine, sizeof(aOrigin));
+ char *pReplacement = LineReader.Get();
+ if(!pReplacement)
+ {
+ Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "unexpected end of index file");
+ break;
+ }
+
+ if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ')
+ {
+ char aBuf[128];
+ str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin);
+ Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf);
+ continue;
+ }
+
+ // load the graphic file
+ char aBuf[128];
+ str_format(aBuf, sizeof(aBuf), "countryflags/%s.png", aOrigin);
+ CImageInfo Info;
+ if(!Graphics()->LoadPNG(&Info, aBuf, IStorage::TYPE_ALL))
+ {
+ char aMsg[128];
+ str_format(aMsg, sizeof(aMsg), "failed to load '%s'", aBuf);
+ Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aMsg);
+ continue;
+ }
+
+ // add entry
+ CCountryFlag CountryFlag;
+ CountryFlag.m_CountryCode = str_toint(pReplacement);
+ CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
+ mem_free(Info.m_pData);
+ str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin);
+ Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf);
+ m_aCountryFlags.add(CountryFlag);
+ }
+ io_close(File);
+}
+
+void CCountryFlags::OnInit()
+{
+ // load country flags
+ m_aCountryFlags.clear();
+ LoadCountryflagsIndexfile();
+ if(!m_aCountryFlags.size())
+ {
+ Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "countryflags", "failed to load country flags. folder='countryflags/'");
+ CCountryFlag DummyEntry;
+ DummyEntry.m_CountryCode = -1;
+ DummyEntry.m_Texture = -1;
+ m_aCountryFlags.add(DummyEntry);
+ }
+}
+
+int CCountryFlags::Num() const
+{
+ return m_aCountryFlags.size();
+}
+
+const CCountryFlags::CCountryFlag *CCountryFlags::Get(int Index) const
+{
+ return &m_aCountryFlags[Index%m_aCountryFlags.size()];
+}
+
+int CCountryFlags::Find(int CountryCode) const
+{
+ for(int i = 0; i < m_aCountryFlags.size(); ++i)
+ {
+ if(m_aCountryFlags[i].m_CountryCode == CountryCode)
+ return i;
+ }
+ return -1;
+}
diff --git a/src/game/client/components/countryflags.h b/src/game/client/components/countryflags.h
new file mode 100644
index 000000000..b0960661f
--- /dev/null
+++ b/src/game/client/components/countryflags.h
@@ -0,0 +1,31 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com. */
+#ifndef GAME_CLIENT_COMPONENTS_COUNTRYFLAGS_H
+#define GAME_CLIENT_COMPONENTS_COUNTRYFLAGS_H
+#include
+#include
+#include
+
+class CCountryFlags : public CComponent
+{
+public:
+ struct CCountryFlag
+ {
+ int m_CountryCode;
+ int m_Texture;
+
+ bool operator<(const CCountryFlag &Other) { return m_CountryCode < Other.m_CountryCode; }
+ };
+
+ void OnInit();
+
+ int Num() const;
+ const CCountryFlag *Get(int Index) const;
+ int Find(int CountryCode) const;
+
+private:
+ sorted_array m_aCountryFlags;
+
+ void LoadCountryflagsIndexfile();
+};
+#endif
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index b6e89a7b3..157861102 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -26,6 +26,7 @@
#include "components/chat.h"
#include "components/console.h"
#include "components/controls.h"
+#include "components/countryflags.h"
#include "components/damageind.h"
#include "components/debughud.h"
#include "components/effects.h"
@@ -60,6 +61,7 @@ static CBinds gs_Binds;
static CParticles gs_Particles;
static CMenus gs_Menus;
static CSkins gs_Skins;
+static CCountryFlags gs_CountryFlags;
static CFlow gs_Flow;
static CHud gs_Hud;
static CDebugHud gs_DebugHud;
@@ -107,6 +109,7 @@ void CGameClient::OnConsoleInit()
m_pParticles = &::gs_Particles;
m_pMenus = &::gs_Menus;
m_pSkins = &::gs_Skins;
+ m_pCountryFlags = &::gs_CountryFlags;
m_pChat = &::gs_Chat;
m_pFlow = &::gs_Flow;
m_pCamera = &::gs_Camera;
@@ -121,6 +124,7 @@ void CGameClient::OnConsoleInit()
// make a list of all the systems, make sure to add them in the corrent render order
m_All.Add(m_pSkins);
+ m_All.Add(m_pCountryFlags);
m_All.Add(m_pMapimages);
m_All.Add(m_pEffects); // doesn't render anything, just updates effects
m_All.Add(m_pParticles);
@@ -697,6 +701,15 @@ void CGameClient::OnNewSnapshot()
m_aClients[ClientID].m_UseCustomColor = pInfo->m_UseCustomColor;
m_aClients[ClientID].m_ColorBody = pInfo->m_ColorBody;
m_aClients[ClientID].m_ColorFeet = pInfo->m_ColorFeet;
+
+ // find country flag
+ m_aClients[ClientID].m_Country = g_GameClient.m_pCountryFlags->Find(m_aClients[ClientID].m_Country);
+ if(m_aClients[ClientID].m_Country < 0)
+ {
+ m_aClients[ClientID].m_Country = g_GameClient.m_pCountryFlags->Find(-1);
+ if(m_aClients[ClientID].m_Country < 0)
+ m_aClients[ClientID].m_Country = 0;
+ }
// prepare the info
if(m_aClients[ClientID].m_aSkinName[0] == 'x' || m_aClients[ClientID].m_aSkinName[1] == '_')
diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h
index a3092514d..26c839a33 100644
--- a/src/game/client/gameclient.h
+++ b/src/game/client/gameclient.h
@@ -219,6 +219,7 @@ public:
class CParticles *m_pParticles;
class CMenus *m_pMenus;
class CSkins *m_pSkins;
+ class CCountryFlags *m_pCountryFlags;
class CFlow *m_pFlow;
class CChat *m_pChat;
class CDamageInd *m_pDamageind;