Add freezing snow flakes effect and fix 50HZ timer + add 10Hz Timer to particle system

This commit is contained in:
c0d3d3v 2022-06-14 19:30:01 +02:00
parent 2475e844e0
commit 51133dee2e
No known key found for this signature in database
GPG key ID: 068AF680530DFF31
8 changed files with 296 additions and 208 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 53 KiB

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

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

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

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

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

View file

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