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