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

368 lines
12 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. */
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/demo.h>
2010-05-29 07:25:38 +00:00
#include <game/generated/protocol.h>
#include <game/generated/client_data.h>
2013-10-09 14:02:23 +00:00
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
#include <game/gamecore.h> // get_angle
#include <game/client/gameclient.h>
#include <game/client/ui.h>
#include <game/client/render.h>
2010-05-29 07:25:38 +00:00
#include <game/client/components/flow.h>
#include <game/client/components/effects.h>
2010-05-29 07:25:38 +00:00
#include "items.h"
2013-10-09 14:02:23 +00:00
#include <stdio.h>
#include <engine/serverbrowser.h>
2011-04-03 08:11:23 +00:00
void CItems::OnReset()
{
2011-09-06 13:27:56 +00:00
m_NumExtraProjectiles = 0;
2011-04-03 08:11:23 +00:00
}
void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID)
{
// get positions
2010-05-29 07:25:38 +00:00
float Curvature = 0;
float Speed = 0;
if(pCurrent->m_Type == WEAPON_GRENADE)
{
Curvature = m_pClient->m_Tuning[g_Config.m_ClDummy].m_GrenadeCurvature;
Speed = m_pClient->m_Tuning[g_Config.m_ClDummy].m_GrenadeSpeed;
}
2010-05-29 07:25:38 +00:00
else if(pCurrent->m_Type == WEAPON_SHOTGUN)
{
Curvature = m_pClient->m_Tuning[g_Config.m_ClDummy].m_ShotgunCurvature;
Speed = m_pClient->m_Tuning[g_Config.m_ClDummy].m_ShotgunSpeed;
}
2010-05-29 07:25:38 +00:00
else if(pCurrent->m_Type == WEAPON_GUN)
{
Curvature = m_pClient->m_Tuning[g_Config.m_ClDummy].m_GunCurvature;
Speed = m_pClient->m_Tuning[g_Config.m_ClDummy].m_GunSpeed;
}
2012-01-09 23:49:31 +00:00
static float s_LastGameTickTime = Client()->GameTickTime();
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
s_LastGameTickTime = Client()->GameTickTime();
float Ct = (Client()->PrevGameTick()-pCurrent->m_StartTick)/(float)SERVER_TICK_SPEED + s_LastGameTickTime;
2010-05-29 07:25:38 +00:00
if(Ct < 0)
2008-10-14 12:11:42 +00:00
return; // projectile havn't been shot yet
vec2 StartPos;
vec2 StartVel;
CServerInfo Info;
Client()->GetServerInfo(&Info);
bool IsDDNet = str_find_nocase(Info.m_aGameType, "ddracenetw") || str_find_nocase(Info.m_aGameType, "ddnet");
ExtractInfo(pCurrent, &StartPos, &StartVel, IsDDNet);
2010-05-29 07:25:38 +00:00
vec2 Pos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct);
vec2 PrevPos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct-0.001f);
2008-10-14 12:11:42 +00:00
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
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[clamp(pCurrent->m_Type, 0, NUM_WEAPONS-1)].m_pSpriteProj);
vec2 Vel = Pos-PrevPos;
//vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), Client()->IntraGameTick());
// add particle for this projectile
2010-05-29 07:25:38 +00:00
if(pCurrent->m_Type == WEAPON_GRENADE)
{
2010-05-29 07:25:38 +00:00
m_pClient->m_pEffects->SmokeTrail(Pos, Vel*-1);
2012-01-09 23:49:31 +00:00
static float s_Time = 0.0f;
static float s_LastLocalTime = Client()->LocalTime();
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
if(!pInfo->m_Paused)
2012-01-09 23:49:31 +00:00
s_Time += (Client()->LocalTime()-s_LastLocalTime)*pInfo->m_Speed;
}
else
2012-01-09 23:49:31 +00:00
{
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
s_Time += Client()->LocalTime()-s_LastLocalTime;
}
Graphics()->QuadsSetRotation(s_Time*pi*2*2 + ItemID);
s_LastLocalTime = Client()->LocalTime();
}
else
{
2010-05-29 07:25:38 +00:00
m_pClient->m_pEffects->BulletTrail(Pos);
2010-05-29 07:25:38 +00:00
if(length(Vel) > 0.00001f)
Graphics()->QuadsSetRotation(GetAngle(Vel));
else
2009-10-27 14:38:53 +00:00
Graphics()->QuadsSetRotation(0);
}
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(Pos.x, Pos.y, 32, 32);
2013-10-09 14:02:23 +00:00
2014-01-27 04:06:03 +00:00
bool LocalPlayerInGame = false;
if(m_pClient->m_Snap.m_pLocalInfo)
LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientID].m_Team != -1;
if (g_Config.m_ClAntiPingGrenade && LocalPlayerInGame && !(Client()->State() == IClient::STATE_DEMOPLAYBACK))
2013-10-09 14:02:23 +00:00
{
2013-10-15 16:08:06 +00:00
// Draw shadows of grenades
static int Offset = 0;
Offset = (int)(0.8f * (float)Offset + 0.2f * (float)(Client()->PredGameTick() - Client()->GameTick()));
2013-10-15 16:08:06 +00:00
int PredictedTick = Client()->PrevGameTick() + Offset;
float PredictedCt = (PredictedTick - pCurrent->m_StartTick)/(float)SERVER_TICK_SPEED + Client()->GameTickTime();
2013-10-15 16:08:06 +00:00
int shadow_type = pCurrent->m_Type;
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[clamp(shadow_type, 0, NUM_WEAPONS-1)].m_pSpriteProj);
2013-10-15 16:08:06 +00:00
vec2 PredictedPos = CalcPos(StartPos, StartVel, Curvature, Speed, PredictedCt);
2013-10-15 16:08:06 +00:00
IGraphics::CQuadItem QuadItem(PredictedPos.x, PredictedPos.y, 32, 32);
Graphics()->QuadsDraw(&QuadItem, 1);
2013-10-09 14:02:23 +00:00
}
else
Graphics()->QuadsDraw(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsSetRotation(0);
Graphics()->QuadsEnd();
}
2010-05-29 07:25:38 +00:00
void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent)
{
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
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), Client()->IntraGameTick());
float Angle = 0.0f;
float Size = 64.0f;
if (pCurrent->m_Type == POWERUP_WEAPON)
{
2010-05-29 07:25:38 +00:00
Angle = 0; //-pi/6;//-0.25f * pi * 2.0f;
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS-1)].m_pSpriteBody);
Size = g_pData->m_Weapons.m_aId[clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS-1)].m_VisualSize;
}
else
{
const int c[] = {
SPRITE_PICKUP_HEALTH,
SPRITE_PICKUP_ARMOR,
SPRITE_PICKUP_WEAPON,
SPRITE_PICKUP_NINJA
};
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(c[pCurrent->m_Type]);
2010-05-29 07:25:38 +00:00
if(c[pCurrent->m_Type] == SPRITE_PICKUP_NINJA)
{
2010-05-29 07:25:38 +00:00
m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18));
Size *= 2.0f;
Pos.x -= 10.0f;
}
}
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(Angle);
2012-01-09 23:49:31 +00:00
static float s_Time = 0.0f;
static float s_LastLocalTime = Client()->LocalTime();
2010-05-29 07:25:38 +00:00
float Offset = Pos.y/32.0f + Pos.x/32.0f;
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
if(!pInfo->m_Paused)
2012-01-09 23:49:31 +00:00
s_Time += (Client()->LocalTime()-s_LastLocalTime)*pInfo->m_Speed;
}
else
{
2012-01-09 23:49:31 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
s_Time += Client()->LocalTime()-s_LastLocalTime;
}
Pos.x += cosf(s_Time*2.0f+Offset)*2.5f;
Pos.y += sinf(s_Time*2.0f+Offset)*2.5f;
s_LastLocalTime = Client()->LocalTime();
2010-05-29 07:25:38 +00:00
RenderTools()->DrawSprite(Pos.x, Pos.y, Size);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
}
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)
{
2010-05-29 07:25:38 +00:00
float Angle = 0.0f;
float Size = 42.0f;
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
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();
2011-01-03 11:50:38 +00:00
if(pCurrent->m_Team == TEAM_RED)
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(SPRITE_FLAG_RED);
else
2010-05-29 07:25:38 +00:00
RenderTools()->SelectSprite(SPRITE_FLAG_BLUE);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsSetRotation(Angle);
2010-05-29 07:25:38 +00:00
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), Client()->IntraGameTick());
2011-03-04 16:08:10 +00:00
if(pCurGameData)
{
// 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) ||
(pCurrent->m_Team == TEAM_BLUE && pPrevGameData->m_FlagCarrierBlue != pCurGameData->m_FlagCarrierBlue)))
Pos = vec2(pCurrent->m_X, pCurrent->m_Y);
// make sure to use predicted position if we are the carrier
if(m_pClient->m_Snap.m_pLocalInfo &&
((pCurrent->m_Team == TEAM_RED && pCurGameData->m_FlagCarrierRed == m_pClient->m_Snap.m_LocalClientID) ||
(pCurrent->m_Team == TEAM_BLUE && pCurGameData->m_FlagCarrierBlue == m_pClient->m_Snap.m_LocalClientID)))
Pos = m_pClient->m_LocalCharacterPos;
}
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(Pos.x, Pos.y-Size*0.75f, Size, Size*2);
Graphics()->QuadsDraw(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
}
2010-05-29 07:25:38 +00:00
void CItems::RenderLaser(const struct CNetObj_Laser *pCurrent)
{
vec3 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);
vec2 Dir = normalize(Pos-From);
2010-05-29 07:25:38 +00:00
float Ticks = Client()->GameTick() + Client()->IntraGameTick() - pCurrent->m_StartTick;
float Ms = (Ticks/50.0f) * 1000.0f;
float a = Ms / m_pClient->m_Tuning[g_Config.m_ClDummy].m_LaserBounceDelay;
a = clamp(a, 0.0f, 1.0f);
2010-05-29 07:25:38 +00:00
float Ia = 1-a;
2010-05-29 07:25:38 +00:00
vec2 Out, Border;
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
//vec4 inner_color(0.15f,0.35f,0.75f,1.0f);
//vec4 outer_color(0.65f,0.85f,1.0f,1.0f);
// do outline
RGB = HslToRgb(vec3(g_Config.m_ClLaserOutlineHue / 255.0f, g_Config.m_ClLaserOutlineSat / 255.0f, g_Config.m_ClLaserOutlineLht / 255.0f));
vec4 OuterColor(RGB.r, RGB.g, RGB.b, 1.0f);
2010-05-29 07:25:38 +00:00
Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f);
Out = vec2(Dir.y, -Dir.x) * (7.0f*Ia);
2010-05-29 07:25:38 +00:00
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
RGB = HslToRgb(vec3(g_Config.m_ClLaserInnerHue / 255.0f, g_Config.m_ClLaserInnerSat / 255.0f, g_Config.m_ClLaserInnerLht / 255.0f));
vec4 InnerColor(RGB.r, RGB.g, RGB.b, 1.0f);
2010-05-29 07:25:38 +00:00
Out = vec2(Dir.y, -Dir.x) * (5.0f*Ia);
Graphics()->SetColor(InnerColor.r, InnerColor.g, InnerColor.b, 1.0f); // center
2010-05-29 07:25:38 +00:00
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);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
// render head
{
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_PARTICLES].m_Id);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
int Sprites[] = {SPRITE_PART_SPLAT01, SPRITE_PART_SPLAT02, SPRITE_PART_SPLAT03};
RenderTools()->SelectSprite(Sprites[Client()->GameTick()%3]);
Graphics()->QuadsSetRotation(Client()->GameTick());
Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f);
IGraphics::CQuadItem QuadItem(Pos.x, Pos.y, 24, 24);
Graphics()->QuadsDraw(&QuadItem, 1);
Graphics()->SetColor(InnerColor.r, InnerColor.g, InnerColor.b, 1.0f);
QuadItem = IGraphics::CQuadItem(Pos.x, Pos.y, 20, 20);
Graphics()->QuadsDraw(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
}
Graphics()->BlendNormal();
}
2010-05-29 07:25:38 +00:00
void CItems::OnRender()
{
if(Client()->State() < IClient::STATE_ONLINE)
return;
2010-05-29 07:25:38 +00:00
int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT);
for(int i = 0; i < Num; i++)
{
2010-05-29 07:25:38 +00:00
IClient::CSnapItem Item;
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
2010-05-29 07:25:38 +00:00
if(Item.m_Type == NETOBJTYPE_PROJECTILE)
{
RenderProjectile((const CNetObj_Projectile *)pData, Item.m_ID);
}
2010-05-29 07:25:38 +00:00
else if(Item.m_Type == NETOBJTYPE_PICKUP)
{
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);
}
2010-05-29 07:25:38 +00:00
else if(Item.m_Type == NETOBJTYPE_LASER)
{
2010-05-29 07:25:38 +00:00
RenderLaser((const CNetObj_Laser *)pData);
}
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)
{
const void *pPrev = Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID);
2010-05-29 07:25:38 +00:00
if (pPrev)
2011-03-04 16:08:10 +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),
static_cast<const CNetObj_GameData *>(pPrevGameData), m_pClient->m_Snap.m_pGameDataObj);
}
}
}
// render extra projectiles
2011-09-06 13:27:56 +00:00
for(int i = 0; i < m_NumExtraProjectiles; i++)
{
2011-09-06 13:27:56 +00:00
if(m_aExtraProjectiles[i].m_StartTick < Client()->GameTick())
{
2011-09-06 13:27:56 +00:00
m_aExtraProjectiles[i] = m_aExtraProjectiles[m_NumExtraProjectiles-1];
m_NumExtraProjectiles--;
}
else
2011-09-06 13:27:56 +00:00
RenderProjectile(&m_aExtraProjectiles[i], 0);
2011-04-03 08:11:23 +00:00
}
}
void CItems::AddExtraProjectile(CNetObj_Projectile *pProj)
{
2011-09-06 13:27:56 +00:00
if(m_NumExtraProjectiles != MAX_EXTRA_PROJECTILES)
2011-04-03 08:11:23 +00:00
{
2011-09-06 13:27:56 +00:00
m_aExtraProjectiles[m_NumExtraProjectiles] = *pProj;
m_NumExtraProjectiles++;
2011-04-03 08:11:23 +00:00
}
}