5420: Improvments for new HUD r=def- a=C0D3D3V

for testing set `#define CLIENT_VERSIONNR 16020`
Some of the changes are only available in the next version

Impressions: https://youtu.be/E770vGp4KKY

Implements a few of the recommendations from https://github.com/ddnet/ddnet/issues/5159 and Discord
- removes all player capability messages send by the server, that are now displayed in the HUD
- ~~remove `cl_ddrace_hud` and cl_show_freeze_bars~~, 
- Added option `cl_freezebars_alpha_inside_freeze` setting to change the opacity if the player is inside a freeze tile (default visible 100%)
- Added option `cl_show_jumps_indicator`
- We send now the real weapon the player is holding if he is frozen
    -> for that we added a new particle "snow flakes" or frozen flakes :D that are spawned over the tees body, to indicate he is frozen.
    -> new extras.png asset (+ corresponding asset tab, that can potentially be used for all sorts of extras for our mod, e.g. material particles, but in the future maybe also for other mods using a similar structure like it is for entities)
- stars are no longer send to new clients, because it is duplication to the freezebar, and we decided to not allow to disable it 
- also ninja stars are no longer send. They are not vanilla, and we now have a ninja bar in the new HUD.
- display target angle from 0 to 360 (looks mirrored on the x-axis to the normal trigonometry circle, but that is just how the world coordinates are) 
- dummy action display is increased in size ( but only the border margin :D not the icons. so the icons are still the same size as the icons on the left side)
- allow the server to also show old HUD elements (see https://github.com/ddnet/ddnet/pull/5427 for screenshots)


fixes #5149
fixes #198
closes #5159

fixes #2252   ~~(But not clear if we should also display the weapon, still investigating)~~
- we do no longer display a weapon inside freeze, instead we have nice freeze particles

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [x] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [x] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: c0d3d3v <c0d3d3v@mag-keinen-spam.de>
This commit is contained in:
bors[bot] 2022-06-26 07:57:33 +00:00 committed by GitHub
commit 1e31db257f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 851 additions and 447 deletions

View file

@ -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

BIN
data/extras.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View file

@ -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))

View file

@ -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,
};
'''

View file

@ -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)")

View file

@ -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

View file

@ -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

View file

@ -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;)
{

View file

@ -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;

View file

@ -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();
}

View file

@ -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();
};

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -5,6 +5,7 @@
#include <game/client/component.h>
#include <game/client/components/menus.h>
#include <game/generated/protocol.h>
#include <game/client/render.h>
@ -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();

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -256,12 +256,17 @@ public:
{
};
struct SCustomExtras : public SCustomItem
{
};
protected:
std::vector<SCustomEntities> m_vEntitiesList;
std::vector<SCustomGame> m_vGameList;
std::vector<SCustomEmoticon> m_vEmoticonList;
std::vector<SCustomParticle> m_vParticlesList;
std::vector<SCustomHud> m_vHudList;
std::vector<SCustomExtras> 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);

View file

@ -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);

View file

@ -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];

View file

@ -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<const CMenus::SCustomEntities *> s_vpSearchEntitiesList;
static std::vector<const CMenus::SCustomGame *> s_vpSearchGamesList;
static std::vector<const CMenus::SCustomEmoticon *> s_vpSearchEmoticonsList;
static std::vector<const CMenus::SCustomParticle *> s_vpSearchParticlesList;
static std::vector<const CMenus::SCustomHud *> s_vpSearchHudList;
static std::vector<const CMenus::SCustomExtras *> 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<const TName *> &vpSearchList, std::vector<TName>
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);
}

View file

@ -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);

View file

@ -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<GROUP_PROJECTILE_TRAIL> m_RenderTrail;
CRenderGroup<GROUP_EXPLOSIONS> m_RenderExplosions;
CRenderGroup<GROUP_EXTRA> m_RenderExtra;
CRenderGroup<GROUP_GENERAL> m_RenderGeneral;
bool ParticleIsVisibleOnScreen(const vec2 &CurPos, float CurSize);

View file

@ -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");

View file

@ -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);

View file

@ -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)

View file

@ -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<CSnapEntities> &SnapEntities() { return m_vSnapEntities; }
private:

View file

@ -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);

View file

@ -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;
}

View file

@ -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; });

View file

@ -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;

View file

@ -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))

View file

@ -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);
}
}

View file

@ -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?
{

View file

@ -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")