mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-20 01:24:18 +00:00
Add freezing snow flakes effect and fix 50HZ timer + add 10Hz Timer to particle system
This commit is contained in:
parent
2475e844e0
commit
51133dee2e
BIN
data/extras.png
BIN
data/extras.png
Binary file not shown.
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 53 KiB |
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -232,6 +232,14 @@ 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;
|
||||
|
@ -442,7 +450,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
}
|
||||
else if(s_CurCustomTab == ASSETS_TAB_EXTRAS)
|
||||
{
|
||||
InitAssetList(m_vExtrasList, "assets/extras", "extras", HudScan, Graphics(), Storage(), &User);
|
||||
InitAssetList(m_vExtrasList, "assets/extras", "extras", ExtrasScan, Graphics(), Storage(), &User);
|
||||
}
|
||||
|
||||
MainView.HSplitTop(10.0f, 0, &MainView);
|
||||
|
|
|
@ -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_SpriteParticles;
|
||||
int FirstParticleOffset = SPRITE_PART_SLICE;
|
||||
int ParticleQuadContainerIndex = m_ParticleQuadContainerIndex;
|
||||
if(Group == GROUP_EXTRA)
|
||||
{
|
||||
aParticles = GameClient()->m_ExtrasSkin.m_SpriteParticles;
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -451,200 +451,199 @@ 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_SpriteWeapons[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)
|
||||
{
|
||||
|
@ -725,7 +724,12 @@ 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;
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,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;
|
||||
|
@ -34,7 +34,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
|
||||
|
@ -58,7 +65,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);
|
||||
|
||||
|
@ -102,6 +108,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);
|
||||
|
|
Loading…
Reference in a new issue