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 | |
4 | #include "projectile_data.h" |
5 | |
6 | #include <engine/shared/snapshot.h> |
7 | #include <game/client/prediction/gameworld.h> |
8 | #include <game/generated/protocol.h> |
9 | |
10 | #include <game/collision.h> |
11 | |
12 | bool (const CNetObj_Projectile *pProj) |
13 | { |
14 | return pProj->m_VelY >= 0 && (pProj->m_VelY & LEGACYPROJECTILEFLAG_IS_DDNET) != 0; |
15 | } |
16 | |
17 | CProjectileData (int NetObjType, const void *pData, CGameWorld *pGameWorld, const CNetObj_EntityEx *pEntEx) |
18 | { |
19 | CNetObj_Projectile *pProj = (CNetObj_Projectile *)pData; |
20 | |
21 | if(NetObjType == NETOBJTYPE_DDNETPROJECTILE) |
22 | { |
23 | return ExtractProjectileInfoDDNet(pProj: (CNetObj_DDNetProjectile *)pData); |
24 | } |
25 | else if(NetObjType == NETOBJTYPE_DDRACEPROJECTILE || (NetObjType == NETOBJTYPE_PROJECTILE && UseProjectileExtraInfo(pProj))) |
26 | { |
27 | return ExtractProjectileInfoDDRace(pProj: (CNetObj_DDRaceProjectile *)pData, pGameWorld, pEntEx); |
28 | } |
29 | |
30 | CProjectileData Result = {.m_StartPos: vec2(0, 0)}; |
31 | Result.m_StartPos.x = pProj->m_X; |
32 | Result.m_StartPos.y = pProj->m_Y; |
33 | Result.m_StartVel.x = pProj->m_VelX / 100.0f; |
34 | Result.m_StartVel.y = pProj->m_VelY / 100.0f; |
35 | Result.m_Type = pProj->m_Type; |
36 | Result.m_StartTick = pProj->m_StartTick; |
37 | Result.m_ExtraInfo = false; |
38 | Result.m_Owner = -1; |
39 | Result.m_TuneZone = pGameWorld && pGameWorld->m_WorldConfig.m_UseTuneZones ? pGameWorld->Collision()->IsTune(Index: pGameWorld->Collision()->GetMapIndex(Pos: Result.m_StartPos)) : 0; |
40 | Result.m_SwitchNumber = pEntEx ? pEntEx->m_SwitchNumber : 0; |
41 | return Result; |
42 | } |
43 | |
44 | CProjectileData (const CNetObj_DDRaceProjectile *pProj, CGameWorld *pGameWorld, const CNetObj_EntityEx *pEntEx) |
45 | { |
46 | CProjectileData Result = {.m_StartPos: vec2(0, 0)}; |
47 | |
48 | Result.m_StartPos.x = pProj->m_X / 100.0f; |
49 | Result.m_StartPos.y = pProj->m_Y / 100.0f; |
50 | float Angle = pProj->m_Angle / 1000000.0f; |
51 | Result.m_StartVel.x = std::sin(x: -Angle); |
52 | Result.m_StartVel.y = std::cos(x: -Angle); |
53 | Result.m_Type = pProj->m_Type; |
54 | Result.m_StartTick = pProj->m_StartTick; |
55 | |
56 | Result.m_ExtraInfo = true; |
57 | Result.m_Owner = pProj->m_Data & 255; |
58 | if(pProj->m_Data & LEGACYPROJECTILEFLAG_NO_OWNER || Result.m_Owner < 0 || Result.m_Owner >= MAX_CLIENTS) |
59 | { |
60 | Result.m_Owner = -1; |
61 | } |
62 | // LEGACYPROJECTILEFLAG_BOUNCE_HORIZONTAL, LEGACYPROJECTILEFLAG_BOUNCE_VERTICAL |
63 | Result.m_Bouncing = (pProj->m_Data >> 10) & 3; |
64 | Result.m_Explosive = pProj->m_Data & LEGACYPROJECTILEFLAG_EXPLOSIVE; |
65 | Result.m_Freeze = pProj->m_Data & LEGACYPROJECTILEFLAG_FREEZE; |
66 | Result.m_TuneZone = pGameWorld && pGameWorld->m_WorldConfig.m_UseTuneZones ? pGameWorld->Collision()->IsTune(Index: pGameWorld->Collision()->GetMapIndex(Pos: Result.m_StartPos)) : 0; |
67 | Result.m_SwitchNumber = pEntEx ? pEntEx->m_SwitchNumber : 0; |
68 | return Result; |
69 | } |
70 | |
71 | CProjectileData (const CNetObj_DDNetProjectile *pProj) |
72 | { |
73 | CProjectileData Result = {.m_StartPos: vec2(0, 0)}; |
74 | |
75 | Result.m_StartPos = vec2(pProj->m_X / 100.0f, pProj->m_Y / 100.0f); |
76 | Result.m_StartVel = vec2(pProj->m_VelX / 1e6f, pProj->m_VelY / 1e6f); |
77 | |
78 | if(pProj->m_Flags & PROJECTILEFLAG_NORMALIZE_VEL) |
79 | { |
80 | Result.m_StartVel = normalize(v: Result.m_StartVel); |
81 | } |
82 | |
83 | Result.m_Type = pProj->m_Type; |
84 | Result.m_StartTick = pProj->m_StartTick; |
85 | |
86 | Result.m_ExtraInfo = true; |
87 | Result.m_Owner = pProj->m_Owner; |
88 | Result.m_SwitchNumber = pProj->m_SwitchNumber; |
89 | Result.m_TuneZone = pProj->m_TuneZone; |
90 | |
91 | Result.m_Bouncing = 0; |
92 | if(pProj->m_Flags & PROJECTILEFLAG_BOUNCE_HORIZONTAL) |
93 | { |
94 | Result.m_Bouncing |= 1; |
95 | } |
96 | if(pProj->m_Flags & PROJECTILEFLAG_BOUNCE_VERTICAL) |
97 | { |
98 | Result.m_Bouncing |= 2; |
99 | } |
100 | |
101 | Result.m_Explosive = pProj->m_Flags & PROJECTILEFLAG_EXPLOSIVE; |
102 | Result.m_Freeze = pProj->m_Flags & PROJECTILEFLAG_FREEZE; |
103 | |
104 | return Result; |
105 | } |
106 | |
107 | void (CSnapshot *pSnap) |
108 | { |
109 | for(int Index = 0; Index < pSnap->NumItems(); Index++) |
110 | { |
111 | const CSnapshotItem *pItem = pSnap->GetItem(Index); |
112 | if(pItem->Type() == NETOBJTYPE_PROJECTILE) |
113 | { |
114 | CNetObj_Projectile *pProj = (CNetObj_Projectile *)((void *)pItem->Data()); |
115 | if(UseProjectileExtraInfo(pProj)) |
116 | { |
117 | CProjectileData Data = ExtractProjectileInfo(NetObjType: NETOBJTYPE_PROJECTILE, pData: pProj, pGameWorld: nullptr, pEntEx: nullptr); |
118 | pProj->m_X = Data.m_StartPos.x; |
119 | pProj->m_Y = Data.m_StartPos.y; |
120 | pProj->m_VelX = (int)(Data.m_StartVel.x * 100.0f); |
121 | pProj->m_VelY = (int)(Data.m_StartVel.y * 100.0f); |
122 | } |
123 | } |
124 | } |
125 | } |
126 | |