2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2010-09-26 12:53:20 +00:00
|
|
|
#include <engine/demo.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <engine/graphics.h>
|
2013-10-09 14:02:23 +00:00
|
|
|
#include <engine/shared/config.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/generated/client_data.h>
|
|
|
|
#include <game/generated/protocol.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/gameclient.h>
|
2021-01-17 16:18:08 +00:00
|
|
|
#include <game/client/projectile_data.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/render.h>
|
2022-05-29 16:33:38 +00:00
|
|
|
|
|
|
|
#include <game/client/prediction/entities/laser.h>
|
|
|
|
#include <game/client/prediction/entities/pickup.h>
|
|
|
|
#include <game/client/prediction/entities/projectile.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/components/effects.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "items.h"
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2021-01-17 16:18:08 +00:00
|
|
|
void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemID)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-11-17 19:58:49 +00:00
|
|
|
int CurWeapon = clamp(pCurrent->m_Type, 0, NUM_WEAPONS - 1);
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// get positions
|
2010-05-29 07:25:38 +00:00
|
|
|
float Curvature = 0;
|
|
|
|
float Speed = 0;
|
2021-04-23 05:53:54 +00:00
|
|
|
CTuningParams Tuning = GameClient()->GetTunes(pCurrent->m_TuneZone);
|
2020-11-17 19:58:49 +00:00
|
|
|
if(CurWeapon == WEAPON_GRENADE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_GrenadeCurvature;
|
|
|
|
Speed = Tuning.m_GrenadeSpeed;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2020-11-17 19:58:49 +00:00
|
|
|
else if(CurWeapon == WEAPON_SHOTGUN)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_ShotgunCurvature;
|
|
|
|
Speed = Tuning.m_ShotgunSpeed;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2020-11-17 19:58:49 +00:00
|
|
|
else if(CurWeapon == WEAPON_GUN)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_GunCurvature;
|
|
|
|
Speed = Tuning.m_GunSpeed;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2014-12-08 18:14:44 +00:00
|
|
|
bool LocalPlayerInGame = false;
|
|
|
|
|
|
|
|
if(m_pClient->m_Snap.m_pLocalInfo)
|
2022-03-07 21:16:28 +00:00
|
|
|
LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientID].m_Team != TEAM_SPECTATORS;
|
2014-12-08 18:14:44 +00:00
|
|
|
|
2020-02-19 10:24:58 +00:00
|
|
|
static float s_LastGameTickTime = Client()->GameTickTime(g_Config.m_ClDummy);
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED))
|
2020-02-19 10:24:58 +00:00
|
|
|
s_LastGameTickTime = Client()->GameTickTime(g_Config.m_ClDummy);
|
2014-12-08 18:14:44 +00:00
|
|
|
|
2021-02-07 19:51:28 +00:00
|
|
|
bool IsOtherTeam = (pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner));
|
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
float Ct;
|
2021-02-07 19:51:28 +00:00
|
|
|
if(m_pClient->Predict() && m_pClient->AntiPingGrenade() && LocalPlayerInGame && !IsOtherTeam)
|
2020-09-26 19:41:58 +00:00
|
|
|
Ct = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED;
|
2019-04-11 22:46:54 +00:00
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + s_LastGameTickTime;
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Ct < 0)
|
2021-12-25 10:21:48 +00:00
|
|
|
{
|
|
|
|
if(Ct > -s_LastGameTickTime / 2)
|
|
|
|
{
|
|
|
|
// Fixup the timing which might be screwed during demo playback because
|
|
|
|
// s_LastGameTickTime depends on the system timer, while the other part
|
|
|
|
// (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED
|
|
|
|
// is virtually constant (for projectiles fired on the current game tick):
|
|
|
|
// (x - (x+2)) / 50 = -0.04
|
|
|
|
//
|
|
|
|
// We have a strict comparison for the passed time being more than the time between ticks
|
|
|
|
// if(CurtickStart > m_Info.m_CurrentTime) in CDemoPlayer::Update()
|
|
|
|
// so on the practice the typical value of s_LastGameTickTime varies from 0.02386 to 0.03999
|
|
|
|
// which leads to Ct from -0.00001 to -0.01614.
|
|
|
|
// Round up those to 0.0 to fix missing rendering of the projectile.
|
|
|
|
Ct = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return; // projectile haven't been shot yet
|
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-01-17 16:18:08 +00:00
|
|
|
vec2 Pos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, Ct);
|
|
|
|
vec2 PrevPos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, Ct - 0.001f);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2019-07-16 20:06:57 +00:00
|
|
|
float Alpha = 1.f;
|
2021-02-07 19:51:28 +00:00
|
|
|
if(IsOtherTeam)
|
2019-07-16 20:06:57 +00:00
|
|
|
{
|
2021-01-17 16:18:08 +00:00
|
|
|
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
2019-07-16 20:06:57 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:49 +00:00
|
|
|
vec2 Vel = Pos - PrevPos;
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-11-17 19:58:49 +00:00
|
|
|
// add particle for this projectile
|
|
|
|
// don't check for validity of the projectile for the current weapon here, so particle effects are rendered for mod compability
|
|
|
|
if(CurWeapon == WEAPON_GRENADE)
|
2020-10-09 07:07:05 +00:00
|
|
|
{
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.SmokeTrail(Pos, Vel * -1, Alpha);
|
2020-11-17 19:58:49 +00:00
|
|
|
static float s_Time = 0.0f;
|
|
|
|
static float s_LastLocalTime = LocalTime();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-11-17 19:58:49 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
2010-10-19 11:37:36 +00:00
|
|
|
{
|
2020-11-17 19:58:49 +00:00
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
|
|
|
if(!pInfo->m_Paused)
|
|
|
|
s_Time += (LocalTime() - s_LastLocalTime) * pInfo->m_Speed;
|
2010-10-19 11:37:36 +00:00
|
|
|
}
|
|
|
|
else
|
2012-01-09 23:49:31 +00:00
|
|
|
{
|
2020-11-17 19:58:49 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED))
|
|
|
|
s_Time += LocalTime() - s_LastLocalTime;
|
2020-10-09 07:07:05 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-11-17 19:58:49 +00:00
|
|
|
Graphics()->QuadsSetRotation(s_Time * pi * 2 * 2 + ItemID);
|
|
|
|
s_LastLocalTime = LocalTime();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.BulletTrail(Pos, Alpha);
|
2020-11-17 19:58:49 +00:00
|
|
|
|
|
|
|
if(length(Vel) > 0.00001f)
|
2014-02-18 16:20:28 +00:00
|
|
|
Graphics()->QuadsSetRotation(angle(Vel));
|
2020-11-17 19:58:49 +00:00
|
|
|
else
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
}
|
|
|
|
|
2012-08-12 12:02:50 +00:00
|
|
|
if(GameClient()->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon].IsValid())
|
2020-11-17 19:58:49 +00:00
|
|
|
{
|
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon]);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-05-16 13:31:46 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ProjectileOffset[CurWeapon], Pos.x, Pos.y);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 01:05:34 +00:00
|
|
|
void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
int CurWeapon = clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS - 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
int QuadOffset = 2;
|
|
|
|
float Angle = 0.0f;
|
|
|
|
float IntraTick = IsPredicted ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
|
|
|
|
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), IntraTick);
|
2022-05-10 17:03:09 +00:00
|
|
|
if(pCurrent->m_Type == POWERUP_HEALTH)
|
2022-05-16 13:31:46 +00:00
|
|
|
{
|
|
|
|
QuadOffset = m_PickupHealthOffset;
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupHealth);
|
2022-05-16 13:31:46 +00:00
|
|
|
}
|
2022-05-10 17:03:09 +00:00
|
|
|
else if(pCurrent->m_Type == POWERUP_ARMOR)
|
2022-05-16 13:31:46 +00:00
|
|
|
{
|
|
|
|
QuadOffset = m_PickupArmorOffset;
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmor);
|
2022-05-16 13:31:46 +00:00
|
|
|
}
|
2022-05-10 17:03:09 +00:00
|
|
|
else if(pCurrent->m_Type == POWERUP_WEAPON)
|
2020-10-09 07:07:05 +00:00
|
|
|
{
|
2022-05-16 13:31:46 +00:00
|
|
|
QuadOffset = m_PickupWeaponOffset[CurWeapon];
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeapons[CurWeapon]);
|
|
|
|
}
|
2022-05-10 17:03:09 +00:00
|
|
|
else if(pCurrent->m_Type == POWERUP_NINJA)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2022-05-16 13:31:46 +00:00
|
|
|
QuadOffset = m_PickupNinjaOffset;
|
|
|
|
m_pClient->m_Effects.PowerupShine(Pos, vec2(96, 18));
|
|
|
|
Pos.x -= 10.0f;
|
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupNinja);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2022-05-16 13:31:46 +00:00
|
|
|
else if(pCurrent->m_Type >= POWERUP_ARMOR_SHOTGUN && pCurrent->m_Type <= POWERUP_ARMOR_LASER)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2022-05-16 13:31:46 +00:00
|
|
|
QuadOffset = m_PickupWeaponArmorOffset[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN];
|
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeaponArmor[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN]);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2022-05-16 13:31:46 +00:00
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->QuadsSetRotation(Angle);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2012-01-09 23:49:31 +00:00
|
|
|
static float s_Time = 0.0f;
|
2016-08-30 23:39:59 +00:00
|
|
|
static float s_LastLocalTime = LocalTime();
|
2020-09-26 19:41:58 +00:00
|
|
|
float Offset = Pos.y / 32.0f + Pos.x / 32.0f;
|
2010-09-26 12:53:20 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
|
|
|
if(!pInfo->m_Paused)
|
2020-09-26 19:41:58 +00:00
|
|
|
s_Time += (LocalTime() - s_LastLocalTime) * pInfo->m_Speed;
|
2010-09-26 12:53:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED))
|
|
|
|
s_Time += LocalTime() - s_LastLocalTime;
|
2015-07-09 00:08:14 +00:00
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
Pos.x += cosf(s_Time * 2.0f + Offset) * 2.5f;
|
|
|
|
Pos.y += sinf(s_Time * 2.0f + Offset) * 2.5f;
|
2016-08-30 23:39:59 +00:00
|
|
|
s_LastLocalTime = LocalTime();
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2011-03-04 16:08:10 +00:00
|
|
|
void CItems::RenderFlag(const CNetObj_Flag *pPrev, const CNetObj_Flag *pCurrent, const CNetObj_GameData *pPrevGameData, const CNetObj_GameData *pCurGameData)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
float Angle = 0.0f;
|
|
|
|
float Size = 42.0f;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
if(pCurrent->m_Team == TEAM_RED)
|
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteFlagRed);
|
|
|
|
else
|
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteFlagBlue);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
2022-05-16 13:31:46 +00:00
|
|
|
int QuadOffset;
|
|
|
|
if(pCurrent->m_Team == TEAM_RED)
|
|
|
|
{
|
|
|
|
QuadOffset = m_RedFlagOffset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QuadOffset = m_BlueFlagOffset;
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->QuadsSetRotation(Angle);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-02-19 10:24:58 +00:00
|
|
|
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), Client()->IntraGameTick(g_Config.m_ClDummy));
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-04 16:08:10 +00:00
|
|
|
if(pCurGameData)
|
|
|
|
{
|
2019-04-11 22:46:54 +00:00
|
|
|
int FlagCarrier = (pCurrent->m_Team == TEAM_RED) ? pCurGameData->m_FlagCarrierRed : pCurGameData->m_FlagCarrierBlue;
|
|
|
|
// use the flagcarriers position if available
|
|
|
|
if(FlagCarrier >= 0 && m_pClient->m_Snap.m_aCharacters[FlagCarrier].m_Active)
|
|
|
|
Pos = m_pClient->m_aClients[FlagCarrier].m_RenderPos;
|
|
|
|
|
2011-03-04 16:08:10 +00:00
|
|
|
// make sure that the flag isn't interpolated between capture and return
|
|
|
|
if(pPrevGameData &&
|
|
|
|
((pCurrent->m_Team == TEAM_RED && pPrevGameData->m_FlagCarrierRed != pCurGameData->m_FlagCarrierRed) ||
|
2020-09-26 19:41:58 +00:00
|
|
|
(pCurrent->m_Team == TEAM_BLUE && pPrevGameData->m_FlagCarrierBlue != pCurGameData->m_FlagCarrierBlue)))
|
2011-03-04 16:08:10 +00:00
|
|
|
Pos = vec2(pCurrent->m_X, pCurrent->m_Y);
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y - Size * 0.75f);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
void CItems::RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2019-04-25 16:49:27 +00:00
|
|
|
ColorRGBA RGB;
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Pos = vec2(pCurrent->m_X, pCurrent->m_Y);
|
|
|
|
vec2 From = vec2(pCurrent->m_FromX, pCurrent->m_FromY);
|
2020-10-17 19:34:10 +00:00
|
|
|
float Len = distance(Pos, From);
|
2019-05-10 21:34:21 +00:00
|
|
|
RGB = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClLaserOutlineColor));
|
2019-04-26 22:11:15 +00:00
|
|
|
ColorRGBA OuterColor(RGB.r, RGB.g, RGB.b, 1.0f);
|
2019-05-10 21:34:21 +00:00
|
|
|
RGB = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClLaserInnerColor));
|
2019-04-26 22:11:15 +00:00
|
|
|
ColorRGBA InnerColor(RGB.r, RGB.g, RGB.b, 1.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-04-23 05:53:54 +00:00
|
|
|
int TuneZone = GameClient()->m_GameWorld.m_WorldConfig.m_UseTuneZones ? Collision()->IsTune(Collision()->GetMapIndex(From)) : 0;
|
|
|
|
|
2020-10-17 19:34:10 +00:00
|
|
|
vec2 Dir;
|
|
|
|
if(Len > 0)
|
|
|
|
{
|
|
|
|
Dir = normalize_pre_length(Pos - From, Len);
|
|
|
|
|
|
|
|
float Ticks;
|
|
|
|
if(IsPredicted)
|
|
|
|
Ticks = (float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy);
|
|
|
|
else
|
|
|
|
Ticks = (float)(Client()->GameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->IntraGameTick(g_Config.m_ClDummy);
|
|
|
|
float Ms = (Ticks / 50.0f) * 1000.0f;
|
2021-04-23 05:53:54 +00:00
|
|
|
float a = Ms / m_pClient->GetTunes(TuneZone).m_LaserBounceDelay;
|
2020-10-17 19:34:10 +00:00
|
|
|
a = clamp(a, 0.0f, 1.0f);
|
|
|
|
float Ia = 1 - a;
|
|
|
|
|
2020-11-20 11:14:04 +00:00
|
|
|
vec2 Out;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-10-17 19:34:10 +00:00
|
|
|
Graphics()->TextureClear();
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
|
|
|
// do outline
|
|
|
|
Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f);
|
|
|
|
Out = vec2(Dir.y, -Dir.x) * (7.0f * Ia);
|
|
|
|
|
|
|
|
IGraphics::CFreeformItem Freeform(
|
|
|
|
From.x - Out.x, From.y - Out.y,
|
|
|
|
From.x + Out.x, From.y + Out.y,
|
|
|
|
Pos.x - Out.x, Pos.y - Out.y,
|
|
|
|
Pos.x + Out.x, Pos.y + Out.y);
|
|
|
|
Graphics()->QuadsDrawFreeform(&Freeform, 1);
|
|
|
|
|
|
|
|
// do inner
|
|
|
|
Out = vec2(Dir.y, -Dir.x) * (5.0f * Ia);
|
|
|
|
Graphics()->SetColor(InnerColor.r, InnerColor.g, InnerColor.b, 1.0f); // center
|
|
|
|
|
|
|
|
Freeform = IGraphics::CFreeformItem(
|
|
|
|
From.x - Out.x, From.y - Out.y,
|
|
|
|
From.x + Out.x, From.y + Out.y,
|
|
|
|
Pos.x - Out.x, Pos.y - Out.y,
|
|
|
|
Pos.x + Out.x, Pos.y + Out.y);
|
|
|
|
Graphics()->QuadsDrawFreeform(&Freeform, 1);
|
|
|
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// render head
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
int CurParticle = (Client()->GameTick(g_Config.m_ClDummy) % 3);
|
|
|
|
Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticleSplat[CurParticle]);
|
2020-02-19 10:24:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(Client()->GameTick(g_Config.m_ClDummy));
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f);
|
2022-05-16 13:31:46 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ParticleSplatOffset[CurParticle], Pos.x, Pos.y);
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->SetColor(InnerColor.r, InnerColor.g, InnerColor.b, 1.0f);
|
2022-05-16 13:31:46 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ParticleSplatOffset[CurParticle], Pos.x, Pos.y, 20.f / 24.f, 20.f / 24.f);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CItems::OnRender()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-04-08 09:22:44 +00:00
|
|
|
if(Client()->State() < IClient::STATE_ONLINE)
|
|
|
|
return;
|
|
|
|
|
2021-10-14 20:59:39 +00:00
|
|
|
bool IsSuper = m_pClient->IsLocalCharSuper();
|
2021-09-19 12:14:00 +00:00
|
|
|
int Ticks = Client()->GameTick(g_Config.m_ClDummy) % Client()->GameTickSpeed();
|
2021-10-14 20:59:39 +00:00
|
|
|
bool BlinkingPickup = (Ticks % 22) < 4;
|
|
|
|
bool BlinkingGun = (Ticks % 22) < 4;
|
|
|
|
bool BlinkingDragger = (Ticks % 22) < 4;
|
|
|
|
bool BlinkingProj = (Ticks % 20) < 2;
|
|
|
|
bool BlinkingProjEx = (Ticks % 6) < 2;
|
|
|
|
bool BlinkingLight = (Ticks % 6) < 2;
|
2021-11-08 22:51:09 +00:00
|
|
|
int SwitcherTeam = m_pClient->SwitchStateTeam();
|
2021-10-14 20:59:39 +00:00
|
|
|
int DraggerStartTick = maximum((Client()->GameTick(g_Config.m_ClDummy) / 7) * 7, Client()->GameTick(g_Config.m_ClDummy) - 4);
|
2021-11-06 11:13:42 +00:00
|
|
|
int GunStartTick = (Client()->GameTick(g_Config.m_ClDummy) / 7) * 7;
|
2021-09-19 12:14:00 +00:00
|
|
|
|
2019-06-19 00:12:57 +00:00
|
|
|
bool UsePredicted = GameClient()->Predict() && GameClient()->AntiPingGunfire();
|
2022-02-13 19:57:27 +00:00
|
|
|
auto &aSwitchers = GameClient()->Switchers();
|
2019-04-11 22:46:54 +00:00
|
|
|
if(UsePredicted)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
for(auto *pProj = (CProjectile *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity())
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2022-02-13 19:57:27 +00:00
|
|
|
if(!IsSuper && pProj->m_Number > 0 && pProj->m_Number < Collision()->m_NumSwitchers + 1 && !aSwitchers[pProj->m_Number].m_Status[SwitcherTeam] && (pProj->m_Explosive ? BlinkingProjEx : BlinkingProj))
|
2021-09-19 12:14:00 +00:00
|
|
|
continue;
|
|
|
|
|
2021-01-17 16:18:08 +00:00
|
|
|
CProjectileData Data = pProj->GetData();
|
2019-04-11 22:46:54 +00:00
|
|
|
RenderProjectile(&Data, pProj->ID());
|
|
|
|
}
|
2021-12-11 22:56:21 +00:00
|
|
|
for(CEntity *pEnt = GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->NextEntity())
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2021-12-11 22:56:21 +00:00
|
|
|
auto *const pLaser = dynamic_cast<CLaser *>(pEnt);
|
|
|
|
if(!pLaser || pLaser->GetOwner() < 0 || !GameClient()->m_aClients[pLaser->GetOwner()].m_IsPredictedLocal)
|
2019-04-11 22:46:54 +00:00
|
|
|
continue;
|
|
|
|
CNetObj_Laser Data;
|
|
|
|
pLaser->FillInfo(&Data);
|
|
|
|
RenderLaser(&Data, true);
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
for(auto *pPickup = (CPickup *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PICKUP); pPickup; pPickup = (CPickup *)pPickup->NextEntity())
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2022-02-13 19:57:27 +00:00
|
|
|
if(!IsSuper && pPickup->m_Layer == LAYER_SWITCH && pPickup->m_Number > 0 && pPickup->m_Number < Collision()->m_NumSwitchers + 1 && !aSwitchers[pPickup->m_Number].m_Status[SwitcherTeam] && BlinkingPickup)
|
2021-09-19 12:14:00 +00:00
|
|
|
continue;
|
|
|
|
|
2021-05-27 07:45:41 +00:00
|
|
|
if(pPickup->InDDNetTile())
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2021-05-27 07:45:41 +00:00
|
|
|
if(auto *pPrev = (CPickup *)GameClient()->m_PrevPredictedWorld.GetEntity(pPickup->ID(), CGameWorld::ENTTYPE_PICKUP))
|
|
|
|
{
|
|
|
|
CNetObj_Pickup Data, Prev;
|
|
|
|
pPickup->FillInfo(&Data);
|
|
|
|
pPrev->FillInfo(&Prev);
|
|
|
|
RenderPickup(&Prev, &Data, true);
|
|
|
|
}
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-21 01:18:54 +00:00
|
|
|
for(const CSnapEntities &Ent : m_pClient->SnapEntities())
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-10-21 01:18:54 +00:00
|
|
|
const IClient::CSnapItem Item = Ent.m_Item;
|
|
|
|
const void *pData = Ent.m_pData;
|
|
|
|
const CNetObj_EntityEx *pEntEx = Ent.m_pDataEx;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2021-10-14 20:59:39 +00:00
|
|
|
bool Inactive = false;
|
|
|
|
if(pEntEx)
|
2022-02-13 19:57:27 +00:00
|
|
|
Inactive = !IsSuper && pEntEx->m_SwitchNumber > 0 && pEntEx->m_SwitchNumber < Collision()->m_NumSwitchers + 1 && !aSwitchers[pEntEx->m_SwitchNumber].m_Status[SwitcherTeam];
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2021-01-17 16:18:08 +00:00
|
|
|
if(Item.m_Type == NETOBJTYPE_PROJECTILE || Item.m_Type == NETOBJTYPE_DDNETPROJECTILE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-01-17 16:18:08 +00:00
|
|
|
CProjectileData Data;
|
|
|
|
if(Item.m_Type == NETOBJTYPE_PROJECTILE)
|
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Data = ExtractProjectileInfo((const CNetObj_Projectile *)pData, &GameClient()->m_GameWorld);
|
2021-01-17 16:18:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Data = ExtractProjectileInfoDDNet((const CNetObj_DDNetProjectile *)pData, &GameClient()->m_GameWorld);
|
2021-01-17 16:18:08 +00:00
|
|
|
}
|
2019-04-11 22:46:54 +00:00
|
|
|
if(UsePredicted)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(auto *pProj = (CProjectile *)GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData))
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2022-01-16 20:58:51 +00:00
|
|
|
bool IsOtherTeam = m_pClient->IsOtherTeam(pProj->GetOwner());
|
|
|
|
if(pProj->m_LastRenderTick <= 0 && (pProj->m_Type != WEAPON_SHOTGUN || (!pProj->m_Freeze && !pProj->m_Explosive)) // skip ddrace shotgun bullets
|
2022-03-21 06:10:44 +00:00
|
|
|
&& (pProj->m_Type == WEAPON_SHOTGUN || fabs(length(pProj->m_Direction) - 1.f) < 0.02f) // workaround to skip grenades on ball mod
|
2022-01-16 20:58:51 +00:00
|
|
|
&& (pProj->GetOwner() < 0 || !GameClient()->m_aClients[pProj->GetOwner()].m_IsPredictedLocal || IsOtherTeam) // skip locally predicted projectiles
|
|
|
|
&& !Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID))
|
2019-04-12 22:51:15 +00:00
|
|
|
{
|
2022-01-16 20:58:51 +00:00
|
|
|
ReconstructSmokeTrail(&Data, pProj->m_DestroyTick);
|
2019-04-12 22:51:15 +00:00
|
|
|
}
|
2022-01-16 20:58:51 +00:00
|
|
|
pProj->m_LastRenderTick = Client()->GameTick(g_Config.m_ClDummy);
|
|
|
|
if(!IsOtherTeam)
|
|
|
|
continue;
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-14 20:59:39 +00:00
|
|
|
if(Inactive && (Data.m_Explosive ? BlinkingProjEx : BlinkingProj))
|
2021-09-19 12:14:00 +00:00
|
|
|
continue;
|
2021-01-17 16:18:08 +00:00
|
|
|
RenderProjectile(&Data, Item.m_ID);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Item.m_Type == NETOBJTYPE_PICKUP)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-10-14 20:59:39 +00:00
|
|
|
if(Inactive && BlinkingPickup)
|
|
|
|
continue;
|
2019-04-11 22:46:54 +00:00
|
|
|
if(UsePredicted)
|
2021-05-27 07:45:41 +00:00
|
|
|
{
|
|
|
|
auto *pPickup = (CPickup *)GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData);
|
|
|
|
if(pPickup && pPickup->InDDNetTile())
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-12 10:40:36 +00:00
|
|
|
const void *pPrev = Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID);
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pPrev)
|
|
|
|
RenderPickup((const CNetObj_Pickup *)pPrev, (const CNetObj_Pickup *)pData);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Item.m_Type == NETOBJTYPE_LASER)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2019-04-11 22:46:54 +00:00
|
|
|
if(UsePredicted)
|
2019-04-12 22:51:15 +00:00
|
|
|
{
|
2021-12-11 22:56:21 +00:00
|
|
|
auto *pLaser = dynamic_cast<CLaser *>(GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData));
|
2019-04-12 22:51:15 +00:00
|
|
|
if(pLaser && pLaser->GetOwner() >= 0 && GameClient()->m_aClients[pLaser->GetOwner()].m_IsPredictedLocal)
|
|
|
|
continue;
|
|
|
|
}
|
2021-09-19 18:48:50 +00:00
|
|
|
CNetObj_Laser Laser = *((const CNetObj_Laser *)pData);
|
2021-10-14 20:59:39 +00:00
|
|
|
|
|
|
|
if(pEntEx)
|
2021-09-19 18:48:50 +00:00
|
|
|
{
|
2021-11-06 11:13:42 +00:00
|
|
|
if(pEntEx->m_EntityClass == ENTITYCLASS_LIGHT)
|
|
|
|
{
|
|
|
|
if(Inactive && BlinkingLight)
|
|
|
|
continue;
|
|
|
|
Laser.m_StartTick = DraggerStartTick;
|
|
|
|
}
|
|
|
|
if(pEntEx->m_EntityClass >= ENTITYCLASS_GUN_NORMAL && pEntEx->m_EntityClass <= ENTITYCLASS_GUN_UNFREEZE)
|
|
|
|
{
|
|
|
|
if(Inactive && BlinkingGun)
|
|
|
|
continue;
|
|
|
|
Laser.m_StartTick = GunStartTick;
|
|
|
|
}
|
2021-10-14 20:59:39 +00:00
|
|
|
if(pEntEx->m_EntityClass >= ENTITYCLASS_DRAGGER_WEAK && pEntEx->m_EntityClass <= ENTITYCLASS_DRAGGER_STRONG)
|
2021-09-19 18:48:50 +00:00
|
|
|
{
|
2021-10-14 20:59:39 +00:00
|
|
|
if(Inactive && BlinkingDragger)
|
2021-09-19 18:48:50 +00:00
|
|
|
continue;
|
2021-10-14 20:59:39 +00:00
|
|
|
Laser.m_StartTick = DraggerStartTick;
|
|
|
|
}
|
|
|
|
if(pEntEx->m_EntityClass == ENTITYCLASS_DOOR)
|
|
|
|
{
|
|
|
|
if(Inactive || IsSuper)
|
|
|
|
{
|
|
|
|
Laser.m_FromX = Laser.m_X;
|
|
|
|
Laser.m_FromY = Laser.m_Y;
|
|
|
|
}
|
|
|
|
Laser.m_StartTick = Client()->GameTick(g_Config.m_ClDummy);
|
2021-09-19 18:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
RenderLaser(&Laser);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2021-10-21 01:18:54 +00:00
|
|
|
int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// render flag
|
|
|
|
for(int i = 0; i < Num; i++)
|
|
|
|
{
|
|
|
|
IClient::CSnapItem Item;
|
|
|
|
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
|
|
|
|
|
|
|
|
if(Item.m_Type == NETOBJTYPE_FLAG)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
const void *pPrev = Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID);
|
2018-03-13 20:52:44 +00:00
|
|
|
if(pPrev)
|
2011-03-04 16:08:10 +00:00
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
const void *pPrevGameData = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_GAMEDATA, m_pClient->m_Snap.m_GameDataSnapID);
|
2011-03-04 16:08:10 +00:00
|
|
|
RenderFlag(static_cast<const CNetObj_Flag *>(pPrev), static_cast<const CNetObj_Flag *>(pData),
|
2020-09-26 19:41:58 +00:00
|
|
|
static_cast<const CNetObj_GameData *>(pPrevGameData), m_pClient->m_Snap.m_pGameDataObj);
|
2011-03-04 16:08:10 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CItems::OnInit()
|
|
|
|
{
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
2021-09-13 21:14:04 +00:00
|
|
|
m_ItemsQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_RedFlagOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_BlueFlagOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
float ScaleX, ScaleY;
|
|
|
|
RenderTools()->GetSpriteScale(SPRITE_PICKUP_HEALTH, ScaleX, ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_PickupHealthOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
|
2020-10-09 07:07:05 +00:00
|
|
|
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR, ScaleX, ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_PickupArmorOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < NUM_WEAPONS; ++i)
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_PickupWeaponOffset[i] = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleX, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
2022-05-16 13:31:46 +00:00
|
|
|
RenderTools()->GetSpriteScale(SPRITE_PICKUP_NINJA, ScaleX, ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
m_PickupNinjaOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 128.f * ScaleX, 128.f * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2022-05-16 13:31:46 +00:00
|
|
|
for(int i = 0; i < 4; i++)
|
2018-03-13 20:52:44 +00:00
|
|
|
{
|
2022-05-16 13:31:46 +00:00
|
|
|
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_SHOTGUN + i, ScaleX, ScaleY);
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2022-05-16 13:31:46 +00:00
|
|
|
m_PickupWeaponArmorOffset[i] = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-16 13:31:46 +00:00
|
|
|
for(int &ProjectileOffset : m_ProjectileOffset)
|
|
|
|
{
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
ProjectileOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 32.f);
|
|
|
|
}
|
2021-09-13 21:14:04 +00:00
|
|
|
|
2022-05-16 13:31:46 +00:00
|
|
|
for(int &ParticleSplatOffset : m_ParticleSplatOffset)
|
|
|
|
{
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
ParticleSplatOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 24.f);
|
|
|
|
}
|
2022-02-17 23:51:02 +00:00
|
|
|
|
2021-09-13 21:14:04 +00:00
|
|
|
Graphics()->QuadContainerUpload(m_ItemsQuadContainerIndex);
|
2011-04-03 08:11:23 +00:00
|
|
|
}
|
|
|
|
|
2021-01-17 16:18:08 +00:00
|
|
|
void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyTick)
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
|
|
|
bool LocalPlayerInGame = false;
|
|
|
|
|
|
|
|
if(m_pClient->m_Snap.m_pLocalInfo)
|
2022-03-07 21:16:28 +00:00
|
|
|
LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientID].m_Team != TEAM_SPECTATORS;
|
2019-06-19 00:12:57 +00:00
|
|
|
if(!m_pClient->AntiPingGunfire() || !LocalPlayerInGame)
|
2019-04-11 22:46:54 +00:00
|
|
|
return;
|
2020-02-19 10:24:58 +00:00
|
|
|
if(Client()->PredGameTick(g_Config.m_ClDummy) == pCurrent->m_StartTick)
|
2019-04-11 22:46:54 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// get positions
|
|
|
|
float Curvature = 0;
|
|
|
|
float Speed = 0;
|
2021-04-23 05:53:54 +00:00
|
|
|
CTuningParams Tuning = GameClient()->GetTunes(pCurrent->m_TuneZone);
|
2021-04-23 03:01:38 +00:00
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
if(pCurrent->m_Type == WEAPON_GRENADE)
|
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_GrenadeCurvature;
|
|
|
|
Speed = Tuning.m_GrenadeSpeed;
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
else if(pCurrent->m_Type == WEAPON_SHOTGUN)
|
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_ShotgunCurvature;
|
|
|
|
Speed = Tuning.m_ShotgunSpeed;
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
else if(pCurrent->m_Type == WEAPON_GUN)
|
|
|
|
{
|
2021-04-23 03:01:38 +00:00
|
|
|
Curvature = Tuning.m_GunCurvature;
|
|
|
|
Speed = Tuning.m_GunSpeed;
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
float Pt = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED;
|
2019-04-11 22:46:54 +00:00
|
|
|
if(Pt < 0)
|
|
|
|
return; // projectile haven't been shot yet
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
float Gt = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy);
|
2019-04-11 22:46:54 +00:00
|
|
|
|
2019-07-16 20:06:57 +00:00
|
|
|
float Alpha = 1.f;
|
2021-01-17 16:18:08 +00:00
|
|
|
if(pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner))
|
2019-07-16 20:06:57 +00:00
|
|
|
{
|
2021-01-17 16:18:08 +00:00
|
|
|
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
2019-07-16 20:06:57 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
float T = Pt;
|
|
|
|
if(DestroyTick >= 0)
|
2020-09-26 19:41:58 +00:00
|
|
|
T = minimum(Pt, ((float)(DestroyTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED);
|
2019-04-11 22:46:54 +00:00
|
|
|
|
|
|
|
float MinTrailSpan = 0.4f * ((pCurrent->m_Type == WEAPON_GRENADE) ? 0.5f : 0.25f);
|
2019-04-26 19:36:49 +00:00
|
|
|
float Step = maximum(Client()->FrameTimeAvg(), (pCurrent->m_Type == WEAPON_GRENADE) ? 0.02f : 0.01f);
|
2020-09-26 19:41:58 +00:00
|
|
|
for(int i = 1 + (int)(Gt / Step); i < (int)(T / Step); i++)
|
2019-04-11 22:46:54 +00:00
|
|
|
{
|
2021-01-12 18:25:20 +00:00
|
|
|
float t = Step * (float)i + 0.4f * Step * (random_float() - 0.5f);
|
2021-01-17 16:18:08 +00:00
|
|
|
vec2 Pos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, t);
|
|
|
|
vec2 PrevPos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, t - 0.001f);
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 Vel = Pos - PrevPos;
|
|
|
|
float TimePassed = Pt - t;
|
2019-04-11 22:46:54 +00:00
|
|
|
if(Pt - MinTrailSpan > 0.01f)
|
2020-09-26 19:41:58 +00:00
|
|
|
TimePassed = minimum(TimePassed, (TimePassed - MinTrailSpan) / (Pt - MinTrailSpan) * (MinTrailSpan * 0.5f) + MinTrailSpan);
|
2019-04-11 22:46:54 +00:00
|
|
|
// add particle for this projectile
|
|
|
|
if(pCurrent->m_Type == WEAPON_GRENADE)
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.SmokeTrail(Pos, Vel * -1, Alpha, TimePassed);
|
2019-04-11 22:46:54 +00:00
|
|
|
else
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.BulletTrail(Pos, Alpha, TimePassed);
|
2019-04-11 22:46:54 +00:00
|
|
|
}
|
|
|
|
}
|