diff --git a/CMakeLists.txt b/CMakeLists.txt index b11425b1d..1b1a94fe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1269,6 +1269,7 @@ set(EXPECTED_DATA editor/water.rules editor/winter_main.rules emoticons.png + extras.png file_icons.png fonts/DejaVuSans.ttf fonts/GlowSansJCompressed-Book.otf diff --git a/data/extras.png b/data/extras.png new file mode 100644 index 000000000..f1e2d2205 Binary files /dev/null and b/data/extras.png differ diff --git a/data/hud.png b/data/hud.png index ccf57668e..840f63243 100644 Binary files a/data/hud.png and b/data/hud.png differ diff --git a/datasrc/content.py b/datasrc/content.py index 1a60149a6..473931e1f 100644 --- a/datasrc/content.py +++ b/datasrc/content.py @@ -239,6 +239,7 @@ image_demobuttons2 = Image("demobuttons2", "demo_buttons2.png") image_audio_source = Image("audio_source", "editor/audio_source.png") image_strongweak = Image("strongweak", "strong_weak.png") image_hud = Image("hud", "hud.png") +image_extras = Image("extras", "extras.png") container.images.Add(image_null) container.images.Add(image_game) @@ -258,6 +259,7 @@ container.images.Add(image_demobuttons2) container.images.Add(image_audio_source) container.images.Add(image_strongweak) container.images.Add(image_hud) +container.images.Add(image_extras) container.pickups.Add(Pickup("health")) container.pickups.Add(Pickup("armor")) @@ -280,7 +282,8 @@ set_guiicons = SpriteSet("guiicons", image_guiicons, 12, 2) set_demobuttons2 = SpriteSet("demobuttons2", image_demobuttons2, 4, 1) set_audio_source = SpriteSet("audio_source", image_audio_source, 1, 1) set_strongweak = SpriteSet("strongweak", image_strongweak, 2, 1) -set_hud = SpriteSet("hud", image_hud, 14, 12) +set_hud = SpriteSet("hud", image_hud, 16, 16) +set_extras = SpriteSet("extras", image_extras, 16, 16) container.spritesets.Add(set_particles) container.spritesets.Add(set_game) @@ -295,6 +298,7 @@ container.spritesets.Add(set_demobuttons2) container.spritesets.Add(set_audio_source) container.spritesets.Add(set_strongweak) container.spritesets.Add(set_hud) +container.spritesets.Add(set_extras) container.sprites.Add(Sprite("part_slice", set_particles, 0,0,1,1)) container.sprites.Add(Sprite("part_ball", set_particles, 1,0,1,1)) @@ -462,6 +466,7 @@ container.sprites.Add(Sprite("hud_no_hammer_hit", set_hud, 6,2,2,2)) container.sprites.Add(Sprite("hud_no_shotgun_hit", set_hud, 8,2,2,2)) container.sprites.Add(Sprite("hud_no_grenade_hit", set_hud, 10,2,2,2)) container.sprites.Add(Sprite("hud_no_laser_hit", set_hud, 12,2,2,2)) +container.sprites.Add(Sprite("hud_no_gun_hit", set_hud, 14,2,2,2)) container.sprites.Add(Sprite("hud_deep_frozen", set_hud, 10,4,2,2)) container.sprites.Add(Sprite("hud_live_frozen", set_hud, 12,4,2,2)) container.sprites.Add(Sprite("hud_teleport_grenade", set_hud, 4,4,2,2)) @@ -471,6 +476,9 @@ container.sprites.Add(Sprite("hud_practice_mode", set_hud, 4,6,2,2)) container.sprites.Add(Sprite("hud_dummy_hammer", set_hud, 6,6,2,2)) container.sprites.Add(Sprite("hud_dummy_copy", set_hud, 8,6,2,2)) +container.sprites.Add(Sprite("part_snowflake", set_extras, 0,0,2,2)) + + anim = Animation("base") anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0)) anim.back_foot.frames.Add(AnimKeyframe(0, 0, 10, 0)) diff --git a/datasrc/network.py b/datasrc/network.py index c6c641c57..512549c22 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -10,7 +10,8 @@ GameStateFlags = ["GAMEOVER", "SUDDENDEATH", "PAUSED", "RACETIME"] CharacterFlags = ["SOLO", "JETPACK", "NO_COLLISION", "ENDLESS_HOOK", "ENDLESS_JUMP", "SUPER", "NO_HAMMER_HIT", "NO_SHOTGUN_HIT", "NO_GRENADE_HIT", "NO_LASER_HIT", "NO_HOOK", "TELEGUN_GUN", "TELEGUN_GRENADE", "TELEGUN_LASER", - "WEAPON_HAMMER", "WEAPON_GUN", "WEAPON_SHOTGUN", "WEAPON_GRENADE", "WEAPON_LASER", "WEAPON_NINJA", "NO_MOVEMENTS"] + "WEAPON_HAMMER", "WEAPON_GUN", "WEAPON_SHOTGUN", "WEAPON_GRENADE", "WEAPON_LASER", "WEAPON_NINJA", + "NO_MOVEMENTS"] GameInfoFlags = [ "TIMESCORE", "GAMETYPE_RACE", "GAMETYPE_FASTCAP", "GAMETYPE_FNG", "GAMETYPE_DDRACE", "GAMETYPE_DDNET", "GAMETYPE_BLOCK_WORLDS", @@ -24,7 +25,8 @@ GameInfoFlags = [ # Full, use GameInfoFlags2 for more flags ] GameInfoFlags2 = [ - "ALLOW_X_SKINS", "GAMETYPE_CITY", "GAMETYPE_FDDRACE", "ENTITIES_FDDRACE", + "ALLOW_X_SKINS", "GAMETYPE_CITY", "GAMETYPE_FDDRACE", "ENTITIES_FDDRACE", "HUD_HEALTH_ARMOR", "HUD_AMMO", + "HUD_DDRACE", ] ExPlayerFlags = ["AFK", "PAUSED", "SPEC"] ProjectileFlags = ["CLIENTID_BIT{}".format(i) for i in range(8)] + [ @@ -62,7 +64,7 @@ enum enum { - GAMEINFO_CURVERSION=6, + GAMEINFO_CURVERSION=7, }; ''' diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 52cf187ce..7ffda3d78 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -42,6 +42,7 @@ MACRO_CONFIG_STR(ClAssetGame, cl_asset_game, 50, "default", CFGFLAG_SAVE | CFGFL MACRO_CONFIG_STR(ClAssetEmoticons, cl_asset_emoticons, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for emoticons") MACRO_CONFIG_STR(ClAssetParticles, cl_asset_particles, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for particles") MACRO_CONFIG_STR(ClAssetHud, cl_asset_hud, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for HUD") +MACRO_CONFIG_STR(ClAssetExtras, cl_asset_extras, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for the game graphics that do not come from Teeworlds") MACRO_CONFIG_STR(BrFilterString, br_filter_string, 25, "Novice", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server browser filtering string") MACRO_CONFIG_STR(BrExcludeString, br_exclude_string, 25, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server browser exclusion string") @@ -317,7 +318,8 @@ MACRO_CONFIG_INT(ClRaceSaveGhost, cl_race_save_ghost, 1, 0, 1, CFGFLAG_CLIENT | MACRO_CONFIG_INT(ClDDRaceHud, cl_ddrace_hud, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable DDRace HUD") MACRO_CONFIG_INT(ClDDRaceScoreBoard, cl_ddrace_scoreboard, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable DDRace Scoreboard") -MACRO_CONFIG_INT(ClShowFreezeBars, cl_show_freeze_bars, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show a freeze bar under frozen players to indicate the thaw time") +MACRO_CONFIG_INT(ClShowJumpsIndicator, cl_show_jumps_indicator, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to show in the HUD how many jumps you have and have used") +MACRO_CONFIG_INT(ClShowFreezeBars, cl_show_freeze_bars, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to show a freeze bar under frozen players to indicate the thaw time") MACRO_CONFIG_INT(SvResetPickups, sv_reset_pickups, 0, 0, 1, CFGFLAG_SERVER | CFGFLAG_GAME, "Whether the weapons are reset on passing the start tile or not") MACRO_CONFIG_INT(ClShowOthers, cl_show_others, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show players in other teams (2 to show own team only)") MACRO_CONFIG_INT(ClShowOthersAlpha, cl_show_others_alpha, 40, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show players in other teams (alpha value, 0 invisible, 100 fully visible)") diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h index 859572f32..0777a0569 100644 --- a/src/engine/shared/protocol.h +++ b/src/engine/shared/protocol.h @@ -117,6 +117,7 @@ enum VERSION_DDNET_SWITCH = 15060, VERSION_DDNET_INDEPENDENT_SPECTATORS_TEAM = 16000, VERSION_DDNET_WEAPON_SHIELDS = 16010, + VERSION_DDNET_NEW_HUD = 16020, }; #endif diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index bde6d10d8..bb47d0bb5 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -80,6 +80,7 @@ public: fs_makedir(GetPath(TYPE_SAVE, "assets/game", aPath, sizeof(aPath))); fs_makedir(GetPath(TYPE_SAVE, "assets/particles", aPath, sizeof(aPath))); fs_makedir(GetPath(TYPE_SAVE, "assets/hud", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "assets/extras", aPath, sizeof(aPath))); #if defined(CONF_VIDEORECORDER) fs_makedir(GetPath(TYPE_SAVE, "videos", aPath, sizeof(aPath))); #endif diff --git a/src/game/client/components/damageind.cpp b/src/game/client/components/damageind.cpp index c273d87c1..729e95eed 100644 --- a/src/game/client/components/damageind.cpp +++ b/src/game/client/components/damageind.cpp @@ -47,7 +47,7 @@ void CDamageInd::Create(vec2 Pos, vec2 Dir) void CDamageInd::OnRender() { - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteStars[0]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteStars[0]); static float s_LastLocalTime = LocalTime(); for(int i = 0; i < m_NumItems;) { diff --git a/src/game/client/components/debughud.cpp b/src/game/client/components/debughud.cpp index 71b797b10..be96d96c0 100644 --- a/src/game/client/components/debughud.cpp +++ b/src/game/client/components/debughud.cpp @@ -37,15 +37,15 @@ void CDebugHud::RenderNetCorrections() x = Width - 10.0f; char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "%.2f Bps", Velspeed / 32); + str_format(aBuf, sizeof(aBuf), "%.0f Bps", Velspeed / 32); float w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f); TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f); y += LineHeight; - str_format(aBuf, sizeof(aBuf), "%.2f Bps", VelspeedX / 32 * Ramp); + str_format(aBuf, sizeof(aBuf), "%.0f Bps", VelspeedX / 32 * Ramp); w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f); TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f); y += LineHeight; - str_format(aBuf, sizeof(aBuf), "%.2f Bps", VelspeedY / 32); + str_format(aBuf, sizeof(aBuf), "%.0f Bps", VelspeedY / 32); w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f); TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f); y += LineHeight; diff --git a/src/game/client/components/effects.cpp b/src/game/client/components/effects.cpp index bf8392072..c8c9aa67d 100644 --- a/src/game/client/components/effects.cpp +++ b/src/game/client/components/effects.cpp @@ -19,6 +19,7 @@ inline vec2 RandomDir() { return normalize(vec2(random_float() - 0.5f, random_fl CEffects::CEffects() { + m_Add5hz = false; m_Add50hz = false; m_Add100hz = false; } @@ -57,7 +58,7 @@ void CEffects::ResetDamageIndicator() m_pClient->m_DamageInd.Reset(); } -void CEffects::PowerupShine(vec2 Pos, vec2 size) +void CEffects::PowerupShine(vec2 Pos, vec2 Size) { if(!m_Add50hz) return; @@ -65,7 +66,7 @@ void CEffects::PowerupShine(vec2 Pos, vec2 size) CParticle p; p.SetDefault(); p.m_Spr = SPRITE_PART_SLICE; - p.m_Pos = Pos + vec2((random_float() - 0.5f) * size.x, (random_float() - 0.5f) * size.y); + p.m_Pos = Pos + vec2((random_float() - 0.5f) * Size.x, (random_float() - 0.5f) * Size.y); p.m_Vel = vec2(0, 0); p.m_LifeSpan = 0.5f; p.m_StartSize = 16.0f; @@ -78,6 +79,31 @@ void CEffects::PowerupShine(vec2 Pos, vec2 size) m_pClient->m_Particles.Add(CParticles::GROUP_GENERAL, &p); } +void CEffects::FreezingFlakes(vec2 Pos, vec2 Size) +{ + if(!m_Add5hz) + return; + + CParticle p; + p.SetDefault(); + p.m_Spr = SPRITE_PART_SNOWFLAKE; + p.m_Pos = Pos + vec2((random_float() - 0.5f) * Size.x, (random_float() - 0.5f) * Size.y); + p.m_Vel = vec2(0, 0); + p.m_LifeSpan = 1.5f; + p.m_StartSize = (random_float() + 0.5f) * 16.0f; + p.m_EndSize = p.m_StartSize * 0.5f; + p.m_UseAlphaFading = true; + p.m_StartAlpha = 1.0f; + p.m_EndAlpha = 0.0f; + p.m_Rot = random_float() * pi * 2; + p.m_Rotspeed = pi; + p.m_Gravity = random_float() * 250.0f; + p.m_Friction = 0.9f; + p.m_FlowAffected = 0.0f; + p.m_Collides = false; + m_pClient->m_Particles.Add(CParticles::GROUP_EXTRA, &p); +} + void CEffects::SmokeTrail(vec2 Pos, vec2 Vel, float Alpha, float TimePassed) { if(!m_Add50hz && TimePassed < 0.001f) @@ -255,51 +281,38 @@ void CEffects::HammerHit(vec2 Pos) void CEffects::OnRender() { - static int64_t LastUpdate100hz = 0; - static int64_t LastUpdate50hz = 0; + static int64_t s_LastUpdate100hz = 0; + static int64_t s_LastUpdate50hz = 0; + static int64_t s_LastUpdate5hz = 0; + float Speed = 1.0f; if(Client()->State() == IClient::STATE_DEMOPLAYBACK) - { - const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); + Speed = DemoPlayer()->BaseInfo()->m_Speed; - if(time() - LastUpdate100hz > time_freq() / (100 * pInfo->m_Speed)) - { - m_Add100hz = true; - LastUpdate100hz = time(); - } - else - m_Add100hz = false; - - if(time() - LastUpdate50hz > time_freq() / (100 * pInfo->m_Speed)) - { - m_Add50hz = true; - LastUpdate50hz = time(); - } - else - m_Add50hz = false; - - if(m_Add50hz) - m_pClient->m_Flow.Update(); - - return; - } - - if(time() - LastUpdate100hz > time_freq() / 100) + if(time() - s_LastUpdate100hz > time_freq() / (100 * Speed)) { m_Add100hz = true; - LastUpdate100hz = time(); + s_LastUpdate100hz = time(); } else m_Add100hz = false; - if(time() - LastUpdate50hz > time_freq() / 100) + if(time() - s_LastUpdate50hz > time_freq() / (50 * Speed)) { m_Add50hz = true; - LastUpdate50hz = time(); + s_LastUpdate50hz = time(); } else m_Add50hz = false; + if(time() - s_LastUpdate5hz > time_freq() / (5 * Speed)) + { + m_Add5hz = true; + s_LastUpdate5hz = time(); + } + else + m_Add5hz = false; + if(m_Add50hz) m_pClient->m_Flow.Update(); } diff --git a/src/game/client/components/effects.h b/src/game/client/components/effects.h index df64ce6ea..323aa46b4 100644 --- a/src/game/client/components/effects.h +++ b/src/game/client/components/effects.h @@ -6,6 +6,7 @@ class CEffects : public CComponent { + bool m_Add5hz; bool m_Add50hz; bool m_Add100hz; @@ -26,6 +27,7 @@ public: void PlayerSpawn(vec2 Pos); void PlayerDeath(vec2 Pos, int ClientID); void PowerupShine(vec2 Pos, vec2 Size); + void FreezingFlakes(vec2 Pos, vec2 Size); void Update(); }; diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp index 35d84b730..a457509a1 100644 --- a/src/game/client/components/emoticon.cpp +++ b/src/game/client/components/emoticon.cpp @@ -121,7 +121,7 @@ void CEmoticon::OnRender() float Size = Selected ? 80.0f : 50.0f; - Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[i]); + Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[i]); Graphics()->QuadsSetSubset(0, 0, 1, 1); Graphics()->QuadsBegin(); diff --git a/src/game/client/components/freezebars.cpp b/src/game/client/components/freezebars.cpp index c7bcdcd79..8d70e76ad 100644 --- a/src/game/client/components/freezebars.cpp +++ b/src/game/client/components/freezebars.cpp @@ -10,7 +10,7 @@ void CFreezeBars::RenderFreezeBar(const int ClientID) // pCharacter contains the predicted character for local players or the last snap for players who are spectated CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted; - if(pCharacter->m_FreezeEnd <= 0.0f || pCharacter->m_FreezeTick == 0 || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || pCharacter->m_IsInFreeze) + if(pCharacter->m_FreezeEnd <= 0.0f || pCharacter->m_FreezeTick == 0 || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || (pCharacter->m_IsInFreeze && g_Config.m_ClFreezeBarsAlphaInsideFreeze == 0)) { return; } @@ -27,6 +27,10 @@ void CFreezeBars::RenderFreezeBar(const int ClientID) Position.y += 32; float Alpha = m_pClient->IsOtherTeam(ClientID) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f; + if(pCharacter->m_IsInFreeze) + { + Alpha *= g_Config.m_ClFreezeBarsAlphaInsideFreeze / 100.0f; + } RenderFreezeBarPos(Position.x, Position.y, FreezeBarWidth, FreezeBarHight, FreezeProgress, Alpha); } diff --git a/src/game/client/components/ghost.cpp b/src/game/client/components/ghost.cpp index ef2f134e2..73d77eb51 100644 --- a/src/game/client/components/ghost.cpp +++ b/src/game/client/components/ghost.cpp @@ -26,7 +26,7 @@ void CGhost::GetGhostSkin(CGhostSkin *pSkin, const char *pSkinName, int UseCusto pSkin->m_ColorFeet = ColorFeet; } -void CGhost::GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar) +void CGhost::GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar) { pGhostChar->m_X = pChar->m_X; pGhostChar->m_Y = pChar->m_Y; @@ -34,7 +34,12 @@ void CGhost::GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Charac pGhostChar->m_VelY = 0; pGhostChar->m_Angle = pChar->m_Angle; pGhostChar->m_Direction = pChar->m_Direction; - pGhostChar->m_Weapon = pChar->m_Weapon; + int Weapon = pChar->m_Weapon; + if(pDDnetChar != nullptr && pDDnetChar->m_FreezeEnd != 0) + { + Weapon = WEAPON_NINJA; + } + pGhostChar->m_Weapon = Weapon; pGhostChar->m_HookState = pChar->m_HookState; pGhostChar->m_HookX = pChar->m_HookX; pGhostChar->m_HookY = pChar->m_HookY; @@ -134,7 +139,7 @@ void CGhost::GetPath(char *pBuf, int Size, const char *pPlayerName, int Time) co str_format(pBuf, Size, "%s/%s_%s_%d.%03d_%s.gho", ms_pGhostDir, pMap, aPlayerName, Time / 1000, Time % 1000, aSha256); } -void CGhost::AddInfos(const CNetObj_Character *pChar) +void CGhost::AddInfos(const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar) { int NumTicks = m_CurGhost.m_Path.Size(); @@ -151,7 +156,7 @@ void CGhost::AddInfos(const CNetObj_Character *pChar) } CGhostCharacter GhostChar; - GetGhostCharacter(&GhostChar, pChar); + GetGhostCharacter(&GhostChar, pChar, pDDnetChar); m_CurGhost.m_Path.Add(GhostChar); if(GhostRecorder()->IsRecording()) GhostRecorder()->WriteData(GHOSTDATA_TYPE_CHARACTER, &GhostChar, sizeof(CGhostCharacter)); @@ -279,7 +284,7 @@ void CGhost::OnNewSnapshot() CheckStart(); if(m_Recording) - AddInfos(m_pClient->m_Snap.m_pLocalCharacter); + AddInfos(m_pClient->m_Snap.m_pLocalCharacter, (m_pClient->m_Snap.m_LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData) ? &m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_ExtendedData : nullptr); } // Record m_LastRaceTick for g_Config.m_ClConfirmDisconnect/QuitTime anyway diff --git a/src/game/client/components/ghost.h b/src/game/client/components/ghost.h index 49c09a6fe..a51c5c7bd 100644 --- a/src/game/client/components/ghost.h +++ b/src/game/client/components/ghost.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -124,12 +125,12 @@ private: bool m_RenderingStartedByServer; static void GetGhostSkin(CGhostSkin *pSkin, const char *pSkinName, int UseCustomColor, int ColorBody, int ColorFeet); - static void GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar); + static void GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar); static void GetNetObjCharacter(CNetObj_Character *pChar, const CGhostCharacter *pGhostChar); void GetPath(char *pBuf, int Size, const char *pPlayerName, int Time = -1) const; - void AddInfos(const CNetObj_Character *pChar); + void AddInfos(const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar); int GetSlot() const; void CheckStart(); diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 35e9522e5..bf9f0c93d 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -658,7 +658,7 @@ void CHud::RenderCursor() // render cursor int CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS; Graphics()->SetColor(1.f, 1.f, 1.f, 1.f); - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteWeaponCursors[CurWeapon]); + Graphics()->TextureSet(m_pClient->m_GameSkin.m_aSpriteWeaponCursors[CurWeapon]); Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_CursorOffset[CurWeapon], m_pClient->m_Controls.m_TargetPos[g_Config.m_ClDummy].x, m_pClient->m_Controls.m_TargetPos[g_Config.m_ClDummy].y); } @@ -673,7 +673,7 @@ void CHud::PrepareAmmoHealthAndArmorQuads() { // 0.6 for(int n = 0; n < 10; n++) - Array[n] = IGraphics::CQuadItem(x + n * 12, y + 24, 10, 10); + Array[n] = IGraphics::CQuadItem(x + n * 12, y, 10, 10); m_AmmoOffset[i] = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10); @@ -682,12 +682,12 @@ void CHud::PrepareAmmoHealthAndArmorQuads() { // special case for 0.7 grenade for(int n = 0; n < 10; n++) - Array[n] = IGraphics::CQuadItem(1 + x + n * 12, y + 24, 10, 10); + Array[n] = IGraphics::CQuadItem(1 + x + n * 12, y, 10, 10); } else { for(int n = 0; n < 10; n++) - Array[n] = IGraphics::CQuadItem(x + n * 12, y + 24, 12, 12); + Array[n] = IGraphics::CQuadItem(x + n * 12, y, 12, 12); } Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10); @@ -742,25 +742,39 @@ void CHud::RenderAmmoHealthAndArmor(const CNetObj_Character *pCharacter) bool IsSixupGameSkin = m_pClient->m_GameSkin.IsSixup(); int QuadOffsetSixup = (IsSixupGameSkin ? 10 : 0); - // ammo display - int CurWeapon = pCharacter->m_Weapon % NUM_WEAPONS; - if(m_pClient->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon].IsValid()) + if(GameClient()->m_GameInfo.m_HudAmmo) { - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon]); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AmmoOffset[CurWeapon] + QuadOffsetSixup, minimum(pCharacter->m_AmmoCount, 10)); + // ammo display + float AmmoOffsetY = GameClient()->m_GameInfo.m_HudHealthArmor ? 24 : 0; + int CurWeapon = pCharacter->m_Weapon % NUM_WEAPONS; + if(m_pClient->m_GameSkin.m_aSpriteWeaponProjectiles[CurWeapon].IsValid()) + { + Graphics()->TextureSet(m_pClient->m_GameSkin.m_aSpriteWeaponProjectiles[CurWeapon]); + if(AmmoOffsetY > 0) + { + Graphics()->RenderQuadContainerEx(m_HudQuadContainerIndex, m_AmmoOffset[CurWeapon] + QuadOffsetSixup, minimum(pCharacter->m_AmmoCount, 10), 0, AmmoOffsetY); + } + else + { + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AmmoOffset[CurWeapon] + QuadOffsetSixup, minimum(pCharacter->m_AmmoCount, 10)); + } + } } - // health display - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthFull); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_HealthOffset + QuadOffsetSixup, minimum(pCharacter->m_Health, 10)); - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthEmpty); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_EmptyHealthOffset + QuadOffsetSixup + minimum(pCharacter->m_Health, 10), 10 - minimum(pCharacter->m_Health, 10)); + if(GameClient()->m_GameInfo.m_HudHealthArmor) + { + // health display + Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthFull); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_HealthOffset + QuadOffsetSixup, minimum(pCharacter->m_Health, 10)); + Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthEmpty); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_EmptyHealthOffset + QuadOffsetSixup + minimum(pCharacter->m_Health, 10), 10 - minimum(pCharacter->m_Health, 10)); - // armor display - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorFull); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup, minimum(pCharacter->m_Armor, 10)); - Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorEmpty); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup + minimum(pCharacter->m_Armor, 10), 10 - minimum(pCharacter->m_Armor, 10)); + // armor display + Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorFull); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup, minimum(pCharacter->m_Armor, 10)); + Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorEmpty); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup + minimum(pCharacter->m_Armor, 10), 10 - minimum(pCharacter->m_Armor, 10)); + } } void CHud::PreparePlayerStateQuads() @@ -807,6 +821,7 @@ void CHud::PreparePlayerStateQuads() m_NoCollisionOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); m_NoHookHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); m_NoHammerHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); + m_NoGunHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); m_NoShotgunHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); m_NoGrenadeHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); m_NoLaserHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f); @@ -829,65 +844,80 @@ void CHud::RenderPlayerState(const int ClientID) // pCharacter contains the predicted character for local players or the last snap for players who are spectated CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted; - - int TotalJumpsToDisplay, AvailableJumpsToDisplay; - if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) + int TotalJumpsToDisplay = 0, AvailableJumpsToDisplay = 0; + if(g_Config.m_ClShowJumpsIndicator) { - bool Grounded = false; - if(Collision()->CheckPoint(pCharacter->m_Pos.x + CCharacterCore::PhysicalSize() / 2, - pCharacter->m_Pos.y + CCharacterCore::PhysicalSize() / 2 + 5)) + if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) { - Grounded = true; + bool Grounded = false; + if(Collision()->CheckPoint(pCharacter->m_Pos.x + CCharacterCore::PhysicalSize() / 2, + pCharacter->m_Pos.y + CCharacterCore::PhysicalSize() / 2 + 5)) + { + Grounded = true; + } + if(Collision()->CheckPoint(pCharacter->m_Pos.x - CCharacterCore::PhysicalSize() / 2, + pCharacter->m_Pos.y + CCharacterCore::PhysicalSize() / 2 + 5)) + { + Grounded = true; + } + + int UsedJumps = pCharacter->m_JumpedTotal; + if(pCharacter->m_Jumps > 1) + { + UsedJumps += !Grounded; + } + else if(pCharacter->m_Jumps == 1) + { + // If the player has only one jump, each jump is the last one + UsedJumps = pCharacter->m_Jumped & 2; + } + else if(pCharacter->m_Jumps == -1) + { + // The player has only one ground jump + UsedJumps = !Grounded; + } + + if(pCharacter->m_EndlessJump && UsedJumps >= abs(pCharacter->m_Jumps)) + { + UsedJumps = abs(pCharacter->m_Jumps) - 1; + } + + int UnusedJumps = abs(pCharacter->m_Jumps) - UsedJumps; + if(!(pCharacter->m_Jumped & 2) && UnusedJumps <= 0) + { + // In some edge cases when the player just got another number of jumps, UnusedJumps is not correct + UnusedJumps = 1; + } + TotalJumpsToDisplay = maximum(minimum(abs(pCharacter->m_Jumps), 10), 0); + AvailableJumpsToDisplay = maximum(minimum(UnusedJumps, TotalJumpsToDisplay), 0); } - if(Collision()->CheckPoint(pCharacter->m_Pos.x - CCharacterCore::PhysicalSize() / 2, - pCharacter->m_Pos.y + CCharacterCore::PhysicalSize() / 2 + 5)) + else { - Grounded = true; + TotalJumpsToDisplay = AvailableJumpsToDisplay = abs(m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData.m_Jumps); } - int UsedJumps = pCharacter->m_JumpedTotal; - if(pCharacter->m_Jumps > 1) + // render available and used jumps + int JumpsOffsetY = ((GameClient()->m_GameInfo.m_HudHealthArmor && g_Config.m_ClShowhudHealthAmmo ? 24 : 0) + + (GameClient()->m_GameInfo.m_HudAmmo && g_Config.m_ClShowhudHealthAmmo ? 12 : 0)); + if(JumpsOffsetY > 0) { - UsedJumps += !Grounded; + Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjump); + Graphics()->RenderQuadContainerEx(m_HudQuadContainerIndex, m_AirjumpOffset, AvailableJumpsToDisplay, 0, JumpsOffsetY); + Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjumpEmpty); + Graphics()->RenderQuadContainerEx(m_HudQuadContainerIndex, m_AirjumpEmptyOffset + AvailableJumpsToDisplay, TotalJumpsToDisplay - AvailableJumpsToDisplay, 0, JumpsOffsetY); } - else if(pCharacter->m_Jumps == 1) + else { - // If the player has only one jump, each jump is the last one - UsedJumps = pCharacter->m_Jumped & 2; + Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjump); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpOffset, AvailableJumpsToDisplay); + Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjumpEmpty); + Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpEmptyOffset + AvailableJumpsToDisplay, TotalJumpsToDisplay - AvailableJumpsToDisplay); } - else if(pCharacter->m_Jumps == -1) - { - // The player has only one ground jump - UsedJumps = !Grounded; - } - - if(pCharacter->m_EndlessJump && UsedJumps >= abs(pCharacter->m_Jumps)) - { - UsedJumps = abs(pCharacter->m_Jumps) - 1; - } - - int UnusedJumps = abs(pCharacter->m_Jumps) - UsedJumps; - if(!(pCharacter->m_Jumped & 2) && UnusedJumps <= 0) - { - // In some edge cases when the player just got another number of jumps, UnusedJumps is not correct - UnusedJumps = 1; - } - TotalJumpsToDisplay = maximum(minimum(abs(pCharacter->m_Jumps), 10), 0); - AvailableJumpsToDisplay = maximum(minimum(UnusedJumps, TotalJumpsToDisplay), 0); } - else - { - TotalJumpsToDisplay = AvailableJumpsToDisplay = abs(m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData.m_Jumps); - } - - // render available and used jumps - Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjump); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpOffset, AvailableJumpsToDisplay); - Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjumpEmpty); - Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpEmptyOffset + AvailableJumpsToDisplay, TotalJumpsToDisplay - AvailableJumpsToDisplay); float x = 5 + 12; - float y = 5 + 12; + float y = (5 + 12 + (GameClient()->m_GameInfo.m_HudHealthArmor && g_Config.m_ClShowhudHealthAmmo ? 24 : 0) + + (GameClient()->m_GameInfo.m_HudAmmo && g_Config.m_ClShowhudHealthAmmo ? 12 : 0)); // render weapons if(pCharacter->m_aWeapons[WEAPON_HAMMER].m_Got) @@ -1062,6 +1092,13 @@ void CHud::RenderPlayerState(const int ClientID) Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoHammerHitOffset, x, y); x += 12; } + if((pCharacter->m_NoGrenadeHit && pCharacter->m_HasTelegunGun && pCharacter->m_aWeapons[WEAPON_GUN].m_Got)) + { + HasProhibitedCapabilities = true; + Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoGunHit); + Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoLaserHitOffset, x, y); + x += 12; + } if((pCharacter->m_NoShotgunHit && pCharacter->m_aWeapons[WEAPON_SHOTGUN].m_Got)) { HasProhibitedCapabilities = true; @@ -1266,8 +1303,8 @@ void CHud::RenderDummyActions() return; } // render small dummy actions hud - const float BoxHeight = 27.0f; - const float BoxWidth = 14.0f; + const float BoxHeight = 29.0f; + const float BoxWidth = 16.0f; float StartX = m_Width - BoxWidth; float StartY = 285.0f - BoxHeight - 4; // 4 units distance to the next display; @@ -1289,8 +1326,8 @@ void CHud::RenderDummyActions() Graphics()->QuadsEnd(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); - float y = StartY + 1; - float x = StartX + 1; + float y = StartY + 2; + float x = StartX + 2; Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f); if(g_Config.m_ClDummyHammer) { @@ -1390,17 +1427,21 @@ void CHud::RenderMovementInformation(const int ClientID) DisplaySpeedX *= (m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo.m_RampValue / 1000.0f); } - float Angle = Character->m_Angle / 256.0f; - if(Angle > pi) - { - Angle -= 2.0f * pi; - } + float Angle = 0.0f; if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) { // On DDNet servers the more accurate angle is displayed, calculated from the target coordinates CNetObj_DDNetCharacterDisplayInfo *CharacterDisplayInfo = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo; Angle = atan2f(CharacterDisplayInfo->m_TargetY, CharacterDisplayInfo->m_TargetX); } + else + { + Angle = Character->m_Angle / 256.0f; + } + if(Angle < 0) + { + Angle += 2.0f * pi; + } float DisplayAngle = Angle * 180.0f / pi; char aBuf[128]; @@ -1528,11 +1569,11 @@ void CHud::OnRender() { if(m_pClient->m_Snap.m_pLocalCharacter && !m_pClient->m_Snap.m_SpecInfo.m_Active && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER)) { - if(g_Config.m_ClShowhudHealthAmmo && (!m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData || !g_Config.m_ClDDRaceHud)) + if(g_Config.m_ClShowhudHealthAmmo) { RenderAmmoHealthAndArmor(m_pClient->m_Snap.m_pLocalCharacter); } - if(m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData && g_Config.m_ClDDRaceHud) + if(m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData && g_Config.m_ClDDRaceHud && GameClient()->m_GameInfo.m_HudDDRace) { RenderPlayerState(m_pClient->m_Snap.m_LocalClientID); } @@ -1542,11 +1583,11 @@ void CHud::OnRender() else if(m_pClient->m_Snap.m_SpecInfo.m_Active) { int SpectatorID = m_pClient->m_Snap.m_SpecInfo.m_SpectatorID; - if(SpectatorID != SPEC_FREEVIEW && g_Config.m_ClShowhudHealthAmmo && (!m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData || !g_Config.m_ClDDRaceHud)) + if(SpectatorID != SPEC_FREEVIEW && g_Config.m_ClShowhudHealthAmmo) { RenderAmmoHealthAndArmor(&m_pClient->m_Snap.m_aCharacters[SpectatorID].m_Cur); } - if(SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData && g_Config.m_ClDDRaceHud) + if(SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData && g_Config.m_ClDDRaceHud && GameClient()->m_GameInfo.m_HudDDRace) { RenderPlayerState(SpectatorID); } diff --git a/src/game/client/components/hud.h b/src/game/client/components/hud.h index d28ba3a19..7ae200597 100644 --- a/src/game/client/components/hud.h +++ b/src/game/client/components/hud.h @@ -123,6 +123,7 @@ private: int m_NoCollisionOffset; int m_NoHookHitOffset; int m_NoHammerHitOffset; + int m_NoGunHitOffset; int m_NoShotgunHitOffset; int m_NoGrenadeHitOffset; int m_NoLaserHitOffset; diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp index 39a0d9ea9..142221641 100644 --- a/src/game/client/components/items.cpp +++ b/src/game/client/components/items.cpp @@ -128,9 +128,9 @@ void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemID) Graphics()->QuadsSetRotation(0); } - if(GameClient()->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon].IsValid()) + if(GameClient()->m_GameSkin.m_aSpriteWeaponProjectiles[CurWeapon].IsValid()) { - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeaponProjectiles[CurWeapon]); Graphics()->SetColor(1.f, 1.f, 1.f, Alpha); Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ProjectileOffset[CurWeapon], Pos.x, Pos.y); } @@ -156,7 +156,7 @@ void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCu else if(pCurrent->m_Type == POWERUP_WEAPON) { QuadOffset = m_PickupWeaponOffset[CurWeapon]; - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeapons[CurWeapon]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpritePickupWeapons[CurWeapon]); } else if(pCurrent->m_Type == POWERUP_NINJA) { @@ -168,7 +168,7 @@ void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCu else if(pCurrent->m_Type >= POWERUP_ARMOR_SHOTGUN && pCurrent->m_Type <= POWERUP_ARMOR_LASER) { QuadOffset = m_PickupWeaponArmorOffset[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN]; - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeaponArmor[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpritePickupWeaponArmor[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN]); } Graphics()->QuadsSetRotation(0); Graphics()->SetColor(1.f, 1.f, 1.f, 1.f); @@ -298,7 +298,7 @@ void CItems::RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted) // render head { int CurParticle = (Client()->GameTick(g_Config.m_ClDummy) % 3); - Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticleSplat[CurParticle]); + Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_aSpriteParticleSplat[CurParticle]); Graphics()->QuadsSetRotation(Client()->GameTick(g_Config.m_ClDummy)); Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f); Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ParticleSplatOffset[CurParticle], Pos.x, Pos.y); diff --git a/src/game/client/components/killmessages.cpp b/src/game/client/components/killmessages.cpp index ea9ee499f..990898c3f 100644 --- a/src/game/client/components/killmessages.cpp +++ b/src/game/client/components/killmessages.cpp @@ -254,7 +254,7 @@ void CKillMessages::OnRender() x -= 44.0f; if(m_aKillmsgs[r].m_Weapon >= 0) { - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeapons[m_aKillmsgs[r].m_Weapon]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeapons[m_aKillmsgs[r].m_Weapon]); Graphics()->RenderQuadContainerAsSprite(m_SpriteQuadContainerIndex, 4 + m_aKillmsgs[r].m_Weapon, x, y + 28); } x -= 52.0f; diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 82a88966a..eebc1c85c 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -346,7 +346,7 @@ void CMenus::DoLaserPreview(const CUIRect *pRect, const ColorHSLA LaserOutlineCo Graphics()->BlendNormal(); int SpriteIndex = time_get() % 3; - Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticleSplat[SpriteIndex]); + Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_aSpriteParticleSplat[SpriteIndex]); Graphics()->QuadsBegin(); Graphics()->QuadsSetRotation(time_get()); Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f); @@ -999,6 +999,7 @@ void CMenus::OnInit() Console()->Chain("cl_asset_emoticons", ConchainAssetEmoticons, this); Console()->Chain("cl_asset_particles", ConchainAssetParticles, this); Console()->Chain("cl_asset_hud", ConchainAssetHud, this); + Console()->Chain("cl_asset_extras", ConchainAssetExtras, this); m_TextureBlob = Graphics()->LoadTexture("blob.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 28c1a2458..167552997 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -256,12 +256,17 @@ public: { }; + struct SCustomExtras : public SCustomItem + { + }; + protected: std::vector m_vEntitiesList; std::vector m_vGameList; std::vector m_vEmoticonList; std::vector m_vParticlesList; std::vector m_vHudList; + std::vector m_vExtrasList; bool m_IsInit = false; @@ -272,12 +277,14 @@ protected: static int EmoticonsScan(const char *pName, int IsDir, int DirType, void *pUser); static int ParticlesScan(const char *pName, int IsDir, int DirType, void *pUser); static int HudScan(const char *pName, int IsDir, int DirType, void *pUser); + static int ExtrasScan(const char *pName, int IsDir, int DirType, void *pUser); static void ConchainAssetsEntities(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainAssetGame(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainAssetParticles(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainAssetEmoticons(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainAssetHud(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + static void ConchainAssetExtras(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void ClearCustomItems(int CurTab); diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index 1a7c881a0..8e900949d 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -1041,7 +1041,7 @@ void CMenus::RenderGhost(CUIRect MainView) if(pItem->Active()) { Graphics()->WrapClamp(); - Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[(SPRITE_OOP + 7) - SPRITE_OOP]); + Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[(SPRITE_OOP + 7) - SPRITE_OOP]); Graphics()->QuadsBegin(); IGraphics::CQuadItem QuadItem(Button.x + Button.w / 2, Button.y + Button.h / 2, 20.0f, 20.0f); Graphics()->QuadsDraw(&QuadItem, 1); diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 933a512ed..659d7ab9e 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -2508,6 +2508,7 @@ ColorHSLA CMenus::RenderHSLScrollbars(CUIRect *pRect, unsigned int *pColor, bool void CMenus::RenderSettingsHUD(CUIRect MainView) { + char aBuf[128]; static int s_CurTab = 0; CUIRect TabLabel1, TabLabel2, Column, @@ -2540,10 +2541,9 @@ void CMenus::RenderSettingsHUD(CUIRect MainView) // ***** HUD ***** // DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhud, Localize("Show ingame HUD"), &g_Config.m_ClShowhud, &MainView, LineMargin); - DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClDDRaceHud, Localize("Use DDRace HUD"), &g_Config.m_ClDDRaceHud, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClDDRaceScoreBoard, Localize("Use DDRace Scoreboard"), &g_Config.m_ClDDRaceScoreBoard, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudDummyActions, Localize("Show dummy actions"), &g_Config.m_ClShowhudDummyActions, &MainView, LineMargin); - DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowFreezeBars, Localize("Show freeze bars"), &g_Config.m_ClShowFreezeBars, &MainView, LineMargin); + DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowJumpsIndicator, Localize("Show jump indicator"), &g_Config.m_ClShowJumpsIndicator, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowIDs, Localize("Show client IDs"), &g_Config.m_ClShowIDs, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudPlayerPosition, Localize("Show player position"), &g_Config.m_ClShowhudPlayerPosition, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudPlayerSpeed, Localize("Show player speed"), &g_Config.m_ClShowhudPlayerSpeed, &MainView, LineMargin); @@ -2554,22 +2554,21 @@ void CMenus::RenderSettingsHUD(CUIRect MainView) DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClChatTeamColors, Localize("Show names in chat in team colors"), &g_Config.m_ClChatTeamColors, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowVotesAfterVoting, Localize("Show votes window after voting"), &g_Config.m_ClShowVotesAfterVoting, &MainView, LineMargin); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowKillMessages, Localize("Show kill messages"), &g_Config.m_ClShowKillMessages, &MainView, LineMargin); + DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowFreezeBars, Localize("Show freeze bars"), &g_Config.m_ClShowFreezeBars, &MainView, LineMargin); + { + if(g_Config.m_ClShowFreezeBars) + { + CUIRect Button, Label; + MainView.HSplitTop(2.5f, 0, &MainView); + MainView.HSplitTop(20.0f, &Label, &MainView); + MainView.HSplitTop(20.0f, &Button, &MainView); + str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Opacity of freeze bars inside freeze"), g_Config.m_ClFreezeBarsAlphaInsideFreeze); + UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT); + g_Config.m_ClFreezeBarsAlphaInsideFreeze = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClFreezeBarsAlphaInsideFreeze, &Button, g_Config.m_ClFreezeBarsAlphaInsideFreeze / 100.0f) * 100.0f); + } + } - MainView.HSplitTop(60.0f, 0x0, &MainView); - - // ***** Kill Messages ***** // - - MainView.HSplitTop(30.0f, &Section, &MainView); - UI()->DoLabel(&Section, Localize("Kill Messages"), 20.0f, TEXTALIGN_LEFT); - MainView.VSplitLeft(5.0f, 0x0, &MainView); - - MainView.HSplitTop(10.0f, 0x0, &MainView); - - static int KillMessageNormalColorID; - DoLine_ColorPicker(&KillMessageNormalColorID, 25.0f, 250.0f, 13.0f, 5.0f, &MainView, Localize("Kill Message Normal Color"), &g_Config.m_ClKillMessageNormalColor, ColorRGBA(1.0f, 1.0f, 1.0f), false); - - static int KillMessageHighlightColorID; - DoLine_ColorPicker(&KillMessageHighlightColorID, 25.0f, 250.0f, 13.0f, 5.0f, &MainView, Localize("Kill Message Highlight Color"), &g_Config.m_ClKillMessageHighlightColor, ColorRGBA(1.0f, 1.0f, 1.0f), false); + MainView.HSplitTop(30.0f, 0x0, &MainView); // ***** Laser ***** // @@ -2597,6 +2596,8 @@ void CMenus::RenderSettingsHUD(CUIRect MainView) DoLaserPreview(&Section, LaserOutlineColor, LaserInnerColor); + // ***** Hookline ***** // + MainView.HSplitTop(25.0f, 0x0, &MainView); MainView.HSplitTop(20.0f, &SectionTwo, &MainView); @@ -2636,6 +2637,23 @@ void CMenus::RenderSettingsHUD(CUIRect MainView) MainView.HSplitTop(25.0f, &SectionTwo, &MainView); DoLine_ColorPicker(&HookCollTeeCollResetID, 25.0f, 180.0f, 13.0f, 5.0f, &SectionTwo, Localize("Tee"), &g_Config.m_ClHookCollColorTeeColl, ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f), false); + + // ***** Kill Messages ***** // + + MainView.HSplitTop(25.0f, 0x0, &MainView); + MainView.HSplitTop(20.0f, &Section, &MainView); + UI()->DoLabel(&Section, Localize("Kill Messages"), 20.0f, TEXTALIGN_LEFT); + + MainView.HSplitTop(5.0f, 0x0, &MainView); + MainView.HSplitTop(25.0f, &SectionTwo, &MainView); + + static int KillMessageNormalColorID, KillMessageHighlightColorID; + DoLine_ColorPicker(&KillMessageNormalColorID, 25.0f, 180.0f, 13.0f, 5.0f, &SectionTwo, Localize("Normal Color"), &g_Config.m_ClKillMessageNormalColor, ColorRGBA(1.0f, 1.0f, 1.0f), false); + + MainView.HSplitTop(5.0f, 0x0, &MainView); + MainView.HSplitTop(25.0f, &SectionTwo, &MainView); + + DoLine_ColorPicker(&KillMessageHighlightColorID, 25.0f, 180.0f, 13.0f, 5.0f, &SectionTwo, Localize("Highlight Color"), &g_Config.m_ClKillMessageHighlightColor, ColorRGBA(1.0f, 1.0f, 1.0f), false); } else if(s_CurTab == 1) { // ***** CHAT TAB ***** // @@ -2659,8 +2677,6 @@ void CMenus::RenderSettingsHUD(CUIRect MainView) const float LabelSize = 13.0f; const float LineSpacing = 5.0f; - char aBuf[64]; - int i = 0; static int ResetIDs[24]; diff --git a/src/game/client/components/menus_settings_assets.cpp b/src/game/client/components/menus_settings_assets.cpp index 3b92dccd7..648186726 100644 --- a/src/game/client/components/menus_settings_assets.cpp +++ b/src/game/client/components/menus_settings_assets.cpp @@ -27,7 +27,8 @@ enum ASSETS_TAB_GAME = 1, ASSETS_TAB_EMOTICONS = 2, ASSETS_TAB_PARTICLES = 3, - ASSETS_TAB_HUD = 4 + ASSETS_TAB_HUD = 4, + ASSETS_TAB_EXTRAS = 5 }; void CMenus::LoadEntities(SCustomEntities *pEntitiesItem, void *pUser) @@ -231,13 +232,22 @@ int CMenus::HudScan(const char *pName, int IsDir, int DirType, void *pUser) return AssetScan(pName, IsDir, DirType, pThis->m_vHudList, "hud", pGraphics, pUser); } +int CMenus::ExtrasScan(const char *pName, int IsDir, int DirType, void *pUser) +{ + auto *pRealUser = (SMenuAssetScanUser *)pUser; + auto *pThis = (CMenus *)pRealUser->m_pUser; + IGraphics *pGraphics = pThis->Graphics(); + return AssetScan(pName, IsDir, DirType, pThis->m_vExtrasList, "extras", pGraphics, pUser); +} + static std::vector s_vpSearchEntitiesList; static std::vector s_vpSearchGamesList; static std::vector s_vpSearchEmoticonsList; static std::vector s_vpSearchParticlesList; static std::vector s_vpSearchHudList; +static std::vector s_vpSearchExtrasList; -static const int NumberOfAssetsTabs = 5; +static const int NumberOfAssetsTabs = 6; static bool s_InitCustomList[NumberOfAssetsTabs] = { true, }; @@ -262,6 +272,8 @@ static const CMenus::SCustomItem *GetCustomItem(int CurTab, size_t Index) return s_vpSearchParticlesList[Index]; else if(CurTab == ASSETS_TAB_HUD) return s_vpSearchHudList[Index]; + else if(CurTab == ASSETS_TAB_EXTRAS) + return s_vpSearchExtrasList[Index]; return NULL; } @@ -324,6 +336,13 @@ void CMenus::ClearCustomItems(int CurTab) // reload current hud skin GameClient()->LoadHudSkin(g_Config.m_ClAssetHud); } + else if(CurTab == ASSETS_TAB_EXTRAS) + { + ClearAssetList(m_vExtrasList, Graphics()); + + // reload current DDNet particles skin + GameClient()->LoadExtrasSkin(g_Config.m_ClAssetExtras); + } s_InitCustomList[CurTab] = true; } @@ -365,7 +384,7 @@ int InitSearchList(std::vector &vpSearchList, std::vector void CMenus::RenderSettingsCustom(CUIRect MainView) { - CUIRect Label, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, Page1Tab, Page2Tab, Page3Tab, Page4Tab, Page5Tab, ReloadButton; + CUIRect Label, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, Page1Tab, Page2Tab, Page3Tab, Page4Tab, Page5Tab, Page6Tab, ReloadButton; MainView.HSplitTop(20, &Label, &MainView); float TabsW = Label.w; @@ -373,6 +392,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) Page2Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page2Tab, &Page3Tab); Page3Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page3Tab, &Page4Tab); Page4Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page4Tab, &Page5Tab); + Page5Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page5Tab, &Page6Tab); static int s_aPageTabs[NumberOfAssetsTabs] = {}; @@ -384,8 +404,10 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) s_CurCustomTab = ASSETS_TAB_EMOTICONS; if(DoButton_MenuTab((void *)&s_aPageTabs[3], Localize("Particles"), s_CurCustomTab == ASSETS_TAB_PARTICLES, &Page4Tab, 0, NULL, NULL, NULL, NULL, 4)) s_CurCustomTab = ASSETS_TAB_PARTICLES; - if(DoButton_MenuTab((void *)&s_aPageTabs[4], Localize("HUD"), s_CurCustomTab == ASSETS_TAB_HUD, &Page5Tab, 10, NULL, NULL, NULL, NULL, 4)) + if(DoButton_MenuTab((void *)&s_aPageTabs[4], Localize("HUD"), s_CurCustomTab == ASSETS_TAB_HUD, &Page5Tab, 0, NULL, NULL, NULL, NULL, 4)) s_CurCustomTab = ASSETS_TAB_HUD; + if(DoButton_MenuTab((void *)&s_aPageTabs[5], Localize("Extras"), s_CurCustomTab == ASSETS_TAB_EXTRAS, &Page6Tab, 10, NULL, NULL, NULL, NULL, 4)) + s_CurCustomTab = ASSETS_TAB_EXTRAS; auto LoadStartTime = time_get_nanoseconds(); SMenuAssetScanUser User; @@ -426,6 +448,10 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) { InitAssetList(m_vHudList, "assets/hud", "hud", HudScan, Graphics(), Storage(), &User); } + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + { + InitAssetList(m_vExtrasList, "assets/extras", "extras", ExtrasScan, Graphics(), Storage(), &User); + } MainView.HSplitTop(10.0f, 0, &MainView); @@ -466,6 +492,10 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) { ListSize = InitSearchList(s_vpSearchHudList, m_vHudList); } + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + { + ListSize = InitSearchList(s_vpSearchExtrasList, m_vExtrasList); + } s_InitCustomList[s_CurCustomTab] = false; s_CustomListSize[s_CurCustomTab] = ListSize; } @@ -497,7 +527,10 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) else if(s_CurCustomTab == ASSETS_TAB_HUD) { SearchListSize = s_vpSearchHudList.size(); - TextureHeight = 128; + } + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + { + SearchListSize = s_vpSearchExtrasList.size(); } UiDoListboxStart(&s_InitCustomList[s_CurCustomTab], &CustomList, TextureHeight + 15.0f + 10.0f + Margin, "", "", SearchListSize, CustomList.w / (Margin + TextureWidth), OldSelected, s_ScrollValue, true); @@ -532,6 +565,11 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) if(str_comp(s->m_aName, g_Config.m_ClAssetHud) == 0) OldSelected = i; } + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + { + if(str_comp(s->m_aName, g_Config.m_ClAssetExtras) == 0) + OldSelected = i; + } CListboxItem Item = UiDoListboxNextItem(s, OldSelected >= 0 && (size_t)OldSelected == i); CUIRect ItemRect = Item.m_Rect; @@ -586,6 +624,11 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) str_copy(g_Config.m_ClAssetHud, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetHud)); GameClient()->LoadHudSkin(g_Config.m_ClAssetHud); } + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + { + str_copy(g_Config.m_ClAssetExtras, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetExtras)); + GameClient()->LoadExtrasSkin(g_Config.m_ClAssetExtras); + } } } @@ -639,6 +682,8 @@ void CMenus::RenderSettingsCustom(CUIRect MainView) str_copy(aBufFull, "assets/particles", sizeof(aBufFull)); else if(s_CurCustomTab == ASSETS_TAB_HUD) str_copy(aBufFull, "assets/hud", sizeof(aBufFull)); + else if(s_CurCustomTab == ASSETS_TAB_EXTRAS) + str_copy(aBufFull, "assets/extras", sizeof(aBufFull)); Storage()->GetCompletePath(IStorage::TYPE_SAVE, aBufFull, aBuf, sizeof(aBuf)); Storage()->CreateFolder("assets", IStorage::TYPE_SAVE); Storage()->CreateFolder(aBufFull, IStorage::TYPE_SAVE); @@ -733,3 +778,18 @@ void CMenus::ConchainAssetHud(IConsole::IResult *pResult, void *pUserData, ICons pfnCallback(pResult, pCallbackUserData); } + +void CMenus::ConchainAssetExtras(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + CMenus *pThis = (CMenus *)pUserData; + if(pResult->NumArguments() == 1) + { + const char *pArg = pResult->GetString(0); + if(str_comp(pArg, g_Config.m_ClAssetExtras) != 0) + { + pThis->GameClient()->LoadExtrasSkin(pArg); + } + } + + pfnCallback(pResult, pCallbackUserData); +} \ No newline at end of file diff --git a/src/game/client/components/particles.cpp b/src/game/client/components/particles.cpp index 9a9d5c011..d33b73ef0 100644 --- a/src/game/client/components/particles.cpp +++ b/src/game/client/components/particles.cpp @@ -15,6 +15,7 @@ CParticles::CParticles() OnReset(); m_RenderTrail.m_pParts = this; m_RenderExplosions.m_pParts = this; + m_RenderExtra.m_pParts = this; m_RenderGeneral.m_pParts = this; } @@ -104,7 +105,14 @@ void CParticles::Update(float TimePassed) // move the point vec2 Vel = m_aParticles[i].m_Vel * TimePassed; - Collision()->MovePoint(&m_aParticles[i].m_Pos, &Vel, 0.1f + 0.9f * random_float(), NULL); + if(m_aParticles[i].m_Collides) + { + Collision()->MovePoint(&m_aParticles[i].m_Pos, &Vel, 0.1f + 0.9f * random_float(), NULL); + } + else + { + m_aParticles[i].m_Pos += Vel; + } m_aParticles[i].m_Vel = Vel * (1.0f / TimePassed); m_aParticles[i].m_Life += TimePassed; @@ -172,6 +180,13 @@ void CParticles::OnInit() RenderTools()->QuadContainerAddSprite(m_ParticleQuadContainerIndex, 1.f); } Graphics()->QuadContainerUpload(m_ParticleQuadContainerIndex); + + m_ExtraParticleQuadContainerIndex = Graphics()->CreateQuadContainer(false); + + // TODO: Use a loop similar to the one for m_ParticleQuadContainerIndex if you add more additional particles + Graphics()->QuadsSetSubset(0, 0, 1, 1); + RenderTools()->QuadContainerAddSprite(m_ExtraParticleQuadContainerIndex, 1.f); + Graphics()->QuadContainerUpload(m_ExtraParticleQuadContainerIndex); } bool CParticles::ParticleIsVisibleOnScreen(const vec2 &CurPos, float CurSize) @@ -191,6 +206,16 @@ bool CParticles::ParticleIsVisibleOnScreen(const vec2 &CurPos, float CurSize) void CParticles::RenderGroup(int Group) { + IGraphics::CTextureHandle *aParticles = GameClient()->m_ParticlesSkin.m_aSpriteParticles; + int FirstParticleOffset = SPRITE_PART_SLICE; + int ParticleQuadContainerIndex = m_ParticleQuadContainerIndex; + if(Group == GROUP_EXTRA) + { + aParticles = GameClient()->m_ExtrasSkin.m_aSpriteParticles; + FirstParticleOffset = SPRITE_PART_SNOWFLAKE; + ParticleQuadContainerIndex = m_ExtraParticleQuadContainerIndex; + } + // don't use the buffer methods here, else the old renderer gets many draw calls if(Graphics()->IsQuadContainerBufferingEnabled()) { @@ -206,16 +231,22 @@ void CParticles::RenderGroup(int Group) if(i != -1) { + float Alpha = m_aParticles[i].m_Color.a; + if(m_aParticles[i].m_UseAlphaFading) + { + float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan; + Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a); + } LastColor[0] = m_aParticles[i].m_Color.r; LastColor[1] = m_aParticles[i].m_Color.g; LastColor[2] = m_aParticles[i].m_Color.b; - LastColor[3] = m_aParticles[i].m_Color.a; + LastColor[3] = Alpha; Graphics()->SetColor( m_aParticles[i].m_Color.r, m_aParticles[i].m_Color.g, m_aParticles[i].m_Color.b, - m_aParticles[i].m_Color.a); + Alpha); LastQuadOffset = m_aParticles[i].m_Spr; } @@ -226,14 +257,19 @@ void CParticles::RenderGroup(int Group) float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan; vec2 p = m_aParticles[i].m_Pos; float Size = mix(m_aParticles[i].m_StartSize, m_aParticles[i].m_EndSize, a); + float Alpha = m_aParticles[i].m_Color.a; + if(m_aParticles[i].m_UseAlphaFading) + { + Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a); + } // the current position, respecting the size, is inside the viewport, render it, else ignore if(ParticleIsVisibleOnScreen(p, Size)) { - if((size_t)CurParticleRenderCount == gs_GraphicsMaxParticlesRenderCount || LastColor[0] != m_aParticles[i].m_Color.r || LastColor[1] != m_aParticles[i].m_Color.g || LastColor[2] != m_aParticles[i].m_Color.b || LastColor[3] != m_aParticles[i].m_Color.a || LastQuadOffset != QuadOffset) + if((size_t)CurParticleRenderCount == gs_GraphicsMaxParticlesRenderCount || LastColor[0] != m_aParticles[i].m_Color.r || LastColor[1] != m_aParticles[i].m_Color.g || LastColor[2] != m_aParticles[i].m_Color.b || LastColor[3] != Alpha || LastQuadOffset != QuadOffset) { - Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticles[LastQuadOffset - SPRITE_PART_SLICE]); - Graphics()->RenderQuadContainerAsSpriteMultiple(m_ParticleQuadContainerIndex, LastQuadOffset, CurParticleRenderCount, s_aParticleRenderInfo); + Graphics()->TextureSet(aParticles[LastQuadOffset - FirstParticleOffset]); + Graphics()->RenderQuadContainerAsSpriteMultiple(ParticleQuadContainerIndex, LastQuadOffset - FirstParticleOffset, CurParticleRenderCount, s_aParticleRenderInfo); CurParticleRenderCount = 0; LastQuadOffset = QuadOffset; @@ -241,12 +277,12 @@ void CParticles::RenderGroup(int Group) m_aParticles[i].m_Color.r, m_aParticles[i].m_Color.g, m_aParticles[i].m_Color.b, - m_aParticles[i].m_Color.a); + Alpha); LastColor[0] = m_aParticles[i].m_Color.r; LastColor[1] = m_aParticles[i].m_Color.g; LastColor[2] = m_aParticles[i].m_Color.b; - LastColor[3] = m_aParticles[i].m_Color.a; + LastColor[3] = Alpha; } s_aParticleRenderInfo[CurParticleRenderCount].m_Pos[0] = p.x; @@ -261,8 +297,8 @@ void CParticles::RenderGroup(int Group) i = m_aParticles[i].m_NextPart; } - Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticles[LastQuadOffset - SPRITE_PART_SLICE]); - Graphics()->RenderQuadContainerAsSpriteMultiple(m_ParticleQuadContainerIndex, LastQuadOffset, CurParticleRenderCount, s_aParticleRenderInfo); + Graphics()->TextureSet(aParticles[LastQuadOffset - FirstParticleOffset]); + Graphics()->RenderQuadContainerAsSpriteMultiple(ParticleQuadContainerIndex, LastQuadOffset - FirstParticleOffset, CurParticleRenderCount, s_aParticleRenderInfo); } else { @@ -276,11 +312,16 @@ void CParticles::RenderGroup(int Group) float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan; vec2 p = m_aParticles[i].m_Pos; float Size = mix(m_aParticles[i].m_StartSize, m_aParticles[i].m_EndSize, a); + float Alpha = m_aParticles[i].m_Color.a; + if(m_aParticles[i].m_UseAlphaFading) + { + Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a); + } // the current position, respecting the size, is inside the viewport, render it, else ignore if(ParticleIsVisibleOnScreen(p, Size)) { - Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticles[m_aParticles[i].m_Spr - SPRITE_PART_SLICE]); + Graphics()->TextureSet(aParticles[m_aParticles[i].m_Spr - FirstParticleOffset]); Graphics()->QuadsBegin(); Graphics()->QuadsSetRotation(m_aParticles[i].m_Rot); @@ -289,7 +330,7 @@ void CParticles::RenderGroup(int Group) m_aParticles[i].m_Color.r, m_aParticles[i].m_Color.g, m_aParticles[i].m_Color.b, - m_aParticles[i].m_Color.a); // pow(a, 0.75f) * + Alpha); IGraphics::CQuadItem QuadItem(p.x, p.y, Size, Size); Graphics()->QuadsDraw(&QuadItem, 1); diff --git a/src/game/client/components/particles.h b/src/game/client/components/particles.h index 300816a9a..7b60aeea2 100644 --- a/src/game/client/components/particles.h +++ b/src/game/client/components/particles.h @@ -14,12 +14,16 @@ struct CParticle m_LifeSpan = 0; m_StartSize = 32; m_EndSize = 32; + m_UseAlphaFading = false; + m_StartAlpha = 1; + m_EndAlpha = 1; m_Rot = 0; m_Rotspeed = 0; m_Gravity = 0; m_Friction = 0; m_FlowAffected = 1.0f; m_Color = ColorRGBA(1, 1, 1, 1); + m_Collides = true; } vec2 m_Pos; @@ -34,6 +38,10 @@ struct CParticle float m_StartSize; float m_EndSize; + bool m_UseAlphaFading; + float m_StartAlpha; + float m_EndAlpha; + float m_Rot; float m_Rotspeed; @@ -42,6 +50,8 @@ struct CParticle ColorRGBA m_Color; + bool m_Collides; + // set by the particle system float m_Life; int m_PrevPart; @@ -57,6 +67,7 @@ public: { GROUP_PROJECTILE_TRAIL = 0, GROUP_EXPLOSIONS, + GROUP_EXTRA, GROUP_GENERAL, NUM_GROUPS }; @@ -72,6 +83,7 @@ public: private: int m_ParticleQuadContainerIndex; + int m_ExtraParticleQuadContainerIndex; enum { @@ -96,6 +108,7 @@ private: CRenderGroup m_RenderTrail; CRenderGroup m_RenderExplosions; + CRenderGroup m_RenderExtra; CRenderGroup m_RenderGeneral; bool ParticleIsVisibleOnScreen(const vec2 &CurPos, float CurSize); diff --git a/src/game/client/components/players.cpp b/src/game/client/components/players.cpp index cbdd6f40a..75d43a243 100644 --- a/src/game/client/components/players.cpp +++ b/src/game/client/components/players.cpp @@ -453,205 +453,204 @@ void CPlayers::RenderPlayer( // draw gun { - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); - Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle * pi * 2 + Angle); - - if(ClientID < 0) - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f); - - // normal weapons - int iw = clamp(Player.m_Weapon, 0, NUM_WEAPONS - 1); - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeapons[iw]); - int QuadOffset = iw * 2 + (Direction.x < 0 ? 1 : 0); - - Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha); - - vec2 Dir = Direction; - float Recoil = 0.0f; - vec2 p; - if(Player.m_Weapon == WEAPON_HAMMER) + if(!(RenderInfo.m_TeeRenderFlags & TEE_NO_WEAPON)) { - // Static position for hammer - p = Position + vec2(State.GetAttach()->m_X, State.GetAttach()->m_Y); - p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; - // if attack is under way, bash stuffs - if(Direction.x < 0) - { - Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2); - p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx; - } - else - { - Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2); - } - Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y); - } - else if(Player.m_Weapon == WEAPON_NINJA) - { - p = Position; - p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle * pi * 2 + Angle); - if(Direction.x < 0) - { - Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2); - p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx; - m_pClient->m_Effects.PowerupShine(p + vec2(32, 0), vec2(32, 12)); - } - else - { - Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2); - m_pClient->m_Effects.PowerupShine(p - vec2(32, 0), vec2(32, 12)); - } - Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y); + if(ClientID < 0) + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f); - // HADOKEN - if(AttackTime <= 1 / 6.f && g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles) + // normal weapons + int CurrentWeapon = clamp(Player.m_Weapon, 0, NUM_WEAPONS - 1); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeapons[CurrentWeapon]); + int QuadOffset = CurrentWeapon * 2 + (Direction.x < 0 ? 1 : 0); + + Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha); + + vec2 Dir = Direction; + float Recoil = 0.0f; + vec2 WeaponPosition; + if(Player.m_Weapon == WEAPON_HAMMER) { - int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles; - static int s_LastIteX = IteX; - if(Client()->State() == IClient::STATE_DEMOPLAYBACK) + // Static position for hammer + WeaponPosition = Position + vec2(State.GetAttach()->m_X, State.GetAttach()->m_Y); + WeaponPosition.y += g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsety; + // if attack is under way, bash stuffs + if(Direction.x < 0) { - const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); - if(pInfo->m_Paused) - IteX = s_LastIteX; - else - s_LastIteX = IteX; + Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2); + WeaponPosition.x -= g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsetx; } else { - if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED) - IteX = s_LastIteX; - else - s_LastIteX = IteX; - } - if(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX]) - { - if(PredictLocalWeapons) - Dir = vec2(pPlayerChar->m_X, pPlayerChar->m_Y) - vec2(pPrevChar->m_X, pPrevChar->m_Y); - else - Dir = vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_Y) - vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_Y); - float HadOkenAngle = 0; - if(absolute(Dir.x) > 0.0001f || absolute(Dir.y) > 0.0001f) - { - Dir = normalize(Dir); - HadOkenAngle = angle(Dir); - } - else - { - Dir = vec2(1, 0); - } - Graphics()->QuadsSetRotation(HadOkenAngle); - QuadOffset = IteX * 2; - vec2 DirY(-Dir.y, Dir.x); - p = Position; - float OffsetX = g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx; - p -= Dir * OffsetX; - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[iw][IteX]); - Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[iw], QuadOffset, p.x, p.y); + Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2); } + Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, WeaponPosition.x, WeaponPosition.y); } - } - else - { - // TODO: should be an animation - Recoil = 0; - float a = AttackTicksPassed / 5.0f; - if(a < 1) - Recoil = sinf(a * pi); - p = Position + Dir * g_pData->m_Weapons.m_aId[iw].m_Offsetx - Dir * Recoil * 10.0f; - p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; - if(Player.m_Weapon == WEAPON_GUN && g_Config.m_ClOldGunPosition) - p.y -= 8; - Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y); - } + else if(Player.m_Weapon == WEAPON_NINJA) + { + WeaponPosition = Position; + WeaponPosition.y += g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsety; - if(RenderInfo.m_ShineDecoration) - { - if(Direction.x < 0) - { - m_pClient->m_Effects.PowerupShine(p + vec2(32, 0), vec2(32, 12)); - } - else - { - m_pClient->m_Effects.PowerupShine(p - vec2(32, 0), vec2(32, 12)); - } - } - - if(Player.m_Weapon == WEAPON_GUN || Player.m_Weapon == WEAPON_SHOTGUN) - { - // check if we're firing stuff - if(g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles) //prev.attackticks) - { - float AlphaMuzzle = 0.0f; - if(AttackTicksPassed < g_pData->m_Weapons.m_aId[iw].m_Muzzleduration + 3) + if(Direction.x < 0) { - float t = AttackTicksPassed / g_pData->m_Weapons.m_aId[iw].m_Muzzleduration; - AlphaMuzzle = mix(2.0f, 0.0f, minimum(1.0f, maximum(0.0f, t))); - } - - int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles; - static int s_LastIteX = IteX; - if(Client()->State() == IClient::STATE_DEMOPLAYBACK) - { - const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); - if(pInfo->m_Paused) - IteX = s_LastIteX; - else - s_LastIteX = IteX; + Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2); + WeaponPosition.x -= g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsetx; + m_pClient->m_Effects.PowerupShine(WeaponPosition + vec2(32, 0), vec2(32, 12)); } else { - if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED) - IteX = s_LastIteX; - else - s_LastIteX = IteX; + Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2); + m_pClient->m_Effects.PowerupShine(WeaponPosition - vec2(32, 0), vec2(32, 12)); } - if(AlphaMuzzle > 0.0f && g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX]) - { - float OffsetY = -g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsety; - QuadOffset = IteX * 2 + (Direction.x < 0 ? 1 : 0); - if(Direction.x < 0) - OffsetY = -OffsetY; + Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, WeaponPosition.x, WeaponPosition.y); - vec2 DirY(-Dir.y, Dir.x); - vec2 MuzzlePos = p + Dir * g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx + DirY * OffsetY; - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[iw][IteX]); - Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[iw], QuadOffset, MuzzlePos.x, MuzzlePos.y); + // HADOKEN + if(AttackTime <= 1 / 6.f && g_pData->m_Weapons.m_aId[CurrentWeapon].m_NumSpriteMuzzles) + { + int IteX = rand() % g_pData->m_Weapons.m_aId[CurrentWeapon].m_NumSpriteMuzzles; + static int s_LastIteX = IteX; + if(Client()->State() == IClient::STATE_DEMOPLAYBACK) + { + const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); + if(pInfo->m_Paused) + IteX = s_LastIteX; + else + s_LastIteX = IteX; + } + else + { + if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED) + IteX = s_LastIteX; + else + s_LastIteX = IteX; + } + if(g_pData->m_Weapons.m_aId[CurrentWeapon].m_aSpriteMuzzles[IteX]) + { + if(PredictLocalWeapons) + Dir = vec2(pPlayerChar->m_X, pPlayerChar->m_Y) - vec2(pPrevChar->m_X, pPrevChar->m_Y); + else + Dir = vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_Y) - vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_Y); + float HadOkenAngle = 0; + if(absolute(Dir.x) > 0.0001f || absolute(Dir.y) > 0.0001f) + { + Dir = normalize(Dir); + HadOkenAngle = angle(Dir); + } + else + { + Dir = vec2(1, 0); + } + Graphics()->QuadsSetRotation(HadOkenAngle); + QuadOffset = IteX * 2; + vec2 DirY(-Dir.y, Dir.x); + WeaponPosition = Position; + float OffsetX = g_pData->m_Weapons.m_aId[CurrentWeapon].m_Muzzleoffsetx; + WeaponPosition -= Dir * OffsetX; + Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[CurrentWeapon][IteX]); + Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[CurrentWeapon], QuadOffset, WeaponPosition.x, WeaponPosition.y); + } } } - } - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); - Graphics()->QuadsSetRotation(0); + else + { + // TODO: should be an animation + Recoil = 0; + float a = AttackTicksPassed / 5.0f; + if(a < 1) + Recoil = sinf(a * pi); + WeaponPosition = Position + Dir * g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsetx - Dir * Recoil * 10.0f; + WeaponPosition.y += g_pData->m_Weapons.m_aId[CurrentWeapon].m_Offsety; + if(Player.m_Weapon == WEAPON_GUN && g_Config.m_ClOldGunPosition) + WeaponPosition.y -= 8; + Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, WeaponPosition.x, WeaponPosition.y); + } - switch(Player.m_Weapon) - { - case WEAPON_GUN: RenderHand(&RenderInfo, p, Direction, -3 * pi / 4, vec2(-15, 4), Alpha); break; - case WEAPON_SHOTGUN: RenderHand(&RenderInfo, p, Direction, -pi / 2, vec2(-5, 4), Alpha); break; - case WEAPON_GRENADE: RenderHand(&RenderInfo, p, Direction, -pi / 2, vec2(-4, 7), Alpha); break; + if(Player.m_Weapon == WEAPON_GUN || Player.m_Weapon == WEAPON_SHOTGUN) + { + // check if we're firing stuff + if(g_pData->m_Weapons.m_aId[CurrentWeapon].m_NumSpriteMuzzles) //prev.attackticks) + { + float AlphaMuzzle = 0.0f; + if(AttackTicksPassed < g_pData->m_Weapons.m_aId[CurrentWeapon].m_Muzzleduration + 3) + { + float t = AttackTicksPassed / g_pData->m_Weapons.m_aId[CurrentWeapon].m_Muzzleduration; + AlphaMuzzle = mix(2.0f, 0.0f, minimum(1.0f, maximum(0.0f, t))); + } + + int IteX = rand() % g_pData->m_Weapons.m_aId[CurrentWeapon].m_NumSpriteMuzzles; + static int s_LastIteX = IteX; + if(Client()->State() == IClient::STATE_DEMOPLAYBACK) + { + const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); + if(pInfo->m_Paused) + IteX = s_LastIteX; + else + s_LastIteX = IteX; + } + else + { + if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED) + IteX = s_LastIteX; + else + s_LastIteX = IteX; + } + if(AlphaMuzzle > 0.0f && g_pData->m_Weapons.m_aId[CurrentWeapon].m_aSpriteMuzzles[IteX]) + { + float OffsetY = -g_pData->m_Weapons.m_aId[CurrentWeapon].m_Muzzleoffsety; + QuadOffset = IteX * 2 + (Direction.x < 0 ? 1 : 0); + if(Direction.x < 0) + OffsetY = -OffsetY; + + vec2 DirY(-Dir.y, Dir.x); + vec2 MuzzlePos = WeaponPosition + Dir * g_pData->m_Weapons.m_aId[CurrentWeapon].m_Muzzleoffsetx + DirY * OffsetY; + Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[CurrentWeapon][IteX]); + Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[CurrentWeapon], QuadOffset, MuzzlePos.x, MuzzlePos.y); + } + } + } + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + Graphics()->QuadsSetRotation(0); + + switch(Player.m_Weapon) + { + case WEAPON_GUN: RenderHand(&RenderInfo, WeaponPosition, Direction, -3 * pi / 4, vec2(-15, 4), Alpha); break; + case WEAPON_SHOTGUN: RenderHand(&RenderInfo, WeaponPosition, Direction, -pi / 2, vec2(-5, 4), Alpha); break; + case WEAPON_GRENADE: RenderHand(&RenderInfo, WeaponPosition, Direction, -pi / 2, vec2(-4, 7), Alpha); break; + } } } // render the "shadow" tee if(Local && ((g_Config.m_Debug && g_Config.m_ClUnpredictedShadow >= 0) || g_Config.m_ClUnpredictedShadow == 1)) { - vec2 GhostPosition = Position; + vec2 ShadowPosition = Position; if(ClientID >= 0) - GhostPosition = mix( + ShadowPosition = mix( vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Prev.m_Y), vec2(m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_X, m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur.m_Y), Client()->IntraGameTick(g_Config.m_ClDummy)); - CTeeRenderInfo Ghost = RenderInfo; - RenderTools()->RenderTee(&State, &Ghost, Player.m_Emote, Direction, GhostPosition, 0.5f); // render ghost + CTeeRenderInfo Shadow = RenderInfo; + RenderTools()->RenderTee(&State, &Shadow, Player.m_Emote, Direction, ShadowPosition, 0.5f); // render ghost } RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position, Alpha); + float TeeAnimScale, TeeBaseSize; + RenderTools()->GetRenderTeeAnimScaleAndBaseSize(&State, &RenderInfo, TeeAnimScale, TeeBaseSize); + vec2 BodyPos = Position + vec2(State.GetBody()->m_X, State.GetBody()->m_Y) * TeeAnimScale; + if(RenderInfo.m_TeeRenderFlags & TEE_EFFECT_FROZEN) + { + GameClient()->m_Effects.FreezingFlakes(BodyPos, vec2(32, 32)); + } + int QuadOffsetToEmoticon = NUM_WEAPONS * 2 + 2 + 2; if((Player.m_PlayerFlags & PLAYERFLAG_CHATTING) && !m_pClient->m_aClients[ClientID].m_Afk) { int CurEmoticon = (SPRITE_DOTDOT - SPRITE_OOP); - Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[CurEmoticon]); + Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[CurEmoticon]); int QuadOffset = QuadOffsetToEmoticon + CurEmoticon; Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha); Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x + 24.f, Position.y - 40.f); @@ -666,7 +665,7 @@ void CPlayers::RenderPlayer( if(g_Config.m_ClAfkEmote && m_pClient->m_aClients[ClientID].m_Afk && !(Client()->DummyConnected() && ClientID == m_pClient->m_LocalIDs[!g_Config.m_ClDummy])) { int CurEmoticon = (SPRITE_ZZZ - SPRITE_OOP); - Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[CurEmoticon]); + Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[CurEmoticon]); int QuadOffset = QuadOffsetToEmoticon + CurEmoticon; Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha); Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x + 24.f, Position.y - 40.f); @@ -702,7 +701,7 @@ void CPlayers::RenderPlayer( Graphics()->SetColor(1.0f, 1.0f, 1.0f, a * Alpha); // client_datas::emoticon is an offset from the first emoticon int QuadOffset = QuadOffsetToEmoticon + m_pClient->m_aClients[ClientID].m_Emoticon; - Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[m_pClient->m_aClients[ClientID].m_Emoticon]); + Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[m_pClient->m_aClients[ClientID].m_Emoticon]); Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x, Position.y - 23.f - 32.f * h, 1.f, (64.f * h) / 64.f); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); @@ -727,8 +726,14 @@ void CPlayers::OnRender() for(int i = 0; i < MAX_CLIENTS; ++i) { m_aRenderInfo[i] = m_pClient->m_aClients[i].m_RenderInfo; - m_aRenderInfo[i].m_ShineDecoration = m_pClient->m_aClients[i].m_LiveFrozen; - if(m_pClient->m_Snap.m_aCharacters[i].m_Cur.m_Weapon == WEAPON_NINJA && g_Config.m_ClShowNinja) + m_aRenderInfo[i].m_TeeRenderFlags = 0; + if(m_pClient->m_aClients[i].m_FreezeEnd != 0) + m_aRenderInfo[i].m_TeeRenderFlags |= TEE_EFFECT_FROZEN | TEE_NO_WEAPON; + if(m_pClient->m_aClients[i].m_LiveFrozen) + m_aRenderInfo[i].m_TeeRenderFlags |= TEE_EFFECT_FROZEN; + + CGameClient::CSnapState::CCharacterInfo &CharacterInfo = m_pClient->m_Snap.m_aCharacters[i]; + if((CharacterInfo.m_Cur.m_Weapon == WEAPON_NINJA || (CharacterInfo.m_HasExtendedData && CharacterInfo.m_ExtendedData.m_FreezeEnd != 0)) && g_Config.m_ClShowNinja) { // change the skin for the player to the ninja int Skin = m_pClient->m_Skins.Find("x_ninja"); diff --git a/src/game/client/components/statboard.cpp b/src/game/client/components/statboard.cpp index 5acbb9fc6..e2d64c5ba 100644 --- a/src/game/client/components/statboard.cpp +++ b/src/game/client/components/statboard.cpp @@ -222,7 +222,7 @@ void CStatboard::RenderGlobalStats() continue; float ScaleX, ScaleY; RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_pSpriteBody, ScaleX, ScaleY); - Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeapons[i]); + Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeapons[i]); Graphics()->QuadsBegin(); if(i == 0) RenderTools()->DrawSprite(x + px, y + 10, g_pData->m_Weapons.m_aId[i].m_VisualSize * 0.8f * ScaleX, g_pData->m_Weapons.m_aId[i].m_VisualSize * 0.8f * ScaleY); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 1ba53650e..1d2560db2 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -124,6 +124,7 @@ void CGameClient::OnConsoleInit() &m_MapLayersForeGround, &m_Particles.m_RenderExplosions, &m_NamePlates, + &m_Particles.m_RenderExtra, &m_Particles.m_RenderGeneral, &m_FreezeBars, &m_DamageInd, @@ -275,6 +276,8 @@ void CGameClient::OnInit() LoadParticlesSkin(g_Config.m_ClAssetParticles); else if(i == IMAGE_HUD) LoadHudSkin(g_Config.m_ClAssetHud); + else if(i == IMAGE_EXTRAS) + LoadExtrasSkin(g_Config.m_ClAssetExtras); else g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); m_Menus.RenderLoading(false); @@ -1032,6 +1035,9 @@ static CGameInfo GetGameInfo(const CNetObj_GameInfoEx *pInfoEx, int InfoExSize, Info.m_DontMaskEntities = !DDNet; Info.m_AllowXSkins = false; Info.m_EntitiesFDDrace = FDDrace; + Info.m_HudHealthArmor = !DDNet; + Info.m_HudAmmo = !DDNet; + Info.m_HudDDRace = DDNet; if(Version >= 0) { @@ -1077,6 +1083,12 @@ static CGameInfo GetGameInfo(const CNetObj_GameInfoEx *pInfoEx, int InfoExSize, { Info.m_EntitiesFDDrace = Flags2 & GAMEINFOFLAG2_ENTITIES_FDDRACE; } + if(Version >= 7) + { + Info.m_HudHealthArmor = Flags2 & GAMEINFOFLAG2_HUD_HEALTH_ARMOR; + Info.m_HudAmmo = Flags2 & GAMEINFOFLAG2_HUD_AMMO; + Info.m_HudDDRace = Flags2 & GAMEINFOFLAG2_HUD_DDRACE; + } return Info; } @@ -2655,7 +2667,7 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponNinjaCursor); Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponLaserCursor); - for(auto &SpriteWeaponCursor : m_GameSkin.m_SpriteWeaponCursors) + for(auto &SpriteWeaponCursor : m_GameSkin.m_aSpriteWeaponCursors) { SpriteWeaponCursor = IGraphics::CTextureHandle(); } @@ -2669,17 +2681,17 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponNinja); Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponLaser); - for(auto &SpriteWeapon : m_GameSkin.m_SpriteWeapons) + for(auto &SpriteWeapon : m_GameSkin.m_aSpriteWeapons) { SpriteWeapon = IGraphics::CTextureHandle(); } - for(auto &SpriteParticle : m_GameSkin.m_SpriteParticles) + for(auto &SpriteParticle : m_GameSkin.m_aSpriteParticles) { Graphics()->UnloadTexture(&SpriteParticle); } - for(auto &SpriteStar : m_GameSkin.m_SpriteStars) + for(auto &SpriteStar : m_GameSkin.m_aSpriteStars) { Graphics()->UnloadTexture(&SpriteStar); } @@ -2691,7 +2703,7 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponNinjaProjectile); Graphics()->UnloadTexture(&m_GameSkin.m_SpriteWeaponLaserProjectile); - for(auto &SpriteWeaponProjectile : m_GameSkin.m_SpriteWeaponProjectiles) + for(auto &SpriteWeaponProjectile : m_GameSkin.m_aSpriteWeaponProjectiles) { SpriteWeaponProjectile = IGraphics::CTextureHandle(); } @@ -2721,12 +2733,12 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_GameSkin.m_SpritePickupGun); Graphics()->UnloadTexture(&m_GameSkin.m_SpritePickupHammer); - for(auto &SpritePickupWeapon : m_GameSkin.m_SpritePickupWeapons) + for(auto &SpritePickupWeapon : m_GameSkin.m_aSpritePickupWeapons) { SpritePickupWeapon = IGraphics::CTextureHandle(); } - for(auto &SpritePickupWeaponArmor : m_GameSkin.m_SpritePickupWeaponArmor) + for(auto &SpritePickupWeaponArmor : m_GameSkin.m_aSpritePickupWeaponArmor) { SpritePickupWeaponArmor = IGraphics::CTextureHandle(); } @@ -2783,12 +2795,12 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) m_GameSkin.m_SpriteWeaponNinjaCursor = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_WEAPON_NINJA_CURSOR]); m_GameSkin.m_SpriteWeaponLaserCursor = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_WEAPON_LASER_CURSOR]); - m_GameSkin.m_SpriteWeaponCursors[0] = m_GameSkin.m_SpriteWeaponHammerCursor; - m_GameSkin.m_SpriteWeaponCursors[1] = m_GameSkin.m_SpriteWeaponGunCursor; - m_GameSkin.m_SpriteWeaponCursors[2] = m_GameSkin.m_SpriteWeaponShotgunCursor; - m_GameSkin.m_SpriteWeaponCursors[3] = m_GameSkin.m_SpriteWeaponGrenadeCursor; - m_GameSkin.m_SpriteWeaponCursors[4] = m_GameSkin.m_SpriteWeaponLaserCursor; - m_GameSkin.m_SpriteWeaponCursors[5] = m_GameSkin.m_SpriteWeaponNinjaCursor; + m_GameSkin.m_aSpriteWeaponCursors[0] = m_GameSkin.m_SpriteWeaponHammerCursor; + m_GameSkin.m_aSpriteWeaponCursors[1] = m_GameSkin.m_SpriteWeaponGunCursor; + m_GameSkin.m_aSpriteWeaponCursors[2] = m_GameSkin.m_SpriteWeaponShotgunCursor; + m_GameSkin.m_aSpriteWeaponCursors[3] = m_GameSkin.m_SpriteWeaponGrenadeCursor; + m_GameSkin.m_aSpriteWeaponCursors[4] = m_GameSkin.m_SpriteWeaponLaserCursor; + m_GameSkin.m_aSpriteWeaponCursors[5] = m_GameSkin.m_SpriteWeaponNinjaCursor; // weapons and hook m_GameSkin.m_SpriteHookChain = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HOOK_CHAIN]); @@ -2800,23 +2812,23 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) m_GameSkin.m_SpriteWeaponNinja = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_WEAPON_NINJA_BODY]); m_GameSkin.m_SpriteWeaponLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_WEAPON_LASER_BODY]); - m_GameSkin.m_SpriteWeapons[0] = m_GameSkin.m_SpriteWeaponHammer; - m_GameSkin.m_SpriteWeapons[1] = m_GameSkin.m_SpriteWeaponGun; - m_GameSkin.m_SpriteWeapons[2] = m_GameSkin.m_SpriteWeaponShotgun; - m_GameSkin.m_SpriteWeapons[3] = m_GameSkin.m_SpriteWeaponGrenade; - m_GameSkin.m_SpriteWeapons[4] = m_GameSkin.m_SpriteWeaponLaser; - m_GameSkin.m_SpriteWeapons[5] = m_GameSkin.m_SpriteWeaponNinja; + m_GameSkin.m_aSpriteWeapons[0] = m_GameSkin.m_SpriteWeaponHammer; + m_GameSkin.m_aSpriteWeapons[1] = m_GameSkin.m_SpriteWeaponGun; + m_GameSkin.m_aSpriteWeapons[2] = m_GameSkin.m_SpriteWeaponShotgun; + m_GameSkin.m_aSpriteWeapons[3] = m_GameSkin.m_SpriteWeaponGrenade; + m_GameSkin.m_aSpriteWeapons[4] = m_GameSkin.m_SpriteWeaponLaser; + m_GameSkin.m_aSpriteWeapons[5] = m_GameSkin.m_SpriteWeaponNinja; // particles for(int i = 0; i < 9; ++i) { - m_GameSkin.m_SpriteParticles[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART1 + i]); + m_GameSkin.m_aSpriteParticles[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART1 + i]); } // stars for(int i = 0; i < 3; ++i) { - m_GameSkin.m_SpriteStars[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_STAR1 + i]); + m_GameSkin.m_aSpriteStars[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_STAR1 + i]); } // projectiles @@ -2830,12 +2842,12 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) m_GameSkin.m_SpriteWeaponLaserProjectile = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_WEAPON_LASER_PROJ]); - m_GameSkin.m_SpriteWeaponProjectiles[0] = m_GameSkin.m_SpriteWeaponHammerProjectile; - m_GameSkin.m_SpriteWeaponProjectiles[1] = m_GameSkin.m_SpriteWeaponGunProjectile; - m_GameSkin.m_SpriteWeaponProjectiles[2] = m_GameSkin.m_SpriteWeaponShotgunProjectile; - m_GameSkin.m_SpriteWeaponProjectiles[3] = m_GameSkin.m_SpriteWeaponGrenadeProjectile; - m_GameSkin.m_SpriteWeaponProjectiles[4] = m_GameSkin.m_SpriteWeaponLaserProjectile; - m_GameSkin.m_SpriteWeaponProjectiles[5] = m_GameSkin.m_SpriteWeaponNinjaProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[0] = m_GameSkin.m_SpriteWeaponHammerProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[1] = m_GameSkin.m_SpriteWeaponGunProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[2] = m_GameSkin.m_SpriteWeaponShotgunProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[3] = m_GameSkin.m_SpriteWeaponGrenadeProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[4] = m_GameSkin.m_SpriteWeaponLaserProjectile; + m_GameSkin.m_aSpriteWeaponProjectiles[5] = m_GameSkin.m_SpriteWeaponNinjaProjectile; // muzzles for(int i = 0; i < 3; ++i) @@ -2863,17 +2875,17 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir) m_GameSkin.m_SpritePickupArmorNinja = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_NINJA]); m_GameSkin.m_SpritePickupArmorLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_LASER]); - m_GameSkin.m_SpritePickupWeapons[0] = m_GameSkin.m_SpritePickupHammer; - m_GameSkin.m_SpritePickupWeapons[1] = m_GameSkin.m_SpritePickupGun; - m_GameSkin.m_SpritePickupWeapons[2] = m_GameSkin.m_SpritePickupShotgun; - m_GameSkin.m_SpritePickupWeapons[3] = m_GameSkin.m_SpritePickupGrenade; - m_GameSkin.m_SpritePickupWeapons[4] = m_GameSkin.m_SpritePickupLaser; - m_GameSkin.m_SpritePickupWeapons[5] = m_GameSkin.m_SpritePickupNinja; + m_GameSkin.m_aSpritePickupWeapons[0] = m_GameSkin.m_SpritePickupHammer; + m_GameSkin.m_aSpritePickupWeapons[1] = m_GameSkin.m_SpritePickupGun; + m_GameSkin.m_aSpritePickupWeapons[2] = m_GameSkin.m_SpritePickupShotgun; + m_GameSkin.m_aSpritePickupWeapons[3] = m_GameSkin.m_SpritePickupGrenade; + m_GameSkin.m_aSpritePickupWeapons[4] = m_GameSkin.m_SpritePickupLaser; + m_GameSkin.m_aSpritePickupWeapons[5] = m_GameSkin.m_SpritePickupNinja; - m_GameSkin.m_SpritePickupWeaponArmor[0] = m_GameSkin.m_SpritePickupArmorShotgun; - m_GameSkin.m_SpritePickupWeaponArmor[1] = m_GameSkin.m_SpritePickupArmorGrenade; - m_GameSkin.m_SpritePickupWeaponArmor[2] = m_GameSkin.m_SpritePickupArmorNinja; - m_GameSkin.m_SpritePickupWeaponArmor[3] = m_GameSkin.m_SpritePickupArmorLaser; + m_GameSkin.m_aSpritePickupWeaponArmor[0] = m_GameSkin.m_SpritePickupArmorShotgun; + m_GameSkin.m_aSpritePickupWeaponArmor[1] = m_GameSkin.m_SpritePickupArmorGrenade; + m_GameSkin.m_aSpritePickupWeaponArmor[2] = m_GameSkin.m_SpritePickupArmorNinja; + m_GameSkin.m_aSpritePickupWeaponArmor[3] = m_GameSkin.m_SpritePickupArmorLaser; // flags m_GameSkin.m_SpriteFlagBlue = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_FLAG_BLUE]); @@ -2901,7 +2913,7 @@ void CGameClient::LoadEmoticonsSkin(const char *pPath, bool AsDir) { if(m_EmoticonsSkinLoaded) { - for(auto &SpriteEmoticon : m_EmoticonsSkin.m_SpriteEmoticons) + for(auto &SpriteEmoticon : m_EmoticonsSkin.m_aSpriteEmoticons) Graphics()->UnloadTexture(&SpriteEmoticon); m_EmoticonsSkinLoaded = false; @@ -2934,7 +2946,7 @@ void CGameClient::LoadEmoticonsSkin(const char *pPath, bool AsDir) else if(PngLoaded && Graphics()->CheckImageDivisibility(aPath, ImgInfo, g_pData->m_aSprites[SPRITE_OOP].m_pSet->m_Gridx, g_pData->m_aSprites[SPRITE_OOP].m_pSet->m_Gridy, true) && Graphics()->IsImageFormatRGBA(aPath, ImgInfo)) { for(int i = 0; i < 16; ++i) - m_EmoticonsSkin.m_SpriteEmoticons[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_OOP + i]); + m_EmoticonsSkin.m_aSpriteEmoticons[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_OOP + i]); m_EmoticonsSkinLoaded = true; Graphics()->FreePNG(&ImgInfo); @@ -2947,7 +2959,7 @@ void CGameClient::LoadParticlesSkin(const char *pPath, bool AsDir) { Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleSlice); Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleBall); - for(auto &SpriteParticleSplat : m_ParticlesSkin.m_SpriteParticleSplat) + for(auto &SpriteParticleSplat : m_ParticlesSkin.m_aSpriteParticleSplat) Graphics()->UnloadTexture(&SpriteParticleSplat); Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleSmoke); Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleShell); @@ -2955,7 +2967,7 @@ void CGameClient::LoadParticlesSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleAirJump); Graphics()->UnloadTexture(&m_ParticlesSkin.m_SpriteParticleHit); - for(auto &SpriteParticle : m_ParticlesSkin.m_SpriteParticles) + for(auto &SpriteParticle : m_ParticlesSkin.m_aSpriteParticles) SpriteParticle = IGraphics::CTextureHandle(); m_ParticlesSkinLoaded = false; @@ -2990,22 +3002,22 @@ void CGameClient::LoadParticlesSkin(const char *pPath, bool AsDir) m_ParticlesSkin.m_SpriteParticleSlice = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SLICE]); m_ParticlesSkin.m_SpriteParticleBall = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_BALL]); for(int i = 0; i < 3; ++i) - m_ParticlesSkin.m_SpriteParticleSplat[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SPLAT01 + i]); + m_ParticlesSkin.m_aSpriteParticleSplat[i] = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SPLAT01 + i]); m_ParticlesSkin.m_SpriteParticleSmoke = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SMOKE]); m_ParticlesSkin.m_SpriteParticleShell = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SHELL]); m_ParticlesSkin.m_SpriteParticleExpl = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_EXPL01]); m_ParticlesSkin.m_SpriteParticleAirJump = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_AIRJUMP]); m_ParticlesSkin.m_SpriteParticleHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_HIT01]); - m_ParticlesSkin.m_SpriteParticles[0] = m_ParticlesSkin.m_SpriteParticleSlice; - m_ParticlesSkin.m_SpriteParticles[1] = m_ParticlesSkin.m_SpriteParticleBall; + m_ParticlesSkin.m_aSpriteParticles[0] = m_ParticlesSkin.m_SpriteParticleSlice; + m_ParticlesSkin.m_aSpriteParticles[1] = m_ParticlesSkin.m_SpriteParticleBall; for(int i = 0; i < 3; ++i) - m_ParticlesSkin.m_SpriteParticles[2 + i] = m_ParticlesSkin.m_SpriteParticleSplat[i]; - m_ParticlesSkin.m_SpriteParticles[5] = m_ParticlesSkin.m_SpriteParticleSmoke; - m_ParticlesSkin.m_SpriteParticles[6] = m_ParticlesSkin.m_SpriteParticleShell; - m_ParticlesSkin.m_SpriteParticles[7] = m_ParticlesSkin.m_SpriteParticleExpl; - m_ParticlesSkin.m_SpriteParticles[8] = m_ParticlesSkin.m_SpriteParticleAirJump; - m_ParticlesSkin.m_SpriteParticles[9] = m_ParticlesSkin.m_SpriteParticleHit; + m_ParticlesSkin.m_aSpriteParticles[2 + i] = m_ParticlesSkin.m_aSpriteParticleSplat[i]; + m_ParticlesSkin.m_aSpriteParticles[5] = m_ParticlesSkin.m_SpriteParticleSmoke; + m_ParticlesSkin.m_aSpriteParticles[6] = m_ParticlesSkin.m_SpriteParticleShell; + m_ParticlesSkin.m_aSpriteParticles[7] = m_ParticlesSkin.m_SpriteParticleExpl; + m_ParticlesSkin.m_aSpriteParticles[8] = m_ParticlesSkin.m_SpriteParticleAirJump; + m_ParticlesSkin.m_aSpriteParticles[9] = m_ParticlesSkin.m_SpriteParticleHit; m_ParticlesSkinLoaded = true; free(ImgInfo.m_pData); @@ -3036,6 +3048,7 @@ void CGameClient::LoadHudSkin(const char *pPath, bool AsDir) Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoShotgunHit); Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoGrenadeHit); Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoLaserHit); + Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoGunHit); Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudDeepFrozen); Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudLiveFrozen); Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudTeleportGrenade); @@ -3093,6 +3106,7 @@ void CGameClient::LoadHudSkin(const char *pPath, bool AsDir) m_HudSkin.m_SpriteHudNoShotgunHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_SHOTGUN_HIT]); m_HudSkin.m_SpriteHudNoGrenadeHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_GRENADE_HIT]); m_HudSkin.m_SpriteHudNoLaserHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_LASER_HIT]); + m_HudSkin.m_SpriteHudNoGunHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_GUN_HIT]); m_HudSkin.m_SpriteHudDeepFrozen = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_DEEP_FROZEN]); m_HudSkin.m_SpriteHudLiveFrozen = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_LIVE_FROZEN]); m_HudSkin.m_SpriteHudTeleportGrenade = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_TELEPORT_GRENADE]); @@ -3107,6 +3121,51 @@ void CGameClient::LoadHudSkin(const char *pPath, bool AsDir) } } +void CGameClient::LoadExtrasSkin(const char *pPath, bool AsDir) +{ + if(m_ExtrasSkinLoaded) + { + Graphics()->UnloadTexture(&m_ExtrasSkin.m_SpriteParticleSnowflake); + + for(auto &SpriteParticle : m_ExtrasSkin.m_aSpriteParticles) + SpriteParticle = IGraphics::CTextureHandle(); + + m_ExtrasSkinLoaded = false; + } + + char aPath[IO_MAX_PATH_LENGTH]; + bool IsDefault = false; + if(str_comp(pPath, "default") == 0) + { + str_format(aPath, sizeof(aPath), "%s", g_pData->m_aImages[IMAGE_EXTRAS].m_pFilename); + IsDefault = true; + } + else + { + if(AsDir) + str_format(aPath, sizeof(aPath), "assets/extras/%s/%s", pPath, g_pData->m_aImages[IMAGE_EXTRAS].m_pFilename); + else + str_format(aPath, sizeof(aPath), "assets/extras/%s.png", pPath); + } + + CImageInfo ImgInfo; + bool PngLoaded = Graphics()->LoadPNG(&ImgInfo, aPath, IStorage::TYPE_ALL); + if(!PngLoaded && !IsDefault) + { + if(AsDir) + LoadExtrasSkin("default"); + else + LoadExtrasSkin(pPath, true); + } + else if(PngLoaded && Graphics()->CheckImageDivisibility(aPath, ImgInfo, g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE].m_pSet->m_Gridx, g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE].m_pSet->m_Gridy, true) && Graphics()->IsImageFormatRGBA(aPath, ImgInfo)) + { + m_ExtrasSkin.m_SpriteParticleSnowflake = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE]); + m_ExtrasSkin.m_aSpriteParticles[0] = m_ExtrasSkin.m_SpriteParticleSnowflake; + m_ExtrasSkinLoaded = true; + free(ImgInfo.m_pData); + } +} + void CGameClient::RefindSkins() { for(auto &Client : m_aClients) diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 9e8036fcb..d3f29637b 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -90,6 +90,10 @@ public: bool m_DontMaskEntities; bool m_AllowXSkins; + + bool m_HudHealthArmor; + bool m_HudAmmo; + bool m_HudDDRace; }; class CSnapEntities @@ -525,6 +529,7 @@ public: void LoadEmoticonsSkin(const char *pPath, bool AsDir = false); void LoadParticlesSkin(const char *pPath, bool AsDir = false); void LoadHudSkin(const char *pPath, bool AsDir = false); + void LoadExtrasSkin(const char *pPath, bool AsDir = false); void RefindSkins(); @@ -544,7 +549,7 @@ public: IGraphics::CTextureHandle m_SpriteWeaponNinjaCursor; IGraphics::CTextureHandle m_SpriteWeaponLaserCursor; - IGraphics::CTextureHandle m_SpriteWeaponCursors[6]; + IGraphics::CTextureHandle m_aSpriteWeaponCursors[6]; // weapons and hook IGraphics::CTextureHandle m_SpriteHookChain; @@ -556,13 +561,13 @@ public: IGraphics::CTextureHandle m_SpriteWeaponNinja; IGraphics::CTextureHandle m_SpriteWeaponLaser; - IGraphics::CTextureHandle m_SpriteWeapons[6]; + IGraphics::CTextureHandle m_aSpriteWeapons[6]; // particles - IGraphics::CTextureHandle m_SpriteParticles[9]; + IGraphics::CTextureHandle m_aSpriteParticles[9]; // stars - IGraphics::CTextureHandle m_SpriteStars[3]; + IGraphics::CTextureHandle m_aSpriteStars[3]; // projectiles IGraphics::CTextureHandle m_SpriteWeaponGunProjectile; @@ -572,7 +577,7 @@ public: IGraphics::CTextureHandle m_SpriteWeaponNinjaProjectile; IGraphics::CTextureHandle m_SpriteWeaponLaserProjectile; - IGraphics::CTextureHandle m_SpriteWeaponProjectiles[6]; + IGraphics::CTextureHandle m_aSpriteWeaponProjectiles[6]; // muzzles IGraphics::CTextureHandle m_SpriteWeaponGunMuzzles[3]; @@ -595,8 +600,8 @@ public: IGraphics::CTextureHandle m_SpritePickupGun; IGraphics::CTextureHandle m_SpritePickupHammer; - IGraphics::CTextureHandle m_SpritePickupWeapons[6]; - IGraphics::CTextureHandle m_SpritePickupWeaponArmor[4]; + IGraphics::CTextureHandle m_aSpritePickupWeapons[6]; + IGraphics::CTextureHandle m_aSpritePickupWeaponArmor[4]; // flags IGraphics::CTextureHandle m_SpriteFlagBlue; @@ -621,13 +626,13 @@ public: { IGraphics::CTextureHandle m_SpriteParticleSlice; IGraphics::CTextureHandle m_SpriteParticleBall; - IGraphics::CTextureHandle m_SpriteParticleSplat[3]; + IGraphics::CTextureHandle m_aSpriteParticleSplat[3]; IGraphics::CTextureHandle m_SpriteParticleSmoke; IGraphics::CTextureHandle m_SpriteParticleShell; IGraphics::CTextureHandle m_SpriteParticleExpl; IGraphics::CTextureHandle m_SpriteParticleAirJump; IGraphics::CTextureHandle m_SpriteParticleHit; - IGraphics::CTextureHandle m_SpriteParticles[10]; + IGraphics::CTextureHandle m_aSpriteParticles[10]; }; SClientParticlesSkin m_ParticlesSkin; @@ -635,7 +640,7 @@ public: struct SClientEmoticonsSkin { - IGraphics::CTextureHandle m_SpriteEmoticons[16]; + IGraphics::CTextureHandle m_aSpriteEmoticons[16]; }; SClientEmoticonsSkin m_EmoticonsSkin; @@ -663,6 +668,7 @@ public: IGraphics::CTextureHandle m_SpriteHudNoShotgunHit; IGraphics::CTextureHandle m_SpriteHudNoGrenadeHit; IGraphics::CTextureHandle m_SpriteHudNoLaserHit; + IGraphics::CTextureHandle m_SpriteHudNoGunHit; IGraphics::CTextureHandle m_SpriteHudDeepFrozen; IGraphics::CTextureHandle m_SpriteHudLiveFrozen; IGraphics::CTextureHandle m_SpriteHudTeleportGrenade; @@ -676,6 +682,15 @@ public: SClientHudSkin m_HudSkin; bool m_HudSkinLoaded; + struct SClientExtrasSkin + { + IGraphics::CTextureHandle m_SpriteParticleSnowflake; + IGraphics::CTextureHandle m_aSpriteParticles[1]; + }; + + SClientExtrasSkin m_ExtrasSkin; + bool m_ExtrasSkinLoaded; + const std::vector &SnapEntities() { return m_vSnapEntities; } private: diff --git a/src/game/client/render.h b/src/game/client/render.h index 3e74a0f65..1ea2b0ff2 100644 --- a/src/game/client/render.h +++ b/src/game/client/render.h @@ -32,7 +32,7 @@ public: m_ColorFeet = ColorRGBA(1, 1, 1); m_Size = 1.0f; m_GotAirJump = 1; - m_ShineDecoration = 0; + m_TeeRenderFlags = 0; }; CSkin::SSkinTextures m_OriginalRenderSkin; @@ -47,7 +47,14 @@ public: ColorRGBA m_ColorFeet; float m_Size; int m_GotAirJump; - int m_ShineDecoration; + int m_TeeRenderFlags; +}; + +// Tee Render Flags +enum +{ + TEE_EFFECT_FROZEN = 1, + TEE_NO_WEAPON = 2, }; // sprite renderings @@ -71,7 +78,6 @@ class CRenderTools int m_TeeQuadContainerIndex; - void GetRenderTeeAnimScaleAndBaseSize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize); void GetRenderTeeBodyScale(float BaseSize, float &BodyScale); void GetRenderTeeFeetScale(float BaseSize, float &FeetScaleWidth, float &FeetScaleHeight); @@ -116,6 +122,7 @@ public: // larger rendering methods void GetRenderTeeBodySize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &BodyOffset, float &Width, float &Height); void GetRenderTeeFeetSize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height); + void GetRenderTeeAnimScaleAndBaseSize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize); // returns the offset to use, to render the tee with @see RenderTee exactly in the mid void GetRenderTeeOffsetToRenderedTee(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid); diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 84691aeaf..6e17a5833 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -207,7 +207,7 @@ void CCharacter::HandleNinja() if(NinjaTime % Server()->TickSpeed() == 0 && NinjaTime / Server()->TickSpeed() <= 5) { - GameServer()->CreateDamageInd(m_Pos, 0, NinjaTime / Server()->TickSpeed(), TeamMask()); + GameServer()->CreateDamageInd(m_Pos, 0, NinjaTime / Server()->TickSpeed(), TeamMask() & GameServer()->ClientsMaskExcludeClientVersionAndHigher(VERSION_DDNET_NEW_HUD)); } m_Armor = clamp(10 - (NinjaTime / 15), 0, 10); @@ -918,6 +918,9 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) //TODO: Move the emote stuff to a function void CCharacter::SnapCharacter(int SnappingClient, int ID) { + int SnappingClientVersion = SnappingClient != SERVER_DEMO_CLIENT ? + GameServer()->GetClientVersion(SnappingClient) : + CLIENT_VERSIONNR; CCharacterCore *pCore; int Tick, Emote = m_EmoteType, Weapon = m_Core.m_ActiveWeapon, AmmoCount = 0, Health = 0, Armor = 0; @@ -938,7 +941,7 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID) if(Emote == EMOTE_NORMAL) Emote = (m_DeepFreeze || m_LiveFreeze) ? EMOTE_PAIN : EMOTE_BLINK; - if(m_DeepFreeze || m_FreezeTime > 0 || m_FreezeTime == -1) + if((m_DeepFreeze || m_FreezeTime > 0 || m_FreezeTime == -1) && SnappingClientVersion < VERSION_DDNET_NEW_HUD) Weapon = WEAPON_NINJA; } @@ -965,7 +968,8 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID) } // change eyes, use ninja graphic and set ammo count if player has ninjajetpack - if(m_pPlayer->m_NinjaJetpack && m_Jetpack && m_Core.m_ActiveWeapon == WEAPON_GUN && !m_DeepFreeze && !(m_FreezeTime > 0 || m_FreezeTime == -1) && !m_Core.m_HasTelegunGun) + if(m_pPlayer->m_NinjaJetpack && m_Jetpack && m_Core.m_ActiveWeapon == WEAPON_GUN && !m_DeepFreeze && + !(m_FreezeTime > 0 || m_FreezeTime == -1) && !m_Core.m_HasTelegunGun) { if(Emote == EMOTE_NORMAL) Emote = EMOTE_HAPPY; @@ -1155,9 +1159,7 @@ void CCharacter::Snap(int SnappingClient) if(m_Core.m_ActiveWeapon == WEAPON_NINJA) pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_NINJA; if(m_Core.m_LiveFrozen) - { pDDNetCharacter->m_Flags |= CHARACTERFLAG_NO_MOVEMENTS; - } pDDNetCharacter->m_FreezeEnd = m_DeepFreeze ? -1 : m_FreezeTime == 0 ? 0 : Server()->Tick() + m_FreezeTime; pDDNetCharacter->m_Jumps = m_Core.m_Jumps; @@ -1444,7 +1446,10 @@ void CCharacter::HandleTiles(int Index) // hit others if(((m_TileIndex == TILE_HIT_DISABLE) || (m_TileFIndex == TILE_HIT_DISABLE)) && m_Hit != (DISABLE_HIT_GRENADE | DISABLE_HIT_HAMMER | DISABLE_HIT_LASER | DISABLE_HIT_SHOTGUN)) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hit others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hit others"); + } m_Hit = DISABLE_HIT_GRENADE | DISABLE_HIT_HAMMER | DISABLE_HIT_LASER | DISABLE_HIT_SHOTGUN; m_Core.m_NoShotgunHit = true; m_Core.m_NoGrenadeHit = true; @@ -1455,7 +1460,10 @@ void CCharacter::HandleTiles(int Index) } else if(((m_TileIndex == TILE_HIT_ENABLE) || (m_TileFIndex == TILE_HIT_ENABLE)) && m_Hit != HIT_ALL) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hit others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hit others"); + } m_Hit = HIT_ALL; m_Core.m_NoShotgunHit = false; m_Core.m_NoGrenadeHit = false; @@ -1468,14 +1476,20 @@ void CCharacter::HandleTiles(int Index) // collide with others if(((m_TileIndex == TILE_NPC_DISABLE) || (m_TileFIndex == TILE_NPC_DISABLE)) && !m_Core.m_NoCollision) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't collide with others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't collide with others"); + } m_Core.m_NoCollision = true; m_NeededFaketuning |= FAKETUNE_NOCOLL; GameServer()->SendTuningParams(m_pPlayer->GetCID(), m_TuneZone); // update tunings } else if(((m_TileIndex == TILE_NPC_ENABLE) || (m_TileFIndex == TILE_NPC_ENABLE)) && m_Core.m_NoCollision) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can collide with others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can collide with others"); + } m_Core.m_NoCollision = false; m_NeededFaketuning &= ~FAKETUNE_NOCOLL; GameServer()->SendTuningParams(m_pPlayer->GetCID(), m_TuneZone); // update tunings @@ -1484,14 +1498,20 @@ void CCharacter::HandleTiles(int Index) // hook others if(((m_TileIndex == TILE_NPH_DISABLE) || (m_TileFIndex == TILE_NPH_DISABLE)) && !m_Core.m_NoHookHit) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hook others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hook others"); + } m_Core.m_NoHookHit = true; m_NeededFaketuning |= FAKETUNE_NOHOOK; GameServer()->SendTuningParams(m_pPlayer->GetCID(), m_TuneZone); // update tunings } else if(((m_TileIndex == TILE_NPH_ENABLE) || (m_TileFIndex == TILE_NPH_ENABLE)) && m_Core.m_NoHookHit) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hook others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hook others"); + } m_Core.m_NoHookHit = false; m_NeededFaketuning &= ~FAKETUNE_NOHOOK; GameServer()->SendTuningParams(m_pPlayer->GetCID(), m_TuneZone); // update tunings @@ -1500,7 +1520,10 @@ void CCharacter::HandleTiles(int Index) // unlimited air jumps if(((m_TileIndex == TILE_UNLIMITED_JUMPS_ENABLE) || (m_TileFIndex == TILE_UNLIMITED_JUMPS_ENABLE)) && !m_SuperJump) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have unlimited air jumps"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have unlimited air jumps"); + } m_SuperJump = true; m_Core.m_EndlessJump = true; if(m_Core.m_Jumps == 0) @@ -1511,7 +1534,10 @@ void CCharacter::HandleTiles(int Index) } else if(((m_TileIndex == TILE_UNLIMITED_JUMPS_DISABLE) || (m_TileFIndex == TILE_UNLIMITED_JUMPS_DISABLE)) && m_SuperJump) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You don't have unlimited air jumps"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You don't have unlimited air jumps"); + } m_SuperJump = false; m_Core.m_EndlessJump = false; if(m_Core.m_Jumps == 0) @@ -1535,13 +1561,19 @@ void CCharacter::HandleTiles(int Index) // jetpack gun if(((m_TileIndex == TILE_JETPACK_ENABLE) || (m_TileFIndex == TILE_JETPACK_ENABLE)) && !m_Jetpack) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have a jetpack gun"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have a jetpack gun"); + } m_Jetpack = true; m_Core.m_Jetpack = true; } else if(((m_TileIndex == TILE_JETPACK_DISABLE) || (m_TileFIndex == TILE_JETPACK_DISABLE)) && m_Jetpack) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You lost your jetpack gun"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You lost your jetpack gun"); + } m_Jetpack = false; m_Core.m_Jetpack = false; } @@ -1562,34 +1594,52 @@ void CCharacter::HandleTiles(int Index) if(((m_TileIndex == TILE_TELE_GUN_ENABLE) || (m_TileFIndex == TILE_TELE_GUN_ENABLE)) && !m_Core.m_HasTelegunGun) { m_Core.m_HasTelegunGun = true; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport gun enabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport gun enabled"); + } } else if(((m_TileIndex == TILE_TELE_GUN_DISABLE) || (m_TileFIndex == TILE_TELE_GUN_DISABLE)) && m_Core.m_HasTelegunGun) { m_Core.m_HasTelegunGun = false; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport gun disabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport gun disabled"); + } } if(((m_TileIndex == TILE_TELE_GRENADE_ENABLE) || (m_TileFIndex == TILE_TELE_GRENADE_ENABLE)) && !m_Core.m_HasTelegunGrenade) { m_Core.m_HasTelegunGrenade = true; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport grenade enabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport grenade enabled"); + } } else if(((m_TileIndex == TILE_TELE_GRENADE_DISABLE) || (m_TileFIndex == TILE_TELE_GRENADE_DISABLE)) && m_Core.m_HasTelegunGrenade) { m_Core.m_HasTelegunGrenade = false; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport grenade disabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport grenade disabled"); + } } if(((m_TileIndex == TILE_TELE_LASER_ENABLE) || (m_TileFIndex == TILE_TELE_LASER_ENABLE)) && !m_Core.m_HasTelegunLaser) { m_Core.m_HasTelegunLaser = true; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport laser enabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport laser enabled"); + } } else if(((m_TileIndex == TILE_TELE_LASER_DISABLE) || (m_TileFIndex == TILE_TELE_LASER_DISABLE)) && m_Core.m_HasTelegunLaser) { m_Core.m_HasTelegunLaser = false; - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport laser disabled"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Teleport laser disabled"); + } } // stopper @@ -1664,7 +1714,10 @@ void CCharacter::HandleTiles(int Index) } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_ENABLE && m_Hit & DISABLE_HIT_HAMMER && Collision()->GetSwitchDelay(MapIndex) == WEAPON_HAMMER) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hammer hit others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can hammer hit others"); + } m_Hit &= ~DISABLE_HIT_HAMMER; m_NeededFaketuning &= ~FAKETUNE_NOHAMMER; m_Core.m_NoHammerHit = false; @@ -1672,7 +1725,10 @@ void CCharacter::HandleTiles(int Index) } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_DISABLE && !(m_Hit & DISABLE_HIT_HAMMER) && Collision()->GetSwitchDelay(MapIndex) == WEAPON_HAMMER) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hammer hit others"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't hammer hit others"); + } m_Hit |= DISABLE_HIT_HAMMER; m_NeededFaketuning |= FAKETUNE_NOHAMMER; m_Core.m_NoHammerHit = true; @@ -1680,37 +1736,55 @@ void CCharacter::HandleTiles(int Index) } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_ENABLE && m_Hit & DISABLE_HIT_SHOTGUN && Collision()->GetSwitchDelay(MapIndex) == WEAPON_SHOTGUN) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with shotgun"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with shotgun"); + } m_Hit &= ~DISABLE_HIT_SHOTGUN; m_Core.m_NoShotgunHit = false; } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_DISABLE && !(m_Hit & DISABLE_HIT_SHOTGUN) && Collision()->GetSwitchDelay(MapIndex) == WEAPON_SHOTGUN) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with shotgun"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with shotgun"); + } m_Hit |= DISABLE_HIT_SHOTGUN; m_Core.m_NoShotgunHit = true; } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_ENABLE && m_Hit & DISABLE_HIT_GRENADE && Collision()->GetSwitchDelay(MapIndex) == WEAPON_GRENADE) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with grenade"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with grenade"); + } m_Hit &= ~DISABLE_HIT_GRENADE; m_Core.m_NoGrenadeHit = false; } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_DISABLE && !(m_Hit & DISABLE_HIT_GRENADE) && Collision()->GetSwitchDelay(MapIndex) == WEAPON_GRENADE) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with grenade"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with grenade"); + } m_Hit |= DISABLE_HIT_GRENADE; m_Core.m_NoGrenadeHit = true; } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_ENABLE && m_Hit & DISABLE_HIT_LASER && Collision()->GetSwitchDelay(MapIndex) == WEAPON_LASER) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with laser"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can shoot others with laser"); + } m_Hit &= ~DISABLE_HIT_LASER; m_Core.m_NoLaserHit = false; } else if(Collision()->GetSwitchType(MapIndex) == TILE_HIT_DISABLE && !(m_Hit & DISABLE_HIT_LASER) && Collision()->GetSwitchDelay(MapIndex) == WEAPON_LASER) { - GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with laser"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't shoot others with laser"); + } m_Hit |= DISABLE_HIT_LASER; m_Core.m_NoLaserHit = true; } @@ -1724,15 +1798,17 @@ void CCharacter::HandleTiles(int Index) if(NewJumps != m_Core.m_Jumps) { - char aBuf[256]; - if(NewJumps == -1) - str_format(aBuf, sizeof(aBuf), "You only have your ground jump now"); - else if(NewJumps == 1) - str_format(aBuf, sizeof(aBuf), "You can jump %d time", NewJumps); - else - str_format(aBuf, sizeof(aBuf), "You can jump %d times", NewJumps); - GameServer()->SendChatTarget(GetPlayer()->GetCID(), aBuf); - + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + char aBuf[256]; + if(NewJumps == -1) + str_format(aBuf, sizeof(aBuf), "You only have your ground jump now"); + else if(NewJumps == 1) + str_format(aBuf, sizeof(aBuf), "You can jump %d time", NewJumps); + else + str_format(aBuf, sizeof(aBuf), "You can jump %d times", NewJumps); + GameServer()->SendChatTarget(GetPlayer()->GetCID(), aBuf); + } if(NewJumps == 0 && !m_SuperJump) { m_NeededFaketuning |= FAKETUNE_NOJUMP; @@ -1991,7 +2067,7 @@ void CCharacter::SetRescue() void CCharacter::DDRaceTick() { mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input)); - m_Armor = (m_FreezeTime >= 0) ? 10 - (m_FreezeTime / 15) : 0; + m_Armor = (m_FreezeTime >= 0) ? clamp(10 - (m_FreezeTime / 15), 0, 10) : 0; if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0) m_LastMove = Server()->Tick(); @@ -2005,7 +2081,7 @@ void CCharacter::DDRaceTick() { if(m_FreezeTime % Server()->TickSpeed() == Server()->TickSpeed() - 1 || m_FreezeTime == -1) { - GameServer()->CreateDamageInd(m_Pos, 0, (m_FreezeTime + 1) / Server()->TickSpeed(), TeamMask()); + GameServer()->CreateDamageInd(m_Pos, 0, (m_FreezeTime + 1) / Server()->TickSpeed(), TeamMask() & GameServer()->ClientsMaskExcludeClientVersionAndHigher(VERSION_DDNET_NEW_HUD)); } if(m_FreezeTime > 0) m_FreezeTime--; @@ -2209,8 +2285,10 @@ void CCharacter::SetEndlessHook(bool Enable) { return; } - - GameServer()->SendChatTarget(GetPlayer()->GetCID(), Enable ? "Endless hook has been activated" : "Endless hook has been deactivated"); + if(GameServer()->GetClientVersion(GetPlayer()->GetCID()) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(GetPlayer()->GetCID(), Enable ? "Endless hook has been activated" : "Endless hook has been deactivated"); + } m_EndlessHook = Enable; m_Core.m_EndlessHook = Enable; } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index d1e81c5d7..6957bfc0b 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -4105,6 +4105,18 @@ int CGameContext::GetClientVersion(int ClientID) const return Info.m_DDNetVersion; } +int64_t CGameContext::ClientsMaskExcludeClientVersionAndHigher(int Version) +{ + int64_t Mask = 0; + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(GetClientVersion(i) >= Version) + continue; + Mask |= 1LL << i; + } + return Mask; +} + bool CGameContext::PlayerModerating() const { return std::any_of(std::begin(m_apPlayers), std::end(m_apPlayers), [](const CPlayer *pPlayer) { return pPlayer && pPlayer->m_Moderating; }); diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 7f765f3e9..3e7cdced8 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -291,6 +291,7 @@ public: int64_t m_NonEmptySince; int64_t m_LastMapVote; int GetClientVersion(int ClientID) const; + int64_t ClientsMaskExcludeClientVersionAndHigher(int Version); bool PlayerExists(int ClientID) const override { return m_apPlayers[ClientID]; } // Returns true if someone is actively moderating. bool PlayerModerating() const; diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index f4b7f4737..b4cc9f956 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -604,7 +604,7 @@ void IGameController::Snap(int SnappingClient) GAMEINFOFLAG_ENTITIES_DDRACE | GAMEINFOFLAG_ENTITIES_RACE | GAMEINFOFLAG_RACE; - pGameInfoEx->m_Flags2 = 0; + pGameInfoEx->m_Flags2 = GAMEINFOFLAG2_HUD_DDRACE; pGameInfoEx->m_Version = GAMEINFO_CURVERSION; if(Server()->IsSixup(SnappingClient)) diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp index 4f6f2889b..8d3d6170b 100644 --- a/src/game/server/gamemodes/DDRace.cpp +++ b/src/game/server/gamemodes/DDRace.cpp @@ -40,7 +40,7 @@ void CGameControllerDDRace::OnCharacterSpawn(CCharacter *pChr) void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex) { CPlayer *pPlayer = pChr->GetPlayer(); - int ClientID = pPlayer->GetCID(); + const int ClientID = pPlayer->GetCID(); int m_TileIndex = GameServer()->Collision()->GetTileIndex(MapIndex); int m_TileFIndex = GameServer()->Collision()->GetFTileIndex(MapIndex); @@ -106,12 +106,18 @@ void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex) // solo part if(((m_TileIndex == TILE_SOLO_ENABLE) || (m_TileFIndex == TILE_SOLO_ENABLE)) && !m_Teams.m_Core.GetSolo(ClientID)) { - GameServer()->SendChatTarget(ClientID, "You are now in a solo part"); + if(GameServer()->GetClientVersion(ClientID) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(ClientID, "You are now in a solo part"); + } pChr->SetSolo(true); } else if(((m_TileIndex == TILE_SOLO_DISABLE) || (m_TileFIndex == TILE_SOLO_DISABLE)) && m_Teams.m_Core.GetSolo(ClientID)) { - GameServer()->SendChatTarget(ClientID, "You are now out of the solo part"); + if(GameServer()->GetClientVersion(ClientID) < VERSION_DDNET_NEW_HUD) + { + GameServer()->SendChatTarget(ClientID, "You are now out of the solo part"); + } pChr->SetSolo(false); } } diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index 5299cb2dc..892efc332 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -694,7 +694,7 @@ void CGameTeams::OnFinish(CPlayer *Player, float Time, const char *pTimestamp) if(g_Config.m_SvHideScore || !g_Config.m_SvSaveWorseScores) GameServer()->SendChatTarget(ClientID, aBuf, CGameContext::CHAT_SIX); else - GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, CGameContext::CHAT_SIX); + GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, -1, CGameContext::CHAT_SIX); } else if(pData->m_BestTime != 0) // tee has already finished? { diff --git a/src/game/variables.h b/src/game/variables.h index e8f02c375..ef786c9c7 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -45,6 +45,7 @@ MACRO_CONFIG_INT(ClShowhudDummyActions, cl_showhud_dummy_actions, 1, 0, 1, CFGFL MACRO_CONFIG_INT(ClShowhudPlayerPosition, cl_showhud_player_position, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Position)") MACRO_CONFIG_INT(ClShowhudPlayerSpeed, cl_showhud_player_speed, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Speed)") MACRO_CONFIG_INT(ClShowhudPlayerAngle, cl_showhud_player_angle, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Aim Angle)") +MACRO_CONFIG_INT(ClFreezeBarsAlphaInsideFreeze, cl_freezebars_alpha_inside_freeze, 100, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Opacity of freeze bars inside freeze (0 invisible, 100 fully visible)") MACRO_CONFIG_INT(ClShowRecord, cl_showrecord, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show old style DDRace client records") MACRO_CONFIG_INT(ClShowNotifications, cl_shownotifications, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Make the client notify when someone highlights you") MACRO_CONFIG_INT(ClShowEmotes, cl_showemotes, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show tee emotes")