1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "damageind.h"
4
5#include <base/color.h>
6
7#include <engine/demo.h>
8#include <engine/graphics.h>
9
10#include <generated/client_data.h>
11#include <generated/protocol.h>
12
13#include <game/client/gameclient.h>
14
15CDamageInd::CDamageInd()
16{
17 m_NumItems = 0;
18}
19
20void CDamageInd::Create(vec2 Pos, vec2 Dir, float Alpha)
21{
22 if(m_NumItems >= MAX_ITEMS)
23 return;
24
25 CItem *pItem = &m_aItems[m_NumItems];
26 pItem->m_Pos = Pos;
27 pItem->m_Dir = -Dir;
28 pItem->m_RemainingLife = 0.75f;
29 pItem->m_StartAngle = -random_angle();
30 pItem->m_Color = ColorRGBA(1.0f, 1.0f, 1.0f, Alpha);
31 ++m_NumItems;
32}
33
34void CDamageInd::OnRender()
35{
36 if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
37 return;
38
39 static float s_LastLocalTime = LocalTime();
40 float LifeAdjustment;
41 if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
42 {
43 const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
44 if(pInfo->m_Paused)
45 LifeAdjustment = 0.0f;
46 else
47 LifeAdjustment = (LocalTime() - s_LastLocalTime) * pInfo->m_Speed;
48 }
49 else
50 {
51 const auto &pGameInfoObj = GameClient()->m_Snap.m_pGameInfoObj;
52 if(pGameInfoObj && pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED)
53 LifeAdjustment = 0.0f;
54 else
55 LifeAdjustment = LocalTime() - s_LastLocalTime;
56 }
57 s_LastLocalTime = LocalTime();
58
59 Graphics()->TextureSet(Texture: GameClient()->m_GameSkin.m_aSpriteStars[0]);
60 for(int i = 0; i < m_NumItems;)
61 {
62 m_aItems[i].m_RemainingLife -= LifeAdjustment;
63 if(m_aItems[i].m_RemainingLife < 0.0f)
64 {
65 --m_NumItems;
66 m_aItems[i] = m_aItems[m_NumItems];
67 }
68 else
69 {
70 vec2 Pos = mix(a: m_aItems[i].m_Pos + m_aItems[i].m_Dir * 75.0f, b: m_aItems[i].m_Pos, amount: std::clamp(val: (m_aItems[i].m_RemainingLife - 0.60f) / 0.15f, lo: 0.0f, hi: 1.0f));
71 const float LifeAlpha = m_aItems[i].m_RemainingLife / 0.1f;
72 Graphics()->SetColor(m_aItems[i].m_Color.WithMultipliedAlpha(alpha: LifeAlpha));
73 Graphics()->QuadsSetRotation(Angle: m_aItems[i].m_StartAngle + m_aItems[i].m_RemainingLife * 2.0f);
74 Graphics()->RenderQuadContainerAsSprite(ContainerIndex: m_DmgIndQuadContainerIndex, QuadOffset: 0, X: Pos.x, Y: Pos.y);
75 i++;
76 }
77 }
78
79 Graphics()->QuadsSetRotation(Angle: 0);
80 Graphics()->SetColor(r: 1.f, g: 1.f, b: 1.f, a: 1.f);
81}
82
83void CDamageInd::OnInit()
84{
85 Graphics()->QuadsSetRotation(Angle: 0);
86 Graphics()->SetColor(r: 1.f, g: 1.f, b: 1.f, a: 1.f);
87
88 m_DmgIndQuadContainerIndex = Graphics()->CreateQuadContainer(AutomaticUpload: false);
89 float ScaleX, ScaleY;
90 Graphics()->GetSpriteScale(Id: SPRITE_STAR1, ScaleX, ScaleY);
91 Graphics()->QuadsSetSubset(TopLeftU: 0, TopLeftV: 0, BottomRightU: 1, BottomRightV: 1);
92 Graphics()->QuadContainerAddSprite(QuadContainerIndex: m_DmgIndQuadContainerIndex, Width: 48.f * ScaleX, Height: 48.f * ScaleY);
93 Graphics()->QuadContainerUpload(ContainerIndex: m_DmgIndQuadContainerIndex);
94}
95
96void CDamageInd::OnReset()
97{
98 m_NumItems = 0;
99}
100