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 "pickup.h" |
4 | #include "character.h" |
5 | #include <game/client/pickup_data.h> |
6 | #include <game/collision.h> |
7 | #include <game/generated/protocol.h> |
8 | #include <game/mapitems.h> |
9 | |
10 | static constexpr int gs_PickupPhysSize = 14; |
11 | |
12 | void CPickup::Tick() |
13 | { |
14 | Move(); |
15 | // Check if a player intersected us |
16 | CEntity *apEnts[MAX_CLIENTS]; |
17 | int Num = GameWorld()->FindEntities(Pos: m_Pos, Radius: GetProximityRadius() + ms_CollisionExtraSize, ppEnts: apEnts, Max: MAX_CLIENTS, Type: CGameWorld::ENTTYPE_CHARACTER); |
18 | for(int i = 0; i < Num; ++i) |
19 | { |
20 | auto *pChr = static_cast<CCharacter *>(apEnts[i]); |
21 | if(pChr) |
22 | { |
23 | if(GameWorld()->m_WorldConfig.m_IsVanilla && distance(a: m_Pos, b: pChr->m_Pos) >= (GetProximityRadius() + ms_CollisionExtraSize) * 2) // pickup distance is shorter on vanilla due to using ClosestEntity |
24 | continue; |
25 | if(m_Layer == LAYER_SWITCH && m_Number > 0 && m_Number < (int)Switchers().size() && !Switchers()[m_Number].m_aStatus[pChr->Team()]) |
26 | continue; |
27 | bool sound = false; |
28 | // player picked us up, is someone was hooking us, let them go |
29 | switch(m_Type) |
30 | { |
31 | case POWERUP_HEALTH: |
32 | //pChr->Freeze(); |
33 | break; |
34 | |
35 | case POWERUP_ARMOR: |
36 | if(!GameWorld()->m_WorldConfig.m_IsDDRace || !GameWorld()->m_WorldConfig.m_PredictDDRace) |
37 | continue; |
38 | if(pChr->IsSuper()) |
39 | continue; |
40 | for(int j = WEAPON_SHOTGUN; j < NUM_WEAPONS; j++) |
41 | { |
42 | if(pChr->GetWeaponGot(Type: j)) |
43 | { |
44 | pChr->SetWeaponGot(Type: j, Value: false); |
45 | pChr->SetWeaponAmmo(Type: j, Value: 0); |
46 | sound = true; |
47 | } |
48 | } |
49 | pChr->SetNinjaActivationDir(vec2(0, 0)); |
50 | pChr->SetNinjaActivationTick(-500); |
51 | pChr->SetNinjaCurrentMoveTime(0); |
52 | if(sound) |
53 | pChr->SetLastWeapon(WEAPON_GUN); |
54 | if(pChr->GetActiveWeapon() >= WEAPON_SHOTGUN) |
55 | pChr->SetActiveWeapon(WEAPON_HAMMER); |
56 | break; |
57 | |
58 | case POWERUP_ARMOR_SHOTGUN: |
59 | if(!GameWorld()->m_WorldConfig.m_IsDDRace || !GameWorld()->m_WorldConfig.m_PredictDDRace) |
60 | continue; |
61 | if(pChr->Team() == TEAM_SUPER) |
62 | continue; |
63 | if(pChr->GetWeaponGot(Type: WEAPON_SHOTGUN)) |
64 | { |
65 | pChr->SetWeaponGot(Type: WEAPON_SHOTGUN, Value: false); |
66 | pChr->SetWeaponAmmo(Type: WEAPON_SHOTGUN, Value: 0); |
67 | pChr->SetLastWeapon(WEAPON_GUN); |
68 | } |
69 | if(pChr->GetActiveWeapon() == WEAPON_SHOTGUN) |
70 | pChr->SetActiveWeapon(WEAPON_HAMMER); |
71 | break; |
72 | |
73 | case POWERUP_ARMOR_GRENADE: |
74 | if(!GameWorld()->m_WorldConfig.m_IsDDRace || !GameWorld()->m_WorldConfig.m_PredictDDRace) |
75 | continue; |
76 | if(pChr->Team() == TEAM_SUPER) |
77 | continue; |
78 | if(pChr->GetWeaponGot(Type: WEAPON_GRENADE)) |
79 | { |
80 | pChr->SetWeaponGot(Type: WEAPON_GRENADE, Value: false); |
81 | pChr->SetWeaponAmmo(Type: WEAPON_GRENADE, Value: 0); |
82 | pChr->SetLastWeapon(WEAPON_GUN); |
83 | } |
84 | if(pChr->GetActiveWeapon() == WEAPON_GRENADE) |
85 | pChr->SetActiveWeapon(WEAPON_HAMMER); |
86 | break; |
87 | |
88 | case POWERUP_ARMOR_NINJA: |
89 | if(!GameWorld()->m_WorldConfig.m_IsDDRace || !GameWorld()->m_WorldConfig.m_PredictDDRace) |
90 | continue; |
91 | if(pChr->Team() == TEAM_SUPER) |
92 | continue; |
93 | pChr->SetNinjaActivationDir(vec2(0, 0)); |
94 | pChr->SetNinjaActivationTick(-500); |
95 | pChr->SetNinjaCurrentMoveTime(0); |
96 | break; |
97 | |
98 | case POWERUP_ARMOR_LASER: |
99 | if(!GameWorld()->m_WorldConfig.m_IsDDRace || !GameWorld()->m_WorldConfig.m_PredictDDRace) |
100 | continue; |
101 | if(pChr->Team() == TEAM_SUPER) |
102 | continue; |
103 | if(pChr->GetWeaponGot(Type: WEAPON_LASER)) |
104 | { |
105 | pChr->SetWeaponGot(Type: WEAPON_LASER, Value: false); |
106 | pChr->SetWeaponAmmo(Type: WEAPON_LASER, Value: 0); |
107 | pChr->SetLastWeapon(WEAPON_GUN); |
108 | } |
109 | if(pChr->GetActiveWeapon() == WEAPON_LASER) |
110 | pChr->SetActiveWeapon(WEAPON_HAMMER); |
111 | break; |
112 | |
113 | case POWERUP_WEAPON: |
114 | if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->GetWeaponGot(Type: m_Subtype) || pChr->GetWeaponAmmo(Type: m_Subtype) != -1)) |
115 | pChr->GiveWeapon(Weapon: m_Subtype); |
116 | break; |
117 | |
118 | case POWERUP_NINJA: |
119 | { |
120 | // activate ninja on target player |
121 | pChr->GiveNinja(); |
122 | break; |
123 | } |
124 | |
125 | default: |
126 | break; |
127 | }; |
128 | } |
129 | } |
130 | } |
131 | |
132 | void CPickup::Move() |
133 | { |
134 | if(GameWorld()->GameTick() % (int)(GameWorld()->GameTickSpeed() * 0.15f) == 0) |
135 | { |
136 | int Flags; |
137 | int index = Collision()->IsMover(x: m_Pos.x, y: m_Pos.y, pFlags: &Flags); |
138 | if(index) |
139 | { |
140 | m_IsCoreActive = true; |
141 | m_Core = Collision()->CpSpeed(index, Flags); |
142 | } |
143 | m_Pos += m_Core; |
144 | } |
145 | } |
146 | |
147 | CPickup::CPickup(CGameWorld *pGameWorld, int Id, const CPickupData *pPickup) : |
148 | CEntity(pGameWorld, CGameWorld::ENTTYPE_PICKUP, vec2(0, 0), gs_PickupPhysSize) |
149 | { |
150 | m_Pos = pPickup->m_Pos; |
151 | m_Type = pPickup->m_Type; |
152 | m_Subtype = pPickup->m_Subtype; |
153 | m_Core = vec2(0.f, 0.f); |
154 | m_IsCoreActive = false; |
155 | m_Id = Id; |
156 | m_Number = pPickup->m_SwitchNumber; |
157 | m_Layer = m_Number > 0 ? LAYER_SWITCH : LAYER_GAME; |
158 | } |
159 | |
160 | void CPickup::FillInfo(CNetObj_Pickup *pPickup) |
161 | { |
162 | pPickup->m_X = (int)m_Pos.x; |
163 | pPickup->m_Y = (int)m_Pos.y; |
164 | pPickup->m_Type = m_Type; |
165 | pPickup->m_Subtype = m_Subtype; |
166 | } |
167 | |
168 | bool CPickup::Match(CPickup *pPickup) |
169 | { |
170 | if(pPickup->m_Type != m_Type || pPickup->m_Subtype != m_Subtype) |
171 | return false; |
172 | if(distance(a: pPickup->m_Pos, b: m_Pos) > 2.0f) |
173 | return false; |
174 | return true; |
175 | } |
176 | |