ddnet/src/game/client/components/players.cpp

588 lines
19 KiB
C++
Raw Normal View History

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. */
#include <engine/demo.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/shared/config.h>
#include <game/generated/protocol.h>
#include <game/generated/client_data.h>
#include <game/gamecore.h> // get_angle
#include <game/client/animstate.h>
#include <game/client/gameclient.h>
#include <game/client/ui.h>
#include <game/client/render.h>
#include <game/client/components/flow.h>
#include <game/client/components/skins.h>
#include <game/client/components/effects.h>
#include <game/client/components/sounds.h>
#include <game/client/components/controls.h>
#include "players.h"
void CPlayers::RenderHand(CTeeRenderInfo *pInfo, vec2 CenterPos, vec2 Dir, float AngleOffset, vec2 PostRotOffset)
2008-01-12 17:09:00 +00:00
{
// for drawing hand
//const skin *s = skin_get(skin_id);
2010-05-29 07:25:38 +00:00
float BaseSize = 10.0f;
2008-01-12 17:09:00 +00:00
//dir = normalize(hook_pos-pos);
2010-05-29 07:25:38 +00:00
vec2 HandPos = CenterPos + Dir;
float Angle = GetAngle(Dir);
if (Dir.x < 0)
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;
vec2 DirY(-Dir.y,Dir.x);
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
if (Dir.x < 0)
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
2010-05-29 07:25:38 +00:00
//Graphics()->TextureSet(data->m_aImages[IMAGE_CHAR_DEFAULT].id);
Graphics()->TextureSet(pInfo->m_Texture);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, pInfo->m_ColorBody.a);
2008-01-12 17:09:00 +00:00
// two passes
for (int i = 0; i < 2; i++)
{
2010-05-29 07:25:38 +00:00
bool OutLine = i == 0;
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(OutLine?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0);
Graphics()->QuadsSetRotation(Angle);
IGraphics::CQuadItem QuadItem(HandPos.x, HandPos.y, 2*BaseSize, 2*BaseSize);
Graphics()->QuadsDraw(&QuadItem, 1);
2008-01-12 17:09:00 +00:00
}
2009-10-27 14:38:53 +00:00
Graphics()->QuadsSetRotation(0);
Graphics()->QuadsEnd();
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +00:00
inline float NormalizeAngular(float f)
{
2008-10-18 10:30:03 +00:00
return fmod(f+pi*2, pi*2);
}
2010-05-29 07:25:38 +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)
{
2010-05-29 07:25:38 +00:00
float d = AngularMixDirection (Src, Dst);
float n = Src + Amount*d;
if(AngularMixDirection (n, Dst) != d)
return Dst;
2008-10-18 10:30:03 +00:00
return n;
}
2010-05-29 07:25:38 +00:00
void CPlayers::RenderHook(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo
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
2010-05-29 07:25:38 +00:00
CNetObj_PlayerInfo pInfo = *pPlayerInfo;
CTeeRenderInfo RenderInfo = m_pClient->m_aClients[pInfo.m_ClientID].m_RenderInfo;
// check for teamplay modes
2010-05-29 07:25:38 +00:00
bool IsTeamplay = false;
if(m_pClient->m_Snap.m_pGameobj)
IsTeamplay = (m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS) != 0;
// check for ninja
2010-05-29 07:25:38 +00:00
if (Player.m_Weapon == WEAPON_NINJA)
{
// change the skin for the player to the ninja
2010-05-29 07:25:38 +00:00
int Skin = m_pClient->m_pSkins->Find("x_ninja");
if(Skin != -1)
{
2010-05-29 07:25:38 +00:00
if(IsTeamplay)
RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_ColorTexture;
else
{
2010-05-29 07:25:38 +00:00
RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_OrgTexture;
RenderInfo.m_ColorBody = vec4(1,1,1,1);
RenderInfo.m_ColorFeet = vec4(1,1,1,1);
}
}
}
float IntraTick = Client()->IntraGameTick();
// set size
RenderInfo.m_Size = 64.0f;
// use preditect players if needed
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
2011-01-18 17:53:19 +00:00
if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver))
2010-05-29 07:25:38 +00:00
{
}
else
{
// apply predicted results
m_pClient->m_PredictedChar.Write(&Player);
m_pClient->m_PredictedPrevChar.Write(&Prev);
IntraTick = Client()->PredIntraGameTick();
}
}
vec2 Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
// draw hook
if (Prev.m_HookState>0 && Player.m_HookState>0)
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
//Graphics()->QuadsBegin();
vec2 Pos = Position;
vec2 HookPos;
if(pPlayerChar->m_HookedPlayer != -1)
{
if(m_pClient->m_Snap.m_pLocalInfo && pPlayerChar->m_HookedPlayer == m_pClient->m_Snap.m_pLocalInfo->m_ClientID)
2010-05-29 07:25:38 +00:00
{
if(Client()->State() == IClient::STATE_DEMOPLAYBACK) // only use prediction if needed
HookPos = vec2(m_pClient->m_LocalCharacterPos.x, m_pClient->m_LocalCharacterPos.y);
else
HookPos = mix(vec2(m_pClient->m_PredictedPrevChar.m_Pos.x, m_pClient->m_PredictedPrevChar.m_Pos.y),
vec2(m_pClient->m_PredictedChar.m_Pos.x, m_pClient->m_PredictedChar.m_Pos.y), Client()->PredIntraGameTick());
}
else if(pInfo.m_Local)
{
HookPos = mix(vec2(m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Prev.m_X,
m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Prev.m_Y),
vec2(m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Cur.m_X,
m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Cur.m_Y),
Client()->IntraGameTick());
}
2010-05-29 07:25:38 +00:00
else
HookPos = mix(vec2(pPrevChar->m_HookX, pPrevChar->m_HookY), vec2(pPlayerChar->m_HookX, pPlayerChar->m_HookY), Client()->IntraGameTick());
}
else
HookPos = mix(vec2(Prev.m_HookX, Prev.m_HookY), vec2(Player.m_HookX, Player.m_HookY), IntraTick);
float d = distance(Pos, HookPos);
vec2 Dir = normalize(Pos-HookPos);
Graphics()->QuadsSetRotation(GetAngle(Dir)+pi);
// render head
RenderTools()->SelectSprite(SPRITE_HOOK_HEAD);
IGraphics::CQuadItem QuadItem(HookPos.x, HookPos.y, 24,16);
Graphics()->QuadsDraw(&QuadItem, 1);
// render chain
RenderTools()->SelectSprite(SPRITE_HOOK_CHAIN);
IGraphics::CQuadItem Array[1024];
int i = 0;
for(float f = 24; f < d && i < 1024; f += 24, i++)
{
vec2 p = HookPos + Dir*f;
Array[i] = IGraphics::CQuadItem(p.x, p.y,24,16);
}
Graphics()->QuadsDraw(Array, i);
Graphics()->QuadsSetRotation(0);
Graphics()->QuadsEnd();
RenderHand(&RenderInfo, Position, normalize(HookPos-Pos), -pi/2, vec2(20, 0));
}
}
void CPlayers::RenderPlayer(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo
)
{
CNetObj_Character Prev;
CNetObj_Character Player;
Prev = *pPrevChar;
Player = *pPlayerChar;
CNetObj_PlayerInfo pInfo = *pPlayerInfo;
CTeeRenderInfo RenderInfo = m_pClient->m_aClients[pInfo.m_ClientID].m_RenderInfo;
2010-05-29 07:25:38 +00:00
// check for teamplay modes
bool IsTeamplay = false;
bool NewTick = m_pClient->m_NewTick;
if(m_pClient->m_Snap.m_pGameobj)
IsTeamplay = (m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS) != 0;
// check for ninja
if (Player.m_Weapon == WEAPON_NINJA)
{
// change the skin for the player to the ninja
int Skin = m_pClient->m_pSkins->Find("x_ninja");
if(Skin != -1)
{
if(IsTeamplay)
RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_ColorTexture;
else
{
RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_OrgTexture;
RenderInfo.m_ColorBody = vec4(1,1,1,1);
RenderInfo.m_ColorFeet = vec4(1,1,1,1);
}
}
}
// set size
2010-05-29 07:25:38 +00:00
RenderInfo.m_Size = 64.0f;
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
float IntraTick = Client()->IntraGameTick();
2008-03-10 19:36:05 +00:00
2010-05-29 07:25:38 +00:00
float Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, IntraTick)/256.0f;
//float angle = 0;
2010-05-29 07:25:38 +00:00
if(pInfo.m_Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
2008-10-18 10:30:03 +00:00
{
// just use the direct input if it's local player we are rendering
2010-05-29 07:25:38 +00:00
Angle = GetAngle(m_pClient->m_pControls->m_MousePos);
2008-10-18 10:30:03 +00:00
}
else
{
/*
2010-05-29 07:25:38 +00:00
float mixspeed = Client()->FrameTime()*2.5f;
2008-10-18 10:30:03 +00:00
if(player.attacktick != prev.attacktick) // shooting boosts the mixing speed
mixspeed *= 15.0f;
// move the delta on a constant speed on a x^2 curve
2010-05-29 07:25:38 +00:00
float current = g_GameClient.m_aClients[info.cid].angle;
2008-10-18 10:30:03 +00:00
float target = player.angle/256.0f;
float delta = angular_distance(current, target);
float sign = delta < 0 ? -1 : 1;
float new_delta = delta - 2*mixspeed*sqrt(delta*sign)*sign + mixspeed*mixspeed;
// make sure that it doesn't vibrate when it's still
if(fabs(delta) < 2/256.0f)
angle = target;
else
angle = angular_approach(current, target, fabs(delta-new_delta));
2010-05-29 07:25:38 +00:00
g_GameClient.m_aClients[info.cid].angle = angle;*/
2008-10-18 10:30:03 +00:00
}
2008-10-18 10:30:03 +00:00
// use preditect players if needed
2010-05-29 07:25:38 +00:00
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
2008-01-12 17:09:00 +00:00
{
2011-01-18 17:53:19 +00:00
if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver))
2008-01-12 17:09:00 +00:00
{
}
else
{
// apply predicted results
2010-05-29 07:25:38 +00:00
m_pClient->m_PredictedChar.Write(&Player);
m_pClient->m_PredictedPrevChar.Write(&Prev);
IntraTick = Client()->PredIntraGameTick();
NewTick = m_pClient->m_NewPredictedTick;
2008-01-12 17:09:00 +00:00
}
}
2008-10-14 12:11:42 +00:00
2010-05-29 07:25:38 +00:00
vec2 Direction = GetDirection((int)(Angle*256.0f));
vec2 Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
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);
2010-05-29 07:25:38 +00:00
m_pClient->m_pFlow->Add(Position, Vel*100.0f, 10.0f);
2010-05-29 07:25:38 +00:00
RenderInfo.m_GotAirJump = Player.m_Jumped&2?0:1;
// detect events
2010-05-29 07:25:38 +00:00
if(NewTick)
{
// detect air jump
2010-05-29 07:25:38 +00:00
if(!RenderInfo.m_GotAirJump && !(Prev.m_Jumped&2))
m_pClient->m_pEffects->AirJump(Position);
}
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
bool Stationary = Player.m_VelX <= 1 && Player.m_VelX >= -1;
bool InAir = !Collision()->CheckPoint(Player.m_X, Player.m_Y+16);
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
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);
if (Player.m_Weapon == WEAPON_HAMMER)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
float ct = (Client()->PrevGameTick()-Player.m_AttackTick)/(float)SERVER_TICK_SPEED + Client()->GameTickTime();
State.Add(&g_pData->m_aAnimations[ANIM_HAMMER_SWING], clamp(ct*5.0f,0.0f,1.0f), 1.0f);
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +00:00
if (Player.m_Weapon == WEAPON_NINJA)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
float ct = (Client()->PrevGameTick()-Player.m_AttackTick)/(float)SERVER_TICK_SPEED + Client()->GameTickTime();
State.Add(&g_pData->m_aAnimations[ANIM_NINJA_SWING], clamp(ct*2.0f,0.0f,1.0f), 1.0f);
2008-01-12 17:09:00 +00:00
}
// do skidding
2010-05-29 07:25:38 +00:00
if(!InAir && WantOtherDir && length(Vel*50) > 500.0f)
{
2010-05-29 07:25:38 +00:00
static int64 SkidSoundTime = 0;
if(time_get()-SkidSoundTime > time_freq()/10)
{
2010-05-29 07:25:38 +00:00
m_pClient->m_pSounds->Play(CSounds::CHN_WORLD, SOUND_PLAYER_SKID, 0.25f, Position);
SkidSoundTime = time_get();
}
2010-05-29 07:25:38 +00:00
m_pClient->m_pEffects->SkidTrail(
Position+vec2(-Player.m_Direction*6,12),
vec2(-Player.m_Direction*100*length(Vel),-50)
);
}
2008-01-12 17:09:00 +00:00
// draw gun
{
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle*pi*2+Angle);
2008-01-12 17:09:00 +00:00
// normal weapons
2010-05-29 07:25:38 +00:00
int iw = clamp(Player.m_Weapon, 0, NUM_WEAPONS-1);
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_pSpriteBody, Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
2008-01-12 17:09:00 +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;
2010-05-29 07:25:38 +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
{
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(-pi/2-State.GetAttach()->m_Angle*pi*2);
p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx;
2008-01-12 17:09:00 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(-pi/2+State.GetAttach()->m_Angle*pi*2);
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +00:00
RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize);
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +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
{
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(-pi/2-State.GetAttach()->m_Angle*pi*2);
p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx;
m_pClient->m_pEffects->PowerupShine(p+vec2(32,0), vec2(32,12));
2008-01-12 17:09:00 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(-pi/2+State.GetAttach()->m_Angle*pi*2);
m_pClient->m_pEffects->PowerupShine(p-vec2(32,0), vec2(32,12));
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +00:00
RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize);
2008-01-12 17:09:00 +00:00
// HADOKEN
2010-05-29 07:25:38 +00:00
if ((Client()->GameTick()-Player.m_AttackTick) <= (SERVER_TICK_SPEED / 6) && 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;
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
static int s_LastIteX = IteX;
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
if(pInfo->m_Paused)
IteX = s_LastIteX;
else
s_LastIteX = IteX;
}
if(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
vec2 Dir = vec2(pPlayerChar->m_X,pPlayerChar->m_Y) - vec2(pPrevChar->m_X, pPrevChar->m_Y);
Dir = normalize(Dir);
float HadOkenAngle = GetAngle(Dir);
Graphics()->QuadsSetRotation(HadOkenAngle );
2008-01-12 17:09:00 +00:00
//float offsety = -data->weapons[iw].muzzleoffsety;
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX], 0);
vec2 DirY(-Dir.y,Dir.x);
p = Position;
float OffsetX = g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx;
p -= Dir * OffsetX;
RenderTools()->DrawSprite(p.x, p.y, 160.0f);
2008-01-12 17:09:00 +00:00
}
}
}
else
{
// TODO: should be an animation
2010-05-29 07:25:38 +00:00
Recoil = 0;
float a = (Client()->GameTick()-Player.m_AttackTick+IntraTick)/5.0f;
2008-01-12 17:09:00 +00:00
if(a < 1)
2010-05-29 07:25:38 +00:00
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;
RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize);
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +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
2010-05-29 07:25:38 +00:00
if(g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles)//prev.attackticks)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
float Alpha = 0.0f;
int Phase1Tick = (Client()->GameTick() - Player.m_AttackTick);
if (Phase1Tick < (g_pData->m_Weapons.m_aId[iw].m_Muzzleduration + 3))
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
float t = ((((float)Phase1Tick) + IntraTick)/(float)g_pData->m_Weapons.m_aId[iw].m_Muzzleduration);
Alpha = mix(2.0f, 0.0f, min(1.0f,max(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;
if (Alpha > 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;
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX], Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
if(Direction.x < 0)
OffsetY = -OffsetY;
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
vec2 DirY(-Dir.y,Dir.x);
vec2 MuzzlePos = p + Dir * g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx + DirY * OffsetY;
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
RenderTools()->DrawSprite(MuzzlePos.x, MuzzlePos.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize);
2008-01-12 17:09:00 +00:00
}
}
}
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
switch (Player.m_Weapon)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
case WEAPON_GUN: RenderHand(&RenderInfo, p, Direction, -3*pi/4, vec2(-15, 4)); break;
case WEAPON_SHOTGUN: RenderHand(&RenderInfo, p, Direction, -pi/2, vec2(-5, 4)); break;
case WEAPON_GRENADE: RenderHand(&RenderInfo, p, Direction, -pi/2, vec2(-4, 7)); break;
2008-01-12 17:09:00 +00:00
}
}
// render the "shadow" tee
2010-05-29 07:25:38 +00:00
if(pInfo.m_Local && g_Config.m_Debug)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
vec2 GhostPosition = mix(vec2(pPrevChar->m_X, pPrevChar->m_Y), vec2(pPlayerChar->m_X, pPlayerChar->m_Y), Client()->IntraGameTick());
CTeeRenderInfo Ghost = RenderInfo;
Ghost.m_ColorBody.a = 0.5f;
Ghost.m_ColorFeet.a = 0.5f;
RenderTools()->RenderTee(&State, &Ghost, Player.m_Emote, Direction, GhostPosition); // render ghost
2008-01-12 17:09:00 +00:00
}
2010-05-29 07:25:38 +00:00
RenderInfo.m_Size = 64.0f; // force some settings
RenderInfo.m_ColorBody.a = 1.0f;
RenderInfo.m_ColorFeet.a = 1.0f;
RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position);
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
if(Player.m_PlayerState == PLAYERSTATE_CHATTING)
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(SPRITE_DOTDOT);
IGraphics::CQuadItem QuadItem(Position.x + 24, Position.y - 40, 64,64);
Graphics()->QuadsDraw(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2008-01-12 17:09:00 +00:00
}
if (m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart != -1 && m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() > Client()->GameTick())
2008-01-12 17:09:00 +00:00
{
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2008-01-12 17:09:00 +00:00
int SinceStart = Client()->GameTick() - m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart;
int FromEnd = m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() - Client()->GameTick();
2008-01-12 17:09:00 +00:00
float a = 1;
2010-05-29 07:25:38 +00:00
if (FromEnd < Client()->GameTickSpeed() / 5)
a = FromEnd / (Client()->GameTickSpeed() / 5.0);
2008-01-12 17:09:00 +00:00
float h = 1;
2010-05-29 07:25:38 +00:00
if (SinceStart < Client()->GameTickSpeed() / 10)
h = SinceStart / (Client()->GameTickSpeed() / 10.0);
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
float Wiggle = 0;
if (SinceStart < Client()->GameTickSpeed() / 5)
Wiggle = SinceStart / (Client()->GameTickSpeed() / 5.0);
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
float WiggleAngle = sinf(5*Wiggle);
2008-01-12 17:09:00 +00:00
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(pi/6*WiggleAngle);
2008-01-12 17:09:00 +00:00
2009-10-27 14:38:53 +00:00
Graphics()->SetColor(1.0f,1.0f,1.0f,a);
2008-01-12 17:09:00 +00:00
// client_datas::emoticon is an offset from the first emoticon
RenderTools()->SelectSprite(SPRITE_OOP + m_pClient->m_aClients[pInfo.m_ClientID].m_Emoticon);
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(Position.x, Position.y - 23 - 32*h, 64, 64*h);
Graphics()->QuadsDraw(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2008-01-12 17:09:00 +00:00
}
}
2010-05-29 07:25:38 +00:00
void CPlayers::OnRender()
{
// render other players in two passes, first pass we render the other, second pass we render our self
2010-05-29 07:25:38 +00:00
for(int p = 0; p < 4; p++)
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
// only render active characters
2010-05-29 07:25:38 +00:00
if(!m_pClient->m_Snap.m_aCharacters[i].m_Active)
continue;
2010-05-29 07:25:38 +00:00
const void *pPrevInfo = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_PLAYERINFO, i);
const void *pInfo = Client()->SnapFindItem(IClient::SNAP_CURRENT, NETOBJTYPE_PLAYERINFO, i);
2010-05-29 07:25:38 +00:00
if(pPrevInfo && pInfo)
{
//
2010-05-29 07:25:38 +00:00
bool Local = ((const CNetObj_PlayerInfo *)pInfo)->m_Local !=0;
if((p % 2) == 0 && Local) continue;
if((p % 2) == 1 && !Local) continue;
2010-05-29 07:25:38 +00:00
CNetObj_Character PrevChar = m_pClient->m_Snap.m_aCharacters[i].m_Prev;
CNetObj_Character CurChar = m_pClient->m_Snap.m_aCharacters[i].m_Cur;
if(p<2)
RenderHook(
&PrevChar,
&CurChar,
(const CNetObj_PlayerInfo *)pPrevInfo,
(const CNetObj_PlayerInfo *)pInfo
);
else
RenderPlayer(
&PrevChar,
&CurChar,
(const CNetObj_PlayerInfo *)pPrevInfo,
(const CNetObj_PlayerInfo *)pInfo
);
}
}
}
}