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 <base/color.h>
4#include <engine/demo.h>
5#include <engine/graphics.h>
6#include <game/client/gameclient.h>
7#include <game/client/render.h>
8#include <game/generated/client_data.h>
9#include <game/generated/protocol.h>
10
11#include "damageind.h"
12
13CDamageInd::CDamageInd()
14{
15 m_Lastupdate = 0;
16 m_NumItems = 0;
17}
18
19CDamageInd::CItem *CDamageInd::CreateI()
20{
21 if(m_NumItems < MAX_ITEMS)
22 {
23 CItem *p = &m_aItems[m_NumItems];
24 m_NumItems++;
25 return p;
26 }
27 return 0;
28}
29
30void CDamageInd::DestroyI(CDamageInd::CItem *pItem)
31{
32 m_NumItems--;
33 *pItem = m_aItems[m_NumItems];
34}
35
36void CDamageInd::Create(vec2 Pos, vec2 Dir, float Alpha)
37{
38 CItem *pItem = CreateI();
39 if(pItem)
40 {
41 pItem->m_Pos = Pos;
42 pItem->m_StartTime = LocalTime();
43 pItem->m_Dir = -Dir;
44 pItem->m_StartAngle = -random_angle();
45 pItem->m_Color = ColorRGBA(1.0f, 1.0f, 1.0f, Alpha);
46 pItem->m_StartAlpha = Alpha;
47 }
48}
49
50void CDamageInd::OnRender()
51{
52 if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
53 return;
54
55 Graphics()->TextureSet(Texture: GameClient()->m_GameSkin.m_aSpriteStars[0]);
56 static float s_LastLocalTime = LocalTime();
57 for(int i = 0; i < m_NumItems;)
58 {
59 if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
60 {
61 const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
62 if(pInfo->m_Paused)
63 m_aItems[i].m_StartTime += LocalTime() - s_LastLocalTime;
64 else
65 m_aItems[i].m_StartTime += (LocalTime() - s_LastLocalTime) * (1.0f - pInfo->m_Speed);
66 }
67 else
68 {
69 if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED)
70 m_aItems[i].m_StartTime += LocalTime() - s_LastLocalTime;
71 }
72
73 float Life = 0.75f - (LocalTime() - m_aItems[i].m_StartTime);
74 if(Life < 0.0f)
75 DestroyI(pItem: &m_aItems[i]);
76 else
77 {
78 vec2 Pos = mix(a: m_aItems[i].m_Pos + m_aItems[i].m_Dir * 75.0f, b: m_aItems[i].m_Pos, amount: clamp(val: (Life - 0.60f) / 0.15f, lo: 0.0f, hi: 1.0f));
79 ColorRGBA Color = m_aItems[i].m_Color;
80
81 float LifeAlpha = Life / 0.1f;
82 Color.a = m_aItems[i].m_StartAlpha * LifeAlpha;
83 Graphics()->SetColor(Color);
84 Graphics()->QuadsSetRotation(Angle: m_aItems[i].m_StartAngle + Life * 2.0f);
85 Graphics()->RenderQuadContainerAsSprite(ContainerIndex: m_DmgIndQuadContainerIndex, QuadOffset: 0, X: Pos.x, Y: Pos.y);
86 i++;
87 }
88 }
89 s_LastLocalTime = LocalTime();
90
91 Graphics()->QuadsSetRotation(Angle: 0);
92 Graphics()->SetColor(r: 1.f, g: 1.f, b: 1.f, a: 1.f);
93}
94
95void CDamageInd::OnInit()
96{
97 Graphics()->QuadsSetRotation(Angle: 0);
98 Graphics()->SetColor(r: 1.f, g: 1.f, b: 1.f, a: 1.f);
99
100 m_DmgIndQuadContainerIndex = Graphics()->CreateQuadContainer(AutomaticUpload: false);
101 float ScaleX, ScaleY;
102 RenderTools()->GetSpriteScale(Id: SPRITE_STAR1, ScaleX, ScaleY);
103 Graphics()->QuadsSetSubset(TopLeftU: 0, TopLeftV: 0, BottomRightU: 1, BottomRightV: 1);
104 RenderTools()->QuadContainerAddSprite(QuadContainerIndex: m_DmgIndQuadContainerIndex, Width: 48.f * ScaleX, Height: 48.f * ScaleY);
105 Graphics()->QuadContainerUpload(ContainerIndex: m_DmgIndQuadContainerIndex);
106}
107
108void CDamageInd::Reset()
109{
110 for(int i = 0; i < m_NumItems;)
111 {
112 DestroyI(pItem: &m_aItems[i]);
113 }
114}
115