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. */
|
2011-08-31 11:56:04 +00:00
|
|
|
|
|
|
|
#include <base/tl/sorted_array.h>
|
|
|
|
|
2010-11-16 23:38:20 +00:00
|
|
|
#include <engine/demo.h>
|
2011-02-27 16:56:03 +00:00
|
|
|
#include <engine/engine.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/graphics.h>
|
2018-04-25 10:03:27 +00:00
|
|
|
#include <engine/serverbrowser.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <engine/shared/config.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/generated/client_data.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/generated/protocol.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
#include <game/client/animstate.h>
|
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
#include <game/client/render.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/client/ui.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/client/components/controls.h>
|
|
|
|
#include <game/client/components/effects.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/components/flow.h>
|
|
|
|
#include <game/client/components/skins.h>
|
|
|
|
#include <game/client/components/sounds.h>
|
|
|
|
|
2013-10-09 14:02:23 +00:00
|
|
|
#include <engine/textrender.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "players.h"
|
|
|
|
|
2021-05-09 11:21:07 +00:00
|
|
|
#include <base/color.h>
|
|
|
|
|
2019-04-21 16:20:53 +00:00
|
|
|
void CPlayers::RenderHand(CTeeRenderInfo *pInfo, vec2 CenterPos, vec2 Dir, float AngleOffset, vec2 PostRotOffset, float Alpha)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 HandPos = CenterPos + Dir;
|
2014-02-18 16:20:28 +00:00
|
|
|
float Angle = angle(Dir);
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Dir.x < 0)
|
2010-05-29 07:25:38 +00:00
|
|
|
Angle -= AngleOffset;
|
2008-01-12 17:09:00 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
Angle += AngleOffset;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 DirX = Dir;
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 DirY(-Dir.y, Dir.x);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Dir.x < 0)
|
2010-05-29 07:25:38 +00:00
|
|
|
DirY = -DirY;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
HandPos += DirX * PostRotOffset.x;
|
|
|
|
HandPos += DirY * PostRotOffset.y;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
const CSkin::SSkinTextures *pSkinTextures = pInfo->m_CustomColoredSkin ? &pInfo->m_ColorableRenderSkin : &pInfo->m_OriginalRenderSkin;
|
|
|
|
|
2019-04-21 16:20:53 +00:00
|
|
|
Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, Alpha);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
|
|
|
// two passes
|
2018-03-13 20:52:44 +00:00
|
|
|
for(int i = 0; i < 2; i++)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2018-03-13 20:52:44 +00:00
|
|
|
int QuadOffset = NUM_WEAPONS * 2 + i;
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->QuadsSetRotation(Angle);
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(i == 0 ? pSkinTextures->m_HandsOutline : pSkinTextures->m_Hands);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, HandPos.x, HandPos.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
inline float NormalizeAngular(float f)
|
2008-09-03 20:03:01 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
return fmod(f + pi * 2, pi * 2);
|
2008-09-03 20:03:01 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
inline float AngularMixDirection(float Src, float Dst) { return sinf(Dst - Src) > 0 ? 1 : -1; }
|
|
|
|
inline float AngularDistance(float Src, float Dst) { return asinf(sinf(Dst - Src)); }
|
2008-10-18 10:30:03 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
inline float AngularApproach(float Src, float Dst, float Amount)
|
2008-09-03 20:03:01 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
float d = AngularMixDirection(Src, Dst);
|
|
|
|
float n = Src + Amount * d;
|
|
|
|
if(AngularMixDirection(n, Dst) != d)
|
2010-05-29 07:25:38 +00:00
|
|
|
return Dst;
|
2008-10-18 10:30:03 +00:00
|
|
|
return n;
|
2008-09-03 20:03:01 +00:00
|
|
|
}
|
2022-03-22 20:11:01 +00:00
|
|
|
void CPlayers::RenderHookCollLine(
|
|
|
|
const CNetObj_Character *pPrevChar,
|
|
|
|
const CNetObj_Character *pPlayerChar,
|
|
|
|
int ClientID,
|
|
|
|
float Intra)
|
|
|
|
{
|
|
|
|
CNetObj_Character Prev;
|
|
|
|
CNetObj_Character Player;
|
|
|
|
Prev = *pPrevChar;
|
|
|
|
Player = *pPlayerChar;
|
|
|
|
|
|
|
|
bool Local = m_pClient->m_Snap.m_LocalClientID == ClientID;
|
|
|
|
bool OtherTeam = m_pClient->IsOtherTeam(ClientID);
|
|
|
|
float Alpha = (OtherTeam || ClientID < 0) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f;
|
2022-03-31 01:15:27 +00:00
|
|
|
Alpha *= (float)g_Config.m_ClHookCollAlpha / 100;
|
2022-03-22 20:11:01 +00:00
|
|
|
|
|
|
|
float IntraTick = Intra;
|
|
|
|
if(ClientID >= 0)
|
|
|
|
IntraTick = m_pClient->m_aClients[ClientID].m_IsPredicted ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
|
2008-09-03 20:03:01 +00:00
|
|
|
|
2022-03-22 20:11:01 +00:00
|
|
|
float Angle;
|
|
|
|
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
|
|
|
// just use the direct input if it's the local player we are rendering
|
|
|
|
Angle = angle(m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float AngleIntraTick = IntraTick;
|
|
|
|
// using unpredicted angle when rendering other players in-game
|
|
|
|
if(ClientID >= 0)
|
|
|
|
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
|
|
|
|
// If the player moves their weapon through top, then change
|
|
|
|
// the end angle by 2*Pi, so that the mix function will use the
|
|
|
|
// short path and not the long one.
|
|
|
|
if(Player.m_Angle > (256.0f * pi) && Prev.m_Angle < 0)
|
|
|
|
Player.m_Angle -= 256.0f * 2 * pi;
|
|
|
|
else if(Player.m_Angle < 0 && Prev.m_Angle > (256.0f * pi))
|
|
|
|
Player.m_Angle += 256.0f * 2 * pi;
|
|
|
|
|
|
|
|
Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, AngleIntraTick) / 256.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec2 Direction = direction(Angle);
|
|
|
|
vec2 Position;
|
|
|
|
if(in_range(ClientID, MAX_CLIENTS - 1))
|
|
|
|
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
|
|
|
|
else
|
|
|
|
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
|
|
|
|
// draw hook collision line
|
|
|
|
{
|
|
|
|
bool AlwaysRenderHookColl = GameClient()->m_GameInfo.m_AllowHookColl && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) == 2;
|
|
|
|
bool RenderHookCollPlayer = ClientID >= 0 && Player.m_PlayerFlags & PLAYERFLAG_AIM && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) > 0;
|
|
|
|
bool RenderHookCollVideo = true;
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
|
|
|
RenderHookCollVideo = !IVideo::Current() || g_Config.m_ClVideoShowHookCollOther || Local;
|
|
|
|
#endif
|
|
|
|
if((AlwaysRenderHookColl || RenderHookCollPlayer) && RenderHookCollVideo)
|
|
|
|
{
|
|
|
|
vec2 ExDirection = Direction;
|
|
|
|
|
|
|
|
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
2022-04-11 11:32:02 +00:00
|
|
|
{
|
2022-03-30 21:29:35 +00:00
|
|
|
ExDirection = normalize(vec2((int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].x, (int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].y));
|
2022-03-22 20:11:01 +00:00
|
|
|
|
2022-04-11 11:32:02 +00:00
|
|
|
// fix direction if mouse is exactly in the center
|
|
|
|
if(!(int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].x && !(int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].y)
|
|
|
|
ExDirection = vec2(1, 0);
|
|
|
|
}
|
2022-03-22 20:11:01 +00:00
|
|
|
Graphics()->TextureClear();
|
|
|
|
vec2 InitPos = Position;
|
|
|
|
vec2 FinishPos = InitPos + ExDirection * (m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength - 42.0f);
|
|
|
|
|
|
|
|
if(g_Config.m_ClHookCollSize > 0)
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
else
|
|
|
|
Graphics()->LinesBegin();
|
|
|
|
|
|
|
|
ColorRGBA HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorNoColl));
|
|
|
|
|
|
|
|
float PhysSize = 28.0f;
|
|
|
|
|
|
|
|
vec2 OldPos = InitPos + ExDirection * PhysSize * 1.5f;
|
|
|
|
vec2 NewPos = OldPos;
|
|
|
|
|
|
|
|
bool DoBreak = false;
|
|
|
|
int Hit = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
OldPos = NewPos;
|
|
|
|
NewPos = OldPos + ExDirection * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookFireSpeed;
|
|
|
|
|
|
|
|
if(distance(InitPos, NewPos) > m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength)
|
|
|
|
{
|
|
|
|
NewPos = InitPos + normalize(NewPos - InitPos) * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength;
|
|
|
|
DoBreak = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TeleNr = 0;
|
|
|
|
Hit = Collision()->IntersectLineTeleHook(OldPos, NewPos, &FinishPos, 0x0, &TeleNr);
|
|
|
|
|
|
|
|
if(!DoBreak && Hit)
|
|
|
|
{
|
|
|
|
if(Hit != TILE_NOHOOK)
|
|
|
|
{
|
|
|
|
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorHookableColl));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_pClient->IntersectCharacter(OldPos, FinishPos, FinishPos, ClientID) != -1)
|
|
|
|
{
|
|
|
|
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorTeeColl));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Hit)
|
|
|
|
break;
|
|
|
|
|
|
|
|
NewPos.x = round_to_int(NewPos.x);
|
|
|
|
NewPos.y = round_to_int(NewPos.y);
|
|
|
|
|
|
|
|
if(OldPos == NewPos)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ExDirection.x = round_to_int(ExDirection.x * 256.0f) / 256.0f;
|
|
|
|
ExDirection.y = round_to_int(ExDirection.y * 256.0f) / 256.0f;
|
|
|
|
} while(!DoBreak);
|
|
|
|
|
|
|
|
if(AlwaysRenderHookColl && RenderHookCollPlayer)
|
|
|
|
{
|
|
|
|
// invert the hook coll colors when using cl_show_hook_coll_always and +showhookcoll is pressed
|
|
|
|
HookCollColor = color_invert(HookCollColor);
|
|
|
|
}
|
|
|
|
Graphics()->SetColor(HookCollColor.WithAlpha(Alpha));
|
|
|
|
if(g_Config.m_ClHookCollSize > 0)
|
|
|
|
{
|
|
|
|
float LineWidth = 0.5f + (float)(g_Config.m_ClHookCollSize - 1) * 0.25f;
|
|
|
|
vec2 PerpToAngle = normalize(vec2(ExDirection.y, -ExDirection.x)) * GameClient()->m_Camera.m_Zoom;
|
|
|
|
vec2 Pos0 = FinishPos + PerpToAngle * -LineWidth;
|
|
|
|
vec2 Pos1 = FinishPos + PerpToAngle * LineWidth;
|
|
|
|
vec2 Pos2 = InitPos + PerpToAngle * -LineWidth;
|
|
|
|
vec2 Pos3 = InitPos + PerpToAngle * LineWidth;
|
|
|
|
IGraphics::CFreeformItem FreeformItem(Pos0.x, Pos0.y, Pos1.x, Pos1.y, Pos2.x, Pos2.y, Pos3.x, Pos3.y);
|
|
|
|
Graphics()->QuadsDrawFreeform(&FreeformItem, 1);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IGraphics::CLineItem LineItem(InitPos.x, InitPos.y, FinishPos.x, FinishPos.y);
|
|
|
|
Graphics()->LinesDraw(&LineItem, 1);
|
|
|
|
Graphics()->LinesEnd();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayers::RenderHook(
|
|
|
|
const CNetObj_Character *pPrevChar,
|
|
|
|
const CNetObj_Character *pPlayerChar,
|
2017-09-09 22:57:32 +00:00
|
|
|
const CTeeRenderInfo *pRenderInfo,
|
|
|
|
int ClientID,
|
2020-09-26 19:41:58 +00:00
|
|
|
float Intra)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetObj_Character Prev;
|
|
|
|
CNetObj_Character Player;
|
|
|
|
Prev = *pPrevChar;
|
|
|
|
Player = *pPlayerChar;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2017-09-09 22:57:32 +00:00
|
|
|
CTeeRenderInfo RenderInfo = *pRenderInfo;
|
|
|
|
|
2014-08-25 14:53:11 +00:00
|
|
|
// don't render hooks to not active character cores
|
2020-06-25 12:56:23 +00:00
|
|
|
if(pPlayerChar->m_HookedPlayer != -1 && !m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Active)
|
2014-08-25 14:53:11 +00:00
|
|
|
return;
|
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
float IntraTick = Intra;
|
|
|
|
if(ClientID >= 0)
|
2020-02-19 10:24:58 +00:00
|
|
|
IntraTick = (m_pClient->m_aClients[ClientID].m_IsPredicted) ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2019-07-16 20:06:57 +00:00
|
|
|
bool OtherTeam = m_pClient->IsOtherTeam(ClientID);
|
2022-03-30 18:40:46 +00:00
|
|
|
float Alpha = (OtherTeam || ClientID < 0) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f;
|
2014-01-24 22:11:33 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
RenderInfo.m_Size = 64.0f;
|
|
|
|
|
2013-10-09 14:02:23 +00:00
|
|
|
vec2 Position;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(in_range(ClientID, MAX_CLIENTS - 1))
|
2019-04-11 22:46:54 +00:00
|
|
|
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
|
2013-10-09 14:02:23 +00:00
|
|
|
else
|
2019-04-11 22:46:54 +00:00
|
|
|
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// draw hook
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Prev.m_HookState > 0 && Player.m_HookState > 0)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2017-09-09 22:57:32 +00:00
|
|
|
if(ClientID < 0)
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Pos = Position;
|
|
|
|
vec2 HookPos;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(in_range(pPlayerChar->m_HookedPlayer, MAX_CLIENTS - 1))
|
2020-06-25 12:56:23 +00:00
|
|
|
HookPos = m_pClient->m_aClients[pPlayerChar->m_HookedPlayer].m_RenderPos;
|
2010-05-29 07:25:38 +00:00
|
|
|
else
|
2019-04-11 22:46:54 +00:00
|
|
|
HookPos = mix(vec2(Prev.m_HookX, Prev.m_HookY), vec2(Player.m_HookX, Player.m_HookY), IntraTick);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
float d = distance(Pos, HookPos);
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 Dir = normalize(Pos - HookPos);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteHookHead);
|
2014-02-18 16:20:28 +00:00
|
|
|
Graphics()->QuadsSetRotation(angle(Dir) + pi);
|
2010-05-29 07:25:38 +00:00
|
|
|
// render head
|
2018-03-13 20:52:44 +00:00
|
|
|
int QuadOffset = NUM_WEAPONS * 2 + 2;
|
2022-03-30 18:40:46 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, HookPos.x, HookPos.y);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
// render chain
|
2018-03-13 20:52:44 +00:00
|
|
|
++QuadOffset;
|
|
|
|
static IGraphics::SRenderSpriteInfo s_HookChainRenderInfo[1024];
|
|
|
|
int HookChainCount = 0;
|
|
|
|
for(float f = 24; f < d && HookChainCount < 1024; f += 24, ++HookChainCount)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 p = HookPos + Dir * f;
|
2018-03-13 20:52:44 +00:00
|
|
|
s_HookChainRenderInfo[HookChainCount].m_Pos[0] = p.x;
|
|
|
|
s_HookChainRenderInfo[HookChainCount].m_Pos[1] = p.y;
|
|
|
|
|
|
|
|
s_HookChainRenderInfo[HookChainCount].m_Scale = 1;
|
2014-02-18 16:20:28 +00:00
|
|
|
s_HookChainRenderInfo[HookChainCount].m_Rotation = angle(Dir) + pi;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteHookChain);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSpriteMultiple(m_WeaponEmoteQuadContainerIndex, QuadOffset, HookChainCount, s_HookChainRenderInfo);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2022-03-30 18:40:46 +00:00
|
|
|
RenderHand(&RenderInfo, Position, normalize(HookPos - Pos), -pi / 2, vec2(20, 0), Alpha);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPlayers::RenderPlayer(
|
|
|
|
const CNetObj_Character *pPrevChar,
|
|
|
|
const CNetObj_Character *pPlayerChar,
|
2017-09-09 22:57:32 +00:00
|
|
|
const CTeeRenderInfo *pRenderInfo,
|
|
|
|
int ClientID,
|
2020-09-26 19:41:58 +00:00
|
|
|
float Intra)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
CNetObj_Character Prev;
|
|
|
|
CNetObj_Character Player;
|
|
|
|
Prev = *pPrevChar;
|
|
|
|
Player = *pPlayerChar;
|
|
|
|
|
2017-09-09 22:57:32 +00:00
|
|
|
CTeeRenderInfo RenderInfo = *pRenderInfo;
|
|
|
|
|
|
|
|
bool Local = m_pClient->m_Snap.m_LocalClientID == ClientID;
|
2019-07-16 20:06:57 +00:00
|
|
|
bool OtherTeam = m_pClient->IsOtherTeam(ClientID);
|
2022-02-06 18:15:51 +00:00
|
|
|
float Alpha = (OtherTeam || ClientID < 0) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f;
|
2019-05-09 22:57:28 +00:00
|
|
|
|
2008-03-22 10:59:36 +00:00
|
|
|
// set size
|
2010-05-29 07:25:38 +00:00
|
|
|
RenderInfo.m_Size = 64.0f;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
float IntraTick = Intra;
|
|
|
|
if(ClientID >= 0)
|
2020-02-19 10:24:58 +00:00
|
|
|
IntraTick = m_pClient->m_aClients[ClientID].m_IsPredicted ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-02-19 10:24:58 +00:00
|
|
|
static float s_LastGameTickTime = Client()->GameTickTime(g_Config.m_ClDummy);
|
|
|
|
static float s_LastPredIntraTick = Client()->PredIntraGameTick(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))
|
2019-05-11 19:28:25 +00:00
|
|
|
{
|
2020-02-19 10:24:58 +00:00
|
|
|
s_LastGameTickTime = Client()->GameTickTime(g_Config.m_ClDummy);
|
|
|
|
s_LastPredIntraTick = Client()->PredIntraGameTick(g_Config.m_ClDummy);
|
2019-05-11 19:28:25 +00:00
|
|
|
}
|
|
|
|
|
2019-05-11 23:43:06 +00:00
|
|
|
bool PredictLocalWeapons = false;
|
2020-02-19 10:24:58 +00:00
|
|
|
float AttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy);
|
|
|
|
float LastAttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + s_LastGameTickTime;
|
2020-10-10 10:57:48 +00:00
|
|
|
if(ClientID >= 0 && m_pClient->m_aClients[ClientID].m_IsPredictedLocal && m_pClient->AntiPingGunfire())
|
2019-05-11 19:28:25 +00:00
|
|
|
{
|
2019-05-11 23:43:06 +00:00
|
|
|
PredictLocalWeapons = true;
|
2020-02-19 10:24:58 +00:00
|
|
|
AttackTime = (Client()->PredIntraGameTick(g_Config.m_ClDummy) + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)SERVER_TICK_SPEED;
|
|
|
|
LastAttackTime = (s_LastPredIntraTick + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)SERVER_TICK_SPEED;
|
2019-05-11 19:28:25 +00:00
|
|
|
}
|
2022-02-14 16:36:54 +00:00
|
|
|
float AttackTicksPassed = AttackTime * (float)SERVER_TICK_SPEED;
|
2019-05-11 19:28:25 +00:00
|
|
|
|
2015-11-15 14:39:58 +00:00
|
|
|
float Angle;
|
2017-09-09 22:57:32 +00:00
|
|
|
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
2008-10-18 10:30:03 +00:00
|
|
|
{
|
2015-11-15 14:39:58 +00:00
|
|
|
// just use the direct input if it's the local player we are rendering
|
2021-07-12 09:43:56 +00:00
|
|
|
Angle = angle(m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy]);
|
2008-10-18 10:30:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-11 22:46:54 +00:00
|
|
|
float AngleIntraTick = IntraTick;
|
|
|
|
// using unpredicted angle when rendering other players in-game
|
|
|
|
if(ClientID >= 0)
|
2020-02-19 10:24:58 +00:00
|
|
|
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
|
2015-11-15 14:39:58 +00:00
|
|
|
// If the player moves their weapon through top, then change
|
|
|
|
// the end angle by 2*Pi, so that the mix function will use the
|
|
|
|
// short path and not the long one.
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Angle > (256.0f * pi) && Prev.m_Angle < 0)
|
2015-11-14 16:34:48 +00:00
|
|
|
Player.m_Angle -= 256.0f * 2 * pi;
|
2018-03-13 20:52:44 +00:00
|
|
|
else if(Player.m_Angle < 0 && Prev.m_Angle > (256.0f * pi))
|
2015-11-14 16:34:48 +00:00
|
|
|
Player.m_Angle += 256.0f * 2 * pi;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, AngleIntraTick) / 256.0f;
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-01-13 17:41:32 +00:00
|
|
|
vec2 Direction = direction(Angle);
|
2013-10-09 14:02:23 +00:00
|
|
|
vec2 Position;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(in_range(ClientID, MAX_CLIENTS - 1))
|
2019-04-11 22:46:54 +00:00
|
|
|
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
|
2013-10-09 14:02:23 +00:00
|
|
|
else
|
2019-04-11 22:46:54 +00:00
|
|
|
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 Vel = mix(vec2(Prev.m_VelX / 256.0f, Prev.m_VelY / 256.0f), vec2(Player.m_VelX / 256.0f, Player.m_VelY / 256.0f), IntraTick);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Flow.Add(Position, Vel * 100.0f, 10.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
|
|
|
RenderInfo.m_GotAirJump = Player.m_Jumped & 2 ? 0 : 1;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
bool Stationary = Player.m_VelX <= 1 && Player.m_VelX >= -1;
|
2020-09-26 19:41:58 +00:00
|
|
|
bool InAir = !Collision()->CheckPoint(Player.m_X, Player.m_Y + 16);
|
2010-05-29 07:25:38 +00:00
|
|
|
bool WantOtherDir = (Player.m_Direction == -1 && Vel.x > 0) || (Player.m_Direction == 1 && Vel.x < 0);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
|
|
|
// evaluate animation
|
2020-09-26 19:41:58 +00:00
|
|
|
float WalkTime = fmod(absolute(Position.x), 100.0f) / 100.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
CAnimState State;
|
|
|
|
State.Set(&g_pData->m_aAnimations[ANIM_BASE], 0);
|
|
|
|
|
|
|
|
if(InAir)
|
|
|
|
State.Add(&g_pData->m_aAnimations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here
|
|
|
|
else if(Stationary)
|
|
|
|
State.Add(&g_pData->m_aAnimations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here
|
|
|
|
else if(!WantOtherDir)
|
|
|
|
State.Add(&g_pData->m_aAnimations[ANIM_WALK], WalkTime, 1.0f);
|
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Weapon == WEAPON_HAMMER)
|
2020-09-26 19:41:58 +00:00
|
|
|
State.Add(&g_pData->m_aAnimations[ANIM_HAMMER_SWING], clamp(LastAttackTime * 5.0f, 0.0f, 1.0f), 1.0f);
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Weapon == WEAPON_NINJA)
|
2020-09-26 19:41:58 +00:00
|
|
|
State.Add(&g_pData->m_aAnimations[ANIM_NINJA_SWING], clamp(LastAttackTime * 2.0f, 0.0f, 1.0f), 1.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-03-16 22:32:17 +00:00
|
|
|
// do skidding
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!InAir && WantOtherDir && length(Vel * 50) > 500.0f)
|
2008-03-16 22:32:17 +00:00
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
static int64_t SkidSoundTime = 0;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(time() - SkidSoundTime > time_freq() / 10)
|
2008-03-16 22:32:17 +00:00
|
|
|
{
|
2014-10-25 00:52:08 +00:00
|
|
|
if(g_Config.m_SndGame)
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Sounds.PlayAt(CSounds::CHN_WORLD, SOUND_PLAYER_SKID, 0.25f, Position);
|
2016-08-30 23:39:59 +00:00
|
|
|
SkidSoundTime = time();
|
2008-03-16 22:32:17 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.SkidTrail(
|
2020-09-26 19:41:58 +00:00
|
|
|
Position + vec2(-Player.m_Direction * 6, 12),
|
|
|
|
vec2(-Player.m_Direction * 100 * length(Vel), -50));
|
2008-03-16 22:32:17 +00:00
|
|
|
}
|
2008-01-12 17:09:00 +00:00
|
|
|
|
|
|
|
// draw gun
|
|
|
|
{
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle * pi * 2 + Angle);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2017-09-09 22:57:32 +00:00
|
|
|
if(ClientID < 0)
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
2008-01-12 17:09:00 +00:00
|
|
|
// normal weapons
|
2020-09-26 19:41:58 +00:00
|
|
|
int iw = clamp(Player.m_Weapon, 0, NUM_WEAPONS - 1);
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeapons[iw]);
|
2018-03-13 20:52:44 +00:00
|
|
|
int QuadOffset = iw * 2 + (Direction.x < 0 ? 1 : 0);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2019-05-09 22:57:28 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha);
|
2014-01-24 22:11:33 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Dir = Direction;
|
|
|
|
float Recoil = 0.0f;
|
2008-01-12 17:09:00 +00:00
|
|
|
vec2 p;
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Weapon == WEAPON_HAMMER)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
|
|
|
// Static position for hammer
|
2010-05-29 07:25:38 +00:00
|
|
|
p = Position + vec2(State.GetAttach()->m_X, State.GetAttach()->m_Y);
|
|
|
|
p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety;
|
2008-01-12 17:09:00 +00:00
|
|
|
// if attack is under way, bash stuffs
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Direction.x < 0)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2);
|
2010-05-29 07:25:38 +00:00
|
|
|
p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx;
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
else if(Player.m_Weapon == WEAPON_NINJA)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
p = Position;
|
|
|
|
p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Direction.x < 0)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(-pi / 2 - State.GetAttach()->m_Angle * pi * 2);
|
2010-05-29 07:25:38 +00:00
|
|
|
p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx;
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.PowerupShine(p + vec2(32, 0), vec2(32, 12));
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
Graphics()->QuadsSetRotation(-pi / 2 + State.GetAttach()->m_Angle * pi * 2);
|
2021-07-12 09:43:56 +00:00
|
|
|
m_pClient->m_Effects.PowerupShine(p - vec2(32, 0), vec2(32, 12));
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
|
|
|
// HADOKEN
|
2020-09-26 19:41:58 +00:00
|
|
|
if(AttackTime <= 1 / 6.f && g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles;
|
2012-01-09 23:49:31 +00:00
|
|
|
static int s_LastIteX = IteX;
|
2010-11-16 23:38:20 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
|
|
|
if(pInfo->m_Paused)
|
|
|
|
IteX = s_LastIteX;
|
|
|
|
else
|
|
|
|
s_LastIteX = IteX;
|
|
|
|
}
|
2012-01-09 23:49:31 +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)
|
2012-01-09 23:49:31 +00:00
|
|
|
IteX = s_LastIteX;
|
|
|
|
else
|
|
|
|
s_LastIteX = IteX;
|
|
|
|
}
|
2010-11-16 23:38:20 +00:00
|
|
|
if(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX])
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2019-05-11 23:43:06 +00:00
|
|
|
if(PredictLocalWeapons)
|
2020-09-26 19:41:58 +00:00
|
|
|
Dir = vec2(pPlayerChar->m_X, pPlayerChar->m_Y) - vec2(pPrevChar->m_X, pPrevChar->m_Y);
|
2019-05-11 23:43:06 +00:00
|
|
|
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);
|
2020-10-17 17:27:40 +00:00
|
|
|
float HadOkenAngle = 0;
|
|
|
|
if(absolute(Dir.x) > 0.0001f || absolute(Dir.y) > 0.0001f)
|
|
|
|
{
|
|
|
|
Dir = normalize(Dir);
|
2014-02-18 16:20:28 +00:00
|
|
|
HadOkenAngle = angle(Dir);
|
2020-10-17 17:27:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Dir = vec2(1, 0);
|
|
|
|
}
|
2017-09-16 16:31:44 +00:00
|
|
|
Graphics()->QuadsSetRotation(HadOkenAngle);
|
2022-03-20 11:57:50 +00:00
|
|
|
QuadOffset = IteX * 2;
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 DirY(-Dir.y, Dir.x);
|
2010-05-29 07:25:38 +00:00
|
|
|
p = Position;
|
|
|
|
float OffsetX = g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx;
|
|
|
|
p -= Dir * OffsetX;
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[iw][IteX]);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[iw], QuadOffset, p.x, p.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// TODO: should be an animation
|
2010-05-29 07:25:38 +00:00
|
|
|
Recoil = 0;
|
2020-09-26 19:41:58 +00:00
|
|
|
float a = AttackTicksPassed / 5.0f;
|
2008-01-12 17:09:00 +00:00
|
|
|
if(a < 1)
|
2020-09-26 19:41:58 +00:00
|
|
|
Recoil = sinf(a * pi);
|
|
|
|
p = Position + Dir * g_pData->m_Weapons.m_aId[iw].m_Offsetx - Dir * Recoil * 10.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety;
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Weapon == WEAPON_GUN && g_Config.m_ClOldGunPosition)
|
2014-05-06 14:25:00 +00:00
|
|
|
p.y -= 8;
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, p.x, p.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
|
2022-01-07 15:53:40 +00:00
|
|
|
if(RenderInfo.m_ShineDecoration)
|
|
|
|
{
|
|
|
|
if(Direction.x < 0)
|
|
|
|
{
|
2022-01-07 16:12:57 +00:00
|
|
|
m_pClient->m_Effects.PowerupShine(p + vec2(32, 0), vec2(32, 12));
|
2022-01-07 15:53:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-07 16:12:57 +00:00
|
|
|
m_pClient->m_Effects.PowerupShine(p - vec2(32, 0), vec2(32, 12));
|
2022-01-07 15:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
if(Player.m_Weapon == WEAPON_GUN || Player.m_Weapon == WEAPON_SHOTGUN)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
|
|
|
// check if we're firing stuff
|
2020-09-26 19:41:58 +00:00
|
|
|
if(g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles) //prev.attackticks)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2022-03-01 22:47:47 +00:00
|
|
|
float AlphaMuzzle = 0.0f;
|
2019-05-11 19:28:25 +00:00
|
|
|
if(AttackTicksPassed < g_pData->m_Weapons.m_aId[iw].m_Muzzleduration + 3)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
float t = AttackTicksPassed / g_pData->m_Weapons.m_aId[iw].m_Muzzleduration;
|
2022-03-01 22:47:47 +00:00
|
|
|
AlphaMuzzle = mix(2.0f, 0.0f, minimum(1.0f, maximum(0.0f, t)));
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles;
|
2012-01-09 23:49:31 +00:00
|
|
|
static int s_LastIteX = IteX;
|
2012-01-09 22:43:53 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
|
|
|
if(pInfo->m_Paused)
|
|
|
|
IteX = s_LastIteX;
|
|
|
|
else
|
|
|
|
s_LastIteX = IteX;
|
|
|
|
}
|
2012-01-09 23:49:31 +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)
|
2012-01-09 23:49:31 +00:00
|
|
|
IteX = s_LastIteX;
|
|
|
|
else
|
|
|
|
s_LastIteX = IteX;
|
|
|
|
}
|
2022-03-01 22:47:47 +00:00
|
|
|
if(AlphaMuzzle > 0.0f && g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX])
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
float OffsetY = -g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsety;
|
2022-03-20 11:57:50 +00:00
|
|
|
QuadOffset = IteX * 2 + (Direction.x < 0 ? 1 : 0);
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Direction.x < 0)
|
|
|
|
OffsetY = -OffsetY;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 DirY(-Dir.y, Dir.x);
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 MuzzlePos = p + Dir * g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx + DirY * OffsetY;
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponsMuzzles[iw][IteX]);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponSpriteMuzzleQuadContainerIndex[iw], QuadOffset, MuzzlePos.x, MuzzlePos.y);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
switch(Player.m_Weapon)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
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;
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// render the "shadow" tee
|
2020-03-29 21:14:30 +00:00
|
|
|
if(Local && ((g_Config.m_Debug && g_Config.m_ClUnpredictedShadow >= 0) || g_Config.m_ClUnpredictedShadow == 1))
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2019-04-11 22:46:54 +00:00
|
|
|
vec2 GhostPosition = Position;
|
|
|
|
if(ClientID >= 0)
|
|
|
|
GhostPosition = mix(
|
2020-09-26 19:41:58 +00:00
|
|
|
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));
|
2019-04-11 22:46:54 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CTeeRenderInfo Ghost = RenderInfo;
|
2019-04-21 16:20:53 +00:00
|
|
|
RenderTools()->RenderTee(&State, &Ghost, Player.m_Emote, Direction, GhostPosition, 0.5f); // render ghost
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
|
2022-02-06 18:15:51 +00:00
|
|
|
RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position, Alpha);
|
2019-04-21 16:20:53 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
int QuadOffsetToEmoticon = NUM_WEAPONS * 2 + 2 + 2;
|
2020-10-07 19:04:07 +00:00
|
|
|
if((Player.m_PlayerFlags & PLAYERFLAG_CHATTING) && !m_pClient->m_aClients[ClientID].m_Afk)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
int CurEmoticon = (SPRITE_DOTDOT - SPRITE_OOP);
|
|
|
|
Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[CurEmoticon]);
|
|
|
|
int QuadOffset = QuadOffsetToEmoticon + CurEmoticon;
|
2019-05-09 22:57:28 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha);
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x + 24.f, Position.y - 40.f);
|
2019-07-29 12:46:21 +00:00
|
|
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
}
|
|
|
|
|
2019-11-03 17:10:30 +00:00
|
|
|
if(ClientID < 0)
|
|
|
|
return;
|
|
|
|
|
2020-10-07 19:04:07 +00:00
|
|
|
if(g_Config.m_ClAfkEmote && m_pClient->m_aClients[ClientID].m_Afk && !(Client()->DummyConnected() && ClientID == m_pClient->m_LocalIDs[!g_Config.m_ClDummy]))
|
2019-07-29 12:46:21 +00:00
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
int CurEmoticon = (SPRITE_ZZZ - SPRITE_OOP);
|
|
|
|
Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[CurEmoticon]);
|
|
|
|
int QuadOffset = QuadOffsetToEmoticon + CurEmoticon;
|
2019-07-29 12:46:21 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, Alpha);
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x + 24.f, Position.y - 40.f);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
if(g_Config.m_ClShowEmotes && !m_pClient->m_aClients[ClientID].m_EmoticonIgnore && m_pClient->m_aClients[ClientID].m_EmoticonStartTick != -1)
|
2008-01-12 17:09:00 +00:00
|
|
|
{
|
2021-09-14 22:37:06 +00:00
|
|
|
float SinceStart = (Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_aClients[ClientID].m_EmoticonStartTick) + (Client()->IntraGameTickSincePrev(g_Config.m_ClDummy) - m_pClient->m_aClients[ClientID].m_EmoticonStartFraction);
|
|
|
|
float FromEnd = (2 * Client()->GameTickSpeed()) - SinceStart;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
if(0 <= SinceStart && FromEnd > 0)
|
|
|
|
{
|
|
|
|
float a = 1;
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
if(FromEnd < Client()->GameTickSpeed() / 5)
|
|
|
|
a = FromEnd / (Client()->GameTickSpeed() / 5.0f);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
float h = 1;
|
|
|
|
if(SinceStart < Client()->GameTickSpeed() / 10)
|
|
|
|
h = SinceStart / (Client()->GameTickSpeed() / 10.0f);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
float Wiggle = 0;
|
|
|
|
if(SinceStart < Client()->GameTickSpeed() / 5)
|
|
|
|
Wiggle = SinceStart / (Client()->GameTickSpeed() / 5.0f);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
float WiggleAngle = sinf(5 * Wiggle);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
Graphics()->QuadsSetRotation(pi / 6 * WiggleAngle);
|
2008-01-12 17:09:00 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, a * Alpha);
|
|
|
|
// client_datas::emoticon is an offset from the first emoticon
|
|
|
|
int QuadOffset = QuadOffsetToEmoticon + m_pClient->m_aClients[ClientID].m_Emoticon;
|
|
|
|
Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[m_pClient->m_aClients[ClientID].m_Emoticon]);
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_WeaponEmoteQuadContainerIndex, QuadOffset, Position.x, Position.y - 23.f - 32.f * h, 1.f, (64.f * h) / 64.f);
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2021-09-14 22:37:06 +00:00
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
}
|
2013-10-09 14:02:23 +00:00
|
|
|
}
|
2008-01-12 17:09:00 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2022-03-02 22:35:40 +00:00
|
|
|
inline bool CPlayers::IsPlayerInfoAvailable(int ClientID) const
|
|
|
|
{
|
|
|
|
const void *pPrevInfo = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_PLAYERINFO, ClientID);
|
|
|
|
const void *pInfo = Client()->SnapFindItem(IClient::SNAP_CURRENT, NETOBJTYPE_PLAYERINFO, ClientID);
|
|
|
|
return pPrevInfo && pInfo;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayers::OnRender()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2012-01-08 14:44:49 +00:00
|
|
|
// update RenderInfo for ninja
|
|
|
|
bool IsTeamplay = false;
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj)
|
2020-09-26 19:41:58 +00:00
|
|
|
IsTeamplay = (m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) != 0;
|
2012-01-08 14:44:49 +00:00
|
|
|
for(int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
{
|
|
|
|
m_aRenderInfo[i] = m_pClient->m_aClients[i].m_RenderInfo;
|
2022-01-07 15:53:40 +00:00
|
|
|
m_aRenderInfo[i].m_ShineDecoration = m_pClient->m_aClients[i].m_LiveFrozen;
|
2014-03-28 12:39:30 +00:00
|
|
|
if(m_pClient->m_Snap.m_aCharacters[i].m_Cur.m_Weapon == WEAPON_NINJA && g_Config.m_ClShowNinja)
|
2012-01-08 14:44:49 +00:00
|
|
|
{
|
|
|
|
// change the skin for the player to the ninja
|
2021-07-12 09:43:56 +00:00
|
|
|
int Skin = m_pClient->m_Skins.Find("x_ninja");
|
2012-01-08 14:44:49 +00:00
|
|
|
if(Skin != -1)
|
|
|
|
{
|
2021-07-12 09:43:56 +00:00
|
|
|
const CSkin *pSkin = m_pClient->m_Skins.Get(Skin);
|
2020-10-09 07:07:05 +00:00
|
|
|
m_aRenderInfo[i].m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
|
|
|
m_aRenderInfo[i].m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
|
|
|
m_aRenderInfo[i].m_BloodColor = pSkin->m_BloodColor;
|
2020-11-08 05:39:16 +00:00
|
|
|
m_aRenderInfo[i].m_SkinMetrics = pSkin->m_Metrics;
|
2020-10-09 07:07:05 +00:00
|
|
|
m_aRenderInfo[i].m_CustomColoredSkin = IsTeamplay;
|
|
|
|
if(!IsTeamplay)
|
2012-01-08 14:44:49 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aRenderInfo[i].m_ColorBody = ColorRGBA(1, 1, 1);
|
|
|
|
m_aRenderInfo[i].m_ColorFeet = ColorRGBA(1, 1, 1);
|
2012-01-08 14:44:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-12 09:43:56 +00:00
|
|
|
int Skin = m_pClient->m_Skins.Find("x_spec");
|
|
|
|
const CSkin *pSkin = m_pClient->m_Skins.Get(Skin);
|
2020-10-09 07:07:05 +00:00
|
|
|
m_RenderInfoSpec.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
|
|
|
m_RenderInfoSpec.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
|
|
|
m_RenderInfoSpec.m_BloodColor = pSkin->m_BloodColor;
|
2020-11-08 05:39:16 +00:00
|
|
|
m_RenderInfoSpec.m_SkinMetrics = pSkin->m_Metrics;
|
2020-10-09 07:07:05 +00:00
|
|
|
m_RenderInfoSpec.m_CustomColoredSkin = false;
|
2020-06-25 12:56:23 +00:00
|
|
|
m_RenderInfoSpec.m_Size = 64.0f;
|
2022-03-02 22:35:40 +00:00
|
|
|
int LocalClientID = m_pClient->m_Snap.m_LocalClientID;
|
2012-01-08 14:44:49 +00:00
|
|
|
|
2022-03-22 16:20:21 +00:00
|
|
|
// get screen edges to avoid rendering offscreen
|
|
|
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
|
|
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
|
|
|
// expand the edges to prevent popping in/out onscreen
|
2022-03-24 13:36:17 +00:00
|
|
|
//
|
|
|
|
// it is assumed that the tee, all its weapons, and emotes fit into a 200x200 box centered on the tee
|
|
|
|
// this may need to be changed or calculated differently in the future
|
2022-03-22 16:20:21 +00:00
|
|
|
float BorderBuffer = 100;
|
|
|
|
ScreenX0 -= BorderBuffer;
|
|
|
|
ScreenX1 += BorderBuffer;
|
|
|
|
ScreenY0 -= BorderBuffer;
|
|
|
|
ScreenY1 += BorderBuffer;
|
|
|
|
|
2022-03-02 22:35:40 +00:00
|
|
|
// render everyone else's hook, then our own
|
|
|
|
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2022-03-02 22:35:40 +00:00
|
|
|
if(ClientID == LocalClientID || !m_pClient->m_Snap.m_aCharacters[ClientID].m_Active || !IsPlayerInfoAvailable(ClientID))
|
2009-01-11 17:55:23 +00:00
|
|
|
{
|
2022-03-02 22:35:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
RenderHook(&m_pClient->m_aClients[ClientID].m_RenderPrev, &m_pClient->m_aClients[ClientID].m_RenderCur, &m_aRenderInfo[ClientID], ClientID);
|
|
|
|
}
|
|
|
|
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && IsPlayerInfoAvailable(LocalClientID))
|
|
|
|
{
|
|
|
|
const CGameClient::CClientData *pLocalClientData = &m_pClient->m_aClients[LocalClientID];
|
2022-03-12 17:48:04 +00:00
|
|
|
RenderHook(&pLocalClientData->m_RenderPrev, &pLocalClientData->m_RenderCur, &m_aRenderInfo[LocalClientID], LocalClientID);
|
2022-03-02 22:35:40 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2022-03-02 22:35:40 +00:00
|
|
|
// render spectating players
|
|
|
|
for(auto &m_aClient : m_pClient->m_aClients)
|
|
|
|
{
|
|
|
|
if(!m_aClient.m_SpecCharPresent)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
RenderTools()->RenderTee(CAnimState::GetIdle(), &m_RenderInfoSpec, EMOTE_BLINK, vec2(1, 0), m_aClient.m_SpecChar);
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2022-03-02 22:35:40 +00:00
|
|
|
// render everyone else's tee, then our own
|
|
|
|
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
|
|
|
|
{
|
|
|
|
if(ClientID == LocalClientID || !m_pClient->m_Snap.m_aCharacters[ClientID].m_Active || !IsPlayerInfoAvailable(ClientID))
|
|
|
|
{
|
|
|
|
continue;
|
2009-01-11 17:55:23 +00:00
|
|
|
}
|
2022-03-22 16:20:21 +00:00
|
|
|
|
2022-03-22 20:11:01 +00:00
|
|
|
RenderHookCollLine(&m_pClient->m_aClients[ClientID].m_RenderPrev, &m_pClient->m_aClients[ClientID].m_RenderCur, ClientID);
|
|
|
|
|
2022-03-22 16:20:21 +00:00
|
|
|
//don't render offscreen
|
|
|
|
vec2 *pRenderPos = &m_pClient->m_aClients[ClientID].m_RenderPos;
|
|
|
|
if(pRenderPos->x < ScreenX0 || pRenderPos->x > ScreenX1 || pRenderPos->y < ScreenY0 || pRenderPos->y > ScreenY1)
|
|
|
|
{
|
2022-03-22 20:11:01 +00:00
|
|
|
continue;
|
2022-03-22 16:20:21 +00:00
|
|
|
}
|
2022-03-02 22:35:40 +00:00
|
|
|
RenderPlayer(&m_pClient->m_aClients[ClientID].m_RenderPrev, &m_pClient->m_aClients[ClientID].m_RenderCur, &m_aRenderInfo[ClientID], ClientID);
|
|
|
|
}
|
|
|
|
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && IsPlayerInfoAvailable(LocalClientID))
|
|
|
|
{
|
|
|
|
const CGameClient::CClientData *pLocalClientData = &m_pClient->m_aClients[LocalClientID];
|
2022-03-22 20:11:01 +00:00
|
|
|
RenderHookCollLine(&pLocalClientData->m_RenderPrev, &pLocalClientData->m_RenderCur, LocalClientID);
|
2022-03-12 17:48:04 +00:00
|
|
|
RenderPlayer(&pLocalClientData->m_RenderPrev, &pLocalClientData->m_RenderCur, &m_aRenderInfo[LocalClientID], LocalClientID);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
void CPlayers::OnInit()
|
|
|
|
{
|
2021-09-13 21:14:04 +00:00
|
|
|
m_WeaponEmoteQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
|
|
|
for(int i = 0; i < NUM_WEAPONS; ++i)
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
float ScaleX, ScaleY;
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleX, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleY);
|
|
|
|
Graphics()->QuadsSetSubset(0, 1, 1, 0);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, 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
|
|
|
}
|
2020-10-09 07:07:05 +00:00
|
|
|
float ScaleX, ScaleY;
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
// at the end the hand
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, 20.f);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, 20.f);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2018-03-13 20:52:44 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, -12.f, -8.f, 24.f, 16.f);
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2018-03-13 20:52:44 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, -12.f, -8.f, 24.f, 16.f);
|
|
|
|
|
|
|
|
for(int i = 0; i < NUM_EMOTICONS; ++i)
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponEmoteQuadContainerIndex, 64.f);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
2021-09-13 21:14:04 +00:00
|
|
|
Graphics()->QuadContainerUpload(m_WeaponEmoteQuadContainerIndex);
|
2019-04-21 16:20:53 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
for(int i = 0; i < NUM_WEAPONS; ++i)
|
|
|
|
{
|
2021-09-13 21:14:04 +00:00
|
|
|
m_WeaponSpriteMuzzleQuadContainerIndex[i] = Graphics()->CreateQuadContainer(false);
|
2018-03-13 20:52:44 +00:00
|
|
|
for(int n = 0; n < g_pData->m_Weapons.m_aId[i].m_NumSpriteMuzzles; ++n)
|
|
|
|
{
|
|
|
|
if(g_pData->m_Weapons.m_aId[i].m_aSpriteMuzzles[n])
|
|
|
|
{
|
2020-10-25 13:32:41 +00:00
|
|
|
if(i == WEAPON_GUN || i == WEAPON_SHOTGUN)
|
|
|
|
{
|
|
|
|
// TODO: hardcoded for now to get the same particle size as before
|
|
|
|
RenderTools()->GetSpriteScaleImpl(96, 64, ScaleX, ScaleY);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_aSpriteMuzzles[n], ScaleX, ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
2020-10-25 13:34:02 +00:00
|
|
|
|
2020-10-25 13:32:41 +00:00
|
|
|
float SWidth = (g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleX) * (4.0f / 3.0f);
|
|
|
|
float SHeight = g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleY;
|
|
|
|
|
2020-10-25 13:34:02 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
2018-03-13 20:52:44 +00:00
|
|
|
if(WEAPON_NINJA == i)
|
2020-10-09 07:07:05 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponSpriteMuzzleQuadContainerIndex[i], 160.f * ScaleX, 160.f * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
else
|
2020-10-25 13:32:41 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponSpriteMuzzleQuadContainerIndex[i], SWidth, SHeight);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 1, 1, 0);
|
2018-03-13 20:52:44 +00:00
|
|
|
if(WEAPON_NINJA == i)
|
2020-10-09 07:07:05 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponSpriteMuzzleQuadContainerIndex[i], 160.f * ScaleX, 160.f * ScaleY);
|
2018-03-13 20:52:44 +00:00
|
|
|
else
|
2020-10-25 13:32:41 +00:00
|
|
|
RenderTools()->QuadContainerAddSprite(m_WeaponSpriteMuzzleQuadContainerIndex[i], SWidth, SHeight);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
2021-09-13 21:14:04 +00:00
|
|
|
Graphics()->QuadContainerUpload(m_WeaponSpriteMuzzleQuadContainerIndex[i]);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Graphics()->QuadsSetSubset(0.f, 0.f, 1.f, 1.f);
|
|
|
|
Graphics()->QuadsSetRotation(0.f);
|
|
|
|
}
|