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 | |
13 | CDamageInd::CDamageInd() |
14 | { |
15 | m_Lastupdate = 0; |
16 | m_NumItems = 0; |
17 | } |
18 | |
19 | CDamageInd::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 | |
30 | void CDamageInd::DestroyI(CDamageInd::CItem *pItem) |
31 | { |
32 | m_NumItems--; |
33 | *pItem = m_aItems[m_NumItems]; |
34 | } |
35 | |
36 | void 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 | |
50 | void 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 | |
95 | void 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 | |
108 | void CDamageInd::Reset() |
109 | { |
110 | for(int i = 0; i < m_NumItems;) |
111 | { |
112 | DestroyI(pItem: &m_aItems[i]); |
113 | } |
114 | } |
115 | |