1 /* 2 Copyright (c) 2013 yvt 3 based on code of pysnip (c) Mathias Kaerlev 2011-2012. 4 5 This file is part of OpenSpades. 6 7 OpenSpades is free software: you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 OpenSpades is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. 19 20 */ 21 22 #include <cstdlib> 23 24 #include "Client.h" 25 26 #include <Core/Settings.h> 27 #include <Core/Strings.h> 28 #include <Core/Strings.h> 29 30 #include "IAudioChunk.h" 31 #include "IAudioDevice.h" 32 33 #include "CTFGameMode.h" 34 #include "GameMap.h" 35 #include "IGameMode.h" 36 #include "TCGameMode.h" 37 #include "World.h" 38 #include "GameProperties.h" 39 40 #include "CenterMessageView.h" 41 #include "ChatWindow.h" 42 #include "ClientUI.h" 43 44 #include "NetClient.h" 45 46 DEFINE_SPADES_SETTING(cg_centerMessage, "2"); 47 48 namespace spades { 49 namespace client { 50 51 #pragma mark - Server Packet Handlers 52 LocalPlayerCreated()53 void Client::LocalPlayerCreated() { 54 freeCameraState.position = world->GetLocalPlayer()->GetEye(); 55 weapInput = WeaponInput(); 56 playerInput = PlayerInput(); 57 keypadInput = KeypadInput(); 58 59 toolRaiseState = .0f; 60 } 61 JoinedGame()62 void Client::JoinedGame() { 63 // Note: A local player doesn't exist yet 64 65 // Prepare the spectate mode 66 followCameraState.enabled = false; 67 freeCameraState.position = MakeVector3(256, 256, 30); 68 freeCameraState.velocity = MakeVector3(0, 0, 0); 69 } 70 PlayerCreatedBlock(spades::client::Player * p)71 void Client::PlayerCreatedBlock(spades::client::Player *p) { 72 SPADES_MARK_FUNCTION(); 73 74 if (!IsMuted()) { 75 Handle<IAudioChunk> c = 76 audioDevice->RegisterSound("Sounds/Weapons/Block/Build.opus"); 77 audioDevice->Play(c, p->GetEye() + p->GetFront(), AudioParam()); 78 } 79 } 80 TeamCapturedTerritory(int teamId,int terId)81 void Client::TeamCapturedTerritory(int teamId, int terId) { 82 TCGameMode::Territory *ter = 83 static_cast<TCGameMode *>(world->GetMode())->GetTerritory(terId); 84 int old = ter->ownerTeamId; 85 std::string msg; 86 std::string teamName = 87 chatWindow->TeamColorMessage(world->GetTeam(teamId).name, teamId); 88 if (old < 2) { 89 std::string otherTeam = chatWindow->TeamColorMessage(world->GetTeam(old).name, old); 90 msg = _Tr("Client", "{0} captured {1}'s territory", teamName, otherTeam); 91 } else { 92 msg = _Tr("Client", "{0} captured an neutral territory", teamName); 93 } 94 chatWindow->AddMessage(msg); 95 96 if ((int)cg_centerMessage != 0) { 97 teamName = world->GetTeam(teamId).name; 98 if (old < 2) { 99 std::string otherTeam = world->GetTeam(old).name; 100 msg = _Tr("Client", "{0} captured {1}'s Territory", teamName, otherTeam); 101 } else { 102 msg = _Tr("Client", "{0} captured an Neutral Territory", teamName); 103 } 104 NetLog("%s", msg.c_str()); 105 centerMessageView->AddMessage(msg); 106 } 107 108 if (world->GetLocalPlayer() && !IsMuted()) { 109 if (teamId == world->GetLocalPlayer()->GetTeamId()) { 110 Handle<IAudioChunk> chunk = 111 audioDevice->RegisterSound("Sounds/Feedback/TC/YourTeamCaptured.opus"); 112 audioDevice->PlayLocal(chunk, AudioParam()); 113 } else { 114 Handle<IAudioChunk> chunk = 115 audioDevice->RegisterSound("Sounds/Feedback/TC/EnemyCaptured.opus"); 116 audioDevice->PlayLocal(chunk, AudioParam()); 117 } 118 } 119 } 120 PlayerCapturedIntel(spades::client::Player * p)121 void Client::PlayerCapturedIntel(spades::client::Player *p) { 122 std::string msg; 123 { 124 std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId()); 125 126 std::string otherTeamName = chatWindow->TeamColorMessage( 127 world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId()); 128 msg = _Tr("Client", "{0} captured {1}'s intel", holderName, otherTeamName); 129 chatWindow->AddMessage(msg); 130 } 131 132 if ((int)cg_centerMessage != 0) { 133 std::string holderName = p->GetName(); 134 std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name; 135 msg = _Tr("Client", "{0} captured {1}'s Intel.", holderName, otherTeamName); 136 NetLog("%s", msg.c_str()); 137 centerMessageView->AddMessage(msg); 138 } 139 140 if (world->GetLocalPlayer() && !IsMuted()) { 141 if (p->GetTeamId() == world->GetLocalPlayer()->GetTeamId()) { 142 Handle<IAudioChunk> chunk = 143 audioDevice->RegisterSound("Sounds/Feedback/CTF/YourTeamCaptured.opus"); 144 audioDevice->PlayLocal(chunk, AudioParam()); 145 } else { 146 Handle<IAudioChunk> chunk = 147 audioDevice->RegisterSound("Sounds/Feedback/CTF/EnemyCaptured.opus"); 148 audioDevice->PlayLocal(chunk, AudioParam()); 149 } 150 } 151 } 152 PlayerPickedIntel(spades::client::Player * p)153 void Client::PlayerPickedIntel(spades::client::Player *p) { 154 std::string msg; 155 { 156 std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId()); 157 std::string otherTeamName = chatWindow->TeamColorMessage( 158 world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId()); 159 msg = _Tr("Client", "{0} picked up {1}'s intel", holderName, otherTeamName); 160 chatWindow->AddMessage(msg); 161 } 162 163 if ((int)cg_centerMessage != 0) { 164 std::string holderName = p->GetName(); 165 std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name; 166 msg = _Tr("Client", "{0} picked up {1}'s Intel.", holderName, otherTeamName); 167 NetLog("%s", msg.c_str()); 168 centerMessageView->AddMessage(msg); 169 } 170 171 if (!IsMuted()) { 172 Handle<IAudioChunk> chunk = 173 audioDevice->RegisterSound("Sounds/Feedback/CTF/PickedUp.opus"); 174 audioDevice->PlayLocal(chunk, AudioParam()); 175 } 176 } 177 PlayerDropIntel(spades::client::Player * p)178 void Client::PlayerDropIntel(spades::client::Player *p) { 179 std::string msg; 180 { 181 std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId()); 182 std::string otherTeamName = chatWindow->TeamColorMessage( 183 world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId()); 184 msg = _Tr("Client", "{0} dropped {1}'s intel", holderName, otherTeamName); 185 chatWindow->AddMessage(msg); 186 } 187 188 if ((int)cg_centerMessage != 0) { 189 std::string holderName = p->GetName(); 190 std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name; 191 msg = _Tr("Client", "{0} dropped {1}'s Intel", holderName, otherTeamName); 192 NetLog("%s", msg.c_str()); 193 centerMessageView->AddMessage(msg); 194 } 195 } 196 PlayerDestroyedBlockWithWeaponOrTool(spades::IntVector3 blk)197 void Client::PlayerDestroyedBlockWithWeaponOrTool(spades::IntVector3 blk) { 198 Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f}; 199 200 if (!map->IsSolid(blk.x, blk.y, blk.z)) 201 return; 202 ; 203 204 Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Misc/BlockDestroy.opus"); 205 if (!IsMuted()) { 206 audioDevice->Play(c, origin, AudioParam()); 207 } 208 209 uint32_t col = map->GetColor(blk.x, blk.y, blk.z); 210 IntVector3 colV = {(uint8_t)col, (uint8_t)(col >> 8), (uint8_t)(col >> 16)}; 211 212 EmitBlockDestroyFragments(blk, colV); 213 } 214 PlayerDiggedBlock(spades::IntVector3 blk)215 void Client::PlayerDiggedBlock(spades::IntVector3 blk) { 216 Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f}; 217 218 Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Misc/BlockDestroy.opus"); 219 if (!IsMuted()) { 220 audioDevice->Play(c, origin, AudioParam()); 221 } 222 223 for (int z = blk.z - 1; z <= blk.z + 1; z++) { 224 if (z < 0 || z > 61) 225 continue; 226 if (!map->IsSolid(blk.x, blk.y, z)) 227 continue; 228 uint32_t col = map->GetColor(blk.x, blk.y, z); 229 IntVector3 colV = {(uint8_t)col, (uint8_t)(col >> 8), (uint8_t)(col >> 16)}; 230 231 EmitBlockDestroyFragments(IntVector3::Make(blk.x, blk.y, z), colV); 232 } 233 } 234 PlayerLeaving(spades::client::Player * p)235 void Client::PlayerLeaving(spades::client::Player *p) { 236 // Choose the next player if a follow cam is active on this player 237 if (FollowsNonLocalPlayer(GetCameraMode()) && &GetCameraTargetPlayer() == p) { 238 FollowNextPlayer(false); 239 240 // Still unable to find a substitute? 241 if (&GetCameraTargetPlayer() == p) { 242 // Turn off the follow cam mode 243 followCameraState.enabled = false; 244 } 245 } 246 247 { 248 std::string msg; 249 msg = _Tr("Client", "Player {0} has left", 250 chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId())); 251 chatWindow->AddMessage(msg); 252 } 253 { 254 std::string msg; 255 msg = _Tr("Client", "Player {0} has left", p->GetName()); 256 257 auto col = p->GetTeamId() < 2 ? world->GetTeam(p->GetTeamId()).color 258 : IntVector3::Make(255, 255, 255); 259 260 NetLog("%s", msg.c_str()); 261 scriptedUI->RecordChatLog( 262 msg, MakeVector4(col.x / 255.f, col.y / 255.f, col.z / 255.f, 0.8f)); 263 } 264 RemoveCorpseForPlayer(p->GetId()); 265 } 266 PlayerJoinedTeam(spades::client::Player * p)267 void Client::PlayerJoinedTeam(spades::client::Player *p) { 268 std::string teamName = world->GetTeam(p->GetTeamId()).name; 269 270 if (p->GetTeamId() >= 2) { 271 teamName = _Tr("Client", "Spectator"); 272 } 273 274 { 275 std::string msg; 276 msg = _Tr("Client", "{0} joined {1} team", p->GetName(), 277 chatWindow->TeamColorMessage(teamName, p->GetTeamId())); 278 chatWindow->AddMessage(msg); 279 } 280 { 281 std::string msg; 282 msg = _Tr("Client", "{0} joined {1} team", p->GetName(), teamName); 283 284 auto col = p->GetTeamId() < 2 ? world->GetTeam(p->GetTeamId()).color 285 : IntVector3::Make(255, 255, 255); 286 287 NetLog("%s", msg.c_str()); 288 scriptedUI->RecordChatLog( 289 msg, MakeVector4(col.x / 255.f, col.y / 255.f, col.z / 255.f, 0.8f)); 290 } 291 } 292 PlayerSpawned(Player * p)293 void Client::PlayerSpawned(Player *p) { 294 if (net->GetGameProperties()->clearCorpseOnRespawn) { 295 RemoveCorpseForPlayer(p->GetId()); 296 } 297 } 298 GrenadeDestroyedBlock(spades::IntVector3 blk)299 void Client::GrenadeDestroyedBlock(spades::IntVector3 blk) { 300 for (int x = blk.x - 1; x <= blk.x + 1; x++) 301 for (int y = blk.y - 1; y <= blk.y + 1; y++) 302 for (int z = blk.z - 1; z <= blk.z + 1; z++) { 303 if (z < 0 || z > 61 || x < 0 || x >= 512 || y < 0 || y >= 512) 304 continue; 305 if (!map->IsSolid(x, y, z)) 306 continue; 307 uint32_t col = map->GetColor(x, y, z); 308 IntVector3 colV = {(uint8_t)col, (uint8_t)(col >> 8), (uint8_t)(col >> 16)}; 309 310 EmitBlockDestroyFragments(IntVector3::Make(x, y, z), colV); 311 } 312 } 313 TeamWon(int teamId)314 void Client::TeamWon(int teamId) { 315 std::string msg; 316 msg = chatWindow->TeamColorMessage(world->GetTeam(teamId).name, teamId); 317 msg = _Tr("Client", "{0} wins!", msg); 318 chatWindow->AddMessage(msg); 319 320 msg = world->GetTeam(teamId).name; 321 msg = _Tr("Client", "{0} Wins!", msg); 322 NetLog("%s", msg.c_str()); 323 centerMessageView->AddMessage(msg); 324 325 scriptedUI->RecordChatLog(msg, MakeVector4(1.f, 1.f, 1.f, 0.8f)); 326 327 if (world->GetLocalPlayer()) { 328 if (teamId == world->GetLocalPlayer()->GetTeamId()) { 329 Handle<IAudioChunk> chunk = 330 audioDevice->RegisterSound("Sounds/Feedback/Win.opus"); 331 audioDevice->PlayLocal(chunk, AudioParam()); 332 } else { 333 Handle<IAudioChunk> chunk = 334 audioDevice->RegisterSound("Sounds/Feedback/Lose.opus"); 335 audioDevice->PlayLocal(chunk, AudioParam()); 336 } 337 } 338 } 339 MarkWorldUpdate()340 void Client::MarkWorldUpdate() { 341 upsCounter.MarkFrame(); 342 } 343 } 344 } 345