diff --git a/CMakeLists.txt b/CMakeLists.txt index 50e88beb8..be46d54b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1279,6 +1279,21 @@ set(EXPECTED_DATA skins/whis.png skins/x_ninja.png skins/x_spec.png + themes/auto.png + themes/autumn.png + themes/autumn_day.map + themes/autumn_night.map + themes/heavens.png + themes/heavens_day.map + themes/heavens_night.map + themes/jungle.png + themes/jungle_day.map + themes/jungle_night.map + themes/none.png + themes/rand.png + themes/winter.png + themes/winter_day.map + themes/winter_night.map wordlist.txt ) @@ -1481,6 +1496,7 @@ set_src(ENGINE_SHARED GLOB src/engine/shared linereader.cpp linereader.h map.cpp + map.h masterserver.cpp memheap.cpp memheap.h @@ -1688,6 +1704,8 @@ if(CLIENT) components/maplayers.h components/mapsounds.cpp components/mapsounds.h + components/menu_background.cpp + components/menu_background.h components/menus.cpp components/menus.h components/menus_browser.cpp diff --git a/data/themes/auto.png b/data/themes/auto.png new file mode 100644 index 000000000..a63f6bb0a Binary files /dev/null and b/data/themes/auto.png differ diff --git a/data/themes/autumn.png b/data/themes/autumn.png new file mode 100644 index 000000000..f313b4fee Binary files /dev/null and b/data/themes/autumn.png differ diff --git a/data/themes/autumn_day.map b/data/themes/autumn_day.map new file mode 100644 index 000000000..a3ac0d120 Binary files /dev/null and b/data/themes/autumn_day.map differ diff --git a/data/themes/autumn_night.map b/data/themes/autumn_night.map new file mode 100644 index 000000000..bfcc73d88 Binary files /dev/null and b/data/themes/autumn_night.map differ diff --git a/data/themes/heavens.png b/data/themes/heavens.png new file mode 100644 index 000000000..3a220db17 Binary files /dev/null and b/data/themes/heavens.png differ diff --git a/data/themes/heavens_day.map b/data/themes/heavens_day.map new file mode 100644 index 000000000..29a6718ad Binary files /dev/null and b/data/themes/heavens_day.map differ diff --git a/data/themes/heavens_night.map b/data/themes/heavens_night.map new file mode 100644 index 000000000..3f2fa2895 Binary files /dev/null and b/data/themes/heavens_night.map differ diff --git a/data/themes/jungle.png b/data/themes/jungle.png new file mode 100644 index 000000000..c9a7bb897 Binary files /dev/null and b/data/themes/jungle.png differ diff --git a/data/themes/jungle_day.map b/data/themes/jungle_day.map new file mode 100644 index 000000000..37612fa46 Binary files /dev/null and b/data/themes/jungle_day.map differ diff --git a/data/themes/jungle_night.map b/data/themes/jungle_night.map new file mode 100644 index 000000000..d8b09f21c Binary files /dev/null and b/data/themes/jungle_night.map differ diff --git a/data/themes/none.png b/data/themes/none.png new file mode 100644 index 000000000..e726eb265 Binary files /dev/null and b/data/themes/none.png differ diff --git a/data/themes/rand.png b/data/themes/rand.png new file mode 100644 index 000000000..c09bbd94c Binary files /dev/null and b/data/themes/rand.png differ diff --git a/data/themes/winter.png b/data/themes/winter.png new file mode 100644 index 000000000..9746dc6a6 Binary files /dev/null and b/data/themes/winter.png differ diff --git a/data/themes/winter_day.map b/data/themes/winter_day.map new file mode 100644 index 000000000..e19a648e5 Binary files /dev/null and b/data/themes/winter_day.map differ diff --git a/data/themes/winter_night.map b/data/themes/winter_night.map new file mode 100644 index 000000000..550cc234d Binary files /dev/null and b/data/themes/winter_night.map differ diff --git a/src/base/system.c b/src/base/system.c index 7314e923e..48d693c90 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -2267,6 +2267,46 @@ int time_timestamp(void) return time(0); } +int time_houroftheday(void) +{ + time_t time_data; + struct tm *time_info; + + time(&time_data); + time_info = localtime(&time_data); + return time_info->tm_hour; +} + +int time_season(void) +{ + time_t time_data; + struct tm *time_info; + + time(&time_data); + time_info = localtime(&time_data); + + switch(time_info->tm_mon) + { + case 11: + case 0: + case 1: + return SEASON_WINTER; + case 2: + case 3: + case 4: + return SEASON_SPRING; + case 5: + case 6: + case 7: + return SEASON_SUMMER; + case 8: + case 9: + case 10: + return SEASON_AUTUMN; + } + return SEASON_SPRING; // should never happen +} + void str_append(char *dst, const char *src, int dst_size) { int s = strlen(dst); diff --git a/src/base/system.h b/src/base/system.h index 8bb9dd5e7..a59301ae0 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -617,6 +617,32 @@ int64 time_freq(void); */ int time_timestamp(void); +/* + Function: time_houroftheday + Retrieves the hours since midnight (0..23) + + Returns: + The current hour of the day +*/ +int time_houroftheday(void); + +enum +{ + SEASON_SPRING = 0, + SEASON_SUMMER, + SEASON_AUTUMN, + SEASON_WINTER +}; + +/* + Function: time_season + Retrieves the current season of the year. + + Returns: + one of the SEASON_* enum literals +*/ +int time_season(void); + /* Function: time_get_microseconds Fetches a sample from a high resolution timer and converts it in microseconds. diff --git a/src/base/vmath.h b/src/base/vmath.h index 06862da55..64a51e88c 100644 --- a/src/base/vmath.h +++ b/src/base/vmath.h @@ -5,6 +5,8 @@ #include +#include "math.h" + // ------------------------------------ template @@ -132,6 +134,15 @@ inline T length(const vector3_base &a) return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z); } +template +inline vector2_base rotate(const vector2_base &a, float angle) +{ + angle = angle * pi / 180.0f; + float s = sinf(angle); + float c = cosf(angle); + return vector2_base((T)(c * a.x - s * a.y), (T)(s * a.x + c * a.y)); +} + template inline T distance(const vector3_base &a, const vector3_base &b) { diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 73683a33d..6dd16f471 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -295,6 +295,13 @@ MACRO_CONFIG_INT(ClZoomBackgroundLayers, cl_zoom_background_layers, 0, 0, 1, CFG MACRO_CONFIG_COL(ClBackgroundColor, cl_background_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background color") //0 0 128 MACRO_CONFIG_COL(ClBackgroundEntitiesColor, cl_background_entities_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities) color") //0 0 128 MACRO_CONFIG_STR(ClBackgroundEntities, cl_background_entities, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities)") + +// menu background map +MACRO_CONFIG_STR(ClMenuMap, cl_menu_map, 100, "auto", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background map in the menu") +MACRO_CONFIG_INT(ClRotationRadius, cl_rotation_radius, 30, 1, 500, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Menu camera rotation radius") +MACRO_CONFIG_INT(ClRotationSpeed, cl_rotation_speed, 40, 1, 120, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Menu camera rotations in seconds") +MACRO_CONFIG_INT(ClCameraSpeed, cl_camera_speed, 5, 1, 40, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Menu camera speed") + MACRO_CONFIG_INT(ClBackgroundShowTilesLayers, cl_background_show_tiles_layers, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Whether draw tiles layers when using custom background (entities)") MACRO_CONFIG_INT(SvShowOthers, sv_show_others, 1, 0, 1, CFGFLAG_SERVER, "Whether players can use the command showothers or not") MACRO_CONFIG_INT(SvShowOthersDefault, sv_show_others_default, 0, 0, 2, CFGFLAG_SERVER, "Whether players see others by default (2 for own team)") diff --git a/src/engine/shared/map.cpp b/src/engine/shared/map.cpp index a6da6c98e..ff6ac5e1a 100644 --- a/src/engine/shared/map.cpp +++ b/src/engine/shared/map.cpp @@ -1,63 +1,85 @@ /* (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 "map.h" #include -#include "datafile.h" -class CMap : public IEngineMap +CMap::CMap() { - CDataFileReader m_DataFile; -public: - CMap() {} +} - virtual void *GetData(int Index) { return m_DataFile.GetData(Index); } - virtual int GetDataSize(int Index) { return m_DataFile.GetDataSize(Index); } - virtual void *GetDataSwapped(int Index) { return m_DataFile.GetDataSwapped(Index); } - virtual void UnloadData(int Index) { m_DataFile.UnloadData(Index); } - virtual void *GetItem(int Index, int *pType, int *pID) { return m_DataFile.GetItem(Index, pType, pID); } - virtual int GetItemSize(int Index) { return m_DataFile.GetItemSize(Index); } - virtual void GetType(int Type, int *pStart, int *pNum) { m_DataFile.GetType(Type, pStart, pNum); } - virtual void *FindItem(int Type, int ID) { return m_DataFile.FindItem(Type, ID); } - virtual int NumItems() { return m_DataFile.NumItems(); } +void *CMap::GetData(int Index) +{ + return m_DataFile.GetData(Index); +} +int CMap::GetDataSize(int Index) +{ + return m_DataFile.GetDataSize(Index); +} +void *CMap::GetDataSwapped(int Index) +{ + return m_DataFile.GetDataSwapped(Index); +} +void CMap::UnloadData(int Index) +{ + m_DataFile.UnloadData(Index); +} +void *CMap::GetItem(int Index, int *pType, int *pID) +{ + return m_DataFile.GetItem(Index, pType, pID); +} +int CMap::GetItemSize(int Index) +{ + return m_DataFile.GetItemSize(Index); +} +void CMap::GetType(int Type, int *pStart, int *pNum) +{ + m_DataFile.GetType(Type, pStart, pNum); +} +void *CMap::FindItem(int Type, int ID) +{ + return m_DataFile.FindItem(Type, ID); +} +int CMap::NumItems() +{ + return m_DataFile.NumItems(); +} - virtual void Unload() - { - m_DataFile.Close(); - } +void CMap::Unload() +{ + m_DataFile.Close(); +} - virtual bool Load(const char *pMapName) - { - IStorage *pStorage = Kernel()->RequestInterface(); - if(!pStorage) - return false; - return m_DataFile.Open(pStorage, pMapName, IStorage::TYPE_ALL); - } +bool CMap::Load(const char *pMapName) +{ + IStorage *pStorage = Kernel()->RequestInterface(); + if(!pStorage) + return false; + return m_DataFile.Open(pStorage, pMapName, IStorage::TYPE_ALL); +} - virtual bool IsLoaded() - { - return m_DataFile.IsOpen(); - } +bool CMap::IsLoaded() +{ + return m_DataFile.IsOpen(); +} - virtual SHA256_DIGEST Sha256() - { - return m_DataFile.Sha256(); - } +SHA256_DIGEST CMap::Sha256() +{ + return m_DataFile.Sha256(); +} - virtual unsigned Crc() - { - return m_DataFile.Crc(); - } +unsigned CMap::Crc() +{ + return m_DataFile.Crc(); +} - virtual int MapSize() - { - return m_DataFile.MapSize(); - } +int CMap::MapSize() +{ + return m_DataFile.MapSize(); +} - virtual IOHANDLE File() - { - return m_DataFile.File(); - } -}; +IOHANDLE CMap::File() +{ + return m_DataFile.File(); +} extern IEngineMap *CreateEngineMap() { return new CMap; } diff --git a/src/engine/shared/map.h b/src/engine/shared/map.h new file mode 100644 index 000000000..ed6000ff3 --- /dev/null +++ b/src/engine/shared/map.h @@ -0,0 +1,43 @@ +/* (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 ENGINE_SHARED_MAP_H +#define ENGINE_SHARED_MAP_H + +#include + +#include "datafile.h" +#include + +class CMap : public IEngineMap +{ + CDataFileReader m_DataFile; + +public: + CMap(); + + virtual void *GetData(int Index); + virtual int GetDataSize(int Index); + virtual void *GetDataSwapped(int Index); + virtual void UnloadData(int Index); + virtual void *GetItem(int Index, int *pType, int *pID); + virtual int GetItemSize(int Index); + virtual void GetType(int Type, int *pStart, int *pNum); + virtual void *FindItem(int Type, int ID); + virtual int NumItems(); + + virtual void Unload(); + + virtual bool Load(const char *pMapName); + + virtual bool IsLoaded(); + + virtual SHA256_DIGEST Sha256(); + + virtual unsigned Crc(); + + virtual int MapSize(); + + virtual IOHANDLE File(); +}; + +#endif diff --git a/src/game/client/components/background.cpp b/src/game/client/components/background.cpp index 40282a30b..7604af63c 100644 --- a/src/game/client/components/background.cpp +++ b/src/game/client/components/background.cpp @@ -10,14 +10,15 @@ #include "background.h" -CBackground::CBackground() : CMapLayers(CMapLayers::TYPE_BACKGROUND_FORCE) +CBackground::CBackground(int MapType, bool OnlineOnly) + : CMapLayers(MapType, OnlineOnly) { m_pLayers = new CLayers; m_pBackgroundLayers = m_pLayers; m_pImages = new CMapImages; m_pBackgroundImages = m_pImages; - m_pMap = CreateEngineMap(); - m_pBackgroundMap = m_pMap; + m_pBackgroundMap = CreateBGMap(); + m_pMap = m_pBackgroundMap; m_Loaded = false; m_aMapName[0] = '\0'; m_LastLoad = 0; @@ -29,10 +30,15 @@ CBackground::~CBackground() delete m_pBackgroundImages; } +CBackgroundEngineMap *CBackground::CreateBGMap() +{ + return new CBackgroundEngineMap; +} + void CBackground::OnInit() { m_pImages->m_pClient = GameClient(); - Kernel()->ReregisterInterface(m_pMap); + Kernel()->RegisterInterface(m_pBackgroundMap); if(g_Config.m_ClBackgroundEntities[0] != '\0' && str_comp(g_Config.m_ClBackgroundEntities, CURRENT)) LoadBackground(); } @@ -72,7 +78,7 @@ void CBackground::LoadBackground() m_Loaded = true; } } - + if(m_Loaded) { CMapLayers::OnMapLoad(); diff --git a/src/game/client/components/background.h b/src/game/client/components/background.h index ceca72397..941e09c4f 100644 --- a/src/game/client/components/background.h +++ b/src/game/client/components/background.h @@ -1,13 +1,20 @@ #ifndef GAME_CLIENT_COMPONENTS_BACKGROUND_H #define GAME_CLIENT_COMPONENTS_BACKGROUND_H +#include #include #include // Special value to use background of current map #define CURRENT "%current%" +class CBackgroundEngineMap : public CMap +{ + MACRO_INTERFACE("background_enginemap", 0) +}; + class CBackground : public CMapLayers { +protected: IEngineMap *m_pMap; bool m_Loaded; char m_aMapName[MAX_MAP_LENGTH]; @@ -16,13 +23,15 @@ class CBackground : public CMapLayers int64 m_LastLoad; //to avoid memory leak when switching to %current% - IEngineMap *m_pBackgroundMap; + CBackgroundEngineMap *m_pBackgroundMap; CLayers *m_pBackgroundLayers; CMapImages *m_pBackgroundImages; + virtual CBackgroundEngineMap *CreateBGMap(); + public: - CBackground(); - ~CBackground(); + CBackground(int MapType = CMapLayers::TYPE_BACKGROUND_FORCE, bool OnlineOnly = true); + virtual ~CBackground(); virtual void OnInit(); virtual void OnMapLoad(); diff --git a/src/game/client/components/camera.h b/src/game/client/components/camera.h index 4968f5301..927567b7d 100644 --- a/src/game/client/components/camera.h +++ b/src/game/client/components/camera.h @@ -8,9 +8,11 @@ class CCamera : public CComponent { + friend class CMenuBackground; + enum { - CAMTYPE_UNDEFINED=-1, + CAMTYPE_UNDEFINED = -1, CAMTYPE_SPEC, CAMTYPE_PLAYER, }; diff --git a/src/game/client/components/mapimages.h b/src/game/client/components/mapimages.h index 426ca6538..46c1f3ea0 100644 --- a/src/game/client/components/mapimages.h +++ b/src/game/client/components/mapimages.h @@ -31,6 +31,7 @@ enum EMapImageModType class CMapImages : public CComponent { friend class CBackground; + friend class CMenuBackground; IGraphics::CTextureHandle m_aTextures[64]; int m_aTextureUsedByTileOrQuadLayerFlag[64]; // 0: nothing, 1(as flag): tile layer, 2(as flag): quad layer diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp index 9d46884b6..79ffc417d 100644 --- a/src/game/client/components/maplayers.cpp +++ b/src/game/client/components/maplayers.cpp @@ -19,13 +19,14 @@ #include "maplayers.h" -CMapLayers::CMapLayers(int t) +CMapLayers::CMapLayers(int t, bool OnlineOnly) { m_Type = t; m_pLayers = 0; m_CurrentLocalTick = 0; m_LastLocalTick = 0; m_EnvelopeUpdate = false; + m_OnlineOnly = OnlineOnly; } void CMapLayers::OnInit() @@ -34,6 +35,11 @@ void CMapLayers::OnInit() m_pImages = m_pClient->m_pMapimages; } +CCamera *CMapLayers::GetCurCamera() +{ + return m_pClient->m_pCamera; +} + void CMapLayers::EnvelopeUpdate() { if(Client()->State() == IClient::STATE_DEMOPLAYBACK) @@ -109,19 +115,27 @@ void CMapLayers::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void } else { - if(pThis->m_pClient->m_Snap.m_pGameInfoObj) // && !(pThis->m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)) + if(pThis->m_OnlineOnly && (pItem->m_Version < 2 || pItem->m_Synchronized)) { - if(pItem->m_Version < 2 || pItem->m_Synchronized) + if(pThis->m_OnlineOnly && pThis->m_pClient->m_Snap.m_pGameInfoObj) // && !(pThis->m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)) { s_Time = mix((pThis->Client()->PrevGameTick(g_Config.m_ClDummy)-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)pThis->Client()->GameTickSpeed(), (pThis->Client()->GameTick(g_Config.m_ClDummy)-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)pThis->Client()->GameTickSpeed(), pThis->Client()->IntraGameTick(g_Config.m_ClDummy)); } - else - s_Time += pThis->LocalTime()-s_LastLocalTime; } - pThis->RenderTools()->RenderEvalEnvelope(pPoints+pItem->m_StartPoint, pItem->m_NumPoints, 4, s_Time+TimeOffset, pChannels); - s_LastLocalTime = pThis->LocalTime(); + else if(pThis->m_OnlineOnly) + { + s_Time += pThis->LocalTime() - s_LastLocalTime; + s_LastLocalTime = pThis->LocalTime(); + } + else + { + float CurTime = (float)((double)time_get_microseconds() / 1000000.0); + s_Time += CurTime - s_LastLocalTime; + s_LastLocalTime = CurTime; + } + pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, s_Time + TimeOffset, pChannels); } } @@ -1480,13 +1494,13 @@ void CMapLayers::LayersOfGroupCount(CMapItemGroup* pGroup, int& TileLayerCount, void CMapLayers::OnRender() { - if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) + if(m_OnlineOnly && Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) return; CUIRect Screen; Graphics()->GetScreen(&Screen.x, &Screen.y, &Screen.w, &Screen.h); - vec2 Center = m_pClient->m_pCamera->m_Center; + vec2 Center = GetCurCamera()->m_Center; bool PassedGameLayer = false; int TileLayerCounter = 0; @@ -1504,11 +1518,11 @@ void CMapLayers::OnRender() continue; } - if(!g_Config.m_GfxNoclip && pGroup->m_Version >= 2 && pGroup->m_UseClipping) + if((!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) && pGroup->m_Version >= 2 && pGroup->m_UseClipping) { // set clipping float Points[4]; - MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup(), m_pClient->m_pCamera->m_Zoom); + MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup(), GetCurCamera()->m_Zoom); Graphics()->GetScreen(&Points[0], &Points[1], &Points[2], &Points[3]); float x0 = (pGroup->m_ClipX - Points[0]) / (Points[2]-Points[0]); float y0 = (pGroup->m_ClipY - Points[1]) / (Points[3]-Points[1]); @@ -1526,11 +1540,12 @@ void CMapLayers::OnRender() (int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight())); } - if(!g_Config.m_ClZoomBackgroundLayers && !pGroup->m_ParallaxX && !pGroup->m_ParallaxY) + if((!g_Config.m_ClZoomBackgroundLayers || m_Type == TYPE_FULL_DESIGN) && !pGroup->m_ParallaxX && !pGroup->m_ParallaxY) { MapScreenToGroup(Center.x, Center.y, pGroup, 1.0f); - } else - MapScreenToGroup(Center.x, Center.y, pGroup, m_pClient->m_pCamera->m_Zoom); + } + else + MapScreenToGroup(Center.x, Center.y, pGroup, GetCurCamera()->m_Zoom); for(int l = 0; l < pGroup->m_NumLayers; l++) { @@ -1579,11 +1594,16 @@ void CMapLayers::OnRender() continue; } } - else // TYPE_FOREGROUND + else if(m_Type == TYPE_FOREGROUND) { if(PassedGameLayer && !IsGameLayer) Render = true; } + else if(m_Type == TYPE_FULL_DESIGN) + { + if(!IsGameLayer) + Render = true; + } if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_KP_0)) { @@ -1661,10 +1681,14 @@ void CMapLayers::OnRender() } // skip rendering if detail layers if not wanted, or is entity layer and we are a background map - if((pLayer->m_Flags&LAYERFLAG_DETAIL && !g_Config.m_GfxHighDetail && !IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE && IsEntityLayer)) + if((pLayer->m_Flags & LAYERFLAG_DETAIL && (!g_Config.m_GfxHighDetail && !(m_Type == TYPE_FULL_DESIGN)) && !IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE && IsEntityLayer) || (m_Type == TYPE_FULL_DESIGN && IsEntityLayer)) continue; - if((Render && g_Config.m_ClOverlayEntities < 100 && !IsGameLayer && !IsFrontLayer && !IsSwitchLayer && !IsTeleLayer && !IsSpeedupLayer && !IsTuneLayer) || (g_Config.m_ClOverlayEntities && IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE)) + int EntityOverlayVal = g_Config.m_ClOverlayEntities; + if(m_Type == TYPE_FULL_DESIGN) + EntityOverlayVal = 0; + + if((Render && EntityOverlayVal < 100 && !IsGameLayer && !IsFrontLayer && !IsSwitchLayer && !IsTeleLayer && !IsSpeedupLayer && !IsTuneLayer) || (EntityOverlayVal && IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE)) { if(pLayer->m_Type == LAYERTYPE_TILES) { @@ -1684,11 +1708,11 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f); - if(IsGameLayer && g_Config.m_ClOverlayEntities) - Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - else if(!IsGameLayer && g_Config.m_ClOverlayEntities && !(m_Type == TYPE_BACKGROUND_FORCE)) - Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*(100-g_Config.m_ClOverlayEntities)/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f); + if(IsGameLayer && EntityOverlayVal) + Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); + else if(!IsGameLayer && EntityOverlayVal && !(m_Type == TYPE_BACKGROUND_FORCE)) + Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * (100 - EntityOverlayVal) / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); @@ -1739,9 +1763,9 @@ void CMapLayers::OnRender() Graphics()->TextureSet(m_pImages->Get(pQLayer->m_Image)); CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(pQLayer->m_Data); - if(m_Type == TYPE_BACKGROUND_FORCE) + if(m_Type == TYPE_BACKGROUND_FORCE || m_Type == TYPE_FULL_DESIGN) { - if(g_Config.m_ClShowQuads) + if(g_Config.m_ClShowQuads || m_Type == TYPE_FULL_DESIGN) { if(!Graphics()->IsQuadBufferingEnabled()) { @@ -1755,7 +1779,8 @@ void CMapLayers::OnRender() RenderQuadLayer(QuadLayerCounter-1, pQLayer, pGroup, true); } } - } else + } + else { if(!Graphics()->IsQuadBufferingEnabled()) { @@ -1771,7 +1796,7 @@ void CMapLayers::OnRender() } } } - else if(Render && g_Config.m_ClOverlayEntities && IsFrontLayer) + else if(Render && EntityOverlayVal && IsFrontLayer) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; Graphics()->TextureSet(m_pImages->GetEntities(MAP_IMAGE_ENTITY_LAYER_TYPE_FRONT)); @@ -1781,7 +1806,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); @@ -1798,7 +1823,7 @@ void CMapLayers::OnRender() } } } - else if(Render && g_Config.m_ClOverlayEntities && IsSwitchLayer) + else if(Render && EntityOverlayVal && IsSwitchLayer) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; Graphics()->TextureSet(m_pImages->GetEntities(MAP_IMAGE_ENTITY_LAYER_TYPE_SWITCH)); @@ -1808,14 +1833,14 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CSwitchTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderSwitchmap(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); Graphics()->BlendNormal(); - RenderTools()->RenderSwitchmap(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); - RenderTools()->RenderSwitchOverlay(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, g_Config.m_ClOverlayEntities/100.0f); + RenderTools()->RenderSwitchmap(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); + RenderTools()->RenderSwitchOverlay(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, EntityOverlayVal / 100.0f); } else { @@ -1831,7 +1856,7 @@ void CMapLayers::OnRender() } } } - else if(Render && g_Config.m_ClOverlayEntities && IsTeleLayer) + else if(Render && EntityOverlayVal && IsTeleLayer) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; Graphics()->TextureSet(m_pImages->GetEntities(MAP_IMAGE_ENTITY_LAYER_TYPE_TELE)); @@ -1841,14 +1866,14 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTeleTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTelemap(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); Graphics()->BlendNormal(); - RenderTools()->RenderTelemap(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); - RenderTools()->RenderTeleOverlay(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, g_Config.m_ClOverlayEntities/100.0f); + RenderTools()->RenderTelemap(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); + RenderTools()->RenderTeleOverlay(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, EntityOverlayVal / 100.0f); } else { @@ -1862,7 +1887,7 @@ void CMapLayers::OnRender() } } } - else if(Render && g_Config.m_ClOverlayEntities && IsSpeedupLayer) + else if(Render && EntityOverlayVal && IsSpeedupLayer) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; Graphics()->TextureSet(m_pImages->GetEntities(MAP_IMAGE_ENTITY_LAYER_TYPE_SPEEDUP)); @@ -1872,14 +1897,14 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CSpeedupTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderSpeedupmap(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); Graphics()->BlendNormal(); - RenderTools()->RenderSpeedupmap(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); - RenderTools()->RenderSpeedupOverlay(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, g_Config.m_ClOverlayEntities/100.0f); + RenderTools()->RenderSpeedupmap(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); + RenderTools()->RenderSpeedupOverlay(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, EntityOverlayVal / 100.0f); } else { @@ -1900,7 +1925,7 @@ void CMapLayers::OnRender() } } } - else if(Render && g_Config.m_ClOverlayEntities && IsTuneLayer) + else if(Render && EntityOverlayVal && IsTuneLayer) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; Graphics()->TextureSet(m_pImages->GetEntities(MAP_IMAGE_ENTITY_LAYER_TYPE_TUNE)); @@ -1910,14 +1935,14 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTuneTile)) { - ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); + ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f); if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTunemap(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); Graphics()->BlendNormal(); - RenderTools()->RenderTunemap(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); - //RenderTools()->RenderTuneOverlay(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, g_Config.m_ClOverlayEntities/100.0f); + RenderTools()->RenderTunemap(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); + //RenderTools()->RenderTuneOverlay(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, EntityOverlayVal/100.0f); } else { @@ -1927,11 +1952,11 @@ void CMapLayers::OnRender() } } } - if(!g_Config.m_GfxNoclip) + if(!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) Graphics()->ClipDisable(); } - if(!g_Config.m_GfxNoclip) + if(!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) Graphics()->ClipDisable(); // reset the screen like it was before diff --git a/src/game/client/components/maplayers.h b/src/game/client/components/maplayers.h index c0b737320..58ae1e6b5 100644 --- a/src/game/client/components/maplayers.h +++ b/src/game/client/components/maplayers.h @@ -19,6 +19,7 @@ typedef unsigned int offset_ptr32; class CMapLayers : public CComponent { friend class CBackground; + friend class CMenuBackground; CLayers *m_pLayers; class CMapImages *m_pImages; @@ -27,6 +28,8 @@ class CMapLayers : public CComponent int m_LastLocalTick; bool m_EnvelopeUpdate; + bool m_OnlineOnly; + void MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, float Zoom = 1.0f); struct STileLayerVisuals @@ -114,18 +117,22 @@ class CMapLayers : public CComponent }; std::vector m_QuadLayerVisuals; - void LayersOfGroupCount(CMapItemGroup* pGroup, int& TileLayerCount, int& QuadLayerCount, bool& PassedGameLayer); + virtual class CCamera *GetCurCamera(); + + void LayersOfGroupCount(CMapItemGroup *pGroup, int &TileLayerCount, int &QuadLayerCount, bool &PassedGameLayer); void RenderTileBorderCornerTiles(int WidthOffsetToOrigin, int HeightOffsetToOrigin, int TileCountWidth, int TileCountHeight, int BufferContainerIndex, float *pColor, offset_ptr_size IndexBufferOffset, float *pOffset, float *pDir); public: enum { - TYPE_BACKGROUND=0, + TYPE_BACKGROUND = 0, TYPE_BACKGROUND_FORCE, TYPE_FOREGROUND, + TYPE_FULL_DESIGN, + TYPE_ALL = -1, }; - CMapLayers(int Type); + CMapLayers(int Type, bool OnlineOnly = true); virtual void OnInit(); virtual void OnRender(); virtual void OnMapLoad(); diff --git a/src/game/client/components/menu_background.cpp b/src/game/client/components/menu_background.cpp new file mode 100644 index 000000000..c748a1ed1 --- /dev/null +++ b/src/game/client/components/menu_background.cpp @@ -0,0 +1,368 @@ +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include "menu_background.h" + +CMenuBackground::CMenuBackground() + : CBackground(CMapLayers::TYPE_FULL_DESIGN, false) +{ + m_RotationCenter = vec2(0.0f, 0.0f); + m_AnimationStartPos = vec2(0.0f, 0.0f); + m_Camera.m_Center = vec2(0.0f, 0.0f); + m_Camera.m_PrevCenter = vec2(0.0f, 0.0f); + m_MenuCenter = vec2(0.0f, 0.0f); + + ResetPositions(); + + m_CurrentPosition = -1; + m_MoveTime = 0.0f; + + m_IsInit = false; +} + +CBackgroundEngineMap *CMenuBackground::CreateBGMap() +{ + return new CMenuMap; +} + +void CMenuBackground::OnInit() +{ + m_IsInit = true; + + m_pImages->m_pClient = GameClient(); + Kernel()->RegisterInterface((CMenuMap *)m_pBackgroundMap); + if(g_Config.m_ClMenuMap[0] != '\0') + LoadMenuBackground(); + + m_Camera.m_pClient = GameClient(); + m_Camera.m_ZoomSet = false; + m_Camera.m_ZoomSmoothingTarget = 0; +} + +void CMenuBackground::ResetPositions() +{ + m_Positions[POS_START] = vec2(500.0f, 500.0f); + m_Positions[POS_INTERNET] = vec2(1000.0f, 1000.0f); + m_Positions[POS_LAN] = vec2(1100.0f, 1000.0f); + m_Positions[POS_DEMOS] = vec2(900.0f, 100.0f); + m_Positions[POS_NEWS] = vec2(500.0f, 750.0f); + m_Positions[POS_FAVORITES] = vec2(1250.0f, 500.0f); + m_Positions[POS_SETTINGS_LANGUAGE] = vec2(500.0f, 1200.0f); + m_Positions[POS_SETTINGS_GENERAL] = vec2(500.0f, 1000.0f); + m_Positions[POS_SETTINGS_PLAYER] = vec2(600.0f, 1000.0f); + m_Positions[POS_SETTINGS_TEE] = vec2(700.0f, 1000.0f); + m_Positions[POS_SETTINGS_HUD] = vec2(200.0f, 1000.0f); + m_Positions[POS_SETTINGS_CONTROLS] = vec2(800.0f, 1000.0f); + m_Positions[POS_SETTINGS_GRAPHICS] = vec2(900.0f, 1000.0f); + m_Positions[POS_SETTINGS_SOUND] = vec2(1000.0f, 1000.0f); + m_Positions[POS_SETTINGS_DDNET] = vec2(1200.0f, 200.0f); + for(int i = 0; i < POS_CUSTOM_NUM; ++i) + m_Positions[POS_CUSTOM0 + i] = vec2(500.0f + (75.0f * (float)i), 1250.0f - (75.0f * (float)i)); +} + +int CMenuBackground::ThemeScan(const char *pName, int IsDir, int DirType, void *pUser) +{ + CMenuBackground *pSelf = (CMenuBackground *)pUser; + const char *pSuffix = str_endswith(pName, ".map"); + if(IsDir || !pSuffix) + return 0; + char aFullName[128]; + char aThemeName[128]; + str_truncate(aFullName, sizeof(aFullName), pName, pSuffix - pName); + + bool IsDay = false; + bool IsNight = false; + if((pSuffix = str_endswith(aFullName, "_day"))) + { + str_truncate(aThemeName, sizeof(aThemeName), pName, pSuffix - aFullName); + IsDay = true; + } + else if((pSuffix = str_endswith(aFullName, "_night"))) + { + str_truncate(aThemeName, sizeof(aThemeName), pName, pSuffix - aFullName); + IsNight = true; + } + else + str_copy(aThemeName, aFullName, sizeof(aThemeName)); + + if(str_comp(aThemeName, "none") == 0 || str_comp(aThemeName, "auto") == 0 || str_comp(aThemeName, "rand") == 0) // "none", "auto" and "rand" reserved, disallowed for maps + return 0; + + // try to edit an existing theme + for(int i = 0; i < (int)pSelf->m_lThemes.size(); i++) + { + if(str_comp(pSelf->m_lThemes[i].m_Name, aThemeName) == 0) + { + if(IsDay) + pSelf->m_lThemes[i].m_HasDay = true; + if(IsNight) + pSelf->m_lThemes[i].m_HasNight = true; + return 0; + } + } + + // make new theme + CTheme Theme(aThemeName, IsDay, IsNight); + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "added theme %s from themes/%s", aThemeName, pName); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); + pSelf->m_lThemes.push_back(Theme); + return 0; +} + +int CMenuBackground::ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser) +{ + CMenuBackground *pSelf = (CMenuBackground *)pUser; + const char *pSuffix = str_endswith(pName, ".png"); + if(IsDir || !pSuffix) + return 0; + + char aThemeName[128]; + str_truncate(aThemeName, sizeof(aThemeName), pName, pSuffix - pName); + + // save icon for an existing theme + for(CTheme &Theme : pSelf->m_lThemes) // bit slow but whatever + { + if(str_comp(Theme.m_Name, aThemeName) == 0 || (!Theme.m_Name[0] && str_comp(aThemeName, "none") == 0)) + { + char aBuf[MAX_PATH_LENGTH]; + str_format(aBuf, sizeof(aBuf), "themes/%s", pName); + CImageInfo Info; + if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType)) + { + str_format(aBuf, sizeof(aBuf), "failed to load theme icon from %s", pName); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); + return 0; + } + str_format(aBuf, sizeof(aBuf), "loaded theme icon %s", pName); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); + + Theme.m_IconTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); + return 0; + } + } + return 0; // no existing theme +} + +void CMenuBackground::LoadMenuBackground(bool HasDayHint, bool HasNightHint) +{ + if(!m_IsInit) + return; + + if(m_Loaded && m_pMap == m_pBackgroundMap) + m_pMap->Unload(); + + m_Loaded = false; + m_pMap = m_pBackgroundMap; + m_pLayers = m_pBackgroundLayers; + m_pImages = m_pBackgroundImages; + + ResetPositions(); + + bool NeedImageLoading = false; + + str_copy(m_aMapName, g_Config.m_ClMenuMap, sizeof(m_aMapName)); + + if(g_Config.m_ClMenuMap[0] != '\0') + { + const char *pMenuMap = g_Config.m_ClMenuMap; + if(str_comp(pMenuMap, "auto") == 0) + { + switch(time_season()) + { + case SEASON_SPRING: + pMenuMap = "heavens"; + break; + case SEASON_SUMMER: + pMenuMap = "jungle"; + break; + case SEASON_AUTUMN: + pMenuMap = "autumn"; + break; + case SEASON_WINTER: + pMenuMap = "winter"; + break; + } + } + else if(str_comp(pMenuMap, "rand") == 0) + { + //make sure to load themes + std::vector &ThemesRef = GetThemes(); + int RandomThemeIndex = rand() % (ThemesRef.size() - PREDEFINED_THEMES_COUNT); + if(RandomThemeIndex + PREDEFINED_THEMES_COUNT < (int)ThemesRef.size()) + pMenuMap = ThemesRef[RandomThemeIndex + PREDEFINED_THEMES_COUNT].m_Name.cstr(); + } + + char aBuf[128]; + + const int HourOfTheDay = time_houroftheday(); + const bool IsDaytime = HourOfTheDay >= 6 && HourOfTheDay < 18; + + if(!m_Loaded && ((HasDayHint && IsDaytime) || (HasNightHint && !IsDaytime))) + { + str_format(aBuf, sizeof(aBuf), "themes/%s_%s.map", pMenuMap, IsDaytime ? "day" : "night"); + if(m_pMap->Load(aBuf)) + { + m_Loaded = true; + } + } + + if(!m_Loaded) + { + str_format(aBuf, sizeof(aBuf), "themes/%s.map", pMenuMap); + if(m_pMap->Load(aBuf)) + { + m_Loaded = true; + } + } + + if(!m_Loaded && ((HasDayHint && !IsDaytime) || (HasNightHint && IsDaytime))) + { + str_format(aBuf, sizeof(aBuf), "themes/%s_%s.map", pMenuMap, IsDaytime ? "night" : "day"); + if(m_pMap->Load(aBuf)) + { + m_Loaded = true; + } + } + + if(m_Loaded) + { + m_pLayers->InitBackground(m_pMap); + RenderTools()->RenderTilemapGenerateSkip(m_pLayers); + NeedImageLoading = true; + + CMapLayers::OnMapLoad(); + if(NeedImageLoading) + m_pImages->LoadBackground(m_pLayers, m_pMap); + + // look for custom positions + CMapItemLayerTilemap *pTLayer = m_pLayers->GameLayer(); + if(pTLayer) + { + int DataIndex = pTLayer->m_Data; + unsigned int Size = m_pLayers->Map()->GetDataSize(DataIndex); + void *pTiles = m_pLayers->Map()->GetData(DataIndex); + unsigned int TileSize = sizeof(CTile); + + if(Size >= pTLayer->m_Width * pTLayer->m_Height * TileSize) + { + int x = 0; + int y = 0; + for(y = 0; y < pTLayer->m_Height; ++y) + { + for(x = 0; x < pTLayer->m_Width; ++x) + { + unsigned char Index = ((CTile *)pTiles)[y * pTLayer->m_Width + x].m_Index; + if(Index >= TILE_CHECKPOINT_FIRST && Index <= TILE_CHECKPOINT_LAST) + { + int ArrayIndex = clamp((Index - TILE_CHECKPOINT_FIRST), 0, NUM_POS); + m_Positions[ArrayIndex] = vec2(x * 32.0f + 16.0f, y * 32.0f + 16.0f); + } + + x += ((CTile *)pTiles)[y * pTLayer->m_Width + x].m_Skip; + } + } + } + } + } + + m_LastLoad = time_get(); + } +} + +void CMenuBackground::OnMapLoad() +{ + return; +} + +void CMenuBackground::OnRender() +{ + return; +} + +bool CMenuBackground::Render() +{ + if(!m_Loaded) + return false; + + if(Client()->State() >= IClient::STATE_ONLINE) + return false; + + m_Camera.m_Zoom = 0.7f; + static vec2 Dir = vec2(1.0f, 0.0f); + + if(distance(m_Camera.m_Center, m_RotationCenter) <= (float)g_Config.m_ClRotationRadius + 0.5f) + { + // do little rotation + float RotPerTick = 360.0f / (float)g_Config.m_ClRotationSpeed * clamp(Client()->RenderFrameTime(), 0.0f, 0.1f); + Dir = rotate(Dir, RotPerTick); + m_Camera.m_Center = m_RotationCenter + Dir * (float)g_Config.m_ClRotationRadius; + } + else + { + // positions for the animation + Dir = normalize(m_AnimationStartPos - m_RotationCenter); + vec2 TargetPos = m_RotationCenter + Dir * (float)g_Config.m_ClRotationRadius; + float Distance = distance(m_AnimationStartPos, TargetPos); + + // move time + m_MoveTime += clamp(Client()->RenderFrameTime(), 0.0f, 0.1f) * g_Config.m_ClCameraSpeed / 10.0f; + float XVal = 1 - m_MoveTime; + XVal = pow(XVal, 7.0f); + + m_Camera.m_Center = TargetPos + Dir * (XVal * Distance); + } + + CMapLayers::OnRender(); + + return true; +} + +CCamera *CMenuBackground::GetCurCamera() +{ + return &m_Camera; +} + +void CMenuBackground::ChangePosition(int PositionNumber) +{ + if(PositionNumber != m_CurrentPosition) + { + if(PositionNumber >= POS_START && PositionNumber < NUM_POS) + { + m_CurrentPosition = PositionNumber; + } + else + { + m_CurrentPosition = POS_START; + } + } + m_AnimationStartPos = m_Camera.m_Center; + m_RotationCenter = m_Positions[m_CurrentPosition]; + m_MoveTime = 0.0f; +} + +std::vector &CMenuBackground::GetThemes() +{ + if(m_lThemes.size() == 0) // not loaded yet + { + // when adding more here, make sure to change the value of PREDEFINED_THEMES_COUNT too + m_lThemes.push_back(CTheme("", true, true)); // no theme + m_lThemes.push_back(CTheme("auto", true, true)); // auto theme + m_lThemes.push_back(CTheme("rand", true, true)); // random theme + + Storage()->ListDirectory(IStorage::TYPE_ALL, "themes", ThemeScan, (CMenuBackground *)this); + Storage()->ListDirectory(IStorage::TYPE_ALL, "themes", ThemeIconScan, (CMenuBackground *)this); + + std::sort(m_lThemes.begin() + PREDEFINED_THEMES_COUNT, m_lThemes.end()); + } + return m_lThemes; +} diff --git a/src/game/client/components/menu_background.h b/src/game/client/components/menu_background.h new file mode 100644 index 000000000..e94ba8cd3 --- /dev/null +++ b/src/game/client/components/menu_background.h @@ -0,0 +1,110 @@ +#ifndef GAME_CLIENT_COMPONENTS_MENU_BACKGROUND_H +#define GAME_CLIENT_COMPONENTS_MENU_BACKGROUND_H + +#include +#include + +#include + +class CMenuMap : public CBackgroundEngineMap +{ + MACRO_INTERFACE("menu_enginemap", 0) +}; + +// themes +class CTheme +{ +public: + CTheme() {} + CTheme(const char *n, bool HasDay, bool HasNight) + : m_Name(n), m_HasDay(HasDay), m_HasNight(HasNight) {} + + string m_Name; + bool m_HasDay; + bool m_HasNight; + IGraphics::CTextureHandle m_IconTexture; + bool operator<(const CTheme &Other) const { return m_Name < Other.m_Name; } +}; + +class CMenuBackground : public CBackground +{ +public: + enum + { + POS_START = 0, + POS_INTERNET, + POS_LAN, + POS_DEMOS, + POS_NEWS, + POS_FAVORITES, + POS_SETTINGS_LANGUAGE, + POS_SETTINGS_GENERAL, + POS_SETTINGS_PLAYER, + POS_SETTINGS_TEE, + POS_SETTINGS_HUD, + POS_SETTINGS_CONTROLS, + POS_SETTINGS_GRAPHICS, + POS_SETTINGS_SOUND, + POS_SETTINGS_DDNET, + POS_CUSTOM, + POS_CUSTOM0 = POS_CUSTOM, // ddnet tab + POS_CUSTOM1, // kog tab + POS_CUSTOM2, + POS_CUSTOM3, + POS_CUSTOM4, + POS_CUSTOM5, + POS_CUSTOM6, + POS_CUSTOM7, + POS_CUSTOM8, + POS_CUSTOM9, + + NUM_POS, + + POS_CUSTOM_NUM = (POS_CUSTOM9 - POS_CUSTOM0) + 1, + }; + + enum + { + PREDEFINED_THEMES_COUNT = 3, + }; + + CCamera m_Camera; + + CBackgroundEngineMap *CreateBGMap() override; + + vec2 m_MenuCenter; + vec2 m_RotationCenter; + vec2 m_Positions[NUM_POS]; + int m_CurrentPosition; + vec2 m_AnimationStartPos; + float m_MoveTime; + + bool m_IsInit; + + void ResetPositions(); + + static int ThemeScan(const char *pName, int IsDir, int DirType, void *pUser); + static int ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser); + + std::vector m_lThemes; + +public: + CMenuBackground(); + ~CMenuBackground() override {} + + void OnInit() override; + void OnMapLoad() override; + void OnRender() override; + + void LoadMenuBackground(bool HasDayHint = true, bool HasNightHint = true); + + bool Render(); + + class CCamera *GetCurCamera() override; + + void ChangePosition(int PositionNumber); + + std::vector &GetThemes(); +}; + +#endif diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index b1302ebc7..88ecf7e55 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1,6 +1,8 @@ /* (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 @@ -27,6 +29,7 @@ #include #include +#include #include #include #include @@ -1002,7 +1005,10 @@ void CMenus::RenderLoading() CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); - RenderBackground(); + if(!m_pBackground->Render()) + { + RenderBackground(); + } float w = 700; float h = 200; @@ -1164,7 +1170,10 @@ int CMenus::Render() } else { - RenderBackground(); + if(!m_pBackground->Render()) + { + RenderBackground(); + } ms_ColorTabbarInactive = ms_ColorTabbarInactiveOutgame; ms_ColorTabbarActive = ms_ColorTabbarActiveOutgame; ms_ColorTabbarHover = ms_ColorTabbarHoverOutgame; @@ -1187,7 +1196,10 @@ int CMenus::Render() if(m_Popup == POPUP_NONE) { if(m_ShowStart && Client()->State() == IClient::STATE_OFFLINE) + { + m_pBackground->ChangePosition(CMenuBackground::POS_START); RenderStartMenu(Screen); + } else { Screen.HSplitTop(24.0f, &TabBar, &MainView); @@ -1224,21 +1236,44 @@ int CMenus::Render() RenderSettings(MainView); } else if(m_MenuPage == PAGE_NEWS) + { + m_pBackground->ChangePosition(CMenuBackground::POS_NEWS); RenderNews(MainView); + } else if(m_MenuPage == PAGE_INTERNET) + { + m_pBackground->ChangePosition(CMenuBackground::POS_INTERNET); RenderServerbrowser(MainView); + } else if(m_MenuPage == PAGE_LAN) + { + m_pBackground->ChangePosition(CMenuBackground::POS_LAN); RenderServerbrowser(MainView); + } else if(m_MenuPage == PAGE_DEMOS) + { + m_pBackground->ChangePosition(CMenuBackground::POS_DEMOS); RenderDemoList(MainView); + } else if(m_MenuPage == PAGE_FAVORITES) + { + m_pBackground->ChangePosition(CMenuBackground::POS_FAVORITES); RenderServerbrowser(MainView); + } else if(m_MenuPage == PAGE_DDNET) + { + m_pBackground->ChangePosition(CMenuBackground::POS_CUSTOM0); RenderServerbrowser(MainView); + } else if(m_MenuPage == PAGE_KOG) + { + m_pBackground->ChangePosition(CMenuBackground::POS_CUSTOM0 + 1); RenderServerbrowser(MainView); + } else if(m_MenuPage == PAGE_SETTINGS) + { RenderSettings(MainView); + } // do tab bar RenderMenubar(TabBar); @@ -2013,6 +2048,78 @@ int CMenus::Render() return 0; } +void CMenus::RenderThemeSelection(CUIRect MainView, bool Header) +{ + std::vector &ThemesRef = m_pBackground->GetThemes(); + + int SelectedTheme = -1; + for(int i = 0; i < (int)ThemesRef.size(); i++) + { + if(str_comp(ThemesRef[i].m_Name, g_Config.m_ClMenuMap) == 0) + { + SelectedTheme = i; + break; + } + } + + static int s_ListBox = 0; + static float s_ScrollValue = 0.0f; + UiDoListboxStart(&s_ListBox, &MainView, 26.0f, Localize("Theme"), "", ThemesRef.size(), 1, -1, s_ScrollValue); + + for(int i = 0; i < (int)ThemesRef.size(); i++) + { + CListboxItem Item = UiDoListboxNextItem(&ThemesRef[i].m_Name, i == SelectedTheme); + + CTheme &Theme = ThemesRef[i]; + + if(!Item.m_Visible) + continue; + + CUIRect Icon; + Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Icon, &Item.m_Rect); + + // draw icon if it exists + if(Theme.m_IconTexture != -1) + { + Icon.VMargin(6.0f, &Icon); + Icon.HMargin(3.0f, &Icon); + Graphics()->TextureSet(Theme.m_IconTexture); + Graphics()->QuadsBegin(); + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + IGraphics::CQuadItem QuadItem(Icon.x, Icon.y, Icon.w, Icon.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + } + + char aName[128]; + if(!Theme.m_Name[0]) + str_copy(aName, "(none)", sizeof(aName)); + else if(str_comp(Theme.m_Name, "auto") == 0) + str_copy(aName, "(seasons)", sizeof(aName)); + else if(str_comp(Theme.m_Name, "rand") == 0) + str_copy(aName, "(random)", sizeof(aName)); + else if(Theme.m_HasDay && Theme.m_HasNight) + str_format(aName, sizeof(aName), "%s", Theme.m_Name.cstr()); + else if(Theme.m_HasDay && !Theme.m_HasNight) + str_format(aName, sizeof(aName), "%s (day)", Theme.m_Name.cstr()); + else if(!Theme.m_HasDay && Theme.m_HasNight) + str_format(aName, sizeof(aName), "%s (night)", Theme.m_Name.cstr()); + else // generic + str_format(aName, sizeof(aName), "%s", Theme.m_Name.cstr()); + + UI()->DoLabel(&Item.m_Rect, aName, 16 * ms_FontmodHeight, -1); + } + + bool ItemActive = false; + int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0, &ItemActive); + + if(ItemActive && NewSelected != SelectedTheme) + { + str_format(g_Config.m_ClMenuMap, sizeof(g_Config.m_ClMenuMap), "%s", ThemesRef[NewSelected].m_Name.cstr()); + m_pBackground->LoadMenuBackground(ThemesRef[NewSelected].m_HasDay, ThemesRef[NewSelected].m_HasNight); + } +} + void CMenus::SetActive(bool Active) { if(Active != m_MenuActive) diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 5d3e53660..b2bbe8c60 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -326,6 +326,7 @@ class CMenus : public CComponent // found in menus_settings.cpp void RenderLanguageSelection(CUIRect MainView); + void RenderThemeSelection(CUIRect MainView, bool Header = true); void RenderSettingsGeneral(CUIRect MainView); void RenderSettingsPlayer(CUIRect MainView); void RenderSettingsDummyPlayer(CUIRect MainView); @@ -341,9 +342,13 @@ class CMenus : public CComponent bool CheckHotKey(int Key) const; + class CMenuBackground *m_pBackground; + public: void RenderBackground(); + void SetMenuBackground(class CMenuBackground *pBackground) { m_pBackground = pBackground; } + void UseMouseButtons(bool Use) { m_UseMouseButtons = Use; } static CMenusKeyBinder m_Binder; diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 64eda701a..dab56f1db 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -17,11 +17,12 @@ #include #include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include #include "binds.h" @@ -74,9 +75,8 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView) #endif char aBuf[128]; - CUIRect Label, Button, Left, Right, Game, Client, AutoReconnect; - MainView.HSplitTop(180.0f, &Game, &Client); - Client.HSplitTop(160.0f, &Client, &AutoReconnect); + CUIRect Label, Button, Left, Right, Game, Client; + MainView.HSplitTop(150.0f, &Game, &Client); // game { @@ -178,6 +178,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView) if(DoButton_CheckBox(&g_Config.m_ClAutoDemoRecord, Localize("Automatically record demos"), g_Config.m_ClAutoDemoRecord, &Button)) g_Config.m_ClAutoDemoRecord ^= 1; + Right.HSplitTop(30.0f, 0, &Right); Right.HSplitTop(20.0f, &Button, &Right); if(DoButton_CheckBox(&g_Config.m_ClAutoScreenshot, Localize("Automatically take game over screenshot"), g_Config.m_ClAutoScreenshot, &Button)) g_Config.m_ClAutoScreenshot ^= 1; @@ -217,12 +218,11 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView) else str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Refresh Rate"), "∞"); UI()->DoLabelScaled(&Label, aBuf, 13.0f, -1); - Left.HSplitTop(20.0f, &Button, 0); + Left.HSplitTop(20.0f, &Button, &Left); Button.HMargin(2.0f, &Button); g_Config.m_ClRefreshRate= static_cast(DoScrollbarH(&g_Config.m_ClRefreshRate, &Button, g_Config.m_ClRefreshRate/10000.0f)*10000.0f+0.1f); #if defined(CONF_FAMILY_WINDOWS) - Left.HSplitTop(20.0f, 0, &Left); Left.HSplitTop(20.0f, &Button, &Left); if(DoButton_CheckBox(&g_Config.m_ClShowConsole, Localize("Show console window"), g_Config.m_ClShowConsole, &Button)) { @@ -234,6 +234,9 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView) m_NeedRestartGeneral = s_ClShowConsole != g_Config.m_ClShowConsole; #endif + Left.HSplitTop(20.0f, 0, &Left); + RenderThemeSelection(Left); + // auto statboard screenshot { Right.HSplitTop(20.0f, 0, &Right); // @@ -1398,23 +1401,50 @@ void CMenus::RenderSettings(CUIRect MainView) MainView.Margin(10.0f, &MainView); if(g_Config.m_UiSettingsPage == SETTINGS_LANGUAGE) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_LANGUAGE); RenderLanguageSelection(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_GENERAL) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_GENERAL); RenderSettingsGeneral(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_PLAYER) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_PLAYER); RenderSettingsPlayer(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_TEE) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_TEE); RenderSettingsTee(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_HUD) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_HUD); RenderSettingsHUD(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_CONTROLS) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_CONTROLS); RenderSettingsControls(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_GRAPHICS) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_GRAPHICS); RenderSettingsGraphics(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_SOUND) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_SOUND); RenderSettingsSound(MainView); + } else if(g_Config.m_UiSettingsPage == SETTINGS_DDNET) + { + m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_DDNET); RenderSettingsDDNet(MainView); + } if(m_NeedRestartUpdate) { diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index aedca887a..a5dba6b62 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -50,11 +50,12 @@ #include "components/mapimages.h" #include "components/maplayers.h" #include "components/mapsounds.h" +#include "components/menu_background.h" #include "components/menus.h" #include "components/motd.h" +#include "components/nameplates.h" #include "components/particles.h" #include "components/players.h" -#include "components/nameplates.h" #include "components/scoreboard.h" #include "components/skins.h" #include "components/sounds.h" @@ -101,6 +102,7 @@ static CMapImages gs_MapImages; static CMapLayers gs_MapLayersBackGround(CMapLayers::TYPE_BACKGROUND); static CMapLayers gs_MapLayersForeGround(CMapLayers::TYPE_FOREGROUND); static CBackground gs_BackGround; +static CMenuBackground gs_MenuBackground; static CMapSounds gs_MapSounds; @@ -135,6 +137,7 @@ void CGameClient::OnConsoleInit() #endif // setup pointers + m_pMenuBackground = &::gs_MenuBackground; m_pBinds = &::gs_Binds; m_pGameConsole = &::gs_GameConsole; m_pParticles = &::gs_Particles; @@ -164,6 +167,8 @@ void CGameClient::OnConsoleInit() m_pRaceDemo = &::gs_RaceDemo; m_pGhost = &::gs_Ghost; + m_pMenus->SetMenuBackground(m_pMenuBackground); + gs_NamePlates.SetPlayers(m_pPlayers); // make a list of all the systems, make sure to add them in the correct render order @@ -207,6 +212,8 @@ void CGameClient::OnConsoleInit() m_All.Add(&m_pMenus->m_Binder); m_All.Add(m_pGameConsole); + m_All.Add(m_pMenuBackground); + // build the input stack m_Input.Add(&m_pMenus->m_Binder); // this will take over all input when we want to bind a key m_Input.Add(&m_pBinds->m_SpecialBinds); @@ -272,6 +279,8 @@ void CGameClient::OnConsoleInit() Console()->Chain("cl_dummy", ConchainSpecialDummy, this); Console()->Chain("cl_text_entities_size", ConchainClTextEntitiesSize, this); + Console()->Chain("cl_menu_map", ConchainMenuMap, this); + // m_SuppressEvents = false; } @@ -2536,3 +2545,18 @@ void CGameClient::ConTuneZone(IConsole::IResult *pResult, void *pUserData) if(List >= 0 && List < NUM_TUNEZONES) pSelf->TuningList()[List].Set(pParamName, NewValue); } + +void CGameClient::ConchainMenuMap(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + CGameClient *pSelf = (CGameClient *)pUserData; + if(pResult->NumArguments()) + { + if(str_comp(g_Config.m_ClMenuMap, pResult->GetString(0)) != 0) + { + str_format(g_Config.m_ClMenuMap, sizeof(g_Config.m_ClMenuMap), "%s", pResult->GetString(0)); + pSelf->m_pMenuBackground->LoadMenuBackground(); + } + } + else + pfnCallback(pResult, pCallbackUserData); +} diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index a9d1d4333..447dcdaeb 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -122,6 +122,8 @@ class CGameClient : public IGameClient static void ConTuneZone(IConsole::IResult *pResult, void *pUserData); + static void ConchainMenuMap(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + public: IKernel *Kernel() { return IInterface::Kernel(); } IEngine *Engine() const { return m_pEngine; } @@ -377,6 +379,7 @@ public: void SendKill(int ClientID); // pointers to all systems + class CMenuBackground *m_pMenuBackground; class CGameConsole *m_pGameConsole; class CBinds *m_pBinds; class CParticles *m_pParticles;