2013-08-29 11:45:22 +09:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 yvt
|
2013-09-05 00:52:03 +09:00
|
|
|
based on code of pysnip (c) Mathias Kaerlev 2011-2012.
|
2013-08-29 11:45:22 +09:00
|
|
|
|
|
|
|
This file is part of OpenSpades.
|
|
|
|
|
|
|
|
OpenSpades is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
OpenSpades is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
*/
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
#include "Client.h"
|
|
|
|
#include "IRenderer.h"
|
|
|
|
#include "GameMap.h"
|
|
|
|
#include "SceneDefinition.h"
|
|
|
|
#include "../Core/FileManager.h"
|
|
|
|
#include "../Core/IStream.h"
|
|
|
|
#include "GameMapWrapper.h"
|
|
|
|
#include "World.h"
|
|
|
|
#include "Player.h"
|
|
|
|
#include "IAudioChunk.h"
|
|
|
|
#include "IAudioDevice.h"
|
|
|
|
#include "Weapon.h"
|
|
|
|
#include "Grenade.h"
|
|
|
|
#include "../Core/Debug.h"
|
|
|
|
#include "NetClient.h"
|
|
|
|
#include "FontData.h"
|
|
|
|
#include "Quake3Font.h"
|
|
|
|
#include "../Core/Exception.h"
|
|
|
|
#include "ChatWindow.h"
|
|
|
|
#include "Corpse.h"
|
|
|
|
#include "CenterMessageView.h"
|
|
|
|
#include "HurtRingView.h"
|
|
|
|
#include "CTFGameMode.h"
|
|
|
|
#include "MapView.h"
|
|
|
|
#include "ScoreboardView.h"
|
|
|
|
#include "LimboView.h"
|
|
|
|
#include "ILocalEntity.h"
|
|
|
|
#include "ParticleSpriteEntity.h"
|
|
|
|
#include "SmokeSpriteEntity.h"
|
|
|
|
#include "GameMapWrapper.h"
|
|
|
|
#include "../Core/Settings.h"
|
|
|
|
#include "../Core/Bitmap.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "FallingBlock.h"
|
|
|
|
#include "GunCasing.h"
|
|
|
|
#include "../Core/ConcurrentDispatch.h"
|
|
|
|
#include "PaletteView.h"
|
|
|
|
#include "TCGameMode.h"
|
|
|
|
#include "TCProgressView.h"
|
2013-08-27 01:35:53 +09:00
|
|
|
#include "../Core/IStream.h"
|
2013-08-26 19:24:15 +09:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <time.h>
|
2013-08-30 22:23:05 +09:00
|
|
|
#include "Tracer.h"
|
2013-09-14 20:00:30 -07:00
|
|
|
#include <stdlib.h>
|
2013-09-21 04:17:34 +09:00
|
|
|
#include "ClientPlayer.h"
|
2013-11-27 16:30:54 +09:00
|
|
|
#include "ClientUI.h"
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
static float nextRandom() {
|
|
|
|
return (float)rand() / (float)RAND_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
SPADES_SETTING(cg_ragdoll, "1");
|
|
|
|
SPADES_SETTING(cg_blood, "1");
|
|
|
|
SPADES_SETTING(cg_ejectBrass, "1");
|
|
|
|
|
|
|
|
SPADES_SETTING(cg_mouseSensitivity, "1");
|
2013-08-30 01:33:17 +09:00
|
|
|
SPADES_SETTING(cg_zoomedMouseSensScale, "0.6");
|
2013-12-09 01:48:55 +09:00
|
|
|
SPADES_SETTING(cg_mouseExpPower, "1");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-12-07 17:11:26 +09:00
|
|
|
SPADES_SETTING(cg_chatBeep, "1");
|
|
|
|
|
2013-09-09 17:53:52 +09:00
|
|
|
SPADES_SETTING(cg_holdAimDownSight, "0");
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_SETTING(cg_keyAttack, "LeftMouseButton");
|
|
|
|
SPADES_SETTING(cg_keyAltAttack, "RightMouseButton");
|
|
|
|
SPADES_SETTING(cg_keyToolSpade, "1");
|
|
|
|
SPADES_SETTING(cg_keyToolBlock, "2");
|
|
|
|
SPADES_SETTING(cg_keyToolWeapon, "3");
|
|
|
|
SPADES_SETTING(cg_keyToolGrenade, "4");
|
|
|
|
SPADES_SETTING(cg_keyReloadWeapon, "r");
|
|
|
|
SPADES_SETTING(cg_keyFlashlight, "f");
|
|
|
|
|
|
|
|
SPADES_SETTING(cg_keyMoveLeft, "a");
|
2013-08-26 15:56:27 +09:00
|
|
|
SPADES_SETTING(cg_keyMoveRight, "d");
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_SETTING(cg_keyMoveForward, "w");
|
2013-08-26 15:56:27 +09:00
|
|
|
SPADES_SETTING(cg_keyMoveBackward, "s");
|
2013-08-28 01:26:44 +09:00
|
|
|
SPADES_SETTING(cg_keyJump, "Space");
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_SETTING(cg_keyCrouch, "Control");
|
|
|
|
SPADES_SETTING(cg_keySprint, "Shift");
|
|
|
|
SPADES_SETTING(cg_keySneak, "v");
|
|
|
|
|
|
|
|
SPADES_SETTING(cg_keyCaptureColor, "e");
|
|
|
|
SPADES_SETTING(cg_keyGlobalChat, "t");
|
|
|
|
SPADES_SETTING(cg_keyTeamChat, "y");
|
|
|
|
SPADES_SETTING(cg_keyChangeMapScale, "m");
|
2013-08-27 22:27:49 +09:00
|
|
|
SPADES_SETTING(cg_keyToggleMapZoom, "n");
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_SETTING(cg_keyScoreboard, "Tab");
|
|
|
|
SPADES_SETTING(cg_keyLimbo, "l");
|
|
|
|
|
|
|
|
SPADES_SETTING(cg_keyScreenshot, "0");
|
|
|
|
SPADES_SETTING(cg_keySceneshot, "9");
|
2013-11-22 19:34:20 +09:00
|
|
|
SPADES_SETTING(cg_keySaveMap, "8");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-08-26 21:04:57 +09:00
|
|
|
SPADES_SETTING(cg_switchToolByWheel, "1");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-09-07 21:26:06 +09:00
|
|
|
SPADES_SETTING(cg_fov, "68");
|
|
|
|
|
2013-09-08 02:58:55 +09:00
|
|
|
|
|
|
|
SPADES_SETTING(cg_debugAim, "0");
|
2013-11-18 22:48:47 +09:00
|
|
|
SPADES_SETTING(cg_debugCorpse, "0");
|
2013-09-08 02:58:55 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
namespace spades {
|
|
|
|
namespace client {
|
|
|
|
|
|
|
|
Client::Client(IRenderer *r, IAudioDevice *audioDev,
|
2013-09-15 04:19:34 +02:00
|
|
|
const ServerAddress& host, std::string playerName):
|
2013-08-18 16:18:06 +09:00
|
|
|
renderer(r), audioDevice(audioDev), playerName(playerName) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("Initializing...");
|
2013-09-02 23:09:13 +09:00
|
|
|
|
|
|
|
hostname = host;
|
2013-08-18 16:18:06 +09:00
|
|
|
/*
|
|
|
|
designFont = new Quake3Font(renderer,
|
|
|
|
renderer->RegisterImage("Gfx/Fonts/Orbitron.tga"),
|
|
|
|
(const int*)OrbitronMap,
|
|
|
|
30,
|
|
|
|
18);
|
|
|
|
*/
|
|
|
|
designFont = new Quake3Font(renderer,
|
|
|
|
renderer->RegisterImage("Gfx/Fonts/UnsteadyOversteer.tga"),
|
|
|
|
(const int *)UnsteadyOversteerMap,
|
|
|
|
30,
|
|
|
|
18);
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("Font 'Unsteady Oversteer' Loaded");
|
2013-11-27 16:30:54 +09:00
|
|
|
/*
|
2013-08-18 16:18:06 +09:00
|
|
|
textFont = new Quake3Font(renderer,
|
|
|
|
renderer->RegisterImage("Gfx/Fonts/UbuntuCondensed.tga"),
|
|
|
|
(const int*)UbuntuCondensedMap,
|
|
|
|
24,
|
2013-08-26 01:27:44 +09:00
|
|
|
4);
|
2013-11-27 16:30:54 +09:00
|
|
|
SPLog("Font 'Ubuntu Condensed' Loaded");*/
|
|
|
|
textFont = new client::Quake3Font(renderer,
|
|
|
|
renderer->RegisterImage("Gfx/Fonts/SquareFontModified.png"),
|
|
|
|
(const int*)SquareFontMap,
|
|
|
|
24,
|
|
|
|
4);
|
|
|
|
SPLog("Font 'SquareFont' Loaded");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
bigTextFont = new Quake3Font(renderer,
|
|
|
|
renderer->RegisterImage("Gfx/Fonts/UbuntuCondensedBig.tga"),
|
|
|
|
(const int*)UbuntuCondensedBigMap,
|
|
|
|
48,
|
2013-08-26 01:27:44 +09:00
|
|
|
8);
|
|
|
|
SPLog("Font 'Ubuntu Condensed (Large)' Loaded");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
world = NULL;
|
2013-09-12 14:39:42 +09:00
|
|
|
net = NULL;
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
frameToRendererInit = 5;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// preferences?
|
|
|
|
corpseSoftTimeLimit = 30.f; // TODO: this is not used
|
|
|
|
corpseSoftLimit = 6;
|
|
|
|
corpseHardLimit = 16;
|
|
|
|
|
|
|
|
lastMyCorpse = NULL;
|
|
|
|
|
|
|
|
renderer->SetFogDistance(128.f);
|
|
|
|
renderer->SetFogColor(MakeVector3(.8f, 1.f, 1.f));
|
|
|
|
|
2013-11-02 19:00:50 +01:00
|
|
|
chatWindow = new ChatWindow(this, GetRenderer(), textFont, false);
|
|
|
|
killfeedWindow = new ChatWindow(this, GetRenderer(), textFont, true);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
hurtRingView = new HurtRingView(this);
|
|
|
|
centerMessageView = new CenterMessageView(this, bigTextFont);
|
2013-08-27 22:27:49 +09:00
|
|
|
mapView = new MapView(this, false);
|
|
|
|
largeMapView = new MapView(this, true);
|
2013-08-18 16:18:06 +09:00
|
|
|
scoreboard = new ScoreboardView(this);
|
|
|
|
limbo = new LimboView(this);
|
|
|
|
paletteView = new PaletteView(this);
|
|
|
|
tcView = new TCProgressView(this);
|
2013-11-27 16:30:54 +09:00
|
|
|
scriptedUI.Set(new ClientUI(renderer, audioDev, textFont, this), false);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
time = 0.f;
|
|
|
|
lastAliveTime = 0.f;
|
|
|
|
readyToClose = false;
|
|
|
|
scoreboardVisible = false;
|
|
|
|
flashlightOn = false;
|
|
|
|
lastKills = 0;
|
|
|
|
|
2013-11-28 00:46:45 +09:00
|
|
|
renderer->SetGameMap(NULL);
|
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
logStream = NULL;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
localFireVibrationTime = -1.f;
|
|
|
|
|
|
|
|
lastPosSentTime = 0.f;
|
|
|
|
worldSubFrame = 0.f;
|
|
|
|
grenadeVibration = 0.f;
|
|
|
|
inGameLimbo = false;
|
|
|
|
|
|
|
|
nextScreenShotIndex = 0;
|
2013-11-22 19:34:20 +09:00
|
|
|
nextMapShotIndex = 0;
|
2013-09-02 23:09:13 +09:00
|
|
|
|
|
|
|
timeSinceInit = 0.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
void Client::SetWorld(spades::client::World *w) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(world == w){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-02 19:42:38 +09:00
|
|
|
scriptedUI->CloseUI();
|
2013-08-26 01:27:44 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
RemoveAllCorpses();
|
|
|
|
lastHealth = 0;
|
|
|
|
lastHurtTime = -100.f;
|
|
|
|
hurtRingView->ClearAll();
|
|
|
|
scoreboardVisible = false;
|
|
|
|
flashlightOn = false;
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
for(size_t i = 0; i < clientPlayers.size(); i++) {
|
|
|
|
if(clientPlayers[i]) {
|
|
|
|
clientPlayers[i]->Invalidate();
|
|
|
|
clientPlayers[i]->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clientPlayers.clear();
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(world){
|
|
|
|
world->SetListener(NULL);
|
|
|
|
renderer->SetGameMap(NULL);
|
|
|
|
audioDevice->SetGameMap(NULL);
|
|
|
|
delete world;
|
|
|
|
world = NULL;
|
|
|
|
map = NULL;
|
|
|
|
}
|
|
|
|
world = w;
|
|
|
|
if(world){
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("World set");
|
2013-09-21 04:17:34 +09:00
|
|
|
|
|
|
|
clientPlayers.resize(world->GetNumPlayerSlots());
|
2013-11-22 23:09:16 +01:00
|
|
|
for(size_t i = 0; i < world->GetNumPlayerSlots(); i++) {
|
2013-09-21 04:17:34 +09:00
|
|
|
Player *p = world->GetPlayer(i);
|
|
|
|
if(p){
|
|
|
|
clientPlayers[i] = new ClientPlayer(p, this);
|
|
|
|
}else{
|
|
|
|
clientPlayers[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
world->SetListener(this);
|
|
|
|
map = world->GetMap();
|
|
|
|
renderer->SetGameMap(map);
|
|
|
|
audioDevice->SetGameMap(map);
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("------ World Loaded ------");
|
2013-08-26 01:27:44 +09:00
|
|
|
}else{
|
|
|
|
|
|
|
|
SPLog("World removed");
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("------ World Unloaded ------");
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
limbo->SetSelectedTeam(2);
|
|
|
|
limbo->SetSelectedWeapon(RIFLE_WEAPON);
|
|
|
|
|
|
|
|
RemoveAllLocalEntities();
|
|
|
|
|
|
|
|
worldSubFrame = 0.f;
|
|
|
|
inGameLimbo = false;
|
|
|
|
worldSetTime = time;
|
|
|
|
}
|
|
|
|
|
|
|
|
Client::~Client() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("Disconnecting");
|
|
|
|
if(logStream) {
|
|
|
|
SPLog("Closing netlog");
|
|
|
|
delete logStream;
|
|
|
|
}
|
2013-08-26 01:27:44 +09:00
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
if(net){
|
|
|
|
SPLog("Disconnecting");
|
|
|
|
net->Disconnect();
|
|
|
|
delete net;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("Disconnected");
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
RemoveAllLocalEntities();
|
|
|
|
RemoveAllCorpses();
|
|
|
|
|
|
|
|
renderer->SetGameMap(NULL);
|
2013-11-25 02:46:52 +09:00
|
|
|
audioDevice->SetGameMap(NULL);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
for(size_t i = 0; i < clientPlayers.size(); i++) {
|
|
|
|
if(clientPlayers[i]) {
|
|
|
|
clientPlayers[i]->Invalidate();
|
|
|
|
clientPlayers[i]->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(world)
|
|
|
|
delete world;
|
|
|
|
|
2013-11-27 16:30:54 +09:00
|
|
|
scriptedUI->ClientDestroyed();
|
2013-08-18 16:18:06 +09:00
|
|
|
delete tcView;
|
|
|
|
delete limbo;
|
|
|
|
delete scoreboard;
|
|
|
|
delete mapView;
|
2013-08-27 22:27:49 +09:00
|
|
|
delete largeMapView;
|
2013-08-18 16:18:06 +09:00
|
|
|
delete chatWindow;
|
2013-08-26 17:53:14 +09:00
|
|
|
delete killfeedWindow;
|
2013-08-18 16:18:06 +09:00
|
|
|
delete paletteView;
|
|
|
|
delete centerMessageView;
|
|
|
|
delete hurtRingView;
|
2013-11-22 20:46:20 +09:00
|
|
|
designFont->Release();
|
|
|
|
textFont->Release();
|
|
|
|
bigTextFont->Release();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::WantsToBeClosed() {
|
|
|
|
return readyToClose;
|
|
|
|
}
|
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
void Client::DoInit() {
|
|
|
|
renderer->Init();
|
|
|
|
// preload
|
|
|
|
SmokeSpriteEntity(this, Vector4(), 20.f);
|
|
|
|
|
2013-09-06 11:44:36 +09:00
|
|
|
renderer->RegisterImage("Textures/Fluid.png");
|
|
|
|
renderer->RegisterImage("Textures/WaterExpl.png");
|
|
|
|
renderer->RegisterImage("Gfx/White.tga");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Block/Build.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal1.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal2.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal3.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal4.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Misc/SwitchMapZoom.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Misc/OpenMap.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Misc/CloseMap.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Player/Flashlight.wav");
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/SwitchLocal.wav");
|
|
|
|
renderer->RegisterImage("Gfx/Ball.png");
|
|
|
|
renderer->RegisterModel("Models/Player/Dead.kv6");
|
|
|
|
renderer->RegisterImage("Gfx/Spotlight.tga");
|
|
|
|
renderer->RegisterImage("Gfx/Glare.tga");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Spade/Spade.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Block/Block2.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Grenade/Grenade.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/SMG/Weapon.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/SMG/WeaponNoMagazine.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/SMG/Magazine.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Rifle/Weapon.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Rifle/WeaponNoMagazine.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Rifle/Magazine.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Shotgun/Weapon.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Shotgun/WeaponNoPump.kv6");
|
|
|
|
renderer->RegisterModel("Models/Weapons/Shotgun/Pump.kv6");
|
2013-11-03 17:13:49 +01:00
|
|
|
renderer->RegisterModel("Models/Player/Arm.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/UpperArm.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/LegCrouch.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/TorsoCrouch.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/Leg.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/Torso.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/Arms.kv6");
|
|
|
|
renderer->RegisterModel("Models/Player/Head.kv6");
|
|
|
|
renderer->RegisterModel("Models/MapObjects/Intel.kv6");
|
2013-09-06 11:44:36 +09:00
|
|
|
renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
|
|
|
|
renderer->RegisterImage("Gfx/Sight.tga");
|
|
|
|
renderer->RegisterImage("Gfx/Bullet/7.62mm.tga");
|
|
|
|
renderer->RegisterImage("Gfx/Bullet/9mm.tga");
|
|
|
|
renderer->RegisterImage("Gfx/Bullet/12gauge.tga");
|
|
|
|
renderer->RegisterImage("Gfx/CircleGradient.png");
|
|
|
|
renderer->RegisterImage("Gfx/LoadingWindow.png");
|
|
|
|
renderer->RegisterImage("Gfx/LoadingWindowGlow.png");
|
|
|
|
renderer->RegisterImage("Gfx/LoadingStripe.png");
|
2013-09-12 23:26:08 +09:00
|
|
|
renderer->RegisterImage("Gfx/HurtSprite.png");
|
|
|
|
renderer->RegisterImage("Gfx/HurtRing.tga");
|
2013-09-06 11:44:36 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Feedback/Chat.wav");
|
2013-09-02 23:09:13 +09:00
|
|
|
|
2013-09-14 20:00:30 -07:00
|
|
|
SPLog("Started connecting to '%s'", hostname.asString(true).c_str());
|
2013-09-02 23:09:13 +09:00
|
|
|
net = new NetClient(this);
|
|
|
|
net->Connect(hostname);
|
|
|
|
|
|
|
|
// decide log file name
|
2013-09-15 04:19:34 +02:00
|
|
|
std::string fn = hostname.asString(false);
|
2013-09-02 23:09:13 +09:00
|
|
|
std::string fn2;
|
|
|
|
{
|
|
|
|
time_t t;
|
|
|
|
struct tm tm;
|
|
|
|
::time(&t);
|
|
|
|
tm = *localtime(&t);
|
|
|
|
char buf[256];
|
|
|
|
sprintf(buf, "%04d%02d%02d%02d%02d%02d_",
|
|
|
|
tm.tm_year + 1900,
|
|
|
|
tm.tm_mon + 1,
|
|
|
|
tm.tm_mday,
|
|
|
|
tm.tm_hour,
|
|
|
|
tm.tm_min,
|
|
|
|
tm.tm_sec);
|
|
|
|
fn2 = buf;
|
|
|
|
}
|
|
|
|
for(size_t i = 0; i < fn.size(); i++){
|
|
|
|
char c = fn[i];
|
|
|
|
if((c >= 'a' && c <= 'z') ||
|
|
|
|
(c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= '0' && c <= '9')) {
|
|
|
|
fn2 += c;
|
|
|
|
}else{
|
|
|
|
fn2 += '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn2 = "NetLogs/" + fn2 + ".log";
|
|
|
|
|
|
|
|
try{
|
|
|
|
logStream = FileManager::OpenForWriting(fn2.c_str());
|
|
|
|
SPLog("Netlog Started at '%s'", fn2.c_str());
|
|
|
|
}catch(const std::exception& ex){
|
2013-09-20 23:03:32 +02:00
|
|
|
SPLog("Failed to open netlog file '%s' (%s)", fn2.c_str(), ex.what());
|
2013-09-02 23:09:13 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::RunFrame(float dt) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
if(frameToRendererInit > 0){
|
|
|
|
// waiting for renderer initialization
|
|
|
|
|
|
|
|
DrawStartupScreen();
|
|
|
|
|
|
|
|
frameToRendererInit--;
|
|
|
|
if(frameToRendererInit == 0){
|
|
|
|
DoInit();
|
|
|
|
|
|
|
|
}else{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 04:03:03 +09:00
|
|
|
timeSinceInit += std::min(dt, .03f);
|
2013-09-02 23:09:13 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
try{
|
|
|
|
if(net->GetStatus() == NetClientStatusConnected)
|
|
|
|
net->DoEvents(0);
|
|
|
|
else
|
2013-11-28 00:46:45 +09:00
|
|
|
net->DoEvents(10);
|
2013-08-18 16:18:06 +09:00
|
|
|
}catch(const std::exception& ex){
|
2013-08-26 19:24:15 +09:00
|
|
|
if(net->GetStatus() == NetClientStatusNotConnected){
|
|
|
|
SPLog("Disconnected because of error:\n%s", ex.what());
|
|
|
|
NetLog("Disconnected because of error:\n%s", ex.what());
|
2013-08-18 16:18:06 +09:00
|
|
|
throw;
|
2013-08-26 19:24:15 +09:00
|
|
|
}else{
|
|
|
|
SPLog("Exception while processing network packets (ignored):\n%s", ex.what());
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
hurtRingView->Update(dt);
|
|
|
|
centerMessageView->Update(dt);
|
|
|
|
mapView->Update(dt);
|
2013-08-27 22:27:49 +09:00
|
|
|
largeMapView->Update(dt);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
//puts(net->GetStatusString().c_str());
|
|
|
|
if(world){
|
|
|
|
Player* player = world->GetLocalPlayer();
|
|
|
|
|
|
|
|
if(player && player->GetTeamId() >= 2){
|
|
|
|
// spectating
|
|
|
|
|
|
|
|
Vector3 lastPos = followPos;
|
|
|
|
followVel *= powf(.3f, dt);
|
|
|
|
followPos += followVel * dt;
|
|
|
|
|
2013-11-18 20:02:12 +09:00
|
|
|
if(followPos.x < 0.f) {
|
|
|
|
followVel.x = fabsf(followVel.x) * 0.2f;
|
|
|
|
followPos = lastPos + followVel * dt;
|
|
|
|
}
|
|
|
|
if(followPos.y < 0.f) {
|
|
|
|
followVel.y = fabsf(followVel.y) * 0.2f;
|
|
|
|
followPos = lastPos + followVel * dt;
|
|
|
|
}
|
|
|
|
if(followPos.x > (float)GetWorld()->GetMap()->Width()) {
|
|
|
|
followVel.x = fabsf(followVel.x) * -0.2f;
|
|
|
|
followPos = lastPos + followVel * dt;
|
|
|
|
}
|
|
|
|
if(followPos.y > (float)GetWorld()->GetMap()->Height()) {
|
|
|
|
followVel.y = fabsf(followVel.y) * -0.2f;
|
|
|
|
followPos = lastPos + followVel * dt;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
GameMap::RayCastResult minResult;
|
|
|
|
float minDist = 1.e+10f;
|
|
|
|
Vector3 minShift;
|
|
|
|
|
|
|
|
if(followVel.GetLength() < .01){
|
|
|
|
followPos = lastPos;
|
|
|
|
followVel *= 0.f;
|
|
|
|
}else{
|
|
|
|
for(int sx = -1; sx <= 1; sx ++)
|
|
|
|
for(int sy = -1; sy <= 1; sy++)
|
|
|
|
for(int sz = -1; sz <= 1; sz++){
|
|
|
|
GameMap::RayCastResult result;
|
|
|
|
Vector3 shift = {sx*.1f, sy*.1f,sz*.1f};
|
|
|
|
result = map->CastRay2(lastPos+shift, followPos - lastPos,
|
|
|
|
256);
|
|
|
|
if(result.hit && !result.startSolid &&
|
|
|
|
Vector3::Dot(result.hitPos - followPos - shift,
|
|
|
|
followPos - lastPos) < 0.f){
|
|
|
|
|
|
|
|
float dist = Vector3::Dot(result.hitPos - followPos - shift,
|
|
|
|
(followPos - lastPos).Normalize());
|
|
|
|
if(dist < minDist){
|
|
|
|
minResult = result;
|
|
|
|
minDist = dist;
|
|
|
|
minShift = shift;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if(minDist < 1.e+9f){
|
|
|
|
GameMap::RayCastResult result = minResult;
|
|
|
|
Vector3 shift = minShift;
|
|
|
|
followPos = result.hitPos - shift;
|
|
|
|
followPos.x += result.normal.x * .02f;
|
|
|
|
followPos.y += result.normal.y * .02f;
|
|
|
|
followPos.z += result.normal.z * .02f;
|
|
|
|
|
|
|
|
// reflect
|
|
|
|
Vector3 norm = {(float)result.normal.x,
|
|
|
|
(float)result.normal.y,
|
|
|
|
(float)result.normal.z};
|
|
|
|
float dot = Vector3::Dot(followVel, norm);
|
|
|
|
followVel -= norm * (dot * 1.2f);
|
|
|
|
/*
|
|
|
|
int link = world->mapWrapper->GetLink(result.hitBlock.x,
|
|
|
|
result.hitBlock.y,
|
|
|
|
result.hitBlock.z);
|
|
|
|
|
|
|
|
printf("hit block: link = %d (", link);
|
|
|
|
switch(link){
|
|
|
|
case 0: puts("Invalid)"); break;
|
|
|
|
case 1: puts("Root)"); break;
|
|
|
|
case 2: puts("Neg X)"); break;
|
|
|
|
case 3: puts("Pos X)"); break;
|
|
|
|
case 4: puts("Neg Y)"); break;
|
|
|
|
case 5: puts("Pos Y)"); break;
|
|
|
|
case 6: puts("Neg Z)"); break;
|
|
|
|
case 7: puts("Pos Z)"); break;
|
|
|
|
}*/
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Vector3 front;
|
|
|
|
Vector3 up = {0, 0, -1};
|
|
|
|
|
|
|
|
front.x = -cosf(followYaw) * cosf(followPitch);
|
|
|
|
front.y = -sinf(followYaw) * cosf(followPitch);
|
|
|
|
front.z = sinf(followPitch);
|
|
|
|
|
|
|
|
Vector3 right = -Vector3::Cross(up, front).Normalize();
|
|
|
|
Vector3 up2 = Vector3::Cross(right, front).Normalize();
|
|
|
|
|
|
|
|
float scale = 10.f * dt;
|
|
|
|
if(playerInput.sprint){
|
|
|
|
scale *= 3.f;
|
|
|
|
}
|
|
|
|
front *= scale;
|
|
|
|
right *= scale;
|
|
|
|
up2 *= scale;
|
|
|
|
|
|
|
|
if(playerInput.moveForward){
|
|
|
|
followVel += front;
|
|
|
|
}else if(playerInput.moveBackward){
|
|
|
|
followVel -= front;
|
|
|
|
}
|
|
|
|
if(playerInput.moveLeft){
|
|
|
|
followVel -= right;
|
|
|
|
}else if(playerInput.moveRight){
|
|
|
|
followVel += right;
|
|
|
|
}
|
|
|
|
if(playerInput.jump){
|
|
|
|
followVel += up2;
|
|
|
|
}else if(playerInput.crouch){
|
|
|
|
followVel -= up2;
|
|
|
|
}
|
|
|
|
|
|
|
|
SPAssert(followVel.GetLength() < 100.f);
|
|
|
|
}else if(player){
|
|
|
|
// joined in a team
|
|
|
|
PlayerInput inp = playerInput;
|
2013-08-31 01:12:45 +09:00
|
|
|
WeaponInput winp = weapInput;
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
if(inp.crouch == false){
|
|
|
|
if(player->GetInput().crouch){
|
|
|
|
if(!player->TryUncrouch(false)){
|
|
|
|
inp.crouch = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(inp.jump){
|
|
|
|
if(!player->IsOnGroundOrWade())
|
|
|
|
inp.jump = false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
if(clientPlayers[world->GetLocalPlayerIndex()]->IsChangingTool()) {
|
2013-08-31 01:12:45 +09:00
|
|
|
winp.primary = false;
|
|
|
|
winp.secondary = false;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-08-31 02:50:51 +09:00
|
|
|
if(player->GetTool() == Player::ToolWeapon &&
|
2013-09-02 15:15:40 +09:00
|
|
|
player->IsAwaitingReloadCompletion() &&
|
|
|
|
!player->GetWeapon()->IsReloadSlow()) {
|
2013-08-31 02:50:51 +09:00
|
|
|
winp.primary = false;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
player->SetInput(inp);
|
2013-08-31 01:12:45 +09:00
|
|
|
player->SetWeaponInput(winp);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
//send player input
|
2013-08-31 01:12:45 +09:00
|
|
|
// FIXME: send only there are any changed
|
2013-08-18 16:18:06 +09:00
|
|
|
net->SendPlayerInput(inp);
|
|
|
|
net->SendWeaponInput(weapInput);
|
|
|
|
|
2013-12-02 19:42:38 +09:00
|
|
|
//PlayerInput actualInput = player->GetInput();
|
2013-08-18 16:18:06 +09:00
|
|
|
WeaponInput actualWeapInput = player->GetWeaponInput();
|
|
|
|
|
|
|
|
if(actualWeapInput.secondary && player->IsToolWeapon() &&
|
|
|
|
player->IsAlive()){
|
|
|
|
}else{
|
|
|
|
if(player->IsToolWeapon()){
|
|
|
|
// there is a possibility that player has respawned or something.
|
|
|
|
// stop aiming down
|
|
|
|
weapInput.secondary = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
if(!player->IsToolSelectable(player->GetTool())) {
|
2013-11-18 19:55:27 +09:00
|
|
|
// release mouse button before auto-switching tools
|
|
|
|
winp.primary = false;
|
|
|
|
winp.secondary = false;
|
|
|
|
weapInput = winp;
|
|
|
|
net->SendWeaponInput(weapInput);
|
|
|
|
actualWeapInput = winp = player->GetWeaponInput();
|
|
|
|
|
2013-08-31 01:12:45 +09:00
|
|
|
// select another tool
|
2013-09-21 04:17:34 +09:00
|
|
|
Player::ToolType t = player->GetTool();
|
2013-08-31 01:12:45 +09:00
|
|
|
do{
|
|
|
|
switch(t){
|
|
|
|
case Player::ToolSpade:
|
|
|
|
t = Player::ToolGrenade;
|
|
|
|
break;
|
|
|
|
case Player::ToolBlock:
|
|
|
|
t = Player::ToolSpade;
|
|
|
|
break;
|
|
|
|
case Player::ToolWeapon:
|
|
|
|
t = Player::ToolBlock;
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
t = Player::ToolWeapon;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}while(!world->GetLocalPlayer()->IsToolSelectable(t));
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(t);
|
2013-08-31 01:12:45 +09:00
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector3 curFront = player->GetFront();
|
|
|
|
if(curFront.x != lastFront.x ||
|
|
|
|
curFront.y != lastFront.y ||
|
|
|
|
curFront.z != lastFront.z) {
|
|
|
|
lastFront = curFront;
|
|
|
|
net->SendOrientation(curFront);
|
|
|
|
}
|
|
|
|
|
|
|
|
lastKills = world->GetPlayerPersistent(player->GetId()).kills;
|
|
|
|
|
|
|
|
if(player->IsAlive())
|
|
|
|
lastAliveTime = time;
|
|
|
|
|
|
|
|
if(player->GetHealth() < lastHealth){
|
|
|
|
// hurt!
|
|
|
|
lastHealth = player->GetHealth();
|
|
|
|
lastHurtTime = world->GetTime();
|
|
|
|
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c;
|
2013-08-18 16:18:06 +09:00
|
|
|
switch((rand() >> 3) & 3){
|
|
|
|
case 0:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal1.wav");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal2.wav");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal3.wav");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal4.wav");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-09-12 23:26:08 +09:00
|
|
|
float hpper = player->GetHealth() / 100.f;
|
2013-09-15 01:01:07 +09:00
|
|
|
int cnt = 18 - (int)(player->GetHealth() / 100.f * 8.f);
|
|
|
|
hurtSprites.resize(std::max(cnt, 6));
|
2013-09-12 23:26:08 +09:00
|
|
|
for(size_t i = 0; i < hurtSprites.size(); i++) {
|
|
|
|
HurtSprite& spr = hurtSprites[i];
|
2013-09-20 23:03:32 +02:00
|
|
|
spr.angle = GetRandom() * (2.f * static_cast<float>(M_PI));
|
2013-09-15 01:01:07 +09:00
|
|
|
spr.scale = .2f + GetRandom() * GetRandom() * .7f;
|
2013-09-12 23:26:08 +09:00
|
|
|
spr.horzShift = GetRandom();
|
|
|
|
spr.strength = .3f + GetRandom() * .7f;
|
|
|
|
if(hpper > .5f) {
|
|
|
|
spr.strength *= 1.5f - hpper;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(c, AudioParam());
|
|
|
|
}else{
|
|
|
|
lastHealth = player->GetHealth();
|
|
|
|
}
|
|
|
|
|
|
|
|
inp.jump = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
world->Advance(dt);
|
|
|
|
#else
|
|
|
|
// accurately resembles server's physics
|
|
|
|
// but not smooth
|
|
|
|
if(dt > 0.f)
|
|
|
|
worldSubFrame += dt;
|
|
|
|
|
|
|
|
float frameStep = 1.f / 60.f;
|
|
|
|
while(worldSubFrame >= frameStep){
|
|
|
|
world->Advance(frameStep);
|
|
|
|
worldSubFrame -= frameStep;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
for(size_t i = 0; i < clientPlayers.size(); i++){
|
|
|
|
if(clientPlayers[i]){
|
|
|
|
clientPlayers[i]->Update(dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// corpse never accesses audio nor renderer
|
|
|
|
class CorpseUpdateDispatch: public ConcurrentDispatch{
|
|
|
|
Client *client;
|
|
|
|
float dt;
|
|
|
|
public:
|
|
|
|
CorpseUpdateDispatch(Client *c, float dt):
|
|
|
|
client(c), dt(dt){}
|
|
|
|
virtual void Run(){
|
|
|
|
std::list<Corpse *>::iterator it;
|
|
|
|
for(it = client->corpses.begin(); it != client->corpses.end(); it++){
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
(*it)->Update(dt / 4.f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
CorpseUpdateDispatch corpseDispatch(this, dt);
|
|
|
|
corpseDispatch.Start();
|
|
|
|
|
|
|
|
{
|
|
|
|
std::list<ILocalEntity *>::iterator it;
|
|
|
|
std::vector<std::list<ILocalEntity *>::iterator> its;
|
|
|
|
for(it = localEntities.begin(); it != localEntities.end(); it++){
|
|
|
|
if(!(*it)->Update(dt))
|
|
|
|
its.push_back(it);
|
|
|
|
}
|
|
|
|
for(size_t i = 0; i < its.size(); i++){
|
|
|
|
delete *(its[i]);
|
|
|
|
localEntities.erase(its[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
corpseDispatch.Join();
|
|
|
|
|
|
|
|
if(grenadeVibration > 0.f){
|
|
|
|
grenadeVibration -= dt;
|
|
|
|
if(grenadeVibration < 0.f)
|
|
|
|
grenadeVibration = 0.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(time > lastPosSentTime + 1.f &&
|
|
|
|
world->GetLocalPlayer()){
|
|
|
|
Player *p = world->GetLocalPlayer();
|
2013-09-04 11:03:04 +09:00
|
|
|
if(p->IsAlive() && p->GetTeamId() < 2){
|
2013-08-18 16:18:06 +09:00
|
|
|
net->SendPosition();
|
|
|
|
lastPosSentTime = time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
renderer->SetFogColor(MakeVector3(0.f, 0.f, 0.f));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
chatWindow->Update(dt);
|
2013-08-26 17:53:14 +09:00
|
|
|
killfeedWindow->Update(dt);
|
2013-08-18 16:18:06 +09:00
|
|
|
limbo->Update(dt);
|
|
|
|
|
|
|
|
// SceneDef also can be used for sounds
|
|
|
|
SceneDefinition sceneDef = SceneDef();
|
|
|
|
lastSceneDef = sceneDef;
|
|
|
|
|
|
|
|
// Update sounds
|
|
|
|
try{
|
|
|
|
audioDevice->Respatialize(sceneDef.viewOrigin,
|
|
|
|
sceneDef.viewAxis[2],
|
|
|
|
sceneDef.viewAxis[1]);
|
|
|
|
}catch(const std::exception& ex){
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("Audio subsystem returned error (ignored):\n%s",
|
|
|
|
ex.what());
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// render scene
|
|
|
|
DrawScene();
|
|
|
|
|
|
|
|
// draw 2d
|
|
|
|
Draw2D();
|
|
|
|
|
2013-11-27 16:30:54 +09:00
|
|
|
// draw scripted GUI
|
|
|
|
scriptedUI->RunFrame(dt);
|
|
|
|
if(scriptedUI->WantsClientToBeClosed())
|
|
|
|
readyToClose = true;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// Well done!
|
|
|
|
renderer->FrameDone();
|
|
|
|
renderer->Flip();
|
|
|
|
|
|
|
|
time += dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::Closing() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::MouseEvent(float x, float y) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-11-27 16:30:54 +09:00
|
|
|
if(scriptedUI->NeedsInput()) {
|
|
|
|
scriptedUI->MouseEvent(x, y);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(IsLimboViewActive()){
|
|
|
|
limbo->MouseEvent(x, y);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsFollowing()){
|
|
|
|
SPAssert(world != NULL);
|
|
|
|
if(world->GetLocalPlayer() &&
|
|
|
|
world->GetLocalPlayer()->GetTeamId() >= 2 &&
|
|
|
|
followingPlayerId == world->GetLocalPlayerIndex()){
|
|
|
|
// invert dir
|
|
|
|
x = -x; y = -y;
|
|
|
|
}
|
|
|
|
followYaw -= x * 0.003f;
|
|
|
|
followPitch -= y * 0.003f;
|
2013-09-20 23:11:12 +02:00
|
|
|
if(followPitch < -M_PI*.45f) followPitch = -static_cast<float>(M_PI)*.45f;
|
|
|
|
if(followPitch > M_PI*.45f) followPitch = static_cast<float>(M_PI) * .45f;
|
2013-09-20 23:03:32 +02:00
|
|
|
followYaw = fmodf(followYaw, static_cast<float>(M_PI)*2.f);
|
2013-08-18 16:18:06 +09:00
|
|
|
}else if(world && world->GetLocalPlayer()){
|
|
|
|
Player *p = world->GetLocalPlayer();
|
2013-09-21 04:17:34 +09:00
|
|
|
float aimDownState = GetAimDownState();
|
2013-08-18 16:18:06 +09:00
|
|
|
if(p->IsAlive()){
|
|
|
|
x /= GetAimDownZoomScale();
|
|
|
|
y /= GetAimDownZoomScale();
|
2013-08-29 23:59:28 +09:00
|
|
|
|
2013-12-09 01:48:55 +09:00
|
|
|
float rad = x * x + y * y;
|
|
|
|
if(rad > 0.f) {
|
|
|
|
if((float)cg_mouseExpPower < 0.001f ||
|
|
|
|
isnan((float)cg_mouseExpPower)) {
|
|
|
|
SPLog("Invalid cg_mouseExpPower value, resetting to 1.0");
|
|
|
|
cg_mouseExpPower = 1.f;
|
|
|
|
}
|
|
|
|
float factor = renderer->ScreenWidth() * .1f;
|
|
|
|
factor *= factor;
|
|
|
|
rad /= factor;
|
|
|
|
rad = powf(rad, (float)cg_mouseExpPower * 0.5f - 0.5f);
|
|
|
|
|
|
|
|
// shouldn't happen...
|
|
|
|
if(isnan(rad)) rad = 1.f;
|
|
|
|
|
|
|
|
x *= rad;
|
|
|
|
y *= rad;
|
|
|
|
}
|
|
|
|
|
2013-08-29 23:59:28 +09:00
|
|
|
if(aimDownState > 0.f) {
|
|
|
|
float scale = cg_zoomedMouseSensScale;
|
|
|
|
scale = powf(scale, aimDownState);
|
|
|
|
x *= scale;
|
|
|
|
y *= scale;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
x *= (float)cg_mouseSensitivity;
|
|
|
|
y *= (float)cg_mouseSensitivity;
|
|
|
|
|
|
|
|
p->Turn(x * 0.003f, y * 0.003f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::CharEvent(const std::string &ch){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-11-27 16:30:54 +09:00
|
|
|
if(scriptedUI->NeedsInput()) {
|
|
|
|
scriptedUI->CharEvent(ch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-02 19:42:38 +09:00
|
|
|
|
|
|
|
if(ch == "/") {
|
|
|
|
scriptedUI->EnterCommandWindow();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-28 01:26:44 +09:00
|
|
|
// TODO: this might not be a fast way
|
2013-09-14 07:11:40 +02:00
|
|
|
//lm: ideally we should normalize the key when reading the config.
|
2013-08-28 01:26:44 +09:00
|
|
|
static bool CheckKey(const std::string& cfg,
|
|
|
|
const std::string& input) {
|
|
|
|
if(cfg.empty())
|
|
|
|
return false;
|
|
|
|
std::vector<std::string> keys = Split(cfg,",");
|
|
|
|
static const std::string space1("space");
|
|
|
|
static const std::string space2("spacebar");
|
|
|
|
static const std::string space3("spacekey");
|
|
|
|
for(size_t i = 0; i < keys.size(); i++) {
|
|
|
|
std::string key = keys[i];
|
|
|
|
if(EqualsIgnoringCase(key, space1) ||
|
|
|
|
EqualsIgnoringCase(key, space2) ||
|
|
|
|
EqualsIgnoringCase(key, space3)) {
|
|
|
|
if(input == " ")
|
|
|
|
return true;
|
|
|
|
}else{
|
|
|
|
if(EqualsIgnoringCase(key, input))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::KeyEvent(const std::string& name, bool down){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-11-27 16:30:54 +09:00
|
|
|
if(scriptedUI->NeedsInput()) {
|
|
|
|
scriptedUI->KeyEvent(name, down);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(name == "Escape"){
|
|
|
|
if(down){
|
|
|
|
if(inGameLimbo){
|
|
|
|
inGameLimbo = false;
|
|
|
|
}else{
|
2013-12-02 19:42:38 +09:00
|
|
|
if(GetWorld() == NULL){
|
2013-11-17 21:51:45 +09:00
|
|
|
// no world = loading now.
|
|
|
|
// in this case, quit the game immediately.
|
|
|
|
readyToClose = true;
|
2013-12-02 19:42:38 +09:00
|
|
|
}
|
2013-11-27 16:30:54 +09:00
|
|
|
else {
|
|
|
|
scriptedUI->EnterClientMenu();
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}else if(world){
|
|
|
|
if(IsLimboViewActive()){
|
|
|
|
if(down){
|
|
|
|
limbo->KeyEvent(name);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(IsFollowing()){
|
2013-08-28 01:26:44 +09:00
|
|
|
if(CheckKey(cg_keyAttack, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
if(down){
|
|
|
|
if(world->GetLocalPlayer()->GetTeamId() >= 2 ||
|
|
|
|
time > lastAliveTime + 1.3f)
|
|
|
|
FollowNextPlayer();
|
|
|
|
}
|
|
|
|
return;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyAltAttack, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
if(down){
|
|
|
|
if(world->GetLocalPlayer()){
|
|
|
|
followingPlayerId = world->GetLocalPlayerIndex();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(world->GetLocalPlayer()){
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
|
|
|
|
if(p->IsAlive() && p->GetTool() == Player::ToolBlock && down) {
|
|
|
|
if(paletteView->KeyInput(name)){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-13 00:15:13 +09:00
|
|
|
if(name == "h" && down && false) {
|
|
|
|
// debug
|
2013-09-12 23:26:08 +09:00
|
|
|
int h = p->GetHealth();
|
|
|
|
h -= 10; if(h <= 0) h = 100;
|
|
|
|
p->SetHP(h, HurtTypeWeapon, MakeVector3(0, 0, 0));
|
|
|
|
}
|
|
|
|
|
2013-11-18 22:48:47 +09:00
|
|
|
if(cg_debugCorpse){
|
|
|
|
if(name == "p" && down){
|
|
|
|
Corpse *corp;
|
|
|
|
Player *victim = world->GetLocalPlayer();
|
|
|
|
corp = new Corpse(renderer, map, victim);
|
|
|
|
corp->AddImpulse(victim->GetFront() * 32.f);
|
|
|
|
corpses.push_back(corp);
|
|
|
|
|
|
|
|
if(corpses.size() > corpseHardLimit){
|
|
|
|
corp = corpses.front();
|
|
|
|
delete corp;
|
|
|
|
corpses.pop_front();
|
|
|
|
}else if(corpses.size() > corpseSoftLimit){
|
|
|
|
RemoveInvisibleCorpses();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
if(CheckKey(cg_keyMoveLeft, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.moveLeft = down;
|
|
|
|
keypadInput.left = down;
|
|
|
|
if(down) playerInput.moveRight = false;
|
|
|
|
else playerInput.moveRight = keypadInput.right;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyMoveRight, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.moveRight = down;
|
|
|
|
keypadInput.right = down;
|
|
|
|
if(down) playerInput.moveLeft = false;
|
|
|
|
else playerInput.moveLeft = keypadInput.left;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyMoveForward, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.moveForward = down;
|
|
|
|
keypadInput.forward = down;
|
|
|
|
if(down) playerInput.moveBackward = false;
|
|
|
|
else playerInput.moveBackward = keypadInput.backward;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyMoveBackward, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.moveBackward = down;
|
|
|
|
keypadInput.backward = down;
|
|
|
|
if(down) playerInput.moveForward = false;
|
|
|
|
else playerInput.moveForward = keypadInput.forward;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyCrouch, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.crouch = down;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keySprint, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.sprint = down;
|
|
|
|
if(down){
|
|
|
|
if(world->GetLocalPlayer()->IsToolWeapon()){
|
|
|
|
weapInput.secondary = false;
|
|
|
|
}
|
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keySneak, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.sneak = down;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyJump, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
playerInput.jump = down;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyAttack, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
weapInput.primary = down;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyAltAttack, name)){
|
2013-09-09 17:53:52 +09:00
|
|
|
if(world->GetLocalPlayer()->IsToolWeapon() && (!cg_holdAimDownSight)){
|
2013-08-18 16:18:06 +09:00
|
|
|
if(down && !playerInput.sprint){
|
|
|
|
weapInput.secondary = !weapInput.secondary;
|
|
|
|
}
|
|
|
|
}else{
|
2013-09-09 17:53:52 +09:00
|
|
|
if(!playerInput.sprint){
|
|
|
|
weapInput.secondary = down;
|
|
|
|
}else{
|
|
|
|
weapInput.secondary = down;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyReloadWeapon, name) && down){
|
2013-08-31 02:50:51 +09:00
|
|
|
Weapon *w = world->GetLocalPlayer()->GetWeapon();
|
|
|
|
if(w->GetAmmo() < w->GetClipSize() &&
|
2013-08-31 15:10:20 +09:00
|
|
|
w->GetStock() > 0 &&
|
|
|
|
(!world->GetLocalPlayer()->IsAwaitingReloadCompletion()) &&
|
|
|
|
(!w->IsReloading()) &&
|
|
|
|
world->GetLocalPlayer()->GetTool() == Player::ToolWeapon){
|
2013-08-31 02:50:51 +09:00
|
|
|
world->GetLocalPlayer()->Reload();
|
|
|
|
if(world->GetLocalPlayer()->IsToolWeapon()){
|
|
|
|
weapInput.secondary = false;
|
|
|
|
}
|
|
|
|
net->SendReload();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyToolSpade, name) && down){
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive() &&
|
|
|
|
world->GetLocalPlayer()->IsToolSelectable(Player::ToolSpade)){
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(Player::ToolSpade);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyToolBlock, name) && down){
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive() &&
|
|
|
|
world->GetLocalPlayer()->IsToolSelectable(Player::ToolBlock)){
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(Player::ToolBlock);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyToolWeapon, name) && down){
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive() &&
|
|
|
|
world->GetLocalPlayer()->IsToolSelectable(Player::ToolWeapon)){
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(Player::ToolWeapon);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyToolGrenade, name) && down){
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive() &&
|
|
|
|
world->GetLocalPlayer()->IsToolSelectable(Player::ToolGrenade)){
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(Player::ToolGrenade);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyGlobalChat, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
// global chat
|
2013-12-02 19:42:38 +09:00
|
|
|
scriptedUI->EnterGlobalChatWindow();
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyTeamChat, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
// team chat
|
2013-12-02 19:42:38 +09:00
|
|
|
scriptedUI->EnterTeamChatWindow();
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyCaptureColor, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
CaptureColor();
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyChangeMapScale, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
mapView->SwitchScale();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Misc/SwitchMapZoom.wav");
|
2013-08-27 22:45:36 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyToggleMapZoom, name) && down){
|
2013-08-27 22:45:36 +09:00
|
|
|
if(largeMapView->ToggleZoom()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Misc/OpenMap.wav");
|
2013-08-27 22:45:36 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}else{
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Misc/CloseMap.wav");
|
2013-08-27 22:45:36 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyScoreboard, name)){
|
2013-08-18 16:18:06 +09:00
|
|
|
scoreboardVisible = down;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyLimbo, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
limbo->SetSelectedTeam(world->GetLocalPlayer()->GetTeamId());
|
|
|
|
limbo->SetSelectedWeapon(world->GetLocalPlayer()->GetWeapon()->GetWeaponType());
|
|
|
|
inGameLimbo = true;
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keySceneshot, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
TakeScreenShot(true);
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyScreenshot, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
TakeScreenShot(false);
|
2013-11-22 19:34:20 +09:00
|
|
|
}else if(CheckKey(cg_keySaveMap, name) && down){
|
|
|
|
TakeMapShot();
|
2013-08-28 01:26:44 +09:00
|
|
|
}else if(CheckKey(cg_keyFlashlight, name) && down){
|
2013-08-18 16:18:06 +09:00
|
|
|
flashlightOn = !flashlightOn;
|
|
|
|
flashlightOnTime = time;
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Player/Flashlight.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
2013-08-26 21:04:57 +09:00
|
|
|
}else if(cg_switchToolByWheel && down) {
|
2013-08-31 01:12:45 +09:00
|
|
|
bool rev = (int)cg_switchToolByWheel > 0;
|
2013-08-26 21:04:57 +09:00
|
|
|
if(name == (rev ? "WheelDown":"WheelUp")) {
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive()){
|
2013-09-21 04:17:34 +09:00
|
|
|
Player::ToolType t = world->GetLocalPlayer()->GetTool();
|
2013-08-31 01:12:45 +09:00
|
|
|
do{
|
|
|
|
switch(t){
|
|
|
|
case Player::ToolSpade:
|
|
|
|
t = Player::ToolGrenade;
|
|
|
|
break;
|
|
|
|
case Player::ToolBlock:
|
|
|
|
t = Player::ToolSpade;
|
|
|
|
break;
|
|
|
|
case Player::ToolWeapon:
|
|
|
|
t = Player::ToolBlock;
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
t = Player::ToolWeapon;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}while(!world->GetLocalPlayer()->IsToolSelectable(t));
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(t);
|
2013-08-26 21:04:57 +09:00
|
|
|
}
|
|
|
|
}else if(name == (rev ? "WheelUp":"WheelDown")) {
|
2013-08-31 01:12:45 +09:00
|
|
|
if(world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
world->GetLocalPlayer()->IsAlive()){
|
2013-09-21 04:17:34 +09:00
|
|
|
Player::ToolType t = world->GetLocalPlayer()->GetTool();
|
2013-08-31 01:12:45 +09:00
|
|
|
do{
|
|
|
|
switch(t){
|
|
|
|
case Player::ToolSpade:
|
|
|
|
t = Player::ToolBlock;
|
|
|
|
break;
|
|
|
|
case Player::ToolBlock:
|
|
|
|
t = Player::ToolWeapon;
|
|
|
|
break;
|
|
|
|
case Player::ToolWeapon:
|
|
|
|
t = Player::ToolGrenade;
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
t = Player::ToolSpade;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}while(!world->GetLocalPlayer()->IsToolSelectable(t));
|
2013-08-31 14:54:12 +09:00
|
|
|
SetSelectedTool(t);
|
2013-08-26 21:04:57 +09:00
|
|
|
}
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}else{
|
|
|
|
// limbo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::CaptureColor() {
|
|
|
|
if(!world) return;
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
if(!p) return;
|
|
|
|
if(!p->IsAlive()) return;
|
|
|
|
|
|
|
|
IntVector3 outBlockCoord;
|
|
|
|
if(!world->GetMap()->CastRay(p->GetEye(),
|
|
|
|
p->GetFront(),
|
|
|
|
256.f, outBlockCoord)){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t col = world->GetMap()->GetColorWrapped(outBlockCoord.x,
|
|
|
|
outBlockCoord.y,
|
|
|
|
outBlockCoord.z);
|
|
|
|
|
|
|
|
IntVector3 colV;
|
|
|
|
colV.x = (uint8_t)(col);
|
|
|
|
colV.y = (uint8_t)(col >> 8);
|
|
|
|
colV.z = (uint8_t)(col >> 16);
|
|
|
|
|
|
|
|
p->SetHeldBlockColor(colV);
|
|
|
|
net->SendHeldBlockColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::IsLimboViewActive(){
|
|
|
|
if(world){
|
|
|
|
if(!world->GetLocalPlayer()){
|
|
|
|
return true;
|
|
|
|
}else if(inGameLimbo){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: anytime limbo
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::SpawnPressed() {
|
|
|
|
WeaponType weap = limbo->GetSelectedWeapon();
|
|
|
|
int team = limbo->GetSelectedTeam();
|
|
|
|
inGameLimbo = false;
|
|
|
|
if(team == 2)
|
|
|
|
team = 255;
|
|
|
|
|
|
|
|
if(!world->GetLocalPlayer()){
|
|
|
|
// join
|
|
|
|
net->SendJoin(team, weap,
|
|
|
|
playerName, lastKills);
|
|
|
|
}else{
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
if(p->GetTeamId() != team){
|
|
|
|
net->SendTeamChange(team);
|
|
|
|
}
|
|
|
|
if(team != 2 && p->GetWeapon()->GetWeaponType() != weap){
|
|
|
|
net->SendWeaponChange(weap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-26 19:24:15 +09:00
|
|
|
void Client::NetLog(const char *format, ...) {
|
|
|
|
char buf[4096];
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
vsprintf(buf, format, va);
|
|
|
|
va_end(va);
|
|
|
|
std::string str = buf;
|
|
|
|
|
|
|
|
time_t t;
|
|
|
|
struct tm tm;
|
|
|
|
::time(&t);
|
|
|
|
tm = *localtime(&t);
|
|
|
|
|
|
|
|
std::string timeStr = asctime(&tm);
|
|
|
|
|
|
|
|
// remove '\n' in the end of the result of asctime().
|
|
|
|
timeStr.resize(timeStr.size()-1);
|
|
|
|
|
|
|
|
sprintf(buf, "%s %s\n",
|
|
|
|
timeStr.c_str(), str.c_str());
|
|
|
|
|
|
|
|
printf("%s", buf);
|
|
|
|
|
|
|
|
if(logStream) {
|
|
|
|
logStream->Write(buf);
|
|
|
|
logStream->Flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
float Client::GetSprintState() {
|
|
|
|
if(!world) return 0.f;
|
|
|
|
if(!world->GetLocalPlayer())
|
|
|
|
return 0.f;
|
|
|
|
|
|
|
|
ClientPlayer *p = clientPlayers[(int)world->GetLocalPlayerIndex()];
|
|
|
|
if(!p)
|
|
|
|
return 0.f;
|
|
|
|
return p->GetSprintState();
|
|
|
|
}
|
|
|
|
|
|
|
|
float Client::GetAimDownState() {
|
|
|
|
if(!world) return 0.f;
|
|
|
|
if(!world->GetLocalPlayer())
|
|
|
|
return 0.f;
|
|
|
|
|
|
|
|
ClientPlayer *p = clientPlayers[(int)world->GetLocalPlayerIndex()];
|
|
|
|
if(!p)
|
|
|
|
return 0.f;
|
|
|
|
return p->GetAimDownState();
|
|
|
|
}
|
|
|
|
|
2013-08-31 14:54:12 +09:00
|
|
|
void Client::SetSelectedTool(Player::ToolType type, bool quiet) {
|
2013-09-21 04:17:34 +09:00
|
|
|
if(type == world->GetLocalPlayer()->GetTool())
|
2013-08-31 14:54:12 +09:00
|
|
|
return;
|
2013-09-21 04:17:34 +09:00
|
|
|
world->GetLocalPlayer()->SetTool(type);
|
|
|
|
net->SendTool();
|
2013-08-31 14:54:12 +09:00
|
|
|
|
|
|
|
if(!quiet) {
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/SwitchLocal.wav");
|
2013-08-31 14:54:12 +09:00
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
#pragma mark - Drawing
|
|
|
|
|
2013-11-22 19:34:20 +09:00
|
|
|
void Client::TakeMapShot(){
|
|
|
|
|
|
|
|
try{
|
|
|
|
std::string name = MapShotPath();
|
|
|
|
IStream *stream = FileManager::OpenForWriting(name.c_str());
|
|
|
|
try{
|
|
|
|
GameMap *map = GetWorld()->GetMap();
|
|
|
|
if(map == NULL){
|
|
|
|
SPRaise("No map loaded");
|
|
|
|
}
|
|
|
|
map->Save(stream);
|
|
|
|
delete stream;
|
|
|
|
}catch(...){
|
|
|
|
delete stream;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string msg;
|
|
|
|
msg = "Map saved: " + name;
|
|
|
|
msg = ChatWindow::ColoredMessage(msg, MsgColorSysInfo);
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}catch(const std::exception& ex){
|
|
|
|
std::string msg;
|
|
|
|
msg = "Saving map failed: ";
|
|
|
|
std::vector<std::string> lines = SplitIntoLines(ex.what());
|
|
|
|
msg += lines[0];
|
|
|
|
msg = ChatWindow::ColoredMessage(msg, MsgColorRed);
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Client::MapShotPath() {
|
|
|
|
char buf[256];
|
|
|
|
for(int i = 0; i < 10000;i++){
|
|
|
|
sprintf(buf, "Mapshots/shot%04d.vxl", nextScreenShotIndex);
|
|
|
|
if(FileManager::FileExists(buf)){
|
|
|
|
nextScreenShotIndex++;
|
|
|
|
if(nextScreenShotIndex >= 10000)
|
|
|
|
nextScreenShotIndex = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
SPRaise("No free file name");
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::TakeScreenShot(bool sceneOnly){
|
|
|
|
SceneDefinition sceneDef = SceneDef();
|
|
|
|
lastSceneDef = sceneDef;
|
|
|
|
|
|
|
|
// render scene
|
|
|
|
flashDlights = flashDlightsOld;
|
|
|
|
DrawScene();
|
|
|
|
|
|
|
|
// draw 2d
|
|
|
|
if(!sceneOnly)
|
|
|
|
Draw2D();
|
|
|
|
|
|
|
|
// Well done!
|
|
|
|
renderer->FrameDone();
|
|
|
|
|
2013-11-17 00:26:05 +09:00
|
|
|
Handle<Bitmap> bmp(renderer->ReadBitmap(), false);
|
2013-09-12 23:30:03 +09:00
|
|
|
// force 100% opacity
|
|
|
|
|
|
|
|
uint32_t *pixels = bmp->GetPixels();
|
|
|
|
for(size_t i = bmp->GetWidth() * bmp->GetHeight(); i > 0; i--) {
|
|
|
|
*(pixels++) |= 0xff000000UL;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
try{
|
|
|
|
std::string name = ScreenShotPath();
|
|
|
|
bmp->Save(name);
|
|
|
|
|
|
|
|
std::string msg;
|
|
|
|
if(sceneOnly)
|
|
|
|
msg = "Sceneshot saved: ";
|
|
|
|
else
|
|
|
|
msg = "Screenshot saved: ";
|
|
|
|
msg += name;
|
|
|
|
msg = ChatWindow::ColoredMessage(msg, MsgColorSysInfo);
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}catch(const std::exception& ex){
|
|
|
|
std::string msg;
|
|
|
|
msg = "Screenshot failed: ";
|
|
|
|
std::vector<std::string> lines = SplitIntoLines(ex.what());
|
|
|
|
msg += lines[0];
|
|
|
|
msg = ChatWindow::ColoredMessage(msg, MsgColorRed);
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Client::ScreenShotPath() {
|
|
|
|
char buf[256];
|
|
|
|
for(int i = 0; i < 10000;i++){
|
|
|
|
sprintf(buf, "Screenshots/shot%04d.tga", nextScreenShotIndex);
|
|
|
|
if(FileManager::FileExists(buf)){
|
|
|
|
nextScreenShotIndex++;
|
|
|
|
if(nextScreenShotIndex >= 10000)
|
|
|
|
nextScreenShotIndex = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
SPRaise("No free file name");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::ShouldRenderInThirdPersonView() {
|
|
|
|
//^return true;
|
|
|
|
|
|
|
|
if(world && world->GetLocalPlayer()){
|
|
|
|
if(!world->GetLocalPlayer()->IsAlive())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Client::GetLocalFireVibration() {
|
|
|
|
float localFireVibration = 0.f;
|
|
|
|
localFireVibration = time - localFireVibrationTime;
|
|
|
|
localFireVibration = 1.f - localFireVibration / 0.1f;
|
|
|
|
if(localFireVibration < 0.f)
|
|
|
|
localFireVibration = 0.f;
|
|
|
|
return localFireVibration;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Client::GetAimDownZoomScale(){
|
|
|
|
if(world == NULL || world->GetLocalPlayer() == NULL ||
|
|
|
|
world->GetLocalPlayer()->IsToolWeapon() == false ||
|
|
|
|
world->GetLocalPlayer()->IsAlive() == false)
|
|
|
|
return 1.f;
|
2013-08-21 01:53:06 +09:00
|
|
|
float delta = .8f;
|
|
|
|
switch(world->GetLocalPlayer()->GetWeapon()->GetWeaponType()) {
|
|
|
|
case SMG_WEAPON:
|
|
|
|
delta = .8f;
|
|
|
|
break;
|
|
|
|
case RIFLE_WEAPON:
|
|
|
|
delta = 1.4f;
|
|
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
delta = .4f;
|
|
|
|
break;
|
|
|
|
}
|
2013-09-21 04:17:34 +09:00
|
|
|
float aimDownState = GetAimDownState();
|
2013-08-21 01:53:06 +09:00
|
|
|
return 1.f + powf(aimDownState, 5.f) * delta;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
SceneDefinition Client::SceneDef() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
SceneDefinition def;
|
|
|
|
def.time = (unsigned int)(time * 1000.f);
|
|
|
|
def.denyCameraBlur = true;
|
|
|
|
|
|
|
|
if(world){
|
|
|
|
IntVector3 fogColor = world->GetFogColor();
|
|
|
|
renderer->SetFogColor(MakeVector3(fogColor.x / 255.f,
|
|
|
|
fogColor.y / 255.f,
|
|
|
|
fogColor.z / 255.f));
|
|
|
|
|
|
|
|
Player *player = world->GetLocalPlayer();
|
|
|
|
|
2013-09-12 23:41:07 +09:00
|
|
|
def.blurVignette = .4f;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(IsFollowing()){
|
|
|
|
int limit = 100;
|
|
|
|
// if current following player has left,
|
|
|
|
// or removed,
|
|
|
|
// choose next player.
|
|
|
|
while(!world->GetPlayer(followingPlayerId) ||
|
|
|
|
world->GetPlayer(followingPlayerId)->GetFront().GetPoweredLength() < .01f){
|
|
|
|
FollowNextPlayer();
|
|
|
|
if((limit--) <= 0){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
player = world->GetPlayer(followingPlayerId);
|
|
|
|
}
|
|
|
|
if(player){
|
|
|
|
|
|
|
|
float roll = 0.f;
|
|
|
|
float scale = 1.f;
|
|
|
|
float vibPitch = 0.f;
|
|
|
|
float vibYaw = 0.f;
|
|
|
|
if(ShouldRenderInThirdPersonView() ||
|
|
|
|
(IsFollowing() && player != world->GetLocalPlayer())){
|
|
|
|
Vector3 center = player->GetEye();
|
|
|
|
Vector3 playerFront = player->GetFront2D();
|
|
|
|
Vector3 up = MakeVector3(0,0,-1);
|
|
|
|
|
|
|
|
if((!player->IsAlive()) && lastMyCorpse &&
|
|
|
|
player == world->GetLocalPlayer()){
|
|
|
|
center = lastMyCorpse->GetCenter();
|
|
|
|
}
|
|
|
|
if(map->IsSolidWrapped((int)floorf(center.x),
|
|
|
|
(int)floorf(center.y),
|
|
|
|
(int)floorf(center.z))){
|
|
|
|
float z = center.z;
|
|
|
|
while(z > center.z - 5.f){
|
|
|
|
if(!map->IsSolidWrapped((int)floorf(center.x),
|
|
|
|
(int)floorf(center.y),
|
|
|
|
(int)floorf(z))){
|
|
|
|
center.z = z;
|
|
|
|
break;
|
|
|
|
}else{
|
|
|
|
z -= 1.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float distance = 5.f;
|
|
|
|
if(player == world->GetLocalPlayer() &&
|
|
|
|
world->GetLocalPlayer()->GetTeamId() < 2 &&
|
|
|
|
!world->GetLocalPlayer()->IsAlive()){
|
|
|
|
// deathcam.
|
|
|
|
float elapsedTime = time - lastAliveTime;
|
|
|
|
distance -= 3.f * expf(-elapsedTime * 1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 eye = center;
|
|
|
|
//eye -= playerFront * 5.f;
|
|
|
|
//eye += up * 2.0f;
|
|
|
|
eye.x += cosf(followYaw) * cosf(followPitch) * distance;
|
|
|
|
eye.y += sinf(followYaw) * cosf(followPitch) * distance;
|
|
|
|
eye.z -= sinf(followPitch) * distance;
|
|
|
|
|
|
|
|
if(false){
|
|
|
|
// settings for making limbo stuff
|
|
|
|
eye = center;
|
|
|
|
eye += playerFront * 3.f;
|
|
|
|
eye += up * -.1f;
|
|
|
|
eye += player->GetRight() *2.f;
|
|
|
|
scale *= .6f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try ray casting
|
|
|
|
GameMap::RayCastResult result;
|
|
|
|
result = map->CastRay2(center, (eye - center).Normalize(), 256);
|
|
|
|
if(result.hit) {
|
|
|
|
float dist = (result.hitPos - center).GetLength();
|
|
|
|
float curDist = (eye - center).GetLength();
|
|
|
|
dist -= 0.3f; // near clip plane
|
|
|
|
if(curDist > dist){
|
|
|
|
float diff = curDist - dist;
|
|
|
|
eye += (center - eye).Normalize() * diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 front = center - eye;
|
|
|
|
front = front.Normalize();
|
|
|
|
|
|
|
|
def.viewOrigin = eye;
|
|
|
|
def.viewAxis[0] = -Vector3::Cross(up, front).Normalize();
|
|
|
|
def.viewAxis[1] = -Vector3::Cross(front, def.viewAxis[0]).Normalize();
|
|
|
|
def.viewAxis[2] = front;
|
|
|
|
|
|
|
|
|
2013-09-20 23:03:32 +02:00
|
|
|
def.fovY = (float)cg_fov * static_cast<float>(M_PI) /180.f;
|
2013-09-07 21:26:06 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovY * .5f) *
|
|
|
|
renderer->ScreenWidth() /
|
|
|
|
renderer->ScreenHeight()) * 2.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
// update initial spectate pos
|
|
|
|
// this is not used now, but if the local player is
|
|
|
|
// is spectating, this is used when he/she's no
|
|
|
|
// longer following
|
|
|
|
followPos = def.viewOrigin;
|
|
|
|
followVel = MakeVector3(0, 0, 0);
|
|
|
|
|
|
|
|
}else if(player->GetTeamId() >= 2){
|
|
|
|
// spectator view (noclip view)
|
|
|
|
Vector3 center = followPos;
|
|
|
|
Vector3 front;
|
|
|
|
Vector3 up = {0, 0, -1};
|
|
|
|
|
|
|
|
front.x = -cosf(followYaw) * cosf(followPitch);
|
|
|
|
front.y = -sinf(followYaw) * cosf(followPitch);
|
|
|
|
front.z = sinf(followPitch);
|
|
|
|
|
|
|
|
def.viewOrigin = center;
|
|
|
|
def.viewAxis[0] = -Vector3::Cross(up, front).Normalize();
|
|
|
|
def.viewAxis[1] = -Vector3::Cross(front, def.viewAxis[0]).Normalize();
|
|
|
|
def.viewAxis[2] = front;
|
|
|
|
|
2013-09-20 23:03:32 +02:00
|
|
|
def.fovY = (float)cg_fov * static_cast<float>(M_PI) /180.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovY * .5f) *
|
|
|
|
renderer->ScreenWidth() /
|
|
|
|
renderer->ScreenHeight()) * 2.f;
|
|
|
|
|
|
|
|
// for 1st view, camera blur can be used
|
|
|
|
def.denyCameraBlur = false;
|
|
|
|
|
|
|
|
}else{
|
|
|
|
Vector3 front = player->GetFront();
|
|
|
|
Vector3 right = player->GetRight();
|
|
|
|
Vector3 up = player->GetUp();
|
|
|
|
|
|
|
|
float localFireVibration = GetLocalFireVibration();
|
|
|
|
localFireVibration *= localFireVibration;
|
|
|
|
|
|
|
|
roll += (nextRandom() - nextRandom()) * 0.03f * localFireVibration;
|
|
|
|
scale += nextRandom() * 0.04f * localFireVibration;
|
|
|
|
|
|
|
|
vibPitch += localFireVibration * (1.f - localFireVibration) * 0.01f;
|
|
|
|
vibYaw += sinf(localFireVibration * (float)M_PI * 2.f) * 0.001f;
|
|
|
|
|
|
|
|
// sprint bob
|
2013-09-07 03:53:11 +09:00
|
|
|
{
|
2013-09-21 04:17:34 +09:00
|
|
|
float sp = SmoothStep(GetSprintState());
|
2013-09-20 23:03:32 +02:00
|
|
|
vibYaw += sinf(player->GetWalkAnimationProgress() * static_cast<float>(M_PI) * 2.f) * 0.01f * sp;
|
|
|
|
roll -= sinf(player->GetWalkAnimationProgress() * static_cast<float>(M_PI) * 2.f) * 0.005f * (sp);
|
|
|
|
float p = cosf(player->GetWalkAnimationProgress() * static_cast<float>(M_PI) * 2.f);
|
2013-08-18 16:18:06 +09:00
|
|
|
p = p * p; p *= p; p *= p; p *= p;
|
|
|
|
vibPitch += p * 0.01f * sp;
|
|
|
|
}
|
|
|
|
|
2013-09-07 03:53:11 +09:00
|
|
|
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
scale /= GetAimDownZoomScale();
|
|
|
|
|
|
|
|
def.viewOrigin = player->GetEye();
|
|
|
|
def.viewAxis[0] = right;
|
|
|
|
def.viewAxis[1] = up;
|
|
|
|
def.viewAxis[2] = front;
|
|
|
|
|
2013-09-20 23:03:32 +02:00
|
|
|
def.fovY = (float)cg_fov * static_cast<float>(M_PI) /180.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovY * .5f) *
|
|
|
|
renderer->ScreenWidth() /
|
|
|
|
renderer->ScreenHeight()) * 2.f;
|
|
|
|
|
|
|
|
// for 1st view, camera blur can be used
|
|
|
|
def.denyCameraBlur = false;
|
2013-09-21 04:17:34 +09:00
|
|
|
|
|
|
|
float aimDownState = GetAimDownState();
|
2013-09-12 14:39:42 +09:00
|
|
|
float per = aimDownState;
|
|
|
|
per *= per * per;
|
2013-09-17 19:03:28 +09:00
|
|
|
def.depthOfFieldNearRange = per * 13.f + .054f;
|
2013-09-12 23:26:08 +09:00
|
|
|
|
|
|
|
def.blurVignette = .4f;
|
|
|
|
|
2013-09-17 19:03:28 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// add vibration for both 1st/3rd view
|
|
|
|
{
|
|
|
|
// add grenade vibration
|
|
|
|
float grenVib = grenadeVibration;
|
|
|
|
if(grenVib > 0.f){
|
|
|
|
grenVib *= 10.f;
|
|
|
|
if(grenVib > 1.f)
|
|
|
|
grenVib = 1.f;
|
|
|
|
roll += (nextRandom() - nextRandom()) * 0.2f * grenVib;
|
|
|
|
vibPitch += (nextRandom() - nextRandom()) * 0.1f * grenVib;
|
|
|
|
vibYaw += (nextRandom() - nextRandom()) * 0.1f * grenVib;
|
|
|
|
scale -= (nextRandom()-nextRandom()) * 0.1f * grenVib;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add roll / scale
|
|
|
|
{
|
|
|
|
Vector3 right = def.viewAxis[0];
|
|
|
|
Vector3 up = def.viewAxis[1];
|
|
|
|
|
|
|
|
def.viewAxis[0] = right * cosf(roll) - up * sinf(roll);
|
|
|
|
def.viewAxis[1] = up * cosf(roll) + right * sinf(roll);
|
|
|
|
|
2013-09-08 19:06:39 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovX * .5f) * scale) * 2.f;
|
|
|
|
def.fovY = atanf(tanf(def.fovY * .5f) * scale) * 2.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
{
|
|
|
|
Vector3 u = def.viewAxis[1];
|
|
|
|
Vector3 v = def.viewAxis[2];
|
|
|
|
|
|
|
|
def.viewAxis[1] = u * cosf(vibPitch) - v * sinf(vibPitch);
|
|
|
|
def.viewAxis[2] = v * cosf(vibPitch) + u * sinf(vibPitch);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
Vector3 u = def.viewAxis[0];
|
|
|
|
Vector3 v = def.viewAxis[2];
|
|
|
|
|
|
|
|
def.viewAxis[0] = u * cosf(vibYaw) - v * sinf(vibYaw);
|
|
|
|
def.viewAxis[2] = v * cosf(vibYaw) + u * sinf(vibYaw);
|
|
|
|
}
|
2013-09-17 19:03:28 +09:00
|
|
|
{
|
|
|
|
float wTime = world->GetTime();
|
|
|
|
if(wTime < lastHurtTime + .15f &&
|
|
|
|
wTime >= lastHurtTime){
|
|
|
|
float per = 1.f - (wTime - lastHurtTime) / .15f;
|
2013-11-01 00:55:19 +09:00
|
|
|
per *= .5f - player->GetHealth() / 100.f * .3f;
|
|
|
|
def.blurVignette += per * 6.f;
|
|
|
|
}
|
|
|
|
if(wTime < lastHurtTime + .2f &&
|
|
|
|
wTime >= lastHurtTime){
|
|
|
|
float per = 1.f - (wTime - lastHurtTime) / .2f;
|
|
|
|
per *= .5f - player->GetHealth() / 100.f * .3f;
|
|
|
|
def.saturation *= std::max(0.f, 1.f - per * 4.f);
|
2013-09-17 19:03:28 +09:00
|
|
|
}
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
def.zNear = 0.05f;
|
|
|
|
def.zFar = 130.f;
|
|
|
|
|
|
|
|
def.skipWorld = false;
|
|
|
|
}else{
|
|
|
|
def.viewOrigin = MakeVector3(256, 256, 4);
|
|
|
|
def.viewAxis[0] = MakeVector3(-1, 0, 0);
|
|
|
|
def.viewAxis[1] = MakeVector3(0, 1, 0);
|
|
|
|
def.viewAxis[2] = MakeVector3(0, 0, 1);
|
|
|
|
|
2013-09-20 23:03:32 +02:00
|
|
|
def.fovY = (float)cg_fov * static_cast<float>(M_PI) /180.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovY * .5f) *
|
|
|
|
renderer->ScreenWidth() /
|
|
|
|
renderer->ScreenHeight()) * 2.f;
|
|
|
|
|
|
|
|
def.zNear = 0.05f;
|
|
|
|
def.zFar = 130.f;
|
|
|
|
|
|
|
|
def.skipWorld = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
def.viewOrigin = MakeVector3(0, 0, 0);
|
|
|
|
def.viewAxis[0] = MakeVector3(1, 0, 0);
|
|
|
|
def.viewAxis[1] = MakeVector3(0, 0, -1);
|
|
|
|
def.viewAxis[2] = MakeVector3(0, 0, 1);
|
|
|
|
|
2013-09-20 23:03:32 +02:00
|
|
|
def.fovY = (float)cg_fov * static_cast<float>(M_PI) /180.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
def.fovX = atanf(tanf(def.fovY * .5f) *
|
|
|
|
renderer->ScreenWidth() /
|
|
|
|
renderer->ScreenHeight()) * 2.f;
|
|
|
|
|
|
|
|
def.zNear = 0.05f;
|
|
|
|
def.zFar = 130.f;
|
|
|
|
|
|
|
|
def.skipWorld = true;
|
|
|
|
|
|
|
|
renderer->SetFogColor(MakeVector3(0,0,0));
|
|
|
|
}
|
|
|
|
|
|
|
|
SPAssert(!isnan(def.viewOrigin.x));
|
|
|
|
SPAssert(!isnan(def.viewOrigin.y));
|
|
|
|
SPAssert(!isnan(def.viewOrigin.z));
|
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Client::GetWeaponPrefix(std::string fold, WeaponType type){
|
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
|
|
|
|
std::string weapPrefix;
|
|
|
|
switch(type){
|
|
|
|
case RIFLE_WEAPON:
|
|
|
|
weapPrefix = fold + "/Weapons/Rifle";
|
|
|
|
break;
|
|
|
|
case SMG_WEAPON:
|
|
|
|
weapPrefix = fold + "/Weapons/SMG";
|
|
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
weapPrefix = fold + "/Weapons/Shotgun";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return weapPrefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::AddGrenadeToScene(spades::client::Grenade *g) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
IModel *model;
|
|
|
|
model = renderer->RegisterModel("Models/Weapons/Grenade/Grenade.kv6");
|
|
|
|
|
2013-09-04 23:48:43 +09:00
|
|
|
if(g->GetPosition().z > 63.f) {
|
|
|
|
// work-around for water refraction problem
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
ModelRenderParam param;
|
|
|
|
Matrix4 mat = Matrix4::Scale(0.03f);
|
|
|
|
mat = Matrix4::Translate(g->GetPosition()) * mat;
|
|
|
|
param.matrix = mat;
|
|
|
|
|
|
|
|
renderer->RenderModel(model, param);
|
|
|
|
}
|
|
|
|
|
2013-11-22 23:09:16 +01:00
|
|
|
void Client::AddDebugObjectToScene(const spades::OBB3 &obb, const Vector4& color) {
|
2013-08-18 16:18:06 +09:00
|
|
|
const Matrix4& mat = obb.m;
|
|
|
|
Vector3 v[2][2][2];
|
|
|
|
v[0][0][0] = (mat * MakeVector3(0,0,0)).GetXYZ();
|
|
|
|
v[0][0][1] = (mat * MakeVector3(0,0,1)).GetXYZ();
|
|
|
|
v[0][1][0] = (mat * MakeVector3(0,1,0)).GetXYZ();
|
|
|
|
v[0][1][1] = (mat * MakeVector3(0,1,1)).GetXYZ();
|
|
|
|
v[1][0][0] = (mat * MakeVector3(1,0,0)).GetXYZ();
|
|
|
|
v[1][0][1] = (mat * MakeVector3(1,0,1)).GetXYZ();
|
|
|
|
v[1][1][0] = (mat * MakeVector3(1,1,0)).GetXYZ();
|
|
|
|
v[1][1][1] = (mat * MakeVector3(1,1,1)).GetXYZ();
|
|
|
|
|
|
|
|
renderer->AddDebugLine(v[0][0][0], v[1][0][0], color);
|
|
|
|
renderer->AddDebugLine(v[0][0][1], v[1][0][1], color);
|
|
|
|
renderer->AddDebugLine(v[0][1][0], v[1][1][0], color);
|
|
|
|
renderer->AddDebugLine(v[0][1][1], v[1][1][1], color);
|
|
|
|
|
|
|
|
renderer->AddDebugLine(v[0][0][0], v[0][1][0], color);
|
|
|
|
renderer->AddDebugLine(v[0][0][1], v[0][1][1], color);
|
|
|
|
renderer->AddDebugLine(v[1][0][0], v[1][1][0], color);
|
|
|
|
renderer->AddDebugLine(v[1][0][1], v[1][1][1], color);
|
|
|
|
|
|
|
|
renderer->AddDebugLine(v[0][0][0], v[0][0][1], color);
|
|
|
|
renderer->AddDebugLine(v[0][1][0], v[0][1][1], color);
|
|
|
|
renderer->AddDebugLine(v[1][0][0], v[1][0][1], color);
|
|
|
|
renderer->AddDebugLine(v[1][1][0], v[1][1][1], color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::DrawCTFObjects() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
2013-12-07 16:58:39 +01:00
|
|
|
CTFGameMode *mode = static_cast<CTFGameMode *>(world->GetMode());
|
2013-08-18 16:18:06 +09:00
|
|
|
int tId;
|
|
|
|
IModel *base = renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
|
|
|
|
IModel *intel = renderer->RegisterModel("Models/MapObjects/Intel.kv6");
|
|
|
|
for(tId = 0; tId < 2; tId++){
|
|
|
|
CTFGameMode::Team& team = mode->GetTeam(tId);
|
|
|
|
IntVector3 col = world->GetTeam(tId).color;
|
|
|
|
Vector3 color = {
|
|
|
|
col.x / 255.f, col.y / 255.f, col.z / 255.f
|
|
|
|
};
|
|
|
|
|
|
|
|
ModelRenderParam param;
|
|
|
|
param.customColor = color;
|
|
|
|
|
|
|
|
// draw base
|
|
|
|
param.matrix = Matrix4::Translate(team.basePos);
|
|
|
|
param.matrix = param.matrix * Matrix4::Scale(.3f);
|
|
|
|
renderer->RenderModel(base, param);
|
|
|
|
|
|
|
|
// draw flag
|
|
|
|
if(!mode->GetTeam(1-tId).hasIntel){
|
|
|
|
param.matrix = Matrix4::Translate(team.flagPos);
|
|
|
|
param.matrix = param.matrix * Matrix4::Scale(.1f);
|
|
|
|
renderer->RenderModel(intel, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::DrawTCObjects() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
2013-12-07 16:58:39 +01:00
|
|
|
TCGameMode *mode = static_cast<TCGameMode *>(world->GetMode());
|
2013-08-18 16:18:06 +09:00
|
|
|
int tId;
|
|
|
|
IModel *base = renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
|
|
|
|
int cnt = mode->GetNumTerritories();
|
|
|
|
for(tId = 0; tId < cnt; tId++){
|
|
|
|
TCGameMode::Territory *t = mode->GetTerritory(tId);
|
|
|
|
IntVector3 col;
|
|
|
|
if(t->ownerTeamId == 2){
|
|
|
|
col = IntVector3::Make(255, 255, 255);
|
|
|
|
}else{
|
|
|
|
col = world->GetTeam(t->ownerTeamId).color;
|
|
|
|
}
|
|
|
|
Vector3 color = {
|
|
|
|
col.x / 255.f, col.y / 255.f, col.z / 255.f
|
|
|
|
};
|
|
|
|
|
|
|
|
ModelRenderParam param;
|
|
|
|
param.customColor = color;
|
|
|
|
|
|
|
|
// draw base
|
|
|
|
param.matrix = Matrix4::Translate(t->pos);
|
|
|
|
param.matrix = param.matrix * Matrix4::Scale(.3f);
|
|
|
|
renderer->RenderModel(base, param);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::RemoveAllCorpses(){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
std::list<Corpse *>::iterator it;
|
|
|
|
for(it = corpses.begin(); it != corpses.end(); it++)
|
|
|
|
delete *it;
|
|
|
|
corpses.clear();
|
|
|
|
lastMyCorpse = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Client::RemoveAllLocalEntities(){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
std::list<ILocalEntity *>::iterator it;
|
|
|
|
for(it = localEntities.begin(); it != localEntities.end(); it++)
|
|
|
|
delete *it;
|
|
|
|
localEntities.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::RemoveInvisibleCorpses(){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
std::vector<std::list<Corpse *>::iterator> its;
|
|
|
|
std::list<Corpse *>::iterator it;
|
|
|
|
int cnt = (int)corpses.size() - corpseSoftLimit;
|
|
|
|
for(it = corpses.begin(); it != corpses.end(); it++){
|
|
|
|
if(cnt <= 0)
|
|
|
|
break;
|
|
|
|
Corpse *c = *it;
|
|
|
|
if(!c->IsVisibleFrom(lastSceneDef.viewOrigin)){
|
|
|
|
if(c == lastMyCorpse)
|
|
|
|
lastMyCorpse = NULL;
|
|
|
|
delete c;
|
|
|
|
its.push_back(it);
|
|
|
|
}
|
|
|
|
cnt--;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(size_t i = 0; i < its.size(); i++)
|
|
|
|
corpses.erase(its[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::DrawScene(){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
renderer->StartScene(lastSceneDef);
|
|
|
|
|
|
|
|
if(world){
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
|
2013-11-22 23:09:16 +01:00
|
|
|
for(size_t i = 0; i < world->GetNumPlayerSlots(); i++)
|
2013-09-21 04:17:34 +09:00
|
|
|
if(world->GetPlayer(i)){
|
|
|
|
SPAssert(clientPlayers[i]);
|
|
|
|
clientPlayers[i]->AddToScene();
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
std::vector<Grenade *> nades = world->GetAllGrenades();
|
|
|
|
for(size_t i = 0; i < nades.size(); i++){
|
|
|
|
AddGrenadeToScene(nades[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::list<Corpse *>::iterator it;
|
|
|
|
for(it = corpses.begin(); it != corpses.end(); it++){
|
|
|
|
Vector3 center = (*it)->GetCenter();
|
|
|
|
if((center - lastSceneDef.viewOrigin).GetPoweredLength() > 150.f * 150.f)
|
|
|
|
continue;
|
|
|
|
(*it)->AddToScene();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-07 16:58:39 +01:00
|
|
|
if( IGameMode::m_CTF == world->GetMode()->ModeType() ){
|
2013-08-18 16:18:06 +09:00
|
|
|
DrawCTFObjects();
|
2013-12-07 16:58:39 +01:00
|
|
|
} else if( IGameMode::m_TC == world->GetMode()->ModeType() ){
|
2013-08-18 16:18:06 +09:00
|
|
|
DrawTCObjects();
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::list<ILocalEntity *>::iterator it;
|
|
|
|
for(it = localEntities.begin(); it != localEntities.end(); it++){
|
|
|
|
(*it)->Render3D();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw block cursor
|
|
|
|
// FIXME: don't use debug line
|
|
|
|
if(p){
|
2013-09-06 12:42:11 +09:00
|
|
|
if(p->IsBlockCursorActive() &&
|
|
|
|
p->IsReadyToUseTool()){
|
2013-08-18 16:18:06 +09:00
|
|
|
std::vector<IntVector3> blocks;
|
|
|
|
if(p->IsBlockCursorDragging()){
|
|
|
|
blocks = world->CubeLine(p->GetBlockCursorDragPos(),
|
|
|
|
p->GetBlockCursorPos(),
|
|
|
|
256);
|
|
|
|
}else{
|
|
|
|
blocks.push_back(p->GetBlockCursorPos());
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 color = {1,1,1,1};
|
2013-09-20 23:11:12 +02:00
|
|
|
if((int)blocks.size() > p->GetNumBlocks())
|
2013-08-18 16:18:06 +09:00
|
|
|
color = MakeVector4(1,0,0,1);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < blocks.size(); i++){
|
|
|
|
IntVector3& v = blocks[i];
|
|
|
|
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y, v.z),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y+1, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y+1, v.z),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z+1),
|
|
|
|
MakeVector3(v.x+1, v.y, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y+1, v.z+1),
|
|
|
|
MakeVector3(v.x+1, v.y+1, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y, v.z),
|
|
|
|
color);
|
|
|
|
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
|
|
|
|
MakeVector3(v.x, v.y+1, v.z),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z+1),
|
|
|
|
MakeVector3(v.x, v.y+1, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x+1, v.y, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y+1, v.z),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x+1, v.y, v.z+1),
|
|
|
|
MakeVector3(v.x+1, v.y+1, v.z+1),
|
|
|
|
color);
|
|
|
|
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
|
|
|
|
MakeVector3(v.x, v.y, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x, v.y+1, v.z),
|
|
|
|
MakeVector3(v.x, v.y+1, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x+1, v.y, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y, v.z+1),
|
|
|
|
color);
|
|
|
|
renderer->AddDebugLine(MakeVector3(v.x+1, v.y+1, v.z),
|
|
|
|
MakeVector3(v.x+1, v.y+1, v.z+1),
|
|
|
|
color);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(size_t i = 0; i < flashDlights.size(); i++)
|
|
|
|
renderer->AddLight(flashDlights[i]);
|
|
|
|
flashDlightsOld.clear();
|
|
|
|
flashDlightsOld.swap(flashDlights);
|
|
|
|
|
|
|
|
// draw player hottrack
|
|
|
|
// FIXME: don't use debug line
|
|
|
|
{
|
2013-10-19 02:00:42 +02:00
|
|
|
hitTag_t tag = hit_None;
|
|
|
|
Player *hottracked = HotTrackedPlayer( &tag );
|
2013-08-18 16:18:06 +09:00
|
|
|
if(hottracked){
|
|
|
|
IntVector3 col = world->GetTeam(hottracked->GetTeamId()).color;
|
2013-10-19 02:00:42 +02:00
|
|
|
Vector4 color = Vector4::Make( col.x / 255.f, col.y / 255.f, col.z / 255.f, 1.f );
|
|
|
|
Vector4 color2 = Vector4::Make( 1, 1, 1, 1);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
Player::HitBoxes hb = hottracked->GetHitBoxes();
|
2013-10-19 02:00:42 +02:00
|
|
|
AddDebugObjectToScene(hb.head, (tag & hit_Head) ? color2 : color );
|
|
|
|
AddDebugObjectToScene(hb.torso, (tag & hit_Torso) ? color2 : color );
|
|
|
|
AddDebugObjectToScene(hb.limbs[0], (tag & hit_Legs) ? color2 : color );
|
|
|
|
AddDebugObjectToScene(hb.limbs[1], (tag & hit_Legs) ? color2 : color );
|
|
|
|
AddDebugObjectToScene(hb.limbs[2], (tag & hit_Arms) ? color2 : color );
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer->EndScene();
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 Client::Project(spades::Vector3 v){
|
|
|
|
v -= lastSceneDef.viewOrigin;
|
|
|
|
|
|
|
|
// transform to NDC
|
|
|
|
Vector3 v2;
|
|
|
|
v2.x = Vector3::Dot(v, lastSceneDef.viewAxis[0]);
|
|
|
|
v2.y = Vector3::Dot(v, lastSceneDef.viewAxis[1]);
|
|
|
|
v2.z = Vector3::Dot(v, lastSceneDef.viewAxis[2]);
|
|
|
|
|
|
|
|
float tanX = tanf(lastSceneDef.fovX * .5f);
|
|
|
|
float tanY = tanf(lastSceneDef.fovY * .5f);
|
|
|
|
|
|
|
|
v2.x /= tanX * v2.z;
|
|
|
|
v2.y /= tanY * v2.z;
|
|
|
|
|
|
|
|
// transform to IRenderer 2D coord
|
|
|
|
v2.x = (v2.x + 1.f) / 2.f * renderer->ScreenWidth();
|
|
|
|
v2.y = (-v2.y + 1.f) / 2.f * renderer->ScreenHeight();
|
|
|
|
|
|
|
|
return v2;
|
|
|
|
}
|
|
|
|
|
2013-09-02 23:09:13 +09:00
|
|
|
void Client::DrawSplash() {
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img;
|
2013-09-02 23:09:13 +09:00
|
|
|
Vector2 siz;
|
|
|
|
Vector2 scrSize = {renderer->ScreenWidth(),
|
|
|
|
renderer->ScreenHeight()};
|
2013-11-28 00:46:45 +09:00
|
|
|
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(0, 0, 0, 1));
|
2013-11-28 00:46:45 +09:00
|
|
|
img = renderer->RegisterImage("Gfx/White.tga");
|
|
|
|
renderer->DrawImage(img, AABB2(0, 0, siz.x, siz.y));
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(1, 1, 1, 1.));
|
2013-11-28 00:46:45 +09:00
|
|
|
img = renderer->RegisterImage("Gfx/Title/Logo.png");
|
2013-09-02 23:09:13 +09:00
|
|
|
|
|
|
|
siz = MakeVector2(img->GetWidth(), img->GetHeight());
|
2013-11-28 01:04:03 +09:00
|
|
|
siz *= std::min(1.f, scrSize.x / siz.x * 0.5f);
|
2013-09-02 23:09:13 +09:00
|
|
|
siz *= std::min(1.f, scrSize.y / siz.y);
|
|
|
|
|
|
|
|
renderer->DrawImage(img, AABB2((scrSize.x - siz.x) * .5f,
|
|
|
|
(scrSize.y - siz.y) * .5f,
|
|
|
|
siz.x, siz.y));
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::DrawStartupScreen() {
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img;
|
2013-09-02 23:09:13 +09:00
|
|
|
Vector2 scrSize = {renderer->ScreenWidth(),
|
|
|
|
renderer->ScreenHeight()};
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(0, 0, 0, 1.));
|
2013-09-02 23:09:13 +09:00
|
|
|
img = renderer->RegisterImage("Gfx/White.tga");
|
|
|
|
renderer->DrawImage(img, AABB2(0, 0,
|
|
|
|
scrSize.x, scrSize.y));
|
|
|
|
|
|
|
|
DrawSplash();
|
|
|
|
|
2013-11-28 00:46:45 +09:00
|
|
|
IFont *font = textFont;
|
2013-09-02 23:09:13 +09:00
|
|
|
std::string str = "NOW LOADING";
|
|
|
|
Vector2 size = font->Measure(str);
|
2013-11-02 19:00:50 +01:00
|
|
|
Vector2 pos = MakeVector2(scrSize.x - 16.f, scrSize.y - 16.f);
|
2013-09-02 23:09:13 +09:00
|
|
|
pos -= size;
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(str, pos, 1.f, MakeVector4(1,1,1,1), MakeVector4(0,0,0,0.5));
|
2013-09-02 23:09:13 +09:00
|
|
|
|
|
|
|
renderer->FrameDone();
|
|
|
|
renderer->Flip();
|
|
|
|
}
|
|
|
|
|
2013-09-12 23:26:08 +09:00
|
|
|
void Client::DrawHurtSprites() {
|
2013-09-15 01:01:07 +09:00
|
|
|
float per = (world->GetTime() - lastHurtTime) / 1.5f;
|
2013-09-12 23:26:08 +09:00
|
|
|
if(per > 1.f) return;
|
2013-09-13 02:38:09 +09:00
|
|
|
if(per < 0.f) return;
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/HurtSprite.png");
|
2013-09-12 23:26:08 +09:00
|
|
|
|
|
|
|
Vector2 scrSize = {renderer->ScreenWidth(), renderer->ScreenHeight()};
|
|
|
|
Vector2 scrCenter = scrSize * .5f;
|
|
|
|
float radius = scrSize.GetLength() * .5f;
|
|
|
|
|
|
|
|
for(size_t i = 0 ; i < hurtSprites.size(); i++) {
|
|
|
|
HurtSprite& spr = hurtSprites[i];
|
|
|
|
float alpha = spr.strength - per;
|
|
|
|
if(alpha < 0.f) continue;
|
|
|
|
if(alpha > 1.f) alpha = 1.f;
|
|
|
|
|
|
|
|
Vector2 radDir = {
|
|
|
|
cosf(spr.angle), sinf(spr.angle)
|
|
|
|
};
|
|
|
|
Vector2 angDir = {
|
|
|
|
-sinf(spr.angle), cosf(spr.angle)
|
|
|
|
};
|
|
|
|
float siz = spr.scale * radius;
|
|
|
|
Vector2 base = radDir * radius + scrCenter;
|
|
|
|
Vector2 centVect = radDir * (-siz);
|
|
|
|
Vector2 sideVect1 = angDir * (siz * 4.f * (spr.horzShift));
|
|
|
|
Vector2 sideVect2 = angDir * (siz * 4.f * (spr.horzShift - 1.f));
|
|
|
|
|
|
|
|
Vector2 v1 = base + centVect + sideVect1;
|
|
|
|
Vector2 v2 = base + centVect + sideVect2;
|
|
|
|
Vector2 v3 = base + sideVect1;
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(0.f, 0.f, 0.f, alpha));
|
2013-09-12 23:26:08 +09:00
|
|
|
renderer->DrawImage(img,
|
|
|
|
v1, v2, v3,
|
|
|
|
AABB2(0, 8.f, img->GetWidth(), img->GetHeight()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::Draw2D(){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
float scrWidth = renderer->ScreenWidth();
|
|
|
|
float scrHeight = renderer->ScreenHeight();
|
|
|
|
IFont *font;
|
|
|
|
|
|
|
|
if(GetWorld()){
|
|
|
|
float wTime = world->GetTime();
|
|
|
|
|
|
|
|
{
|
|
|
|
std::list<ILocalEntity *>::iterator it;
|
|
|
|
for(it = localEntities.begin(); it != localEntities.end(); it++){
|
|
|
|
(*it)->Render2D();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Player *p = GetWorld()->GetLocalPlayer();
|
|
|
|
if(p){
|
|
|
|
|
2013-09-12 23:26:08 +09:00
|
|
|
DrawHurtSprites();
|
|
|
|
|
2013-09-13 02:38:09 +09:00
|
|
|
if(wTime < lastHurtTime + .35f &&
|
|
|
|
wTime >= lastHurtTime){
|
2013-09-12 23:26:08 +09:00
|
|
|
float per = (wTime - lastHurtTime) / .35f;
|
|
|
|
per = 1.f - per;
|
2013-09-13 00:15:13 +09:00
|
|
|
per *= .3f + (1.f - p->GetHealth() / 100.f) * .7f;
|
2013-09-12 23:26:08 +09:00
|
|
|
per = std::min(per, 0.9f);
|
|
|
|
per = 1.f - per;
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector3 color = {1.f, per, per};
|
|
|
|
renderer->MultiplyScreenColor(color);
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4((1.f - per) * .1f,0,0,(1.f - per) * .1f));
|
2013-09-13 00:15:13 +09:00
|
|
|
renderer->DrawImage(renderer->RegisterImage("Gfx/White.tga"),
|
|
|
|
AABB2(0, 0, scrWidth, scrHeight));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
2013-10-19 02:00:42 +02:00
|
|
|
hitTag_t tag = hit_None;
|
|
|
|
Player *hottracked = HotTrackedPlayer( &tag );
|
2013-08-18 16:18:06 +09:00
|
|
|
if(hottracked){
|
|
|
|
Vector3 posxyz = Project(hottracked->GetEye());
|
|
|
|
Vector2 pos = {posxyz.x, posxyz.y};
|
|
|
|
float dist = (hottracked->GetEye() - p->GetEye()).GetLength();
|
|
|
|
int idist = (int)floorf(dist + .5f);
|
|
|
|
char buf[64];
|
2013-11-02 19:00:50 +01:00
|
|
|
sprintf(buf, "%s [%d%s]", hottracked->GetName().c_str(), idist, (idist == 1) ? "block":"blocks");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
font = textFont;
|
|
|
|
Vector2 size = font->Measure(buf);
|
|
|
|
pos.x -= size.x * .5f;
|
|
|
|
pos.y -= size.y;
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(buf, pos, 1.f, MakeVector4(1,1,1,1), MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
tcView->Draw();
|
|
|
|
|
|
|
|
if(p->IsAlive() && p->GetTeamId() < 2){
|
|
|
|
// draw damage ring
|
|
|
|
hurtRingView->Draw();
|
|
|
|
|
2013-11-01 00:38:42 +09:00
|
|
|
// draw local weapon's 2d things
|
|
|
|
clientPlayers[p->GetId()]->Draw2D();
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-09-08 02:58:55 +09:00
|
|
|
if(cg_debugAim && p->GetTool() == Player::ToolWeapon) {
|
|
|
|
Weapon *w = p->GetWeapon();
|
|
|
|
float spread = w->GetSpread();
|
|
|
|
|
|
|
|
AABB2 boundary(0,0,0,0);
|
|
|
|
for(int i = 0; i < 8; i++){
|
|
|
|
Vector3 vec = p->GetFront();
|
|
|
|
if(i & 1) vec.x += spread;
|
|
|
|
else vec.x -= spread;
|
|
|
|
if(i & 2) vec.y += spread;
|
|
|
|
else vec.y -= spread;
|
|
|
|
if(i & 4) vec.z += spread;
|
|
|
|
else vec.z -= spread;
|
|
|
|
|
|
|
|
Vector3 viewPos;
|
|
|
|
viewPos.x = Vector3::Dot(vec, p->GetRight());
|
|
|
|
viewPos.y = Vector3::Dot(vec, p->GetUp());
|
|
|
|
viewPos.z = Vector3::Dot(vec, p->GetFront());
|
|
|
|
|
|
|
|
Vector2 p;
|
|
|
|
p.x = viewPos.x / viewPos.z;
|
|
|
|
p.y = viewPos.y / viewPos.z;
|
|
|
|
boundary.min.x = std::min(boundary.min.x, p.x);
|
|
|
|
boundary.min.y = std::min(boundary.min.y, p.y);
|
|
|
|
boundary.max.x = std::max(boundary.max.x, p.x);
|
|
|
|
boundary.max.y = std::max(boundary.max.y, p.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
|
2013-09-08 02:58:55 +09:00
|
|
|
boundary.min *= renderer->ScreenHeight() * .5f;
|
|
|
|
boundary.max *= renderer->ScreenHeight() * .5f;
|
|
|
|
boundary.min /= tanf(lastSceneDef.fovY * .5f);
|
|
|
|
boundary.max /= tanf(lastSceneDef.fovY * .5f);
|
|
|
|
IntVector3 cent;
|
|
|
|
cent.x = (int)(renderer->ScreenWidth() * .5f);
|
|
|
|
cent.y = (int)(renderer->ScreenHeight() * .5f);
|
|
|
|
|
|
|
|
|
|
|
|
IntVector3 p1 = cent;
|
|
|
|
IntVector3 p2 = cent;
|
|
|
|
|
|
|
|
p1.x += (int)floorf(boundary.min.x);
|
|
|
|
p1.y += (int)floorf(boundary.min.y);
|
|
|
|
p2.x += (int)ceilf(boundary.max.x);
|
|
|
|
p2.y += (int)ceilf(boundary.max.y);
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(0,0,0,1));
|
2013-09-08 02:58:55 +09:00
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 2, p1.y - 2,
|
|
|
|
p2.x - p1.x + 4, 1));
|
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 2, p1.y - 2,
|
|
|
|
1, p2.y - p1.y + 4));
|
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 2, p2.y + 1,
|
|
|
|
p2.x - p1.x + 4, 1));
|
|
|
|
renderer->DrawImage(img, AABB2(p2.x + 1, p1.y - 2,
|
|
|
|
1, p2.y - p1.y + 4));
|
|
|
|
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(1,1,1,1));
|
2013-09-08 02:58:55 +09:00
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 1, p1.y - 1,
|
|
|
|
p2.x - p1.x + 2, 1));
|
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 1, p1.y - 1,
|
|
|
|
1, p2.y - p1.y + 2));
|
|
|
|
renderer->DrawImage(img, AABB2(p1.x - 1, p2.y,
|
|
|
|
p2.x - p1.x + 2, 1));
|
|
|
|
renderer->DrawImage(img, AABB2(p2.x, p1.y - 1,
|
|
|
|
1, p2.y - p1.y + 2));
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// draw ammo
|
|
|
|
Weapon *weap = p->GetWeapon();
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> ammoIcon;
|
2013-08-18 16:18:06 +09:00
|
|
|
float iconWidth, iconHeight;
|
|
|
|
float spacing = 2.f;
|
|
|
|
int stockNum;
|
|
|
|
int warnLevel;
|
|
|
|
|
|
|
|
if(p->IsToolWeapon()){
|
|
|
|
switch(weap->GetWeaponType()){
|
|
|
|
case RIFLE_WEAPON:
|
|
|
|
ammoIcon = renderer->RegisterImage("Gfx/Bullet/7.62mm.tga");
|
|
|
|
iconWidth = 6.f;
|
|
|
|
iconHeight = iconWidth * 4.f;
|
|
|
|
break;
|
|
|
|
case SMG_WEAPON:
|
|
|
|
ammoIcon = renderer->RegisterImage("Gfx/Bullet/9mm.tga");
|
|
|
|
iconWidth = 4.f;
|
|
|
|
iconHeight = iconWidth * 4.f;
|
|
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
ammoIcon = renderer->RegisterImage("Gfx/Bullet/12gauge.tga");
|
|
|
|
iconWidth = 30.f;
|
|
|
|
iconHeight = iconWidth / 4.f;
|
|
|
|
spacing = -6.f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPInvalidEnum("weap->GetWeaponType()", weap->GetWeaponType());
|
|
|
|
}
|
|
|
|
|
|
|
|
int clipSize = weap->GetClipSize();
|
|
|
|
int clip = weap->GetAmmo();
|
|
|
|
|
2013-08-31 11:19:14 +09:00
|
|
|
clipSize = std::max(clipSize, clip);
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
for(int i = 0; i < clipSize; i++){
|
|
|
|
float x = scrWidth - 16.f - (float)(i+1) *
|
|
|
|
(iconWidth + spacing);
|
|
|
|
float y = scrHeight - 16.f - iconHeight;
|
|
|
|
|
|
|
|
if(clip >= i + 1){
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(1,1,1,1));
|
2013-08-18 16:18:06 +09:00
|
|
|
}else{
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(0.4,0.4,0.4,1));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
renderer->DrawImage(ammoIcon,
|
|
|
|
AABB2(x,y,iconWidth,iconHeight));
|
|
|
|
}
|
|
|
|
|
|
|
|
stockNum = weap->GetStock();
|
|
|
|
warnLevel = weap->GetMaxStock() / 3;
|
|
|
|
}else{
|
|
|
|
iconHeight = 0.f;
|
|
|
|
warnLevel = 0;
|
|
|
|
|
|
|
|
switch(p->GetTool()){
|
|
|
|
case Player::ToolSpade:
|
|
|
|
case Player::ToolBlock:
|
|
|
|
stockNum = p->GetNumBlocks();
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
stockNum = p->GetNumGrenades();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPInvalidEnum("p->GetTool()", p->GetTool());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 numberColor = {1, 1, 1, 1};
|
|
|
|
|
|
|
|
if(stockNum == 0){
|
|
|
|
numberColor.y = 0.3f;
|
|
|
|
numberColor.z = 0.3f;
|
|
|
|
}else if(stockNum <= warnLevel){
|
|
|
|
numberColor.z = 0.3f;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[64];
|
|
|
|
sprintf(buf, "%d", stockNum);
|
|
|
|
font = designFont;
|
|
|
|
std::string stockStr = buf;
|
|
|
|
Vector2 size = font->Measure(stockStr);
|
|
|
|
Vector2 pos = MakeVector2(scrWidth - 16.f, scrHeight - 16.f - iconHeight);
|
|
|
|
pos -= size;
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(stockStr, pos, 1.f, numberColor, MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
|
|
|
|
// draw "press ... to reload"
|
|
|
|
{
|
|
|
|
std::string msg = "";
|
|
|
|
|
|
|
|
switch(p->GetTool()){
|
|
|
|
case Player::ToolBlock:
|
|
|
|
if(p->GetNumBlocks() == 0){
|
|
|
|
msg = "Out of Block";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
if(p->GetNumGrenades() == 0){
|
|
|
|
msg = "Out of Grenade";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Player::ToolWeapon:
|
|
|
|
{
|
|
|
|
Weapon *weap = p->GetWeapon();
|
2013-08-31 02:50:51 +09:00
|
|
|
if(weap->IsReloading() ||
|
|
|
|
p->IsAwaitingReloadCompletion()){
|
2013-08-18 16:18:06 +09:00
|
|
|
msg = "Reloading";
|
|
|
|
}else if(weap->GetAmmo() == 0 &&
|
|
|
|
weap->GetStock() == 0){
|
|
|
|
msg = "Out of Ammo";
|
|
|
|
}else if(weap->GetStock() > 0 &&
|
|
|
|
weap->GetAmmo() < weap->GetClipSize() / 4){
|
|
|
|
msg = "Press [" + (std::string)cg_keyReloadWeapon + "] to Reload";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:;
|
|
|
|
// no message
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!msg.empty()){
|
|
|
|
font = textFont;
|
|
|
|
Vector2 size = font->Measure(msg);
|
|
|
|
Vector2 pos = MakeVector2((scrWidth - size.x) * .5f,
|
|
|
|
scrHeight * 2.f / 3.f);
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(msg, pos, 1.f, MakeVector4(1,1,1,1), MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p->GetTool() == Player::ToolBlock) {
|
|
|
|
paletteView->Draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw map
|
|
|
|
mapView->Draw();
|
|
|
|
|
|
|
|
// --- end of "player is alive" drawing
|
|
|
|
}else {
|
|
|
|
|
|
|
|
// draw respawn tme
|
|
|
|
if(!p->IsAlive()){
|
|
|
|
std::string msg;
|
|
|
|
|
|
|
|
float secs = p->GetRespawnTime() - world->GetTime();
|
|
|
|
char buf[64];
|
|
|
|
if(secs > 0.f)
|
|
|
|
sprintf(buf, "You will respawn in: %d", (int)ceilf(secs));
|
|
|
|
else
|
|
|
|
strcpy(buf, "Waiting for respawn");
|
|
|
|
|
|
|
|
msg = buf;
|
|
|
|
|
|
|
|
if(!msg.empty()){
|
|
|
|
font = textFont;
|
|
|
|
Vector2 size = font->Measure(msg);
|
2013-11-02 19:00:50 +01:00
|
|
|
Vector2 pos = MakeVector2((scrWidth - size.x) * .5f, scrHeight / 3.f);
|
|
|
|
|
|
|
|
font->DrawShadow(msg, pos, 1.f, MakeVector4(1,1,1,1), MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw map
|
|
|
|
mapView->Draw();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw health
|
|
|
|
if(p->GetTeamId() < 2){
|
|
|
|
char buf[64];
|
|
|
|
sprintf(buf, "%d", p->GetHealth());
|
|
|
|
|
|
|
|
Vector4 numberColor = {1, 1, 1, 1};
|
|
|
|
|
|
|
|
if(p->GetHealth() == 0){
|
|
|
|
numberColor.y = 0.3f;
|
|
|
|
numberColor.z = 0.3f;
|
|
|
|
}else if(p->GetHealth() <= 50){
|
|
|
|
numberColor.z = 0.3f;
|
|
|
|
}
|
|
|
|
|
|
|
|
font = designFont;
|
|
|
|
std::string stockStr = buf;
|
|
|
|
Vector2 size = font->Measure(stockStr);
|
|
|
|
Vector2 pos = MakeVector2(16.f, scrHeight - 16.f);
|
|
|
|
pos.y -= size.y;
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(stockStr, pos, 1.f, numberColor, MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
if(IsFollowing()){
|
|
|
|
if(followingPlayerId == p->GetId()){
|
|
|
|
// just spectating
|
|
|
|
}else{
|
|
|
|
font = textFont;
|
2013-11-03 00:33:59 +01:00
|
|
|
std::string msg = "Following " + world->GetPlayerPersistent(followingPlayerId).name;
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector2 size = font->Measure(msg);
|
2013-08-25 20:49:18 +09:00
|
|
|
Vector2 pos = MakeVector2(scrWidth - 8.f, 256.f + 32.f);
|
2013-08-18 16:18:06 +09:00
|
|
|
pos.x -= size.x;
|
2013-11-02 19:00:50 +01:00
|
|
|
font->DrawShadow(msg, pos, 1.f, MakeVector4(1, 1, 1, 1), MakeVector4(0,0,0,0.5));
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chatWindow->Draw();
|
2013-08-26 17:53:14 +09:00
|
|
|
killfeedWindow->Draw();
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-08-27 22:27:49 +09:00
|
|
|
if(p->IsAlive()) {
|
|
|
|
|
|
|
|
// large map view should come in front
|
|
|
|
largeMapView->Draw();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
if(scoreboardVisible)
|
|
|
|
scoreboard->Draw();
|
|
|
|
|
2013-08-27 22:27:49 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// --- end "player is there" render
|
|
|
|
}else{
|
|
|
|
// world exists, but no local player: not joined
|
|
|
|
|
|
|
|
scoreboard->Draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsLimboViewActive())
|
|
|
|
limbo->Draw();
|
|
|
|
|
|
|
|
|
|
|
|
}else{
|
|
|
|
// no world; loading?
|
2013-09-02 23:09:13 +09:00
|
|
|
DrawSplash();
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img;
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-11-28 00:46:45 +09:00
|
|
|
std::string msg = net->GetStatusString();
|
|
|
|
font = textFont;
|
|
|
|
Vector2 textSize = font->Measure(msg);
|
|
|
|
font->Draw(msg, MakeVector2(scrWidth - 16.f, scrHeight - 24.f) - textSize, 1.f, MakeVector4(1,1,1,0.95f));
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
img = renderer->RegisterImage("Gfx/White.tga");
|
2013-11-28 00:46:45 +09:00
|
|
|
float pos = timeSinceInit / 3.6f;
|
|
|
|
pos -= floorf(pos);
|
|
|
|
pos = 1.f - pos * 2.0f;
|
|
|
|
for(float v = 0; v < 0.6f; v += 0.14f) {
|
|
|
|
float p = pos + v;
|
|
|
|
if(p < 0.01f || p > .99f) continue;
|
|
|
|
p = asin(p * 2.f - 1.f);
|
|
|
|
p = p / (float)M_PI + 0.5f;
|
|
|
|
|
|
|
|
float op = p * (1.f - p) * 4.f;
|
2013-12-09 01:00:09 +09:00
|
|
|
renderer->SetColorAlphaPremultiplied(MakeVector4(op, op, op, op));
|
2013-11-28 00:46:45 +09:00
|
|
|
renderer->DrawImage(img, AABB2(scrWidth - 236.f + p * 234.f, scrHeight - 18.f, 4.f, 4.f));
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
centerMessageView->Draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Chat Messages
|
|
|
|
|
|
|
|
void Client::PlayerSentChatMessage(spades::client::Player *p,
|
|
|
|
bool global,
|
|
|
|
const std::string &msg){
|
|
|
|
std::string s;
|
|
|
|
if(global)
|
|
|
|
s = "[Global] ";
|
|
|
|
s += ChatWindow::TeamColorMessage(p->GetName(), p->GetTeamId());
|
|
|
|
s += ": ";
|
|
|
|
s += msg;
|
|
|
|
chatWindow->AddMessage(s);
|
2013-08-26 19:24:15 +09:00
|
|
|
if(global)
|
|
|
|
NetLog("[Global] %s (%s): %s",
|
|
|
|
p->GetName().c_str(),
|
|
|
|
world->GetTeam(p->GetTeamId()).name.c_str(),
|
|
|
|
msg.c_str());
|
|
|
|
else
|
|
|
|
NetLog("[Team] %s (%s): %s",
|
|
|
|
p->GetName().c_str(),
|
|
|
|
world->GetTeam(p->GetTeamId()).name.c_str(),
|
|
|
|
msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-12-07 17:11:26 +09:00
|
|
|
if((!IsMuted()) && (int)cg_chatBeep) {
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/Chat.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::ServerSentMessage(const std::string &msg) {
|
|
|
|
chatWindow->AddMessage(msg);
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
if(msg.find(playerName) != std::string::npos){
|
|
|
|
printf("Mention: %s\n", msg.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Follow / Spectate
|
|
|
|
|
|
|
|
void Client::FollowNextPlayer() {
|
|
|
|
int myTeam = 2;
|
|
|
|
if(world->GetLocalPlayer()){
|
|
|
|
myTeam = world->GetLocalPlayer()->GetTeamId();
|
|
|
|
}
|
|
|
|
|
|
|
|
int nextId = followingPlayerId;
|
|
|
|
do{
|
|
|
|
nextId++;
|
|
|
|
if(nextId >= world->GetNumPlayerSlots())
|
|
|
|
nextId = 0;
|
|
|
|
|
|
|
|
Player *p = world->GetPlayer(nextId);
|
|
|
|
if(p == NULL)
|
|
|
|
continue;
|
|
|
|
if(myTeam < 2 && p->GetTeamId() != myTeam)
|
|
|
|
continue;
|
|
|
|
if(p->GetFront().GetPoweredLength() < .01f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}while(nextId != followingPlayerId);
|
|
|
|
|
|
|
|
followingPlayerId = nextId;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::IsFollowing() {
|
|
|
|
if(!world) return false;
|
|
|
|
if(!world->GetLocalPlayer())
|
|
|
|
return false;
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
if(p->GetTeamId() >= 2)
|
|
|
|
return true;
|
|
|
|
if(p->IsAlive())
|
|
|
|
return false;
|
|
|
|
else return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Effects
|
|
|
|
|
2013-10-19 02:00:42 +02:00
|
|
|
Player *Client::HotTrackedPlayer( hitTag_t* hitFlag ){
|
2013-08-18 16:18:06 +09:00
|
|
|
if(!world)
|
|
|
|
return NULL;
|
|
|
|
Player *p = world->GetLocalPlayer();
|
|
|
|
if(!p || !p->IsAlive())
|
|
|
|
return NULL;
|
|
|
|
if(ShouldRenderInThirdPersonView())
|
|
|
|
return NULL;
|
|
|
|
Vector3 origin = p->GetEye();
|
|
|
|
Vector3 dir = p->GetFront();
|
2013-10-19 02:00:42 +02:00
|
|
|
World::WeaponRayCastResult result = world->WeaponRayCast(origin, dir, p);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
if(result.hit == false || result.player == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// don't hot track enemies (non-spectator only)
|
|
|
|
if(result.player->GetTeamId() != p->GetTeamId() &&
|
|
|
|
p->GetTeamId() < 2)
|
|
|
|
return NULL;
|
2013-10-19 02:00:42 +02:00
|
|
|
if( hitFlag ) {
|
|
|
|
*hitFlag = result.hitFlag;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
return result.player;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::IsMuted() {
|
|
|
|
// prevent to play loud sound at connection
|
|
|
|
return time < worldSetTime + .05f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::Bleed(spades::Vector3 v){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!cg_blood)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// distance cull
|
|
|
|
if((v - lastSceneDef.viewOrigin).GetPoweredLength() >
|
|
|
|
150.f * 150.f)
|
|
|
|
return;
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
//Handle<IImage> img = renderer->RegisterImage("Textures/SoftBall.tga");
|
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector4 color = {0.5f, 0.02f, 0.04f, 1.f};
|
|
|
|
for(int i = 0; i < 10; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(v,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * 10.f,
|
|
|
|
1.f, 0.7f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.1f + GetRandom()*GetRandom()*0.2f);
|
|
|
|
ent->SetLifeTime(3.f, 0.f, 1.f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
color = MakeVector4(.7f, .35f, .37f, .6f);
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 100.f);
|
|
|
|
ent->SetTrajectory(v,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * .7f,
|
|
|
|
.8f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(.5f + GetRandom()*GetRandom()*0.2f,
|
|
|
|
2.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(.20f + GetRandom() * .2f, 0.06f, .20f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::EmitBlockFragments(Vector3 origin,
|
|
|
|
IntVector3 c){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
// distance cull
|
|
|
|
float distPowered = (origin - lastSceneDef.viewOrigin).GetPoweredLength();
|
|
|
|
if(distPowered >
|
|
|
|
150.f * 150.f)
|
|
|
|
return;
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector4 color = {c.x / 255.f,
|
|
|
|
c.y / 255.f, c.z / 255.f, 1.f};
|
|
|
|
for(int i = 0; i < 7; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * 7.f,
|
|
|
|
1.f, .9f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.2f + GetRandom()*GetRandom()*0.1f);
|
|
|
|
ent->SetLifeTime(2.f, 0.f, 1.f);
|
|
|
|
if(distPowered < 16.f * 16.f)
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(distPowered <
|
|
|
|
32.f * 32.f){
|
|
|
|
for(int i = 0; i < 16; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * 12.f,
|
|
|
|
1.f, .9f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.1f + GetRandom()*GetRandom()*0.14f);
|
|
|
|
ent->SetLifeTime(2.f, 0.f, 1.f);
|
|
|
|
if(distPowered < 16.f * 16.f)
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
color += (MakeVector4(1, 1, 1, 1) - color) * .2f;
|
|
|
|
color.w *= .2f;
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 100.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * .7f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(.6f + GetRandom()*GetRandom()*0.2f,
|
|
|
|
0.8f);
|
|
|
|
ent->SetLifeTime(.3f + GetRandom() * .3f, 0.06f, .4f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::EmitBlockDestroyFragments(IntVector3 blk,
|
|
|
|
IntVector3 c){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f};
|
|
|
|
|
|
|
|
// distance cull
|
|
|
|
if((origin - lastSceneDef.viewOrigin).GetPoweredLength() >
|
|
|
|
150.f * 150.f)
|
|
|
|
return;
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector4 color = {c.x / 255.f,
|
|
|
|
c.y / 255.f, c.z / 255.f, 1.f};
|
|
|
|
for(int i = 0; i < 8; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom()) * 7.f,
|
|
|
|
1.f, 1.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.3f + GetRandom()*GetRandom()*0.2f);
|
|
|
|
ent->SetLifeTime(2.f, 0.f, 1.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::MuzzleFire(spades::Vector3 origin,
|
|
|
|
spades::Vector3 dir,
|
|
|
|
bool local) {
|
|
|
|
DynamicLightParam l;
|
|
|
|
l.origin = origin;
|
|
|
|
l.radius = 5.f;
|
|
|
|
l.type = DynamicLightTypePoint;
|
|
|
|
l.color = MakeVector3(3.f, 1.6f, 0.5f);
|
|
|
|
flashDlights.push_back(l);
|
|
|
|
|
|
|
|
Vector4 color;
|
|
|
|
Vector3 velBias = {0, 0, -0.5f};
|
|
|
|
color = MakeVector4( .8f, .8f, .8f, .3f);
|
|
|
|
|
|
|
|
// rapid smoke
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 120.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom())+velBias*.5f) * 0.3f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(.2f,
|
|
|
|
7.f, 0.0000005f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(0.2f + GetRandom()*0.1f, 0.f, .30f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::GrenadeExplosion(spades::Vector3 origin){
|
|
|
|
float dist = (origin - lastSceneDef.viewOrigin).GetLength();
|
|
|
|
if(dist > 170.f)
|
|
|
|
return;
|
|
|
|
grenadeVibration += 2.f / (dist + 5.f);
|
|
|
|
if(grenadeVibration > 1.f)
|
|
|
|
grenadeVibration = 1.f;
|
|
|
|
|
|
|
|
DynamicLightParam l;
|
|
|
|
l.origin = origin;
|
|
|
|
l.radius = 16.f;
|
|
|
|
l.type = DynamicLightTypePoint;
|
|
|
|
l.color = MakeVector3(3.f, 1.6f, 0.5f);
|
2013-11-16 23:30:54 +09:00
|
|
|
l.useLensFlare = true;
|
2013-08-18 16:18:06 +09:00
|
|
|
flashDlights.push_back(l);
|
|
|
|
|
|
|
|
Vector3 velBias = {0,0,0};
|
|
|
|
if(!map->ClipBox(origin.x, origin.y, origin.z)){
|
|
|
|
if(map->ClipBox(origin.x + 1.f, origin.y, origin.z)){
|
|
|
|
velBias.x -= 1.f;
|
|
|
|
}
|
|
|
|
if(map->ClipBox(origin.x - 1.f, origin.y, origin.z)){
|
|
|
|
velBias.x += 1.f;
|
|
|
|
}
|
|
|
|
if(map->ClipBox(origin.x, origin.y + 1.f, origin.z)){
|
|
|
|
velBias.y -= 1.f;
|
|
|
|
}
|
|
|
|
if(map->ClipBox(origin.x, origin.y - 1.f, origin.z)){
|
|
|
|
velBias.y += 1.f;
|
|
|
|
}
|
|
|
|
if(map->ClipBox(origin.x, origin.y , origin.z + 1.f)){
|
|
|
|
velBias.z -= 1.f;
|
|
|
|
}
|
|
|
|
if(map->ClipBox(origin.x, origin.y , origin.z - 1.f)){
|
|
|
|
velBias.z += 1.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 color;
|
|
|
|
color = MakeVector4( .8f, .8f, .8f, .6f);
|
|
|
|
// rapid smoke
|
|
|
|
for(int i = 0; i < 4; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 60.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom())+velBias*.5f) * 4.f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(1.f + GetRandom()*GetRandom()*0.4f,
|
|
|
|
10.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(.1f + GetRandom()*0.02f, 0.f, .10f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// slow smoke
|
|
|
|
color.w = .25f;
|
|
|
|
for(int i = 0; i < 8; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 20.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
(GetRandom()-GetRandom()) * .2f)) * 2.f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(1.4f + GetRandom()*GetRandom()*0.8f,
|
|
|
|
0.2f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(6.f + GetRandom() * 5.f, 0.1f, 8.f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fragments
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
|
2013-08-18 16:18:06 +09:00
|
|
|
color = MakeVector4(0.01, 0.03, 0, 1.f);
|
|
|
|
for(int i = 0; i < 42; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
Vector3 dir = MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom());
|
|
|
|
dir += velBias * .5f;
|
|
|
|
float radius = 0.1f + GetRandom()*GetRandom()*0.2f;
|
|
|
|
ent->SetTrajectory(origin + dir * .2f,
|
|
|
|
dir * 20.f,
|
|
|
|
.1f + radius * 3.f, 1.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(radius);
|
|
|
|
ent->SetLifeTime(3.5f + GetRandom() * 2.f, 0.f, 1.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fire smoke
|
|
|
|
color= MakeVector4(1.f, .6f, .2f, 1.f);
|
|
|
|
for(int i = 0; i < 4; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 60.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom())+velBias) * 12.f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(1.f + GetRandom()*GetRandom()*0.4f,
|
|
|
|
6.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(.08f + GetRandom()*0.03f, 0.f, .10f);
|
|
|
|
ent->SetAdditive(true);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::GrenadeExplosionUnderwater(spades::Vector3 origin){
|
|
|
|
float dist = (origin - lastSceneDef.viewOrigin).GetLength();
|
|
|
|
if(dist > 170.f)
|
|
|
|
return;
|
|
|
|
grenadeVibration += 1.5f / (dist + 5.f);
|
|
|
|
if(grenadeVibration > 1.f)
|
|
|
|
grenadeVibration = 1.f;
|
|
|
|
|
|
|
|
Vector3 velBias = {0,0,0};
|
|
|
|
|
|
|
|
Vector4 color;
|
|
|
|
color = MakeVector4( .95f, .95f, .95f, .6f);
|
|
|
|
// water1
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = renderer->RegisterImage("Textures/WaterExpl.png");
|
2013-08-18 16:18:06 +09:00
|
|
|
for(int i = 0; i < 7; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
-GetRandom()*7.f)) * 2.5f,
|
|
|
|
.3f, .6f);
|
|
|
|
ent->SetRotation(0.f);
|
|
|
|
ent->SetRadius(1.5f + GetRandom()*GetRandom()*0.4f,
|
|
|
|
1.3f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(3.f + GetRandom()*0.3f, 0.f, .60f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// water2
|
|
|
|
img = renderer->RegisterImage("Textures/Fluid.png");
|
|
|
|
color.w = .9f;
|
|
|
|
for(int i = 0; i < 16; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
-GetRandom()*10.f)) * 3.5f,
|
|
|
|
1.f, 1.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.9f + GetRandom()*GetRandom()*0.4f,
|
|
|
|
0.7f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(3.f + GetRandom()*0.3f, .7f, .60f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// slow smoke
|
|
|
|
color.w = .4f;
|
|
|
|
for(int i = 0; i < 8; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new SmokeSpriteEntity(this, color, 20.f);
|
|
|
|
ent->SetTrajectory(origin,
|
|
|
|
(MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
(GetRandom()-GetRandom()) * .2f)) * 2.f,
|
|
|
|
1.f, 0.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(1.4f + GetRandom()*GetRandom()*0.8f,
|
|
|
|
0.2f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
|
|
|
ent->SetLifeTime(6.f + GetRandom() * 5.f, 0.1f, 8.f);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fragments
|
|
|
|
img = renderer->RegisterImage("Gfx/White.tga");
|
|
|
|
color = MakeVector4(1,1,1, 0.7f);
|
|
|
|
for(int i = 0; i < 42; i++){
|
|
|
|
ParticleSpriteEntity *ent =
|
|
|
|
new ParticleSpriteEntity(this, img, color);
|
|
|
|
Vector3 dir = MakeVector3(GetRandom()-GetRandom(),
|
|
|
|
GetRandom()-GetRandom(),
|
|
|
|
-GetRandom() * 3.f);
|
|
|
|
dir += velBias * .5f;
|
|
|
|
float radius = 0.1f + GetRandom()*GetRandom()*0.2f;
|
|
|
|
ent->SetTrajectory(origin + dir * .2f +
|
|
|
|
MakeVector3(0, 0, -1.2f),
|
|
|
|
dir * 13.f,
|
|
|
|
.1f + radius * 3.f, 1.f);
|
|
|
|
ent->SetRotation(GetRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(radius);
|
|
|
|
ent->SetLifeTime(3.5f + GetRandom() * 2.f, 0.f, 1.f);
|
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Delete);
|
|
|
|
localEntities.push_back(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: wave?
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Server Packet Handlers
|
|
|
|
|
|
|
|
void Client::LocalPlayerCreated(){
|
|
|
|
followPos = world->GetLocalPlayer()->GetEye();
|
|
|
|
weapInput = WeaponInput();
|
|
|
|
playerInput = PlayerInput();
|
|
|
|
keypadInput = KeypadInput();
|
2013-08-31 01:12:45 +09:00
|
|
|
|
|
|
|
toolRaiseState = .0f;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
void Client::JoinedGame() {
|
|
|
|
// note: local player doesn't exist yet now
|
|
|
|
|
|
|
|
// tune for spectate mode
|
|
|
|
followingPlayerId = world->GetLocalPlayerIndex();
|
|
|
|
followPos = MakeVector3(256, 256, 30);
|
|
|
|
followVel = MakeVector3(0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerCreatedBlock(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()) {
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Block/Build.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, p->GetEye() + p->GetFront(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::TeamCapturedTerritory(int teamId,
|
|
|
|
int terId) {
|
|
|
|
TCGameMode::Territory *ter = static_cast<TCGameMode *>(world->GetMode())->GetTerritory(terId);
|
|
|
|
int old = ter->ownerTeamId;
|
|
|
|
std::string msg;
|
|
|
|
msg = chatWindow->TeamColorMessage(world->GetTeam(teamId).name,
|
|
|
|
teamId);
|
|
|
|
msg += " captured ";
|
|
|
|
if(old < 2){
|
|
|
|
msg += chatWindow->TeamColorMessage(world->GetTeam(old).name,
|
|
|
|
old);
|
|
|
|
msg += "'s territory";
|
|
|
|
}else{
|
|
|
|
msg += "an neutral territory";
|
|
|
|
}
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
|
|
|
|
msg = world->GetTeam(teamId).name;
|
|
|
|
msg += " captured ";
|
|
|
|
if(old < 2){
|
|
|
|
msg += world->GetTeam(old).name;
|
|
|
|
msg += "'s Territory";
|
|
|
|
}else{
|
|
|
|
msg += "an Neutral Territory";
|
|
|
|
}
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(msg);
|
|
|
|
|
|
|
|
if(world->GetLocalPlayer() && !IsMuted()){
|
|
|
|
if(teamId == world->GetLocalPlayer()->GetTeamId()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/TC/YourTeamCaptured.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}else{
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/TC/EnemyCaptured.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerCapturedIntel(spades::client::Player *p){
|
|
|
|
std::string msg;
|
|
|
|
msg = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
|
|
|
|
msg += " captured ";
|
|
|
|
msg += chatWindow->TeamColorMessage(world->GetTeam(1 - p->GetTeamId()).name,
|
|
|
|
1 - p->GetTeamId());
|
|
|
|
msg += "'s intel";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
|
|
|
|
msg = p->GetName();
|
|
|
|
msg += " captured ";
|
|
|
|
msg += world->GetTeam(1 - p->GetTeamId()).name;
|
|
|
|
msg += "'s Intel.";
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(msg);
|
|
|
|
|
|
|
|
if(world->GetLocalPlayer() && !IsMuted()){
|
|
|
|
if(p->GetTeamId() == world->GetLocalPlayer()->GetTeamId()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/CTF/YourTeamCaptured.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}else{
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/CTF/EnemyCaptured.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerPickedIntel(spades::client::Player *p) {
|
|
|
|
std::string msg;
|
|
|
|
msg = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
|
|
|
|
msg += " picked up ";
|
|
|
|
msg += chatWindow->TeamColorMessage(world->GetTeam(1 - p->GetTeamId()).name,
|
|
|
|
1 - p->GetTeamId());
|
|
|
|
msg += "'s intel";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
|
|
|
|
msg = p->GetName();
|
|
|
|
msg += " picked up ";
|
|
|
|
msg += world->GetTeam(1 - p->GetTeamId()).name;
|
|
|
|
msg += "'s intel.";
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(msg);
|
|
|
|
|
|
|
|
if(!IsMuted()) {
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/CTF/PickedUp.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerDropIntel(spades::client::Player *p) {
|
|
|
|
std::string msg;
|
|
|
|
msg = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
|
|
|
|
msg += " dropped ";
|
|
|
|
msg += chatWindow->TeamColorMessage(world->GetTeam(1 - p->GetTeamId()).name,
|
|
|
|
1 - p->GetTeamId());
|
|
|
|
msg += "'s intel";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
|
|
|
|
msg = p->GetName();
|
|
|
|
msg += " dropped ";
|
|
|
|
msg += world->GetTeam(1 - p->GetTeamId()).name;
|
|
|
|
msg += "'s intel.";
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerDestroyedBlockWithWeaponOrTool(spades::IntVector3 blk){
|
|
|
|
Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f};
|
|
|
|
|
|
|
|
if(!map->IsSolid(blk.x, blk.y, blk.z))
|
|
|
|
return;;
|
|
|
|
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Misc/BlockDestroy.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
if(!IsMuted()){
|
|
|
|
audioDevice->Play(c, origin,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t col = map->GetColor(blk.x, blk.y, blk.z);
|
|
|
|
IntVector3 colV = {(uint8_t)col,
|
|
|
|
(uint8_t)(col >> 8), (uint8_t)(col >> 16)};
|
|
|
|
|
|
|
|
EmitBlockDestroyFragments(blk, colV);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerDiggedBlock(spades::IntVector3 blk){
|
|
|
|
Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f};
|
|
|
|
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Misc/BlockDestroy.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
if(!IsMuted()){
|
|
|
|
audioDevice->Play(c, origin,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int z = blk.z - 1 ; z <= blk.z + 1; z++){
|
|
|
|
if(z < 0 || z > 61)
|
|
|
|
continue;
|
|
|
|
if(!map->IsSolid(blk.x, blk.y, z))
|
|
|
|
continue;
|
|
|
|
uint32_t col = map->GetColor(blk.x, blk.y, z);
|
|
|
|
IntVector3 colV = {(uint8_t)col,
|
|
|
|
(uint8_t)(col >> 8), (uint8_t)(col >> 16)};
|
|
|
|
|
|
|
|
EmitBlockDestroyFragments(IntVector3::Make(blk.x, blk.y, z), colV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-02 00:42:45 +09:00
|
|
|
void Client::PlayerLeaving(spades::client::Player *p) {
|
|
|
|
std::string msg;
|
|
|
|
msg = "Player " + chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
|
|
|
|
msg += " has left";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerJoinedTeam(spades::client::Player *p) {
|
|
|
|
std::string msg;
|
|
|
|
msg = p->GetName();
|
|
|
|
msg += " joined ";
|
|
|
|
msg += chatWindow->TeamColorMessage(world->GetTeam(p->GetTeamId()).name,
|
|
|
|
p->GetTeamId());
|
|
|
|
msg += " team";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::GrenadeDestroyedBlock(spades::IntVector3 blk){
|
|
|
|
for(int x = blk.x - 1; x <= blk.x + 1; x++)
|
|
|
|
for(int y = blk.y - 1; y <= blk.y + 1; y++)
|
|
|
|
for(int z = blk.z - 1 ; z <= blk.z + 1; z++){
|
|
|
|
if(z < 0 || z > 61 || x < 0 || x >= 512 ||
|
|
|
|
y < 0 || y >= 512)
|
|
|
|
continue;
|
|
|
|
if(!map->IsSolid(x, y, z))
|
|
|
|
continue;
|
|
|
|
uint32_t col = map->GetColor(x, y, z);
|
|
|
|
IntVector3 colV = {(uint8_t)col,
|
|
|
|
(uint8_t)(col >> 8), (uint8_t)(col >> 16)};
|
|
|
|
|
|
|
|
EmitBlockDestroyFragments(IntVector3::Make(x, y, z), colV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Client::TeamWon(int teamId){
|
|
|
|
std::string msg;
|
|
|
|
msg = chatWindow->TeamColorMessage(world->GetTeam(teamId).name,
|
|
|
|
teamId);
|
|
|
|
msg += " wins!";
|
|
|
|
chatWindow->AddMessage(msg);
|
|
|
|
|
|
|
|
msg = world->GetTeam(teamId).name;
|
|
|
|
msg += " wins!";
|
2013-08-26 19:24:15 +09:00
|
|
|
NetLog("%s", msg.c_str());
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(msg);
|
|
|
|
|
|
|
|
if(world->GetLocalPlayer()){
|
|
|
|
if(teamId == world->GetLocalPlayer()->GetTeamId()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/Win.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}else{
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/Lose.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(chunk, AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - IWorldListener Handlers
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
void Client::PlayerObjectSet(int id) {
|
|
|
|
if(clientPlayers[id]){
|
|
|
|
clientPlayers[id]->Invalidate();
|
|
|
|
clientPlayers[id]->Release();
|
|
|
|
clientPlayers[id] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Player *p = world->GetPlayer(id);
|
|
|
|
if(p)
|
|
|
|
clientPlayers[id] = new ClientPlayer(p, this);
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::PlayerJumped(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = p->GetWade() ?
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Player/WaterJump.wav"):
|
|
|
|
audioDevice->RegisterSound("Sounds/Player/Jump.wav");
|
|
|
|
audioDevice->Play(c, p->GetOrigin(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerLanded(spades::client::Player *p,
|
|
|
|
bool hurt) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c;
|
2013-08-18 16:18:06 +09:00
|
|
|
if(hurt)
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Player/FallHurt.wav");
|
|
|
|
else if(p->GetWade())
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Player/WaterLand.wav");
|
|
|
|
else
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Player/Land.wav");
|
|
|
|
audioDevice->Play(c, p->GetOrigin(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerMadeFootstep(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
const char *snds[] = {
|
|
|
|
"Sounds/Player/Footstep1.wav",
|
|
|
|
"Sounds/Player/Footstep2.wav",
|
|
|
|
"Sounds/Player/Footstep3.wav",
|
|
|
|
"Sounds/Player/Footstep4.wav"
|
|
|
|
};
|
|
|
|
const char *wsnds[] = {
|
|
|
|
"Sounds/Player/Wade1.wav",
|
|
|
|
"Sounds/Player/Wade2.wav",
|
|
|
|
"Sounds/Player/Wade3.wav",
|
|
|
|
"Sounds/Player/Wade4.wav"
|
|
|
|
};
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = p->GetWade() ?
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound(wsnds[rand() % 4]):
|
|
|
|
audioDevice->RegisterSound(snds[rand() % 4]);
|
|
|
|
audioDevice->Play(c, p->GetOrigin(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerFiredWeapon(spades::client::Player *p) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
if(p == world->GetLocalPlayer()){
|
|
|
|
localFireVibrationTime = time;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
clientPlayers[p->GetId()]->FiredWeapon();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
void Client::PlayerDryFiredWeapon(spades::client::Player *p) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/DryFire.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f
|
|
|
|
- p->GetUp() * .3f
|
|
|
|
+ p->GetRight() * .4f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerReloadingWeapon(spades::client::Player *p) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
clientPlayers[p->GetId()]->ReloadingWeapon();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerReloadedWeapon(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
|
2013-09-21 04:17:34 +09:00
|
|
|
clientPlayers[p->GetId()]->ReloadedWeapon();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerChangedTool(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c;
|
2013-08-31 14:54:12 +09:00
|
|
|
if(isLocal){
|
|
|
|
switch(p->GetTool()) {
|
|
|
|
case Player::ToolSpade:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Spade/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
case Player::ToolBlock:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Block/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
case Player::ToolWeapon:
|
|
|
|
switch(p->GetWeapon()->GetWeaponType()){
|
|
|
|
case RIFLE_WEAPON:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Rifle/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
case SMG_WEAPON:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/SMG/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Shotgun/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case Player::ToolGrenade:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/RaiseLocal.wav");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Switch.wav");
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f
|
|
|
|
- p->GetUp() * .3f
|
|
|
|
+ p->GetRight() * .4f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerRestocked(spades::client::Player *p){
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = isLocal ?
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/SwitchLocal.wav"):
|
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Switch.wav");
|
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f
|
|
|
|
- p->GetUp() * .3f
|
|
|
|
+ p->GetRight() * .4f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerThrownGrenade(spades::client::Player *p, Grenade *g){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Throw.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
if(g && isLocal){
|
|
|
|
net->SendGrenade(g);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, 0.1f, .3f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f
|
|
|
|
- p->GetUp() * .2f
|
|
|
|
+ p->GetRight() * .3f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerMissedSpade(spades::client::Player *p){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Spade/Miss.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.2f, -.1f, 0.7f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.8f
|
|
|
|
- p->GetUp() * .2f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerHitBlockWithSpade(spades::client::Player *p,
|
|
|
|
Vector3 hitPos,
|
|
|
|
IntVector3 blockPos,
|
|
|
|
IntVector3 normal){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
uint32_t col = map->GetColor(blockPos.x, blockPos.y, blockPos.z);
|
|
|
|
IntVector3 colV = {(uint8_t)col,
|
|
|
|
(uint8_t)(col >> 8), (uint8_t)(col >> 16)};
|
|
|
|
Vector3 shiftedHitPos = hitPos;
|
|
|
|
shiftedHitPos.x += normal.x * .05f;
|
|
|
|
shiftedHitPos.y += normal.y * .05f;
|
|
|
|
shiftedHitPos.z += normal.z * .05f;
|
|
|
|
|
|
|
|
EmitBlockFragments(shiftedHitPos, colV);
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
bool isLocal = p == world->GetLocalPlayer();
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Spade/HitBlock.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
if(isLocal)
|
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.1f, -.1f, 1.2f),
|
|
|
|
AudioParam());
|
|
|
|
else
|
|
|
|
audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.5f
|
|
|
|
- p->GetUp() * .2f,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::PlayerKilledPlayer(spades::client::Player *killer,
|
|
|
|
spades::client::Player *victim,
|
|
|
|
KillType kt) {
|
|
|
|
// play hit sound
|
|
|
|
if(kt == KillTypeWeapon ||
|
|
|
|
kt == KillTypeHeadshot) {
|
|
|
|
// don't play on local: see BullethitPlayer
|
|
|
|
if(victim != world->GetLocalPlayer()) {
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c =
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh.wav");
|
2013-11-02 19:00:50 +01:00
|
|
|
audioDevice->Play(c, victim->GetEye(), AudioParam());
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// begin following
|
|
|
|
if(victim == world->GetLocalPlayer()){
|
|
|
|
followingPlayerId = victim->GetId();
|
|
|
|
|
|
|
|
Vector3 v = -victim->GetFront();
|
|
|
|
followYaw = atan2(v.y, v.x);
|
|
|
|
followPitch = 30.f * M_PI /180.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// emit blood (also for local player)
|
|
|
|
// FIXME: emiting blood for either
|
|
|
|
// client-side or server-side hit?
|
|
|
|
switch(kt){
|
|
|
|
case KillTypeGrenade:
|
|
|
|
case KillTypeHeadshot:
|
|
|
|
case KillTypeMelee:
|
|
|
|
case KillTypeWeapon:
|
|
|
|
Bleed(victim->GetEye());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create ragdoll corpse
|
|
|
|
if(cg_ragdoll && victim->GetTeamId() < 2){
|
|
|
|
Corpse *corp;
|
2013-10-19 02:09:04 +02:00
|
|
|
corp = new Corpse(renderer, map, victim);
|
2013-08-18 16:18:06 +09:00
|
|
|
if(victim == world->GetLocalPlayer())
|
|
|
|
lastMyCorpse = corp;
|
|
|
|
if(killer != victim && kt != KillTypeGrenade){
|
|
|
|
Vector3 dir = victim->GetPosition() - killer->GetPosition();
|
|
|
|
dir = dir.Normalize();
|
|
|
|
if(kt == KillTypeMelee){
|
|
|
|
dir *= 6.f;
|
|
|
|
}else{
|
|
|
|
if(killer->GetWeapon()->GetWeaponType() == SMG_WEAPON){
|
|
|
|
dir *= 2.8f;
|
|
|
|
}else if(killer->GetWeapon()->GetWeaponType() == SHOTGUN_WEAPON){
|
|
|
|
dir *= 4.5f;
|
|
|
|
}else{
|
|
|
|
dir *= 3.5f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
corp->AddImpulse(dir);
|
|
|
|
}else if(kt == KillTypeGrenade){
|
|
|
|
corp->AddImpulse(MakeVector3(0, 0, -4.f - GetRandom() * 4.f));
|
|
|
|
}
|
2013-09-13 00:32:07 +09:00
|
|
|
corp->AddImpulse(victim->GetVelocty() * 32.f);
|
2013-08-18 16:18:06 +09:00
|
|
|
corpses.push_back(corp);
|
|
|
|
|
|
|
|
if(corpses.size() > corpseHardLimit){
|
|
|
|
corp = corpses.front();
|
|
|
|
delete corp;
|
|
|
|
corpses.pop_front();
|
|
|
|
}else if(corpses.size() > corpseSoftLimit){
|
|
|
|
RemoveInvisibleCorpses();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add chat message
|
|
|
|
std::string s;
|
2013-11-02 19:00:50 +01:00
|
|
|
s = ChatWindow::TeamColorMessage(killer->GetName(), killer->GetTeamId());
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
std::string cause;
|
|
|
|
bool ff = killer->GetTeamId() == victim->GetTeamId();
|
|
|
|
if(killer == victim)
|
|
|
|
ff = false;
|
|
|
|
|
|
|
|
cause = " [";
|
2013-11-03 00:52:54 +01:00
|
|
|
Weapon* w = killer ? killer->GetWeapon() : NULL; //only used in case of KillTypeWeapon
|
|
|
|
cause += ChatWindow::killImage( kt, w ? w->GetWeaponType() : RIFLE_WEAPON );
|
2013-08-18 16:18:06 +09:00
|
|
|
cause += "] ";
|
|
|
|
|
|
|
|
if(ff)
|
|
|
|
s += ChatWindow::ColoredMessage(cause, MsgColorRed);
|
|
|
|
else
|
|
|
|
s += cause;
|
|
|
|
|
|
|
|
if(killer != victim){
|
2013-11-02 19:00:50 +01:00
|
|
|
s += ChatWindow::TeamColorMessage(victim->GetName(), victim->GetTeamId());
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
2013-08-26 17:53:14 +09:00
|
|
|
killfeedWindow->AddMessage(s);
|
2013-08-18 16:18:06 +09:00
|
|
|
|
2013-08-26 19:24:15 +09:00
|
|
|
// log to netlog
|
|
|
|
if(killer != victim) {
|
|
|
|
NetLog("%s (%s)%s%s (%s)",
|
|
|
|
killer->GetName().c_str(),
|
|
|
|
world->GetTeam(killer->GetTeamId()).name.c_str(),
|
|
|
|
cause.c_str(),
|
|
|
|
victim->GetName().c_str(),
|
|
|
|
world->GetTeam(victim->GetTeamId()).name.c_str());
|
|
|
|
}else{
|
|
|
|
NetLog("%s (%s)%s",
|
|
|
|
killer->GetName().c_str(),
|
|
|
|
world->GetTeam(killer->GetTeamId()).name.c_str(),
|
|
|
|
cause.c_str());
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// show big message if player is involved
|
|
|
|
if(victim != killer){
|
2013-10-19 02:14:54 +02:00
|
|
|
Player* local = world->GetLocalPlayer();
|
|
|
|
if(killer == local || victim == local){
|
2013-08-18 16:18:06 +09:00
|
|
|
char buf[256];
|
2013-10-19 02:14:54 +02:00
|
|
|
if( killer == local ) {
|
|
|
|
sprintf(buf, "You have killed %s", victim->GetName().c_str());
|
|
|
|
} else {
|
|
|
|
sprintf(buf, "You were killed by %s", killer->GetName().c_str());
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
centerMessageView->AddMessage(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::BulletHitPlayer(spades::client::Player *hurtPlayer,
|
|
|
|
HitType type,
|
|
|
|
spades::Vector3 hitPos,
|
|
|
|
spades::client::Player *by) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
SPAssert(type != HitTypeBlock);
|
|
|
|
|
|
|
|
// don't bleed local player
|
|
|
|
if(hurtPlayer != world->GetLocalPlayer() ||
|
2013-09-07 20:31:19 +09:00
|
|
|
ShouldRenderInThirdPersonView()){
|
2013-08-18 16:18:06 +09:00
|
|
|
Bleed(hitPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hurtPlayer == world->GetLocalPlayer()){
|
|
|
|
// don't player hit sound now;
|
|
|
|
// local bullet impact sound is
|
|
|
|
// played by checking the decrease of HP
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
if(type == HitTypeMelee){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c =
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Spade/HitPlayer.wav");
|
|
|
|
audioDevice->Play(c, hitPos,
|
|
|
|
AudioParam());
|
|
|
|
}else{
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c =
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh.wav");
|
|
|
|
audioDevice->Play(c, hitPos,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(by == world->GetLocalPlayer() &&
|
|
|
|
hurtPlayer){
|
|
|
|
net->SendHit(hurtPlayer->GetId(), type);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::BulletHitBlock(Vector3 hitPos,
|
|
|
|
IntVector3 blockPos,
|
|
|
|
IntVector3 normal){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
uint32_t col = map->GetColor(blockPos.x, blockPos.y, blockPos.z);
|
|
|
|
IntVector3 colV = {(uint8_t)col,
|
|
|
|
(uint8_t)(col >> 8), (uint8_t)(col >> 16)};
|
|
|
|
Vector3 shiftedHitPos = hitPos;
|
|
|
|
shiftedHitPos.x += normal.x * .05f;
|
|
|
|
shiftedHitPos.y += normal.y * .05f;
|
|
|
|
shiftedHitPos.z += normal.z * .05f;
|
|
|
|
|
|
|
|
EmitBlockFragments(shiftedHitPos, colV);
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
2013-11-19 22:29:39 +09:00
|
|
|
AudioParam param;
|
|
|
|
param.volume = 4.f;
|
|
|
|
|
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Block.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, shiftedHitPos,
|
2013-11-19 22:29:39 +09:00
|
|
|
param);
|
|
|
|
|
|
|
|
param.pitch = .9f + GetRandom() * 0.2f;
|
|
|
|
switch((rand() >> 6) & 3){
|
|
|
|
case 0:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet1.wav");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet2.wav");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet3.wav");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet4.wav");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
audioDevice->Play(c, shiftedHitPos,
|
|
|
|
param);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 22:23:05 +09:00
|
|
|
void Client::AddBulletTracer(spades::client::Player *player,
|
|
|
|
spades::Vector3 muzzlePos,
|
|
|
|
spades::Vector3 hitPos) {
|
|
|
|
Tracer *t;
|
|
|
|
float vel;
|
|
|
|
switch(player->GetWeapon()->GetWeaponType()) {
|
|
|
|
case RIFLE_WEAPON:
|
|
|
|
vel = 700.f;
|
|
|
|
break;
|
|
|
|
case SMG_WEAPON:
|
|
|
|
vel = 360.f;
|
|
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
t = new Tracer(this, muzzlePos, hitPos, vel);
|
|
|
|
AddLocalEntity(t);
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void Client::BlocksFell(std::vector<IntVector3> blocks) {
|
|
|
|
if(blocks.empty())
|
|
|
|
return;
|
|
|
|
FallingBlock *b = new FallingBlock(this, blocks);
|
|
|
|
AddLocalEntity(b);
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
|
|
|
|
|
|
|
IntVector3 v = blocks[0];
|
|
|
|
Vector3 o;
|
|
|
|
o.x = v.x; o.y = v.y; o.z = v.z;
|
|
|
|
o += .5f;
|
|
|
|
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c =
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->RegisterSound("Sounds/Misc/BlockFall.wav");
|
|
|
|
audioDevice->Play(c, o,
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::GrenadeBounced(spades::client::Grenade *g){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(g->GetPosition().z < 63.f){
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Bounce.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::GrenadeDroppedIntoWater(spades::client::Grenade *g){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/DropWater.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::GrenadeExploded(spades::client::Grenade *g) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
bool inWater = g->GetPosition().z > 63.f;
|
|
|
|
|
|
|
|
if(inWater){
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplode.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
AudioParam param;
|
|
|
|
param.volume = 10.f;
|
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeFar.wav");
|
|
|
|
param.volume = 40.f;
|
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeStereo.wav");
|
|
|
|
param.volume = 40.f;
|
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
}
|
|
|
|
|
|
|
|
GrenadeExplosionUnderwater(g->GetPosition());
|
|
|
|
}else{
|
|
|
|
|
|
|
|
GrenadeExplosion(g->GetPosition());
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
2013-11-01 00:38:42 +09:00
|
|
|
Handle<IAudioChunk> c;
|
|
|
|
|
|
|
|
switch((rand() >> 8) & 3){
|
|
|
|
case 0:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode1.wav");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode2.wav");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode3.wav");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode4.wav");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
AudioParam param;
|
|
|
|
param.volume = 10.f;
|
2013-10-07 20:19:11 +09:00
|
|
|
param.referenceDistance = 5.f;
|
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeStereo.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFar.wav");
|
2013-10-07 20:19:11 +09:00
|
|
|
param.volume = .3f;
|
|
|
|
param.referenceDistance = 50.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
|
2013-10-07 20:19:11 +09:00
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFarStereo.wav");
|
|
|
|
param.volume = .3f;
|
|
|
|
param.referenceDistance = 50.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->Play(c, g->GetPosition(),
|
|
|
|
param);
|
|
|
|
|
|
|
|
// debri sound
|
|
|
|
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Debris.wav");
|
|
|
|
param.volume = 5.f;
|
2013-10-07 20:19:11 +09:00
|
|
|
param.referenceDistance = 1.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
IntVector3 outPos;
|
|
|
|
Vector3 soundPos = g->GetPosition();
|
|
|
|
if(world->GetMap()->CastRay(soundPos,
|
|
|
|
MakeVector3(0,0,1),
|
|
|
|
8.f, outPos)){
|
|
|
|
soundPos.z = (float)outPos.z - .2f;
|
|
|
|
}
|
|
|
|
audioDevice->Play(c, soundPos,
|
|
|
|
param);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::LocalPlayerPulledGrenadePin() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
if(!IsMuted()){
|
2013-09-14 17:26:43 +09:00
|
|
|
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Fire.wav");
|
2013-08-18 16:18:06 +09:00
|
|
|
audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f),
|
|
|
|
AudioParam());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::LocalPlayerBlockAction(spades::IntVector3 v, BlockActionType type){
|
|
|
|
net->SendBlockAction(v, type);
|
|
|
|
}
|
|
|
|
void Client::LocalPlayerCreatedLineBlock(spades::IntVector3 v1, spades::IntVector3 v2) {
|
|
|
|
net->SendBlockLine(v1, v2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::LocalPlayerHurt(HurtType type,
|
|
|
|
bool sourceGiven,
|
|
|
|
spades::Vector3 source) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
if(sourceGiven){
|
|
|
|
Player * p = world->GetLocalPlayer();
|
|
|
|
if(!p)
|
|
|
|
return;
|
|
|
|
Vector3 rel = source - p->GetEye();
|
|
|
|
rel.z = 0.f; rel = rel.Normalize();
|
|
|
|
hurtRingView->Add(rel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|