Modernize

- Replaced raw pointers with references or smart pointers. Nullable
  references are represented by `stmp::optional<const T&>`. (There are
  many raw pointers still remaining. They should be replaced at some
  point.)
- Added class template specializations `stmp::optional<T &>` and
  `stmp::optional<const T&>`.
- Fixed `stmp::optional`'s various behaviors
- `World::{players, playerPersistents}` are now `std::array`.
- More uses of `stmp::optional` to clarify the semantics
- Renamed `PlayerThrownGrenade` to `PlayerThrewGrenade`
- Replaced old-style `for` loops with range based ones
- Deleted `Player`'s default constructors and `operator =`
- Deleted `TCGameMode`'s default constructor and `operator =`
- Deleted `CTFGameMode`'s default constructor and `operator =`
- Replaced `static_cast` with `dynamic_cast` for down-casting
- `RefCountedObject::operator*()` no longer requires non-constness to
  return `T &`.
- Replaced the uses of `std::vector::operator[]` with `std::vector::at`
  for bounds checking.
- Made some methods of `GameMap` `const`.
- Added some null checks.
This commit is contained in:
yvt 2019-07-17 00:31:00 +09:00
parent 3c90eedfb8
commit 7c3a39e639
No known key found for this signature in database
GPG Key ID: 48F2768FA8D07C92
39 changed files with 1461 additions and 1324 deletions

View File

@ -45,6 +45,9 @@ namespace spades {
CTFGameMode();
~CTFGameMode();
CTFGameMode(const CTFGameMode &) = delete;
void operator=(const CTFGameMode &) = delete;
Team &GetTeam(int t);
int GetCaptureLimit() { return captureLimit; }
void SetCaptureLimit(int v) { captureLimit = v; }

View File

@ -146,11 +146,6 @@ namespace spades {
scoreboardVisible = false;
flashlightOn = false;
for (size_t i = 0; i < clientPlayers.size(); i++) {
if (clientPlayers[i]) {
clientPlayers[i]->Invalidate();
}
}
clientPlayers.clear();
if (world) {
@ -167,9 +162,9 @@ namespace spades {
// initialize player view objects
clientPlayers.resize(world->GetNumPlayerSlots());
for (size_t i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *p = world->GetPlayer(static_cast<unsigned int>(i));
auto p = world->GetPlayer(static_cast<unsigned int>(i));
if (p) {
clientPlayers[i] = new ClientPlayer(p, this);
clientPlayers[i] = new ClientPlayer(*p, *this);
} else {
clientPlayers[i] = nullptr;
}
@ -220,11 +215,6 @@ namespace spades {
renderer->SetGameMap(nullptr);
audioDevice->SetGameMap(nullptr);
for (size_t i = 0; i < clientPlayers.size(); i++) {
if (clientPlayers[i]) {
clientPlayers[i]->Invalidate();
}
}
clientPlayers.clear();
scriptedUI->ClientDestroyed();
@ -421,7 +411,7 @@ namespace spades {
if (world) {
UpdateWorld(dt);
mumbleLink.update(world->GetLocalPlayer());
mumbleLink.update(world->GetLocalPlayer().get_pointer());
} else {
renderer->SetFogColor(MakeVector3(0.f, 0.f, 0.f));
}
@ -509,11 +499,11 @@ namespace spades {
}
net->SendJoin(team, weap, playerName, lastKills);
} else {
Player *p = world->GetLocalPlayer();
if (p->GetTeamId() != team) {
Player &p = world->GetLocalPlayer().value();
if (p.GetTeamId() != team) {
net->SendTeamChange(team);
}
if (team != 2 && p->GetWeapon()->GetWeaponType() != weap) {
if (team != 2 && p.GetWeapon().GetWeaponType() != weap) {
net->SendWeaponChange(weap);
}
}
@ -587,8 +577,8 @@ namespace spades {
{
std::unique_ptr<IStream> stream(FileManager::OpenForWriting(name.c_str()));
try {
GameMap *map = GetWorld()->GetMap();
if (map == nullptr) {
const Handle<GameMap> &map = GetWorld()->GetMap();
if (!map) {
SPRaise("No map loaded");
}
map->Save(stream.get());
@ -635,8 +625,7 @@ namespace spades {
#pragma mark - Chat Messages
void Client::PlayerSentChatMessage(spades::client::Player *p, bool global,
const std::string &msg) {
void Client::PlayerSentChatMessage(Player &p, bool global, const std::string &msg) {
{
std::string s;
if (global)
@ -648,7 +637,7 @@ namespace spades {
//! but it actually can be.
//! The extra whitespace is not a typo.
s = _Tr("Client", "[Global] ");
s += ChatWindow::TeamColorMessage(p->GetName(), p->GetTeamId());
s += ChatWindow::TeamColorMessage(p.GetName(), p.GetTeamId());
s += ": ";
s += msg;
chatWindow->AddMessage(s);
@ -657,22 +646,22 @@ namespace spades {
std::string s;
if (global)
s = "[Global] ";
s += p->GetName();
s += p.GetName();
s += ": ";
s += msg;
auto col = p->GetTeamId() < 2 ? world->GetTeam(p->GetTeamId()).color
: IntVector3::Make(255, 255, 255);
auto col = p.GetTeamId() < 2 ? world->GetTeam(p.GetTeamId()).color
: IntVector3::Make(255, 255, 255);
scriptedUI->RecordChatLog(
s, MakeVector4(col.x / 255.f, col.y / 255.f, col.z / 255.f, 0.8f));
}
if (global)
NetLog("[Global] %s (%s): %s", p->GetName().c_str(),
world->GetTeam(p->GetTeamId()).name.c_str(), msg.c_str());
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());
NetLog("[Team] %s (%s): %s", p.GetName().c_str(),
world->GetTeam(p.GetTeamId()).name.c_str(), msg.c_str());
if ((!IsMuted()) && (int)cg_chatBeep) {
Handle<IAudioChunk> chunk = audioDevice->RegisterSound("Sounds/Feedback/Chat.opus");
@ -716,8 +705,9 @@ namespace spades {
bool localPlayerIsSpectator = localPlayer.IsSpectator();
int nextId = FollowsNonLocalPlayer(GetCameraMode()) ? followedPlayerId
: world->GetLocalPlayerIndex();
int nextId = FollowsNonLocalPlayer(GetCameraMode())
? followedPlayerId
: world->GetLocalPlayerIndex().value();
do {
reverse ? --nextId : ++nextId;
@ -726,8 +716,8 @@ namespace spades {
if (nextId < 0)
nextId = static_cast<int>(world->GetNumPlayerSlots() - 1);
Player *p = world->GetPlayer(nextId);
if (p == nullptr || p->IsSpectator()) {
stmp::optional<Player &> p = world->GetPlayer(nextId);
if (!p || p->IsSpectator()) {
// Do not follow a non-existent player or spectator
continue;
}

View File

@ -181,7 +181,7 @@ namespace spades {
bool CanLocalPlayerUseToolNow();
/** Retrieves `ClientPlayer` for the local player, or `nullptr` if it does not exist. */
ClientPlayer *GetLocalClientPlayer();
ClientPlayer *GetLocalClientPlayer(); // TODO: Use `optional<ClientPlayer &>`
float toolRaiseState;
void SetSelectedTool(Player::ToolType, bool quiet = false);
@ -291,7 +291,8 @@ namespace spades {
bool IsLimboViewActive();
void SpawnPressed();
Player *HotTrackedPlayer(hitTag_t *hitFlag);
// TODO: Stop using pointers as an out parameter
stmp::optional<Player &> HotTrackedPlayer(hitTag_t *hitFlag);
// effects (local entity, etc)
std::vector<DynamicLightParam> flashDlights;
@ -378,7 +379,7 @@ namespace spades {
void DrawStats();
void DrawScene();
void AddGrenadeToScene(Grenade *);
void AddGrenadeToScene(Grenade &);
void AddDebugObjectToScene(const OBB3 &, const Vector4 &col = MakeVector4(1, 1, 1, 1));
void DrawCTFObjects();
void DrawTCObjects();
@ -429,13 +430,13 @@ namespace spades {
bool WantsToBeClosed() override;
bool IsMuted();
void PlayerSentChatMessage(Player *, bool global, const std::string &);
void PlayerSentChatMessage(Player &, bool global, const std::string &);
void ServerSentMessage(const std::string &);
void PlayerCapturedIntel(Player *);
void PlayerCreatedBlock(Player *);
void PlayerPickedIntel(Player *);
void PlayerDropIntel(Player *);
void PlayerCapturedIntel(Player &);
void PlayerCreatedBlock(Player &);
void PlayerPickedIntel(Player &);
void PlayerDropIntel(Player &);
void TeamCapturedTerritory(int teamId, int territoryId);
void TeamWon(int);
void JoinedGame();
@ -443,34 +444,35 @@ namespace spades {
void PlayerDestroyedBlockWithWeaponOrTool(IntVector3);
void PlayerDiggedBlock(IntVector3);
void GrenadeDestroyedBlock(IntVector3);
void PlayerLeaving(Player *);
void PlayerJoinedTeam(Player *);
void PlayerSpawned(Player *);
void PlayerLeaving(Player &);
void PlayerJoinedTeam(Player &);
void PlayerSpawned(Player &);
// IWorldListener begin
void PlayerObjectSet(int) override;
void PlayerMadeFootstep(Player *) override;
void PlayerJumped(Player *) override;
void PlayerLanded(Player *, bool hurt) override;
void PlayerFiredWeapon(Player *) override;
void PlayerDryFiredWeapon(Player *) override;
void PlayerReloadingWeapon(Player *) override;
void PlayerReloadedWeapon(Player *) override;
void PlayerChangedTool(Player *) override;
void PlayerThrownGrenade(Player *, Grenade *) override;
void PlayerMissedSpade(Player *) override;
void PlayerRestocked(Player *) override;
void PlayerMadeFootstep(Player &) override;
void PlayerJumped(Player &) override;
void PlayerLanded(Player &, bool hurt) override;
void PlayerFiredWeapon(Player &) override;
void PlayerDryFiredWeapon(Player &) override;
void PlayerReloadingWeapon(Player &) override;
void PlayerReloadedWeapon(Player &) override;
void PlayerChangedTool(Player &) override;
void PlayerThrewGrenade(Player &, stmp::optional<const Grenade &>) override;
void PlayerMissedSpade(Player &) override;
void PlayerRestocked(Player &) override;
/** @deprecated use BulletHitPlayer */
void PlayerHitBlockWithSpade(Player *, Vector3 hitPos, IntVector3 blockPos,
void PlayerHitBlockWithSpade(Player &, Vector3 hitPos, IntVector3 blockPos,
IntVector3 normal) override;
void PlayerKilledPlayer(Player *killer, Player *victim, KillType) override;
void PlayerKilledPlayer(Player &killer, Player &victim, KillType) override;
void BulletHitPlayer(Player *hurtPlayer, HitType, Vector3 hitPos, Player *by) override;
void BulletHitPlayer(Player &hurtPlayer, HitType, Vector3 hitPos, Player &by) override;
void BulletHitBlock(Vector3, IntVector3 blockPos, IntVector3 normal) override;
void AddBulletTracer(Player *player, Vector3 muzzlePos, Vector3 hitPos) override;
void GrenadeExploded(Grenade *) override;
void GrenadeBounced(Grenade *) override;
void GrenadeDroppedIntoWater(Grenade *) override;
void AddBulletTracer(Player &player, Vector3 muzzlePos, Vector3 hitPos) override;
void GrenadeExploded(const Grenade &) override;
void GrenadeBounced(const Grenade &) override;
void GrenadeDroppedIntoWater(const Grenade &) override;
void BlocksFell(std::vector<IntVector3>) override;
@ -479,6 +481,7 @@ namespace spades {
void LocalPlayerCreatedLineBlock(IntVector3, IntVector3) override;
void LocalPlayerHurt(HurtType type, bool sourceGiven, Vector3 source) override;
void LocalPlayerBuildError(BuildFailureReason reason) override;
// IWorldListener end
};
} // namespace client
} // namespace spades

View File

@ -218,22 +218,23 @@ namespace spades {
float ScreenHeight() { return base->ScreenHeight(); }
};
ClientPlayer::ClientPlayer(Player *p, Client *c) : client(c), player(p), hasValidOriginMatrix(false) {
ClientPlayer::ClientPlayer(Player &p, Client &c)
: client(c), player(p), hasValidOriginMatrix(false) {
SPADES_MARK_FUNCTION();
sprintState = 0.f;
aimDownState = 0.f;
toolRaiseState = 0.f;
currentTool = p->GetTool();
currentTool = p.GetTool();
localFireVibrationTime = -100.f;
time = 0.f;
viewWeaponOffset = MakeVector3(0, 0, 0);
lastFront = MakeVector3(0, 0, 0);
flashlightOrientation = p->GetFront();
flashlightOrientation = p.GetFront();
ScriptContextHandle ctx;
IRenderer *renderer = client->GetRenderer();
IAudioDevice *audio = client->GetAudioDevice();
IRenderer *renderer = client.GetRenderer();
IAudioDevice *audio = client.GetAudioDevice();
sandboxedRenderer.Set(new SandboxedRenderer(renderer), false);
renderer = sandboxedRenderer;
@ -274,7 +275,7 @@ namespace spades {
"IWeaponSkin@ CreateViewSMGSkin(Renderer@, AudioDevice@)");
static ScriptFunction shotgunViewFactory(
"IWeaponSkin@ CreateViewShotgunSkin(Renderer@, AudioDevice@)");
switch (p->GetWeapon()->GetWeaponType()) {
switch (p.GetWeapon().GetWeaponType()) {
case RIFLE_WEAPON:
weaponSkin = initScriptFactory(rifleFactory, renderer, audio);
weaponViewSkin = initScriptFactory(rifleViewFactory, renderer, audio);
@ -313,10 +314,8 @@ namespace spades {
return result;
}
void ClientPlayer::Invalidate() { player = NULL; }
bool ClientPlayer::IsChangingTool() {
return currentTool != player->GetTool() || toolRaiseState < .999f;
return currentTool != player.GetTool() || toolRaiseState < .999f;
}
float ClientPlayer::GetLocalFireVibration() {
@ -331,9 +330,9 @@ namespace spades {
void ClientPlayer::Update(float dt) {
time += dt;
PlayerInput actualInput = player->GetInput();
WeaponInput actualWeapInput = player->GetWeaponInput();
if (actualInput.sprint && player->IsAlive()) {
PlayerInput actualInput = player.GetInput();
WeaponInput actualWeapInput = player.GetWeaponInput();
if (actualInput.sprint && player.IsAlive()) {
sprintState += dt * 4.f;
if (sprintState > 1.f)
sprintState = 1.f;
@ -343,7 +342,7 @@ namespace spades {
sprintState = 0.f;
}
if (actualWeapInput.secondary && player->IsToolWeapon() && player->IsAlive()) {
if (actualWeapInput.secondary && player.IsToolWeapon() && player.IsAlive()) {
// This is the only animation that can be turned off
// here; others affect the gameplay directly and
// turning them off would be considered cheating
@ -364,7 +363,7 @@ namespace spades {
}
}
if (currentTool == player->GetTool()) {
if (currentTool == player.GetTool()) {
toolRaiseState += dt * 4.f;
if (toolRaiseState > 1.f)
toolRaiseState = 1.f;
@ -374,13 +373,13 @@ namespace spades {
toolRaiseState -= dt * 4.f;
if (toolRaiseState < 0.f) {
toolRaiseState = 0.f;
currentTool = player->GetTool();
currentTool = player.GetTool();
// play tool change sound
if (player->IsLocalPlayer()) {
auto *audioDevice = client->GetAudioDevice();
if (player.IsLocalPlayer()) {
auto *audioDevice = client.GetAudioDevice();
Handle<IAudioChunk> c;
switch (player->GetTool()) {
switch (player.GetTool()) {
case Player::ToolSpade:
c = audioDevice->RegisterSound(
"Sounds/Weapons/Spade/RaiseLocal.opus");
@ -390,7 +389,7 @@ namespace spades {
"Sounds/Weapons/Block/RaiseLocal.opus");
break;
case Player::ToolWeapon:
switch (player->GetWeapon()->GetWeaponType()) {
switch (player.GetWeapon().GetWeaponType()) {
case RIFLE_WEAPON:
c = audioDevice->RegisterSound(
"Sounds/Weapons/Rifle/RaiseLocal.opus");
@ -420,10 +419,10 @@ namespace spades {
{
float scale = dt;
Vector3 vel = player->GetVelocty();
Vector3 front = player->GetFront();
Vector3 right = player->GetRight();
Vector3 up = player->GetUp();
Vector3 vel = player.GetVelocty();
Vector3 front = player.GetFront();
Vector3 right = player.GetRight();
Vector3 up = player.GetUp();
// Offset the view weapon according to the player movement
viewWeaponOffset.x += Vector3::Dot(vel, right) * scale;
@ -459,7 +458,7 @@ namespace spades {
// When the player is aiming down the sight, the weapon's movement
// must be restricted so that other parts of the weapon don't
// cover the ironsight.
if (currentTool == Player::ToolWeapon && player->GetWeaponInput().secondary) {
if (currentTool == Player::ToolWeapon && player.GetWeaponInput().secondary) {
if (dt > 0.f)
viewWeaponOffset *= powf(.01f, dt);
@ -473,14 +472,14 @@ namespace spades {
{
// Smooth the flashlight's movement
Vector3 diff = player->GetFront() - flashlightOrientation;
Vector3 diff = player.GetFront() - flashlightOrientation;
float sq = diff.GetLength();
if (sq > 0.1) {
flashlightOrientation += diff.Normalize() * (sq - 0.1);
}
flashlightOrientation =
Mix(flashlightOrientation, player->GetFront(), 1.0f - powf(1.0e-6, dt))
Mix(flashlightOrientation, player.GetFront(), 1.0f - powf(1.0e-6, dt))
.Normalize();
}
@ -518,12 +517,12 @@ namespace spades {
}
Matrix4 ClientPlayer::GetEyeMatrix() {
Vector3 eye = player->GetEye();
Vector3 eye = player.GetEye();
if ((int)cg_shake >= 2) {
float sp = SmoothStep(GetSprintState());
float p =
cosf(player->GetWalkAnimationProgress() * static_cast<float>(M_PI) * 2.f - 0.8f);
cosf(player.GetWalkAnimationProgress() * static_cast<float>(M_PI) * 2.f - 0.8f);
p = p * p;
p *= p;
p *= p;
@ -531,26 +530,26 @@ namespace spades {
eye.z -= p * 0.06f * sp;
}
return Matrix4::FromAxis(-player->GetRight(), player->GetFront(), -player->GetUp(),
return Matrix4::FromAxis(-player.GetRight(), player.GetFront(), -player.GetUp(),
eye);
}
void ClientPlayer::SetSkinParameterForTool(Player::ToolType type, asIScriptObject *skin) {
Player *p = player;
Player &p = player;
if (currentTool == Player::ToolSpade) {
ScriptISpadeSkin interface(skin);
WeaponInput inp = p->GetWeaponInput();
if (p->GetTool() != Player::ToolSpade) {
WeaponInput inp = p.GetWeaponInput();
if (p.GetTool() != Player::ToolSpade) {
interface.SetActionType(SpadeActionTypeIdle);
interface.SetActionProgress(0.f);
} else if (inp.primary) {
interface.SetActionType(SpadeActionTypeBash);
interface.SetActionProgress(p->GetSpadeAnimationProgress());
interface.SetActionProgress(p.GetSpadeAnimationProgress());
} else if (inp.secondary) {
interface.SetActionType(p->IsFirstDig() ? SpadeActionTypeDigStart
interface.SetActionType(p.IsFirstDig() ? SpadeActionTypeDigStart
: SpadeActionTypeDig);
interface.SetActionProgress(p->GetDigAnimationProgress());
interface.SetActionProgress(p.GetDigAnimationProgress());
} else {
interface.SetActionType(SpadeActionTypeIdle);
interface.SetActionProgress(0.f);
@ -559,38 +558,37 @@ namespace spades {
// TODO: smooth ready state
ScriptIBlockSkin interface(skin);
if (p->GetTool() != Player::ToolBlock) {
if (p.GetTool() != Player::ToolBlock) {
// FIXME: use block's IsReadyToUseTool
// for smoother transition
interface.SetReadyState(0.f);
} else if (p->IsReadyToUseTool()) {
} else if (p.IsReadyToUseTool()) {
interface.SetReadyState(1.f);
} else {
interface.SetReadyState(0.f);
}
interface.SetBlockColor(MakeVector3(p->GetBlockColor()) / 255.f);
interface.SetBlockColor(MakeVector3(p.GetBlockColor()) / 255.f);
} else if (currentTool == Player::ToolGrenade) {
ScriptIGrenadeSkin interface(skin);
interface.SetReadyState(1.f - p->GetTimeToNextGrenade() / 0.5f);
interface.SetReadyState(1.f - p.GetTimeToNextGrenade() / 0.5f);
WeaponInput inp = p->GetWeaponInput();
WeaponInput inp = p.GetWeaponInput();
if (inp.primary) {
interface.SetCookTime(p->GetGrenadeCookTime());
interface.SetCookTime(p.GetGrenadeCookTime());
} else {
interface.SetCookTime(0.f);
}
} else if (currentTool == Player::ToolWeapon) {
Weapon *w = p->GetWeapon();
Weapon &w = p.GetWeapon();
ScriptIWeaponSkin interface(skin);
interface.SetReadyState(1.f - w->TimeToNextFire() / w->GetDelay());
interface.SetReadyState(1.f - w.TimeToNextFire() / w.GetDelay());
interface.SetAimDownSightState(aimDownState);
interface.SetAmmo(w->GetAmmo());
interface.SetClipSize(w->GetClipSize());
interface.SetReloading(w->IsReloading());
interface.SetReloadProgress(w->GetReloadProgress());
interface.SetAmmo(w.GetAmmo());
interface.SetClipSize(w.GetClipSize());
interface.SetReloading(w.IsReloading());
interface.SetReloadProgress(w.GetReloadProgress());
} else {
SPInvalidEnum("currentTool", currentTool);
}
@ -632,7 +630,7 @@ namespace spades {
ScriptIToolSkin interface(skin);
interface.SetRaiseState((skin == curSkin) ? (1.f - putdown) : 0.f);
interface.SetSprintState(sprint);
interface.SetMuted(client->IsMuted());
interface.SetMuted(client.IsMuted());
}
}
@ -640,16 +638,16 @@ namespace spades {
std::array<Vector3, 3> axes;
axes[2] = flashlightOrientation;
axes[0] = Vector3::Cross(flashlightOrientation, player->GetUp()).Normalize();
axes[0] = Vector3::Cross(flashlightOrientation, player.GetUp()).Normalize();
axes[1] = Vector3::Cross(axes[0], axes[2]);
return axes;
}
void ClientPlayer::AddToSceneFirstPersonView() {
Player *p = player;
IRenderer *renderer = client->GetRenderer();
World *world = client->GetWorld();
Player &p = player;
IRenderer *renderer = client.GetRenderer();
World *world = client.GetWorld();
Matrix4 eyeMatrix = GetEyeMatrix();
sandboxedRenderer->SetClipBox(AABB3(eyeMatrix.GetOrigin() - Vector3(20.f, 20.f, 20.f),
@ -657,9 +655,9 @@ namespace spades {
sandboxedRenderer->SetAllowDepthHack(true);
// no flashlight if spectating other players while dead
if (client->flashlightOn && world->GetLocalPlayer()->IsAlive()) {
if (client.flashlightOn && world->GetLocalPlayer()->IsAlive()) {
float brightness;
brightness = client->time - client->flashlightOnTime;
brightness = client.time - client.flashlightOnTime;
brightness = 1.f - expf(-brightness * 5.f);
// add flash light
@ -698,10 +696,10 @@ namespace spades {
{
float sp = 1.f - aimDownState;
sp *= .3f;
sp *= std::min(1.f, p->GetVelocty().GetLength() * 5.f);
sp *= std::min(1.f, p.GetVelocty().GetLength() * 5.f);
viewWeaponOffset.x +=
sinf(p->GetWalkAnimationProgress() * M_PI * 2.f) * 0.013f * sp;
float vl = cosf(p->GetWalkAnimationProgress() * M_PI * 2.f);
sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.013f * sp;
float vl = cosf(p.GetWalkAnimationProgress() * M_PI * 2.f);
vl *= vl;
viewWeaponOffset.z += vl * 0.018f * sp;
}
@ -717,7 +715,8 @@ namespace spades {
}
// manual adjustment
viewWeaponOffset += Vector3{cg_viewWeaponX, cg_viewWeaponY, cg_viewWeaponZ} * (1.f - aimDownState);
viewWeaponOffset +=
Vector3{cg_viewWeaponX, cg_viewWeaponY, cg_viewWeaponZ} * (1.f - aimDownState);
asIScriptObject *skin;
@ -762,7 +761,7 @@ namespace spades {
IModel *model = renderer->RegisterModel("Models/Player/Arm.kv6");
IModel *model2 = renderer->RegisterModel("Models/Player/UpperArm.kv6");
IntVector3 col = p->GetColor();
IntVector3 col = p.GetColor();
param.customColor = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
const float armlen = 0.5f;
@ -824,17 +823,16 @@ namespace spades {
}
void ClientPlayer::AddToSceneThirdPersonView() {
Player &p = player;
IRenderer *renderer = client.GetRenderer();
World *world = client.GetWorld();
Player *p = player;
IRenderer *renderer = client->GetRenderer();
World *world = client->GetWorld();
if (!p->IsAlive()) {
if (!p.IsAlive()) {
if (!cg_ragdoll) {
ModelRenderParam param;
param.matrix = Matrix4::Translate(p->GetOrigin() + MakeVector3(0, 0, 1));
param.matrix = Matrix4::Translate(p.GetOrigin() + MakeVector3(0, 0, 1));
param.matrix = param.matrix * Matrix4::Scale(.1f);
IntVector3 col = p->GetColor();
IntVector3 col = p.GetColor();
param.customColor = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
IModel *model = renderer->RegisterModel("Models/Player/Dead.kv6");
@ -843,7 +841,7 @@ namespace spades {
return;
}
auto origin = p->GetOrigin();
auto origin = p.GetOrigin();
sandboxedRenderer->SetClipBox(
AABB3(origin - Vector3(2.f, 2.f, 4.f), origin + Vector3(2.f, 2.f, 2.f)));
sandboxedRenderer->SetAllowDepthHack(false);
@ -875,21 +873,21 @@ namespace spades {
ModelRenderParam param;
IModel *model;
Vector3 front = p->GetFront();
IntVector3 col = p->GetColor();
Vector3 front = p.GetFront();
IntVector3 col = p.GetColor();
param.customColor = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
float yaw = atan2(front.y, front.x) + M_PI * .5f;
float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y));
// lower axis
Matrix4 lower = Matrix4::Translate(p->GetOrigin());
Matrix4 lower = Matrix4::Translate(p.GetOrigin());
lower = lower * Matrix4::Rotate(MakeVector3(0, 0, 1), yaw);
Matrix4 scaler = Matrix4::Scale(0.1f);
scaler = scaler * Matrix4::Scale(-1, -1, 1);
PlayerInput inp = p->GetInput();
PlayerInput inp = p.GetInput();
// lower
Matrix4 torso, head, arms;
@ -897,12 +895,12 @@ namespace spades {
Matrix4 leg1 = Matrix4::Translate(-0.25f, 0.2f, -0.1f);
Matrix4 leg2 = Matrix4::Translate(0.25f, 0.2f, -0.1f);
float ang = sinf(p->GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p->GetVelocty(), p->GetFront2D()) * 4.f;
float ang = sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p.GetVelocty(), p.GetFront2D()) * 4.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(1, 0, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(1, 0, 0), -ang * walkVel);
walkVel = Vector3::Dot(p->GetVelocty(), p->GetRight()) * 3.f;
walkVel = Vector3::Dot(p.GetVelocty(), p.GetRight()) * 3.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(0, 1, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(0, 1, 0), -ang * walkVel);
@ -931,12 +929,12 @@ namespace spades {
Matrix4 leg1 = Matrix4::Translate(-0.25f, 0.f, -0.1f);
Matrix4 leg2 = Matrix4::Translate(0.25f, 0.f, -0.1f);
float ang = sinf(p->GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p->GetVelocty(), p->GetFront2D()) * 4.f;
float ang = sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p.GetVelocty(), p.GetFront2D()) * 4.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(1, 0, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(1, 0, 0), -ang * walkVel);
walkVel = Vector3::Dot(p->GetVelocty(), p->GetRight()) * 3.f;
walkVel = Vector3::Dot(p.GetVelocty(), p.GetRight()) * 3.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(0, 1, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(0, 1, 0), -ang * walkVel);
@ -998,15 +996,15 @@ namespace spades {
hasValidOriginMatrix = true;
// draw intel in ctf
IGameMode *mode = world->GetMode();
stmp::optional<IGameMode &> mode = world->GetMode();
if (mode && IGameMode::m_CTF == mode->ModeType()) {
CTFGameMode *ctfMode = static_cast<CTFGameMode *>(world->GetMode());
int tId = p->GetTeamId();
CTFGameMode &ctfMode = dynamic_cast<CTFGameMode &>(*mode);
int tId = p.GetTeamId();
if (tId < 3) {
CTFGameMode::Team &team = ctfMode->GetTeam(p->GetTeamId());
if (team.hasIntel && team.carrier == p->GetId()) {
CTFGameMode::Team &team = ctfMode.GetTeam(p.GetTeamId());
if (team.hasIntel && team.carrier == p.GetId()) {
IntVector3 col2 = world->GetTeam(1 - p->GetTeamId()).color;
IntVector3 col2 = world->GetTeam(1 - p.GetTeamId()).color;
param.customColor =
MakeVector3(col2.x / 255.f, col2.y / 255.f, col2.z / 255.f);
Matrix4 mIntel = torso * Matrix4::Translate(0, 0.6f, 0.5f);
@ -1027,17 +1025,17 @@ namespace spades {
void ClientPlayer::AddToScene() {
SPADES_MARK_FUNCTION();
Player *p = player;
const SceneDefinition &lastSceneDef = client->GetLastSceneDef();
Player &p = player;
const SceneDefinition &lastSceneDef = client.GetLastSceneDef();
hasValidOriginMatrix = false;
if (p->GetTeamId() >= 2) {
if (p.GetTeamId() >= 2) {
// spectator, or dummy player
return;
}
float distancePowered = (p->GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength();
float distancePowered = (p.GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength();
if (distancePowered > 140.f * 140.f) {
return;
}
@ -1050,7 +1048,7 @@ namespace spades {
}
void ClientPlayer::Draw2D() {
if (!ShouldRenderInThirdPersonView() && player->IsAlive()) {
if (!ShouldRenderInThirdPersonView() && player.IsAlive()) {
asIScriptObject *skin;
if (currentTool == Player::ToolSpade) {
@ -1081,7 +1079,8 @@ namespace spades {
bool ClientPlayer::ShouldRenderInThirdPersonView() {
// The player from whom's perspective the game is
return !IsFirstPerson(client->GetCameraMode()) || player != &client->GetCameraTargetPlayer();
return !IsFirstPerson(client.GetCameraMode()) ||
&player != &client.GetCameraTargetPlayer();
}
struct ClientPlayer::AmbienceInfo {
@ -1091,21 +1090,21 @@ namespace spades {
};
ClientPlayer::AmbienceInfo ClientPlayer::ComputeAmbience() {
const SceneDefinition &lastSceneDef = client->GetLastSceneDef();
const SceneDefinition &lastSceneDef = client.GetLastSceneDef();
if (!cg_environmentalAudio) {
AmbienceInfo result;
result.room = 0.0f;
result.distance = (lastSceneDef.viewOrigin - player->GetEye()).GetLength();
result.distance = (lastSceneDef.viewOrigin - player.GetEye()).GetLength();
result.size = 0.0f;
return result;
}
float maxDistance = 40.f;
GameMap *map = client->map;
GameMap *map = client.map;
SPAssert(map);
Vector3 rayFrom = player->GetEye();
Vector3 rayFrom = player.GetEye();
// uniformly distributed random unit vectors
const Vector3 directions[24] = {
{-0.4806003057749437f, -0.42909622618705534f, 0.7647874049440525f},
@ -1190,7 +1189,7 @@ namespace spades {
AmbienceInfo result;
result.room = reflections * feedbackness;
result.distance = (lastSceneDef.viewOrigin - player->GetEye()).GetLength();
result.distance = (lastSceneDef.viewOrigin - player.GetEye()).GetLength();
result.size = std::max(std::min(roomSize / 15.0f, 1.0f), 0.0f);
result.room *= std::max(0.0f, std::min((result.size - 0.1f) * 4.0f, 1.0f));
result.room *= 1.0f - result.size * 0.3f;
@ -1199,12 +1198,12 @@ namespace spades {
}
void ClientPlayer::FiredWeapon() {
World *world = player->GetWorld();
World &world = player.GetWorld();
Vector3 muzzle;
const SceneDefinition &lastSceneDef = client->GetLastSceneDef();
IRenderer *renderer = client->GetRenderer();
IAudioDevice *audioDevice = client->GetAudioDevice();
Player *p = player;
const SceneDefinition &lastSceneDef = client.GetLastSceneDef();
IRenderer *renderer = client.GetRenderer();
IAudioDevice *audioDevice = client.GetAudioDevice();
Player &p = player;
// make dlight
{
@ -1216,16 +1215,16 @@ namespace spades {
vec = (mat * MakeVector3(0, 1, 0)).GetXYZ();
muzzle = vec;
client->MuzzleFire(vec, player->GetFront(), player == world->GetLocalPlayer());
client.MuzzleFire(vec, player.GetFront(), &player == world.GetLocalPlayer());
}
if (cg_ejectBrass) {
float dist = (player->GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength();
float dist = (player.GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength();
if (dist < 130.f * 130.f) {
IModel *model = NULL;
Handle<IAudioChunk> snd = NULL;
Handle<IAudioChunk> snd2 = NULL;
switch (player->GetWeapon()->GetWeaponType()) {
switch (player.GetWeapon().GetWeaponType()) {
case RIFLE_WEAPON:
model = renderer->RegisterModel("Models/Weapons/Rifle/Casing.kv6");
snd =
@ -1252,19 +1251,19 @@ namespace spades {
}
if (model) {
Vector3 origin;
origin = muzzle - p->GetFront() * 0.5f;
origin = muzzle - p.GetFront() * 0.5f;
Vector3 vel;
vel = p->GetFront() * 0.5f + p->GetRight() + p->GetUp() * 0.2f;
switch (p->GetWeapon()->GetWeaponType()) {
case SMG_WEAPON: vel -= p->GetFront() * 0.7f; break;
vel = p.GetFront() * 0.5f + p.GetRight() + p.GetUp() * 0.2f;
switch (p.GetWeapon().GetWeaponType()) {
case SMG_WEAPON: vel -= p.GetFront() * 0.7f; break;
case SHOTGUN_WEAPON: vel *= .5f; break;
default: break;
}
ILocalEntity *ent;
ent = new GunCasing(client, model, snd, snd2, origin, p->GetFront(), vel);
client->AddLocalEntity(ent);
ent = new GunCasing(&client, model, snd, snd2, origin, p.GetFront(), vel);
client.AddLocalEntity(ent);
}
}
}
@ -1284,7 +1283,7 @@ namespace spades {
ScriptIWeaponSkin2 interface(skin);
if (interface.ImplementsInterface()) {
interface.SetSoundEnvironment(ambience.room, ambience.size, ambience.distance);
interface.SetSoundOrigin(player->GetEye());
interface.SetSoundOrigin(player.GetEye());
} else if (ShouldRenderInThirdPersonView() && !hasValidOriginMatrix) {
// Legacy skin scripts rely on OriginMatrix which is only updated when
// the player's location is within the fog range.
@ -1314,7 +1313,7 @@ namespace spades {
ScriptIWeaponSkin2 interface(skin);
if (interface.ImplementsInterface()) {
interface.SetSoundEnvironment(ambience.room, ambience.size, ambience.distance);
interface.SetSoundOrigin(player->GetEye());
interface.SetSoundOrigin(player.GetEye());
} else if (ShouldRenderInThirdPersonView() && !hasValidOriginMatrix) {
// Legacy skin scripts rely on OriginMatrix which is only updated when
// the player's location is within the fog range.
@ -1342,5 +1341,5 @@ namespace spades {
interface.ReloadedWeapon();
}
}
}
}
} // namespace client
} // namespace spades

View File

@ -42,8 +42,8 @@ namespace spades {
/** Representation of player which is used by
* drawing/view layer of game client. */
class ClientPlayer : public RefCountedObject {
Client *client;
Player *player;
Client &client;
Player &player;
float sprintState;
float aimDownState;
@ -97,10 +97,8 @@ namespace spades {
~ClientPlayer();
public:
ClientPlayer(Player *p, Client *);
Player *GetPlayer() const { return player; }
void Invalidate();
ClientPlayer(Player &p, Client &);
Player &GetPlayer() const { return player; }
void Update(float dt);
void AddToScene();

View File

@ -269,11 +269,11 @@ namespace spades {
float scrWidth = renderer->ScreenWidth();
float scrHeight = renderer->ScreenHeight();
float wTime = world->GetTime();
Player *p = GetWorld()->GetLocalPlayer();
Player &p = GetWorld()->GetLocalPlayer().value();
if (wTime < lastHurtTime + .35f && wTime >= lastHurtTime) {
float per = (wTime - lastHurtTime) / .35f;
per = 1.f - per;
per *= .3f + (1.f - p->GetHealth() / 100.f) * .7f;
per *= .3f + (1.f - p.GetHealth() / 100.f) * .7f;
per = std::min(per, 0.9f);
per = 1.f - per;
Vector3 color = {1.f, per, per};
@ -290,17 +290,17 @@ namespace spades {
if ((int)cg_playerNames == 0)
return;
Player *p = GetWorld()->GetLocalPlayer();
Player &p = GetWorld()->GetLocalPlayer().value();
hitTag_t tag = hit_None;
Player *hottracked = HotTrackedPlayer(&tag);
stmp::optional<Player &> hottracked = HotTrackedPlayer(&tag);
if (hottracked) {
Vector3 posxyz = Project(hottracked->GetEye());
Vector2 pos = {posxyz.x, posxyz.y};
char buf[64];
if ((int)cg_playerNames == 1) {
float dist = (hottracked->GetEye() - p->GetEye()).GetLength();
float dist = (hottracked->GetEye() - p.GetEye()).GetLength();
int idist = (int)floorf(dist + .5f);
sprintf(buf, "%s [%d%s]", hottracked->GetName().c_str(), idist,
(idist == 1) ? "block" : "blocks");
@ -327,7 +327,7 @@ namespace spades {
Player &p = GetCameraTargetPlayer();
// IFont *font;
Weapon &w = *p.GetWeapon();
Weapon &w = p.GetWeapon();
float spread = w.GetSpread();
AABB2 boundary(0, 0, 0, 0);
@ -448,7 +448,7 @@ namespace spades {
float scrWidth = renderer->ScreenWidth();
float scrHeight = renderer->ScreenHeight();
Player *p = GetWorld()->GetLocalPlayer();
Player &p = GetWorld()->GetLocalPlayer().value();
IFont *font;
// Draw damage rings
@ -459,15 +459,15 @@ namespace spades {
// Draw ammo amount
// (Note: this cannot be displayed for a spectated player --- the server
// does not submit sufficient information)
Weapon *weap = p->GetWeapon();
Weapon &weap = p.GetWeapon();
Handle<IImage> ammoIcon;
float iconWidth, iconHeight;
float spacing = 2.f;
int stockNum;
int warnLevel;
if (p->IsToolWeapon()) {
switch (weap->GetWeaponType()) {
if (p.IsToolWeapon()) {
switch (weap.GetWeaponType()) {
case RIFLE_WEAPON:
ammoIcon = renderer->RegisterImage("Gfx/Bullet/7.62mm.png");
iconWidth = 6.f;
@ -484,11 +484,11 @@ namespace spades {
iconHeight = iconWidth / 4.f;
spacing = -6.f;
break;
default: SPInvalidEnum("weap->GetWeaponType()", weap->GetWeaponType());
default: SPInvalidEnum("weap->GetWeaponType()", weap.GetWeaponType());
}
int clipSize = weap->GetClipSize();
int clip = weap->GetAmmo();
int clipSize = weap.GetClipSize();
int clip = weap.GetAmmo();
clipSize = std::max(clipSize, clip);
@ -505,17 +505,17 @@ namespace spades {
renderer->DrawImage(ammoIcon, AABB2(x, y, iconWidth, iconHeight));
}
stockNum = weap->GetStock();
warnLevel = weap->GetMaxStock() / 3;
stockNum = weap.GetStock();
warnLevel = weap.GetMaxStock() / 3;
} else {
iconHeight = 0.f;
warnLevel = 0;
switch (p->GetTool()) {
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());
case Player::ToolBlock: stockNum = p.GetNumBlocks(); break;
case Player::ToolGrenade: stockNum = p.GetNumGrenades(); break;
default: SPInvalidEnum("p->GetTool()", p.GetTool());
}
}
@ -541,25 +541,25 @@ namespace spades {
{
std::string msg = "";
switch (p->GetTool()) {
switch (p.GetTool()) {
case Player::ToolBlock:
if (p->GetNumBlocks() == 0) {
if (p.GetNumBlocks() == 0) {
msg = _Tr("Client", "Out of Block");
}
break;
case Player::ToolGrenade:
if (p->GetNumGrenades() == 0) {
if (p.GetNumGrenades() == 0) {
msg = _Tr("Client", "Out of Grenade");
}
break;
case Player::ToolWeapon: {
Weapon *weap = p->GetWeapon();
if (weap->IsReloading() || p->IsAwaitingReloadCompletion()) {
Weapon &weap = p.GetWeapon();
if (weap.IsReloading() || p.IsAwaitingReloadCompletion()) {
msg = _Tr("Client", "Reloading");
} else if (weap->GetAmmo() == 0 && weap->GetStock() == 0) {
} else if (weap.GetAmmo() == 0 && weap.GetStock() == 0) {
msg = _Tr("Client", "Out of Ammo");
} else if (weap->GetStock() > 0 &&
weap->GetAmmo() < weap->GetClipSize() / 4) {
} else if (weap.GetStock() > 0 &&
weap.GetAmmo() < weap.GetClipSize() / 4) {
msg = _Tr("Client", "Press [{0}] to Reload",
TranslateKeyName(cg_keyReloadWeapon));
}
@ -577,7 +577,7 @@ namespace spades {
}
}
if (p->GetTool() == Player::ToolBlock) {
if (p.GetTool() == Player::ToolBlock) {
paletteView->Draw();
}
@ -591,17 +591,17 @@ namespace spades {
void Client::DrawDeadPlayerHUD() {
SPADES_MARK_FUNCTION();
Player *p = GetWorld()->GetLocalPlayer();
Player &p = GetWorld()->GetLocalPlayer().value();
IFont *font;
float scrWidth = renderer->ScreenWidth();
float scrHeight = renderer->ScreenHeight();
if (!cg_hideHud) {
// draw respawn tme
if (!p->IsAlive()) {
if (!p.IsAlive()) {
std::string msg;
float secs = p->GetRespawnTime() - world->GetTime();
float secs = p.GetRespawnTime() - world->GetTime();
if (secs > 0.f)
msg = _Tr("Client", "You will respawn in: {0}", (int)ceilf(secs));
@ -764,19 +764,19 @@ namespace spades {
void Client::DrawHealth() {
SPADES_MARK_FUNCTION();
Player *p = GetWorld()->GetLocalPlayer();
Player &p = GetWorld()->GetLocalPlayer().value();
IFont *font;
// float scrWidth = renderer->ScreenWidth();
float scrHeight = renderer->ScreenHeight();
std::string str = std::to_string(p->GetHealth());
std::string str = std::to_string(p.GetHealth());
Vector4 numberColor = {1, 1, 1, 1};
if (p->GetHealth() == 0) {
if (p.GetHealth() == 0) {
numberColor.y = 0.3f;
numberColor.z = 0.3f;
} else if (p->GetHealth() <= 50) {
} else if (p.GetHealth() <= 50) {
numberColor.z = 0.3f;
}
@ -794,7 +794,7 @@ namespace spades {
ent->Render2D();
}
Player *p = GetWorld()->GetLocalPlayer();
stmp::optional<Player &> p = GetWorld()->GetLocalPlayer();
if (p) {
DrawHurtSprites();
DrawHurtScreenEffect();

View File

@ -155,8 +155,8 @@ namespace spades {
SPAssert(world);
SPAssert(world->GetLocalPlayer());
Player *p = world->GetLocalPlayer();
if (p->IsAlive()) {
Player &p = world->GetLocalPlayer().value();
if (p.IsAlive()) {
float aimDownState = GetAimDownState();
x /= GetAimDownZoomScale();
y /= GetAimDownZoomScale();
@ -194,7 +194,7 @@ namespace spades {
if (cg_invertMouseY)
y = -y;
p->Turn(x * 0.003f, y * 0.003f);
p.Turn(x * 0.003f, y * 0.003f);
}
break;
}
@ -329,7 +329,7 @@ namespace spades {
if (cameraMode == ClientCameraMode::Free ||
cameraMode == ClientCameraMode::ThirdPersonLocal) {
// Start with the local player
followedPlayerId = world->GetLocalPlayerIndex();
followedPlayerId = world->GetLocalPlayerIndex().value();
}
if (world->GetLocalPlayer()->IsSpectator() ||
time > lastAliveTime + 1.3f) {
@ -342,7 +342,7 @@ namespace spades {
if (cameraMode == ClientCameraMode::Free ||
cameraMode == ClientCameraMode::ThirdPersonLocal) {
// Start with the local player
followedPlayerId = world->GetLocalPlayerIndex();
followedPlayerId = world->GetLocalPlayerIndex().value();
}
if (world->GetLocalPlayer()->IsSpectator() ||
time > lastAliveTime + 1.3f) {
@ -369,9 +369,9 @@ namespace spades {
}
if (world->GetLocalPlayer()) {
Player *p = world->GetLocalPlayer();
Player &p = world->GetLocalPlayer().value();
if (p->IsAlive() && p->GetTool() == Player::ToolBlock && down) {
if (p.IsAlive() && p.GetTool() == Player::ToolBlock && down) {
if (paletteView->KeyInput(name)) {
return;
}
@ -380,9 +380,9 @@ namespace spades {
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);
Player &victim = world->GetLocalPlayer().value();
corp = new Corpse(renderer, map, &victim);
corp->AddImpulse(victim.GetFront() * 32.f);
corpses.emplace_back(corp);
if (corpses.size() > corpseHardLimit) {
@ -433,7 +433,7 @@ namespace spades {
} else if (CheckKey(cg_keyAltAttack, name)) {
auto lastVal = weapInput.secondary;
if (world->GetLocalPlayer()->IsToolWeapon() && (!cg_holdAimDownSight)) {
if (down && !world->GetLocalPlayer()->GetWeapon()->IsReloading()) {
if (down && !world->GetLocalPlayer()->GetWeapon().IsReloading()) {
weapInput.secondary = !weapInput.secondary;
}
} else {
@ -441,7 +441,7 @@ namespace spades {
}
if (world->GetLocalPlayer()->IsToolWeapon() && weapInput.secondary &&
!lastVal && world->GetLocalPlayer()->IsReadyToUseTool() &&
!world->GetLocalPlayer()->GetWeapon()->IsReloading() &&
!world->GetLocalPlayer()->GetWeapon().IsReloading() &&
GetSprintState() == 0.0f) {
AudioParam params;
params.volume = 0.08f;
@ -450,10 +450,10 @@ namespace spades {
audioDevice->PlayLocal(chunk, MakeVector3(.4f, -.3f, .5f), params);
}
} else if (CheckKey(cg_keyReloadWeapon, name) && down) {
Weapon *w = world->GetLocalPlayer()->GetWeapon();
if (w->GetAmmo() < w->GetClipSize() && w->GetStock() > 0 &&
Weapon &w = world->GetLocalPlayer()->GetWeapon();
if (w.GetAmmo() < w.GetClipSize() && w.GetStock() > 0 &&
(!world->GetLocalPlayer()->IsAwaitingReloadCompletion()) &&
(!w->IsReloading()) &&
(!w.IsReloading()) &&
world->GetLocalPlayer()->GetTool() == Player::ToolWeapon) {
if (world->GetLocalPlayer()->IsToolWeapon()) {
if (weapInput.secondary) {
@ -553,7 +553,7 @@ namespace spades {
} else if (CheckKey(cg_keyLimbo, name) && down) {
limbo->SetSelectedTeam(world->GetLocalPlayer()->GetTeamId());
limbo->SetSelectedWeapon(
world->GetLocalPlayer()->GetWeapon()->GetWeaponType());
world->GetLocalPlayer()->GetWeapon().GetWeaponType());
inGameLimbo = true;
} else if (CheckKey(cg_keySceneshot, name) && down) {
TakeScreenShot(true);

View File

@ -111,26 +111,33 @@ namespace spades {
}
}
Player *Client::HotTrackedPlayer(hitTag_t *hitFlag) {
stmp::optional<Player &> Client::HotTrackedPlayer(hitTag_t *hitFlag) {
if (!IsFirstPerson(GetCameraMode()))
return nullptr;
return {};
auto &p = GetCameraTargetPlayer();
SPAssert(world);
Vector3 origin = p.GetEye();
Vector3 dir = p.GetFront();
World::WeaponRayCastResult result = world->WeaponRayCast(origin, dir, &p);
auto &cameraTargetPlayer = GetCameraTargetPlayer();
if (result.hit == false || result.player == nullptr)
return nullptr;
Vector3 origin = cameraTargetPlayer.GetEye();
Vector3 dir = cameraTargetPlayer.GetFront();
World::WeaponRayCastResult result =
world->WeaponRayCast(origin, dir, cameraTargetPlayer.GetId());
if (result.hit == false || !result.playerId)
return {};
Player &player = world->GetPlayer(result.playerId.value()).value();
// don't hot track enemies (non-spectator only)
if (result.player->GetTeamId() != p.GetTeamId() && p.GetTeamId() < 2)
return nullptr;
if (player.GetTeamId() != cameraTargetPlayer.GetTeamId() &&
cameraTargetPlayer.GetTeamId() < 2) {
return {};
}
if (hitFlag) {
*hitFlag = result.hitFlag;
}
return result.player;
return player;
}
bool Client::IsMuted() {
@ -151,14 +158,14 @@ namespace spades {
if ((int)cg_particles < 1)
return;
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
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(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
10.f,
1.f, 0.7f);
@ -177,7 +184,7 @@ namespace spades {
new SmokeSpriteEntity(this, color, 100.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory(v,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
.7f,
.8f, 0.f);
@ -194,7 +201,7 @@ namespace spades {
new SmokeSpriteEntity(this, color, 40.f, SmokeSpriteEntity::Type::Steady);
ent->SetTrajectory(v,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
.7f,
.8f, 0.f);
@ -223,7 +230,7 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
7.f,
1.f, .9f);
@ -241,10 +248,11 @@ namespace spades {
if (distPowered < 32.f * 32.f) {
for (int i = 0; i < 16; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
12.f,
ent->SetTrajectory(origin,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
12.f,
1.f, .9f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.1f + SampleRandomFloat() * SampleRandomFloat() * 0.14f);
@ -261,7 +269,7 @@ namespace spades {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 100.f);
ent->SetTrajectory(origin,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
.7f,
1.f, 0.f);
@ -291,7 +299,7 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) *
7.f,
1.f, 1.f);
@ -322,13 +330,13 @@ namespace spades {
for (int i = 0; i < 2; i++) {
ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory(
origin, (MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias * .5f) *
0.3f,
1.f, 0.f);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias * .5f) *
0.3f,
1.f, 0.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(.4f, 3.f, 0.0000005f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
@ -387,13 +395,13 @@ namespace spades {
for (int i = 0; i < 4; i++) {
ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 60.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory(
origin, (MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias * .5f) *
2.f,
1.f, 0.f);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias * .5f) *
2.f,
1.f, 0.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(.6f + SampleRandomFloat() * SampleRandomFloat() * 0.4f, 2.f, .2f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
@ -406,10 +414,11 @@ namespace spades {
for (int i = 0; i < 8; i++) {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f);
ent->SetTrajectory(
origin, (MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
(SampleRandomFloat() - SampleRandomFloat()) * .2f)) *
2.f,
origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
(SampleRandomFloat() - SampleRandomFloat()) * .2f)) *
2.f,
1.f, 0.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(1.5f + SampleRandomFloat() * SampleRandomFloat() * 0.8f, 0.2f);
@ -429,7 +438,7 @@ namespace spades {
for (int i = 0; i < 42; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat());
dir += velBias * .5f;
float radius = 0.1f + SampleRandomFloat() * SampleRandomFloat() * 0.2f;
@ -446,12 +455,13 @@ namespace spades {
for (int i = 0; i < 4; i++) {
ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory(
origin, (MakeVector3(SampleRandomFloat() - SampleRandomFloat(), SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias) *
6.f,
1.f, 0.f);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat()) +
velBias) *
6.f,
1.f, 0.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(.3f + SampleRandomFloat() * SampleRandomFloat() * 0.4f, 3.f, .1f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
@ -482,7 +492,8 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(), -SampleRandomFloat() * 7.f)) *
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 7.f)) *
2.5f,
.3f, .6f);
ent->SetRotation(0.f);
@ -501,7 +512,8 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(), -SampleRandomFloat() * 10.f)) *
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 10.f)) *
3.5f,
1.f, 1.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
@ -518,9 +530,11 @@ namespace spades {
for (int i = 0; i < 8; i++) {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f);
ent->SetTrajectory(
origin, (MakeVector3(SampleRandomFloat() - SampleRandomFloat(), SampleRandomFloat() - SampleRandomFloat(),
(SampleRandomFloat() - SampleRandomFloat()) * .2f)) *
2.f,
origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
(SampleRandomFloat() - SampleRandomFloat()) * .2f)) *
2.f,
1.f, 0.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(1.4f + SampleRandomFloat() * SampleRandomFloat() * 0.8f, 0.2f);
@ -539,7 +553,8 @@ namespace spades {
color = MakeVector4(1, 1, 1, 0.7f);
for (int i = 0; i < 42; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(SampleRandomFloat() - SampleRandomFloat(), SampleRandomFloat() - SampleRandomFloat(),
Vector3 dir = MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 3.f);
dir += velBias * .5f;
float radius = 0.1f + SampleRandomFloat() * SampleRandomFloat() * 0.2f;
@ -564,7 +579,7 @@ namespace spades {
if ((int)cg_particles < 1)
return;
Vector4 color;
color = MakeVector4(.95f, .95f, .95f, .3f);
// water1
@ -575,7 +590,8 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(), -SampleRandomFloat() * 7.f)) *
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 7.f)) *
1.f,
.3f, .6f);
ent->SetRotation(0.f);
@ -594,13 +610,15 @@ namespace spades {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin,
(MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(), -SampleRandomFloat() * 10.f)) *
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 10.f)) *
2.f,
1.f, 1.f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.6f + SampleRandomFloat() * SampleRandomFloat() * 0.6f, 0.6f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(3.f + SampleRandomFloat() * 0.3f, SampleRandomFloat() * 0.3f, .60f);
ent->SetLifeTime(3.f + SampleRandomFloat() * 0.3f, SampleRandomFloat() * 0.3f,
.60f);
localEntities.emplace_back(ent);
}
@ -610,7 +628,7 @@ namespace spades {
for (int i = 0; i < 10; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
SampleRandomFloat() - SampleRandomFloat(),
-SampleRandomFloat() * 3.f);
float radius = 0.03f + SampleRandomFloat() * SampleRandomFloat() * 0.05f;
ent->SetTrajectory(origin + dir * .2f + MakeVector3(0, 0, -1.2f), dir * 5.f,
@ -692,12 +710,12 @@ namespace spades {
SPAssert(world);
const auto &lastSceneDef = this->lastSceneDef;
World::WeaponRayCastResult result = world->WeaponRayCast(origin, direction, nullptr);
World::WeaponRayCastResult result = world->WeaponRayCast(origin, direction, {});
if (result.hit) {
return Vector3::Dot(result.hitPos - origin, lastSceneDef.viewAxis[2]);
}
return std::nan(nullptr);
}
}
}
} // namespace client
} // namespace spades

View File

@ -25,17 +25,16 @@
#include <Core/Settings.h>
#include <Core/Strings.h>
#include <Core/Strings.h>
#include "IAudioChunk.h"
#include "IAudioDevice.h"
#include "CTFGameMode.h"
#include "GameMap.h"
#include "GameProperties.h"
#include "IGameMode.h"
#include "TCGameMode.h"
#include "World.h"
#include "GameProperties.h"
#include "CenterMessageView.h"
#include "ChatWindow.h"
@ -68,20 +67,20 @@ namespace spades {
freeCameraState.velocity = MakeVector3(0, 0, 0);
}
void Client::PlayerCreatedBlock(spades::client::Player *p) {
void Client::PlayerCreatedBlock(Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Block/Build.opus");
audioDevice->Play(c, p->GetEye() + p->GetFront(), AudioParam());
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;
TCGameMode::Territory &ter =
dynamic_cast<TCGameMode &>(*world->GetMode()).GetTerritory(terId);
int old = ter.ownerTeamId;
std::string msg;
std::string teamName =
chatWindow->TeamColorMessage(world->GetTeam(teamId).name, teamId);
@ -118,27 +117,27 @@ namespace spades {
}
}
void Client::PlayerCapturedIntel(spades::client::Player *p) {
void Client::PlayerCapturedIntel(Player &p) {
std::string msg;
{
std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
std::string holderName = chatWindow->TeamColorMessage(p.GetName(), p.GetTeamId());
std::string otherTeamName = chatWindow->TeamColorMessage(
world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId());
world->GetTeam(1 - p.GetTeamId()).name, 1 - p.GetTeamId());
msg = _Tr("Client", "{0} captured {1}'s intel", holderName, otherTeamName);
chatWindow->AddMessage(msg);
}
if ((int)cg_centerMessage != 0) {
std::string holderName = p->GetName();
std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name;
std::string holderName = p.GetName();
std::string otherTeamName = world->GetTeam(1 - p.GetTeamId()).name;
msg = _Tr("Client", "{0} captured {1}'s Intel.", holderName, otherTeamName);
NetLog("%s", msg.c_str());
centerMessageView->AddMessage(msg);
}
if (world->GetLocalPlayer() && !IsMuted()) {
if (p->GetTeamId() == world->GetLocalPlayer()->GetTeamId()) {
if (p.GetTeamId() == world->GetLocalPlayer()->GetTeamId()) {
Handle<IAudioChunk> chunk =
audioDevice->RegisterSound("Sounds/Feedback/CTF/YourTeamCaptured.opus");
audioDevice->PlayLocal(chunk, AudioParam());
@ -150,19 +149,19 @@ namespace spades {
}
}
void Client::PlayerPickedIntel(spades::client::Player *p) {
void Client::PlayerPickedIntel(Player &p) {
std::string msg;
{
std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
std::string holderName = chatWindow->TeamColorMessage(p.GetName(), p.GetTeamId());
std::string otherTeamName = chatWindow->TeamColorMessage(
world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId());
world->GetTeam(1 - p.GetTeamId()).name, 1 - p.GetTeamId());
msg = _Tr("Client", "{0} picked up {1}'s intel", holderName, otherTeamName);
chatWindow->AddMessage(msg);
}
if ((int)cg_centerMessage != 0) {
std::string holderName = p->GetName();
std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name;
std::string holderName = p.GetName();
std::string otherTeamName = world->GetTeam(1 - p.GetTeamId()).name;
msg = _Tr("Client", "{0} picked up {1}'s Intel.", holderName, otherTeamName);
NetLog("%s", msg.c_str());
centerMessageView->AddMessage(msg);
@ -175,19 +174,19 @@ namespace spades {
}
}
void Client::PlayerDropIntel(spades::client::Player *p) {
void Client::PlayerDropIntel(Player &p) {
std::string msg;
{
std::string holderName = chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId());
std::string holderName = chatWindow->TeamColorMessage(p.GetName(), p.GetTeamId());
std::string otherTeamName = chatWindow->TeamColorMessage(
world->GetTeam(1 - p->GetTeamId()).name, 1 - p->GetTeamId());
world->GetTeam(1 - p.GetTeamId()).name, 1 - p.GetTeamId());
msg = _Tr("Client", "{0} dropped {1}'s intel", holderName, otherTeamName);
chatWindow->AddMessage(msg);
}
if ((int)cg_centerMessage != 0) {
std::string holderName = p->GetName();
std::string otherTeamName = world->GetTeam(1 - p->GetTeamId()).name;
std::string holderName = p.GetName();
std::string otherTeamName = world->GetTeam(1 - p.GetTeamId()).name;
msg = _Tr("Client", "{0} dropped {1}'s Intel", holderName, otherTeamName);
NetLog("%s", msg.c_str());
centerMessageView->AddMessage(msg);
@ -195,6 +194,8 @@ namespace spades {
}
void Client::PlayerDestroyedBlockWithWeaponOrTool(spades::IntVector3 blk) {
SPAssert(map);
Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f};
if (!map->IsSolid(blk.x, blk.y, blk.z))
@ -220,6 +221,8 @@ namespace spades {
audioDevice->Play(c, origin, AudioParam());
}
SPAssert(map);
for (int z = blk.z - 1; z <= blk.z + 1; z++) {
if (z < 0 || z > 61)
continue;
@ -232,13 +235,13 @@ namespace spades {
}
}
void Client::PlayerLeaving(spades::client::Player *p) {
void Client::PlayerLeaving(Player &p) {
// Choose the next player if a follow cam is active on this player
if (FollowsNonLocalPlayer(GetCameraMode()) && &GetCameraTargetPlayer() == p) {
if (FollowsNonLocalPlayer(GetCameraMode()) && &GetCameraTargetPlayer() == &p) {
FollowNextPlayer(false);
// Still unable to find a substitute?
if (&GetCameraTargetPlayer() == p) {
if (&GetCameraTargetPlayer() == &p) {
// Turn off the follow cam mode
followCameraState.enabled = false;
}
@ -247,42 +250,42 @@ namespace spades {
{
std::string msg;
msg = _Tr("Client", "Player {0} has left",
chatWindow->TeamColorMessage(p->GetName(), p->GetTeamId()));
chatWindow->TeamColorMessage(p.GetName(), p.GetTeamId()));
chatWindow->AddMessage(msg);
}
{
std::string msg;
msg = _Tr("Client", "Player {0} has left", p->GetName());
msg = _Tr("Client", "Player {0} has left", p.GetName());
auto col = p->GetTeamId() < 2 ? world->GetTeam(p->GetTeamId()).color
: IntVector3::Make(255, 255, 255);
auto col = p.GetTeamId() < 2 ? world->GetTeam(p.GetTeamId()).color
: IntVector3::Make(255, 255, 255);
NetLog("%s", msg.c_str());
scriptedUI->RecordChatLog(
msg, MakeVector4(col.x / 255.f, col.y / 255.f, col.z / 255.f, 0.8f));
}
RemoveCorpseForPlayer(p->GetId());
RemoveCorpseForPlayer(p.GetId());
}
void Client::PlayerJoinedTeam(spades::client::Player *p) {
std::string teamName = world->GetTeam(p->GetTeamId()).name;
void Client::PlayerJoinedTeam(Player &p) {
std::string teamName = world->GetTeam(p.GetTeamId()).name;
if (p->GetTeamId() >= 2) {
if (p.GetTeamId() >= 2) {
teamName = _Tr("Client", "Spectator");
}
{
std::string msg;
msg = _Tr("Client", "{0} joined {1} team", p->GetName(),
chatWindow->TeamColorMessage(teamName, p->GetTeamId()));
msg = _Tr("Client", "{0} joined {1} team", p.GetName(),
chatWindow->TeamColorMessage(teamName, p.GetTeamId()));
chatWindow->AddMessage(msg);
}
{
std::string msg;
msg = _Tr("Client", "{0} joined {1} team", p->GetName(), teamName);
msg = _Tr("Client", "{0} joined {1} team", p.GetName(), teamName);
auto col = p->GetTeamId() < 2 ? world->GetTeam(p->GetTeamId()).color
: IntVector3::Make(255, 255, 255);
auto col = p.GetTeamId() < 2 ? world->GetTeam(p.GetTeamId()).color
: IntVector3::Make(255, 255, 255);
NetLog("%s", msg.c_str());
scriptedUI->RecordChatLog(
@ -290,13 +293,15 @@ namespace spades {
}
}
void Client::PlayerSpawned(Player *p) {
void Client::PlayerSpawned(Player &p) {
if (net->GetGameProperties()->clearCorpseOnRespawn) {
RemoveCorpseForPlayer(p->GetId());
RemoveCorpseForPlayer(p.GetId());
}
}
void Client::GrenadeDestroyedBlock(spades::IntVector3 blk) {
SPAssert(map);
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++) {
@ -337,8 +342,6 @@ namespace spades {
}
}
void Client::MarkWorldUpdate() {
upsCounter.MarkFrame();
}
}
}
void Client::MarkWorldUpdate() { upsCounter.MarkFrame(); }
} // namespace client
} // namespace spades

View File

@ -56,7 +56,7 @@ namespace spades {
return ClientCameraMode::None;
}
Player *p = world->GetLocalPlayer();
stmp::optional<Player &> p = world->GetLocalPlayer();
if (!p) {
return ClientCameraMode::NotJoined;
}
@ -95,7 +95,7 @@ namespace spades {
case ClientCameraMode::FirstPersonLocal:
case ClientCameraMode::ThirdPersonLocal:
SPAssert(world);
return world->GetLocalPlayerIndex();
return world->GetLocalPlayerIndex().value();
case ClientCameraMode::FirstPersonFollow:
case ClientCameraMode::ThirdPersonFollow: return followedPlayerId;
}
@ -103,9 +103,7 @@ namespace spades {
}
Player &Client::GetCameraTargetPlayer() {
Player *p = world->GetPlayer(GetCameraTargetPlayerId());
SPAssert(p);
return *p;
return world->GetPlayer(GetCameraTargetPlayerId()).value();
}
float Client::GetLocalFireVibration() {
@ -127,7 +125,7 @@ namespace spades {
SPAssert(clientPlayer);
float delta = .8f;
switch (player.GetWeapon()->GetWeaponType()) {
switch (player.GetWeapon().GetWeaponType()) {
case SMG_WEAPON: delta = .8f; break;
case RIFLE_WEAPON: delta = 1.4f; break;
case SHOTGUN_WEAPON: delta = .4f; break;
@ -487,24 +485,24 @@ namespace spades {
return def;
}
void Client::AddGrenadeToScene(spades::client::Grenade *g) {
void Client::AddGrenadeToScene(Grenade &g) {
SPADES_MARK_FUNCTION();
IModel *model;
model = renderer->RegisterModel("Models/Weapons/Grenade/Grenade.kv6");
if (g->GetPosition().z > 63.f) {
if (g.GetPosition().z > 63.f) {
// work-around for water refraction problem
return;
}
// Move the grenade slightly so that it doesn't look like sinking in
// the ground
Vector3 position = g->GetPosition();
Vector3 position = g.GetPosition();
position.z -= 0.03f * 3.0f;
ModelRenderParam param;
Matrix4 mat = g->GetOrientation().ToRotationMatrix() * Matrix4::Scale(0.03f);
Matrix4 mat = g.GetOrientation().ToRotationMatrix() * Matrix4::Scale(0.03f);
mat = Matrix4::Translate(position) * mat;
param.matrix = mat;
@ -541,12 +539,12 @@ namespace spades {
void Client::DrawCTFObjects() {
SPADES_MARK_FUNCTION();
CTFGameMode *mode = static_cast<CTFGameMode *>(world->GetMode());
CTFGameMode &mode = dynamic_cast<CTFGameMode &>(world->GetMode().value());
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);
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};
@ -559,7 +557,7 @@ namespace spades {
renderer->RenderModel(base, param);
// draw flag
if (!mode->GetTeam(1 - tId).hasIntel) {
if (!mode.GetTeam(1 - tId).hasIntel) {
param.matrix = Matrix4::Translate(team.flagPos);
param.matrix = param.matrix * Matrix4::Scale(.1f);
renderer->RenderModel(intel, param);
@ -569,17 +567,17 @@ namespace spades {
void Client::DrawTCObjects() {
SPADES_MARK_FUNCTION();
TCGameMode *mode = static_cast<TCGameMode *>(world->GetMode());
TCGameMode &mode = dynamic_cast<TCGameMode &>(world->GetMode().value());
int tId;
IModel *base = renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
int cnt = mode->GetNumTerritories();
int cnt = mode.GetNumTerritories();
for (tId = 0; tId < cnt; tId++) {
TCGameMode::Territory *t = mode->GetTerritory(tId);
TCGameMode::Territory &t = mode.GetTerritory(tId);
IntVector3 col;
if (t->ownerTeamId == 2) {
if (t.ownerTeamId == 2) {
col = IntVector3::Make(255, 255, 255);
} else {
col = world->GetTeam(t->ownerTeamId).color;
col = world->GetTeam(t.ownerTeamId).color;
}
Vector3 color = {col.x / 255.f, col.y / 255.f, col.z / 255.f};
@ -587,7 +585,7 @@ namespace spades {
param.customColor = color;
// draw base
param.matrix = Matrix4::Translate(t->pos);
param.matrix = Matrix4::Translate(t.pos);
param.matrix = param.matrix * Matrix4::Scale(.3f);
renderer->RenderModel(base, param);
}
@ -599,16 +597,16 @@ namespace spades {
renderer->StartScene(lastSceneDef);
if (world) {
Player *p = world->GetLocalPlayer();
stmp::optional<Player &> p = world->GetLocalPlayer();
for (size_t i = 0; i < world->GetNumPlayerSlots(); i++)
if (world->GetPlayer(static_cast<unsigned int>(i))) {
SPAssert(clientPlayers[i]);
clientPlayers[i]->AddToScene();
}
std::vector<Grenade *> nades = world->GetAllGrenades();
for (size_t i = 0; i < nades.size(); i++) {
AddGrenadeToScene(nades[i]);
auto &nades = world->GetAllGrenades();
for (auto &nade: nades) {
AddGrenadeToScene(*nade);
}
{
@ -680,7 +678,7 @@ namespace spades {
// FIXME: don't use debug line
{
hitTag_t tag = hit_None;
Player *hottracked = HotTrackedPlayer(&tag);
stmp::optional<Player &> hottracked = HotTrackedPlayer(&tag);
if (hottracked) {
IntVector3 col = world->GetTeam(hottracked->GetTeamId()).color;
Vector4 color = Vector4::Make(col.x / 255.f, col.y / 255.f, col.z / 255.f, 1.f);

View File

@ -68,10 +68,8 @@ namespace spades {
float Client::GetSprintState() {
if (!world)
return 0.f;
if (!world->GetLocalPlayer())
return 0.f;
ClientPlayer *p = clientPlayers[(int)world->GetLocalPlayerIndex()];
ClientPlayer *p = GetLocalClientPlayer();
if (!p)
return 0.f;
return p->GetSprintState();
@ -80,10 +78,8 @@ namespace spades {
float Client::GetAimDownState() {
if (!world)
return 0.f;
if (!world->GetLocalPlayer())
return 0.f;
ClientPlayer *p = clientPlayers[(int)world->GetLocalPlayerIndex()];
ClientPlayer *p = GetLocalClientPlayer();
if (!p)
return 0.f;
return p->GetAimDownState();
@ -111,10 +107,10 @@ namespace spades {
}
ClientPlayer *Client::GetLocalClientPlayer() {
if (!world || !world->GetLocalPlayer()) {
if (!world || !world->GetLocalPlayerIndex()) {
return nullptr;
}
return clientPlayers.at(static_cast<std::size_t>(world->GetLocalPlayerIndex()));
return clientPlayers.at(static_cast<std::size_t>(*world->GetLocalPlayerIndex()));
}
#pragma mark - World Actions
@ -122,7 +118,7 @@ namespace spades {
void Client::CaptureColor() {
if (!world)
return;
Player *p = world->GetLocalPlayer();
stmp::optional<Player &> p = world->GetLocalPlayer();
if (!p)
return;
if (!p->IsAlive())
@ -168,10 +164,9 @@ namespace spades {
void Client::UpdateWorld(float dt) {
SPADES_MARK_FUNCTION();
Player *player = world->GetLocalPlayer();
stmp::optional<Player &> player = world->GetLocalPlayer();
if (player) {
// disable input when UI is open
if (scriptedUI->NeedsInput()) {
weapInput.primary = false;
@ -206,9 +201,9 @@ namespace spades {
#endif
// update player view (doesn't affect physics/game logics)
for (size_t i = 0; i < clientPlayers.size(); i++) {
if (clientPlayers[i]) {
clientPlayers[i]->Update(dt);
for (auto &clientPlayer : clientPlayers) {
if (clientPlayer) {
clientPlayer->Update(dt);
}
}
@ -264,7 +259,7 @@ namespace spades {
}
if (time > lastPosSentTime + 1.f && world->GetLocalPlayer()) {
Player *p = world->GetLocalPlayer();
stmp::optional<Player &> p = world->GetLocalPlayer();
if (p->IsAlive() && p->GetTeamId() < 2) {
net->SendPosition();
lastPosSentTime = time;
@ -314,13 +309,15 @@ namespace spades {
for (int sz = -1; sz <= 1; sz++) {
GameMap::RayCastResult result;
Vector3 shift = {sx * .1f, sy * .1f, sz * .1f};
result = map->CastRay2(lastPos + shift, freeState.position - lastPos, 256);
result =
map->CastRay2(lastPos + shift, freeState.position - lastPos, 256);
if (result.hit && !result.startSolid &&
Vector3::Dot(result.hitPos - freeState.position - shift,
freeState.position - lastPos) < 0.f) {
float dist = Vector3::Dot(result.hitPos - freeState.position - shift,
(freeState.position - lastPos).Normalize());
float dist =
Vector3::Dot(result.hitPos - freeState.position - shift,
(freeState.position - lastPos).Normalize());
if (dist < minDist) {
minResult = result;
minDist = dist;
@ -386,13 +383,15 @@ namespace spades {
void Client::UpdateLocalPlayer(float dt) {
SPADES_MARK_FUNCTION();
auto *player = world->GetLocalPlayer();
auto clientPlayer = clientPlayers[world->GetLocalPlayerIndex()];
Player &player = GetWorld()->GetLocalPlayer().value();
SPAssert(GetLocalClientPlayer());
ClientPlayer &clientPlayer = *GetLocalClientPlayer();
PlayerInput inp = playerInput;
WeaponInput winp = weapInput;
Vector3 velocity = player->GetVelocty();
Vector3 velocity = player.GetVelocty();
Vector3 horizontalVelocity{velocity.x, velocity.y, 0.0f};
if (horizontalVelocity.GetLength() < 0.1f) {
@ -407,8 +406,8 @@ namespace spades {
// don't allow to stand up when ceilings are too low
if (inp.crouch == false) {
if (player->GetInput().crouch) {
if (!player->TryUncrouch(false)) {
if (player.GetInput().crouch) {
if (!player.TryUncrouch(false)) {
inp.crouch = true;
}
}
@ -416,25 +415,25 @@ namespace spades {
// don't allow jumping in the air
if (inp.jump) {
if (!player->IsOnGroundOrWade())
if (!player.IsOnGroundOrWade())
inp.jump = false;
}
if (player->GetTool() == Player::ToolWeapon) {
if (player.GetTool() == Player::ToolWeapon) {
// disable weapon while reloading (except shotgun)
if (player->IsAwaitingReloadCompletion() && !player->GetWeapon()->IsReloadSlow()) {
if (player.IsAwaitingReloadCompletion() && !player.GetWeapon().IsReloadSlow()) {
winp.primary = false;
winp.secondary = false;
}
// stop firing if the player is out of ammo
if (player->GetWeapon()->GetAmmo() == 0) {
if (player.GetWeapon().GetAmmo() == 0) {
winp.primary = false;
}
}
player->SetInput(inp);
player->SetWeaponInput(winp);
player.SetInput(inp);
player.SetWeaponInput(winp);
// send player input
{
@ -453,11 +452,11 @@ namespace spades {
}
// PlayerInput actualInput = player->GetInput();
WeaponInput actualWeapInput = player->GetWeaponInput();
WeaponInput actualWeapInput = player.GetWeaponInput();
if (!(actualWeapInput.secondary && player->IsToolWeapon() && player->IsAlive()) &&
!(cg_holdAimDownSight && weapInput.secondary)) {
if (player->IsToolWeapon()) {
if (!(actualWeapInput.secondary && player.IsToolWeapon() && player.IsAlive()) &&
!(cg_holdAimDownSight && weapInput.secondary)) {
if (player.IsToolWeapon()) {
// there is a possibility that player has respawned or something.
// stop aiming down
weapInput.secondary = false;
@ -465,16 +464,16 @@ namespace spades {
}
// is the selected tool no longer usable (ex. out of ammo)?
if (!player->IsToolSelectable(player->GetTool())) {
if (!player.IsToolSelectable(player.GetTool())) {
// release mouse button before auto-switching tools
winp.primary = false;
winp.secondary = false;
weapInput = winp;
net->SendWeaponInput(weapInput);
actualWeapInput = winp = player->GetWeaponInput();
actualWeapInput = winp = player.GetWeaponInput();
// select another tool
Player::ToolType t = player->GetTool();
Player::ToolType t = player.GetTool();
do {
switch (t) {
case Player::ToolSpade: t = Player::ToolGrenade; break;
@ -487,23 +486,23 @@ namespace spades {
}
// send orientation
Vector3 curFront = player->GetFront();
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;
lastKills = world->GetPlayerPersistent(player.GetId()).kills;
// show block count when building block lines.
if (player->IsAlive() && player->GetTool() == Player::ToolBlock &&
player->GetWeaponInput().secondary && player->IsBlockCursorDragging()) {
if (player->IsBlockCursorActive()) {
auto blocks = world->CubeLine(player->GetBlockCursorDragPos(),
player->GetBlockCursorPos(), 256);
if (player.IsAlive() && player.GetTool() == Player::ToolBlock &&
player.GetWeaponInput().secondary && player.IsBlockCursorDragging()) {
if (player.IsBlockCursorActive()) {
auto blocks = world->CubeLine(player.GetBlockCursorDragPos(),
player.GetBlockCursorPos(), 256);
auto msg = _TrN("Client", "{0} block", "{0} blocks", blocks.size());
AlertType type = static_cast<int>(blocks.size()) > player->GetNumBlocks()
AlertType type = static_cast<int>(blocks.size()) > player.GetNumBlocks()
? AlertType::Warning
: AlertType::Notice;
ShowAlert(msg, type, 0.f, true);
@ -515,12 +514,12 @@ namespace spades {
}
}
if (player->IsAlive())
if (player.IsAlive())
lastAliveTime = time;
if (player->GetHealth() < lastHealth) {
if (player.GetHealth() < lastHealth) {
// ouch!
lastHealth = player->GetHealth();
lastHealth = player.GetHealth();
lastHurtTime = world->GetTime();
Handle<IAudioChunk> c;
@ -540,8 +539,8 @@ namespace spades {
}
audioDevice->PlayLocal(c, AudioParam());
float hpper = player->GetHealth() / 100.f;
int cnt = 18 - (int)(player->GetHealth() / 100.f * 8.f);
float hpper = player.GetHealth() / 100.f;
int cnt = 18 - (int)(player.GetHealth() / 100.f * 8.f);
hurtSprites.resize(std::max(cnt, 6));
for (size_t i = 0; i < hurtSprites.size(); i++) {
HurtSprite &spr = hurtSprites[i];
@ -555,7 +554,7 @@ namespace spades {
}
} else {
lastHealth = player->GetHealth();
lastHealth = player.GetHealth();
}
inp.jump = false;
@ -565,117 +564,121 @@ namespace spades {
void Client::PlayerObjectSet(int id) {
if (clientPlayers[id]) {
clientPlayers[id]->Invalidate();
clientPlayers[id] = nullptr;
}
Player *p = world->GetPlayer(id);
if (p)
clientPlayers[id].Set(new ClientPlayer(p, this), false);
stmp::optional<Player &> p = world->GetPlayer(id);
if (p) {
clientPlayers[id].Set(new ClientPlayer(*p, *this), false);
}
}
void Client::PlayerJumped(spades::client::Player *p) {
void Client::PlayerJumped(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
Handle<IAudioChunk> c =
p->GetWade() ? audioDevice->RegisterSound("Sounds/Player/WaterJump.opus")
: audioDevice->RegisterSound("Sounds/Player/Jump.opus");
audioDevice->Play(c, p->GetOrigin(), AudioParam());
p.GetWade() ? audioDevice->RegisterSound("Sounds/Player/WaterJump.opus")
: audioDevice->RegisterSound("Sounds/Player/Jump.opus");
audioDevice->Play(c, p.GetOrigin(), AudioParam());
}
}
void Client::PlayerLanded(spades::client::Player *p, bool hurt) {
void Client::PlayerLanded(spades::client::Player &p, bool hurt) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
Handle<IAudioChunk> c;
if (hurt)
c = audioDevice->RegisterSound("Sounds/Player/FallHurt.opus");
else if (p->GetWade())
else if (p.GetWade())
c = audioDevice->RegisterSound("Sounds/Player/WaterLand.opus");
else
c = audioDevice->RegisterSound("Sounds/Player/Land.opus");
audioDevice->Play(c, p->GetOrigin(), AudioParam());
audioDevice->Play(c, p.GetOrigin(), AudioParam());
}
}
void Client::PlayerMadeFootstep(spades::client::Player *p) {
void Client::PlayerMadeFootstep(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
std::array<const char *, 8> snds = {"Sounds/Player/Footstep1.opus", "Sounds/Player/Footstep2.opus",
"Sounds/Player/Footstep3.opus", "Sounds/Player/Footstep4.opus",
"Sounds/Player/Footstep5.opus", "Sounds/Player/Footstep6.opus",
"Sounds/Player/Footstep7.opus", "Sounds/Player/Footstep8.opus"};
std::array<const char *, 8> snds = {
"Sounds/Player/Footstep1.opus", "Sounds/Player/Footstep2.opus",
"Sounds/Player/Footstep3.opus", "Sounds/Player/Footstep4.opus",
"Sounds/Player/Footstep5.opus", "Sounds/Player/Footstep6.opus",
"Sounds/Player/Footstep7.opus", "Sounds/Player/Footstep8.opus"};
std::array<const char *, 12> rsnds = {
"Sounds/Player/Run1.opus", "Sounds/Player/Run2.opus", "Sounds/Player/Run3.opus",
"Sounds/Player/Run4.opus", "Sounds/Player/Run5.opus", "Sounds/Player/Run6.opus",
"Sounds/Player/Run7.opus", "Sounds/Player/Run8.opus", "Sounds/Player/Run9.opus",
"Sounds/Player/Run10.opus", "Sounds/Player/Run11.opus", "Sounds/Player/Run12.opus",
"Sounds/Player/Run1.opus", "Sounds/Player/Run2.opus",
"Sounds/Player/Run3.opus", "Sounds/Player/Run4.opus",
"Sounds/Player/Run5.opus", "Sounds/Player/Run6.opus",
"Sounds/Player/Run7.opus", "Sounds/Player/Run8.opus",
"Sounds/Player/Run9.opus", "Sounds/Player/Run10.opus",
"Sounds/Player/Run11.opus", "Sounds/Player/Run12.opus",
};
std::array<const char *, 8> wsnds = {"Sounds/Player/Wade1.opus", "Sounds/Player/Wade2.opus",
"Sounds/Player/Wade3.opus", "Sounds/Player/Wade4.opus",
"Sounds/Player/Wade5.opus", "Sounds/Player/Wade6.opus",
"Sounds/Player/Wade7.opus", "Sounds/Player/Wade8.opus"};
bool sprinting = clientPlayers[p->GetId()]
? clientPlayers[p->GetId()]->GetSprintState() > 0.5f
std::array<const char *, 8> wsnds = {
"Sounds/Player/Wade1.opus", "Sounds/Player/Wade2.opus",
"Sounds/Player/Wade3.opus", "Sounds/Player/Wade4.opus",
"Sounds/Player/Wade5.opus", "Sounds/Player/Wade6.opus",
"Sounds/Player/Wade7.opus", "Sounds/Player/Wade8.opus"};
bool sprinting = clientPlayers[p.GetId()]
? clientPlayers[p.GetId()]->GetSprintState() > 0.5f
: false;
Handle<IAudioChunk> c =
p->GetWade() ? audioDevice->RegisterSound(SampleRandomElement(wsnds))
: audioDevice->RegisterSound(SampleRandomElement(snds));
audioDevice->Play(c, p->GetOrigin(), AudioParam());
if (sprinting && !p->GetWade()) {
Handle<IAudioChunk> c = p.GetWade()
? audioDevice->RegisterSound(SampleRandomElement(wsnds))
: audioDevice->RegisterSound(SampleRandomElement(snds));
audioDevice->Play(c, p.GetOrigin(), AudioParam());
if (sprinting && !p.GetWade()) {
AudioParam param;
param.volume *= clientPlayers[p->GetId()]->GetSprintState();
param.volume *= clientPlayers[p.GetId()]->GetSprintState();
c = audioDevice->RegisterSound(SampleRandomElement(rsnds));
audioDevice->Play(c, p->GetOrigin(), param);
audioDevice->Play(c, p.GetOrigin(), param);
}
}
}
void Client::PlayerFiredWeapon(spades::client::Player *p) {
void Client::PlayerFiredWeapon(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (p == world->GetLocalPlayer()) {
if (&p == world->GetLocalPlayer()) {
localFireVibrationTime = time;
}
clientPlayers[p->GetId()]->FiredWeapon();
clientPlayers.at(p.GetId())->FiredWeapon();
}
void Client::PlayerDryFiredWeapon(spades::client::Player *p) {
void Client::PlayerDryFiredWeapon(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/DryFire.opus");
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());
audioDevice->Play(
c, p.GetEye() + p.GetFront() * 0.5f - p.GetUp() * .3f + p.GetRight() * .4f,
AudioParam());
}
}
void Client::PlayerReloadingWeapon(spades::client::Player *p) {
void Client::PlayerReloadingWeapon(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
clientPlayers[p->GetId()]->ReloadingWeapon();
clientPlayers.at(p.GetId())->ReloadingWeapon();
}
void Client::PlayerReloadedWeapon(spades::client::Player *p) {
void Client::PlayerReloadedWeapon(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
clientPlayers[p->GetId()]->ReloadedWeapon();
clientPlayers.at(p.GetId())->ReloadedWeapon();
}
void Client::PlayerChangedTool(spades::client::Player *p) {
void Client::PlayerChangedTool(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c;
if (isLocal) {
// played by ClientPlayer::Update
@ -686,63 +689,67 @@ namespace spades {
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,
audioDevice->Play(c,
p.GetEye() + p.GetFront() * 0.5f - p.GetUp() * .3f +
p.GetRight() * .4f,
AudioParam());
}
}
void Client::PlayerRestocked(spades::client::Player *p) {
void Client::PlayerRestocked(spades::client::Player &p) {
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c =
isLocal ? audioDevice->RegisterSound("Sounds/Weapons/RestockLocal.opus")
: audioDevice->RegisterSound("Sounds/Weapons/Restock.opus");
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,
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) {
void Client::PlayerThrewGrenade(spades::client::Player &p, stmp::optional<const Grenade &> g) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Grenade/Throw.opus");
if (g && isLocal) {
net->SendGrenade(g);
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,
audioDevice->Play(c,
p.GetEye() + p.GetFront() * 0.5f - p.GetUp() * .2f +
p.GetRight() * .3f,
AudioParam());
}
}
void Client::PlayerMissedSpade(spades::client::Player *p) {
void Client::PlayerMissedSpade(spades::client::Player &p) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Spade/Miss.opus");
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Spade/Miss.opus");
if (isLocal)
audioDevice->PlayLocal(c, MakeVector3(.2f, -.1f, 0.7f), AudioParam());
else
audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.8f - p->GetUp() * .2f,
audioDevice->Play(c, p.GetOrigin() + p.GetFront() * 0.8f - p.GetUp() * .2f,
AudioParam());
}
}
void Client::PlayerHitBlockWithSpade(spades::client::Player *p, Vector3 hitPos,
void Client::PlayerHitBlockWithSpade(spades::client::Player &p, Vector3 hitPos,
IntVector3 blockPos, IntVector3 normal) {
SPADES_MARK_FUNCTION();
@ -755,53 +762,56 @@ namespace spades {
EmitBlockFragments(shiftedHitPos, colV);
if (p == world->GetLocalPlayer()) {
if (&p == world->GetLocalPlayer()) {
localFireVibrationTime = time;
}
if (!IsMuted()) {
bool isLocal = p == world->GetLocalPlayer();
bool isLocal = &p == world->GetLocalPlayer();
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Spade/HitBlock.opus");
if (isLocal)
audioDevice->PlayLocal(c, MakeVector3(.1f, -.1f, 1.2f), AudioParam());
else
audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.5f - p->GetUp() * .2f,
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) {
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 (&victim != world->GetLocalPlayer()) {
if (!IsMuted()) {
Handle<IAudioChunk> c;
switch (SampleRandomInt(0, 2)) {
case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus");
c =
audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus");
break;
case 1:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh2.opus");
c =
audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh2.opus");
break;
case 2:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh3.opus");
c =
audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh3.opus");
break;
}
AudioParam param;
param.volume = 4.f;
audioDevice->Play(c, victim->GetEye(), param);
audioDevice->Play(c, victim.GetEye(), param);
}
}
}
// The local player is dead; initialize the look-you-are-dead cam
if (victim == world->GetLocalPlayer()) {
if (&victim == world->GetLocalPlayer()) {
followCameraState.enabled = false;
Vector3 v = -victim->GetFront();
Vector3 v = -victim.GetFront();
followAndFreeCameraState.yaw = atan2(v.y, v.x);
followAndFreeCameraState.pitch = 30.f * M_PI / 180.f;
}
@ -813,25 +823,25 @@ namespace spades {
case KillTypeGrenade:
case KillTypeHeadshot:
case KillTypeMelee:
case KillTypeWeapon: Bleed(victim->GetEye()); break;
case KillTypeWeapon: Bleed(victim.GetEye()); break;
default: break;
}
// create ragdoll corpse
if (cg_ragdoll && victim->GetTeamId() < 2) {
if (cg_ragdoll && victim.GetTeamId() < 2) {
Corpse *corp;
corp = new Corpse(renderer, map, victim);
if (victim == world->GetLocalPlayer())
corp = new Corpse(renderer, map, &victim);
if (&victim == world->GetLocalPlayer())
lastMyCorpse = corp;
if (killer != victim && kt != KillTypeGrenade) {
Vector3 dir = victim->GetPosition() - killer->GetPosition();
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) {
if (killer.GetWeapon().GetWeaponType() == SMG_WEAPON) {
dir *= 2.8f;
} else if (killer->GetWeapon()->GetWeaponType() == SHOTGUN_WEAPON) {
} else if (killer.GetWeapon().GetWeaponType() == SHOTGUN_WEAPON) {
dir *= 4.5f;
} else {
dir *= 3.5f;
@ -841,7 +851,7 @@ namespace spades {
} else if (kt == KillTypeGrenade) {
corp->AddImpulse(MakeVector3(0, 0, -4.f - SampleRandomFloat() * 4.f));
}
corp->AddImpulse(victim->GetVelocty() * 32.f);
corp->AddImpulse(victim.GetVelocty() * 32.f);
corpses.emplace_back(corp);
if (corpses.size() > corpseHardLimit) {
@ -853,21 +863,21 @@ namespace spades {
// add chat message
std::string s;
s = ChatWindow::TeamColorMessage(killer->GetName(), killer->GetTeamId());
s = ChatWindow::TeamColorMessage(killer.GetName(), killer.GetTeamId());
std::string cause;
bool isFriendlyFire = killer->GetTeamId() == victim->GetTeamId();
if (killer == victim)
bool isFriendlyFire = killer.GetTeamId() == victim.GetTeamId();
if (&killer == &victim)
isFriendlyFire = false;
Weapon *w =
killer ? killer->GetWeapon() : nullptr; // only used in case of KillTypeWeapon
Weapon &w = killer.GetWeapon(); // only used in case of KillTypeWeapon
switch (kt) {
case KillTypeWeapon:
switch (w ? w->GetWeaponType() : RIFLE_WEAPON) {
switch (w.GetWeaponType()) {
case RIFLE_WEAPON: cause += _Tr("Client", "Rifle"); break;
case SMG_WEAPON: cause += _Tr("Client", "SMG"); break;
case SHOTGUN_WEAPON: cause += _Tr("Client", "Shotgun"); break;
default: SPUnreachable();
}
break;
case KillTypeFall:
@ -878,9 +888,7 @@ namespace spades {
//! A cause of death shown in the kill feed.
cause += _Tr("Client", "Melee");
break;
case KillTypeGrenade:
cause += _Tr("Client", "Grenade");
break;
case KillTypeGrenade: cause += _Tr("Client", "Grenade"); break;
case KillTypeHeadshot:
//! A cause of death shown in the kill feed.
cause += _Tr("Client", "Headshot");
@ -893,64 +901,62 @@ namespace spades {
//! A cause of death shown in the kill feed.
cause += _Tr("Client", "Weapon Change");
break;
default:
cause += "???";
break;
default: cause += "???"; break;
}
s += " [";
if (isFriendlyFire)
s += ChatWindow::ColoredMessage(cause, MsgColorFriendlyFire);
else if (killer == world->GetLocalPlayer() || victim == world->GetLocalPlayer())
else if (&killer == world->GetLocalPlayer() || &victim == world->GetLocalPlayer())
s += ChatWindow::ColoredMessage(cause, MsgColorGray);
else
s += cause;
s += "] ";
if (killer != victim) {
s += ChatWindow::TeamColorMessage(victim->GetName(), victim->GetTeamId());
if (&killer != &victim) {
s += ChatWindow::TeamColorMessage(victim.GetName(), victim.GetTeamId());
}
killfeedWindow->AddMessage(s);
// 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());
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());
NetLog("%s (%s) [%s]", killer.GetName().c_str(),
world->GetTeam(killer.GetTeamId()).name.c_str(), cause.c_str());
}
// show big message if player is involved
if (victim != killer) {
Player *local = world->GetLocalPlayer();
if (killer == local || victim == local) {
if (&victim != &killer) {
stmp::optional<Player &> local = world->GetLocalPlayer();
if (&killer == local || &victim == local) {
std::string msg;
if (killer == local) {
if (&killer == local) {
if ((int)cg_centerMessage == 2)
msg = _Tr("Client", "You have killed {0}", victim->GetName());
msg = _Tr("Client", "You have killed {0}", victim.GetName());
} else {
msg = _Tr("Client", "You were killed by {0}", killer->GetName());
msg = _Tr("Client", "You were killed by {0}", killer.GetName());
}
centerMessageView->AddMessage(msg);
}
}
}
void Client::BulletHitPlayer(spades::client::Player *hurtPlayer, HitType type,
spades::Vector3 hitPos, spades::client::Player *by) {
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 (!IsFirstPerson(GetCameraMode()) || &GetCameraTargetPlayer() != hurtPlayer) {
if (!IsFirstPerson(GetCameraMode()) || &GetCameraTargetPlayer() != &hurtPlayer) {
Bleed(hitPos);
}
if (hurtPlayer == world->GetLocalPlayer()) {
if (&hurtPlayer == world->GetLocalPlayer()) {
// don't player hit sound now;
// local bullet impact sound is
// played by checking the decrease of HP
@ -981,8 +987,8 @@ namespace spades {
}
}
if (by == world->GetLocalPlayer() && hurtPlayer) {
net->SendHit(hurtPlayer->GetId(), type);
if (&by == world->GetLocalPlayer()) {
net->SendHit(hurtPlayer.GetId(), type);
if (type == HitTypeHead) {
Handle<IAudioChunk> c =
@ -993,7 +999,7 @@ namespace spades {
}
hitFeedbackIconState = 1.f;
if (hurtPlayer->GetTeamId() == world->GetLocalPlayer()->GetTeamId()) {
if (hurtPlayer.GetTeamId() == world->GetLocalPlayer()->GetTeamId()) {
hitFeedbackFriendly = true;
} else {
hitFeedbackFriendly = false;
@ -1044,7 +1050,7 @@ namespace spades {
param.volume = 2.f;
Handle<IAudioChunk> c;
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Block.opus");
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Block.opus");
audioDevice->Play(c, shiftedHitPos, param);
param.pitch = .9f + SampleRandomFloat() * 0.2f;
@ -1068,17 +1074,17 @@ namespace spades {
}
}
void Client::AddBulletTracer(spades::client::Player *player, spades::Vector3 muzzlePos,
void Client::AddBulletTracer(spades::client::Player &player, spades::Vector3 muzzlePos,
spades::Vector3 hitPos) {
SPADES_MARK_FUNCTION();
// Do not display tracers for bullets fired by the local player
if (IsFirstPerson(GetCameraMode()) && GetCameraTargetPlayerId() == player->GetId()) {
if (IsFirstPerson(GetCameraMode()) && GetCameraTargetPlayerId() == player.GetId()) {
return;
}
float vel;
switch (player->GetWeapon()->GetWeaponType()) {
switch (player.GetWeapon().GetWeaponType()) {
case RIFLE_WEAPON: vel = 700.f; break;
case SMG_WEAPON: vel = 360.f; break;
case SHOTGUN_WEAPON: vel = 500.f; break;
@ -1109,32 +1115,32 @@ namespace spades {
}
}
void Client::GrenadeBounced(spades::client::Grenade *g) {
void Client::GrenadeBounced(const Grenade &g) {
SPADES_MARK_FUNCTION();
if (g->GetPosition().z < 63.f) {
if (g.GetPosition().z < 63.f) {
if (!IsMuted()) {
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Grenade/Bounce.opus");
audioDevice->Play(c, g->GetPosition(), AudioParam());
audioDevice->Play(c, g.GetPosition(), AudioParam());
}
}
}
void Client::GrenadeDroppedIntoWater(spades::client::Grenade *g) {
void Client::GrenadeDroppedIntoWater(const Grenade &g) {
SPADES_MARK_FUNCTION();
if (!IsMuted()) {
Handle<IAudioChunk> c =
audioDevice->RegisterSound("Sounds/Weapons/Grenade/DropWater.opus");
audioDevice->Play(c, g->GetPosition(), AudioParam());
audioDevice->Play(c, g.GetPosition(), AudioParam());
}
}
void Client::GrenadeExploded(spades::client::Grenade *g) {
void Client::GrenadeExploded(const Grenade &g) {
SPADES_MARK_FUNCTION();
bool inWater = g->GetPosition().z > 63.f;
bool inWater = g.GetPosition().z > 63.f;
if (inWater) {
if (!IsMuted()) {
@ -1142,22 +1148,23 @@ namespace spades {
audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplode.opus");
AudioParam param;
param.volume = 10.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeFar.opus");
param.volume = 6.f;
param.referenceDistance = 10.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeStereo.opus");
c =
audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeStereo.opus");
param.volume = 2.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
}
GrenadeExplosionUnderwater(g->GetPosition());
GrenadeExplosionUnderwater(g.GetPosition());
} else {
GrenadeExplosion(g->GetPosition());
GrenadeExplosion(g.GetPosition());
if (!IsMuted()) {
Handle<IAudioChunk> c, cs;
@ -1178,26 +1185,26 @@ namespace spades {
AudioParam param;
param.volume = 30.f;
param.referenceDistance = 5.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
param.referenceDistance = 1.f;
audioDevice->Play(cs, g->GetPosition(), param);
audioDevice->Play(cs, g.GetPosition(), param);
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFar.opus");
param.volume = 6.f;
param.referenceDistance = 40.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFarStereo.opus");
param.referenceDistance = 10.f;
audioDevice->Play(c, g->GetPosition(), param);
audioDevice->Play(c, g.GetPosition(), param);
// debri sound
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Debris.opus");
param.volume = 5.f;
param.referenceDistance = 3.f;
IntVector3 outPos;
Vector3 soundPos = g->GetPosition();
Vector3 soundPos = g.GetPosition();
if (world->GetMap()->CastRay(soundPos, MakeVector3(0, 0, 1), 8.f, outPos)) {
soundPos.z = (float)outPos.z - .2f;
}
@ -1229,7 +1236,7 @@ namespace spades {
SPADES_MARK_FUNCTION();
if (sourceGiven) {
Player *p = world->GetLocalPlayer();
stmp::optional<Player &> p = world->GetLocalPlayer();
if (!p)
return;
Vector3 rel = source - p->GetEye();
@ -1256,5 +1263,5 @@ namespace spades {
break;
}
}
}
}
} // namespace client
} // namespace spades

View File

@ -39,7 +39,7 @@ namespace spades {
playerId = p->GetId();
IntVector3 col = p->GetWorld()->GetTeam(p->GetTeamId()).color;
IntVector3 col = p->GetWorld().GetTeam(p->GetTeamId()).color;
color = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
bool crouch = p->GetInput().crouch;

View File

@ -85,6 +85,7 @@ namespace spades {
void LineCollision(NodeType a, NodeType b, float dt);
public:
// TODO: Replace pointers with references
Corpse(IRenderer *renderer, GameMap *map, Player *p);
~Corpse();

View File

@ -61,7 +61,8 @@ namespace spades {
zSum += v.z;
}
GameMap *map = client->GetWorld()->GetMap();
const Handle<GameMap> &map = client->GetWorld()->GetMap();
SPAssert(map);
// build voxel model
vmodel = new VoxelModel(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
@ -101,8 +102,10 @@ namespace spades {
bool FallingBlock::Update(float dt) {
time += dt;
GameMap *map = client->GetWorld()->GetMap();
const Handle<GameMap> &map = client->GetWorld()->GetMap();
Vector3 orig = matrix.GetOrigin();
SPAssert(map);
if (time > 1.f || map->ClipBox(orig.x, orig.y, orig.z)) {
// destroy

View File

@ -28,14 +28,13 @@
namespace spades {
namespace client {
Grenade::Grenade(World *w, Vector3 pos, Vector3 vel, float fuse) {
Grenade::Grenade(World &w, Vector3 pos, Vector3 vel, float fuse) : world{w} {
SPADES_MARK_FUNCTION();
position = pos;
velocity = vel;
this->fuse = fuse;
world = w;
orientation = Quaternion {0.0f, 0.0f, 0.0f, 1.0f};
orientation = Quaternion{0.0f, 0.0f, 0.0f, 1.0f};
}
Grenade::~Grenade() { SPADES_MARK_FUNCTION(); }
@ -50,8 +49,8 @@ namespace spades {
}
if (MoveGrenade(dt) == 2) {
if (world->GetListener())
world->GetListener()->GrenadeBounced(this);
if (world.GetListener())
world.GetListener()->GrenadeBounced(*this);
}
return false;
@ -60,8 +59,8 @@ namespace spades {
void Grenade::Explode() {
SPADES_MARK_FUNCTION();
if (world->GetListener())
world->GetListener()->GrenadeExploded(this);
if (world.GetListener())
world.GetListener()->GrenadeExploded(*this);
}
int Grenade::MoveGrenade(float fsynctics) {
@ -74,17 +73,19 @@ namespace spades {
// Make it roll
float radius = 4.0f * 0.03f;
orientation = Quaternion::MakeRotation(Vector3(-velocity.y, velocity.x, 0.0f) * (f / radius)) * orientation;
orientation =
Quaternion::MakeRotation(Vector3(-velocity.y, velocity.x, 0.0f) * (f / radius)) *
orientation;
orientation = orientation.Normalize();
// Collision
IntVector3 lp = position.Floor();
IntVector3 lp2 = oldPos.Floor();
GameMap *m = world->GetMap();
Handle<GameMap> m = world.GetMap();
if (lp.z >= 63 && lp2.z < 63) {
if (world->GetListener())
world->GetListener()->GrenadeDroppedIntoWater(this);
if (world.GetListener())
world.GetListener()->GrenadeDroppedIntoWater(*this);
}
int ret = 0;
@ -110,5 +111,5 @@ namespace spades {
}
return ret;
}
}
}
} // namespace client
} // namespace spades

View File

@ -28,7 +28,7 @@ namespace spades {
class World;
class Grenade {
World *world;
World &world;
float fuse;
Vector3 position;
Vector3 velocity;
@ -43,16 +43,16 @@ namespace spades {
int MoveGrenade(float fsynctics);
public:
Grenade(World *, Vector3 pos, Vector3 vel, float fuse);
Grenade(World &, Vector3 pos, Vector3 vel, float fuse);
~Grenade();
/** @return true when exploded. */
bool Update(float dt);
Vector3 GetPosition() { return position; }
Vector3 GetVelocity() { return velocity; }
Quaternion GetOrientation() { return orientation; }
float GetFuse() { return fuse; }
Vector3 GetPosition() const { return position; }
Vector3 GetVelocity() const { return velocity; }
Quaternion GetOrientation() const { return orientation; }
float GetFuse() const { return fuse; }
};
}
}
} // namespace client
} // namespace spades

View File

@ -76,7 +76,7 @@ namespace spades {
return false;
}
GameMap *map = client->GetWorld()->GetMap();
const Handle<GameMap> &map = client->GetWorld()->GetMap();
if (!map->ClipWorld(groundPos.x, groundPos.y, groundPos.z)) {
return false;
}
@ -88,7 +88,7 @@ namespace spades {
vel.z += dt * 32.f;
IntVector3 lp = matrix.GetOrigin().Floor();
GameMap *m = client->GetWorld()->GetMap();
Handle<GameMap> m = client->GetWorld()->GetMap();
if (lp.z >= 63) {
// dropped into water
@ -219,5 +219,5 @@ namespace spades {
}
renderer->RenderModel(model, param);
}
}
}
} // namespace client
} // namespace spades

View File

@ -46,6 +46,7 @@ namespace spades {
float rotSpeed;
public:
// TODO: Replace pointers with references
GunCasing(Client *client, IModel *model, IAudioChunk *dropSound,
IAudioChunk *waterSound, Vector3 pos, Vector3 dir, Vector3 flyDir);
~GunCasing();
@ -53,4 +54,4 @@ namespace spades {
void Render3D() override;
};
}
}
}

View File

@ -71,9 +71,9 @@ namespace spades {
renderer->SetFogColor(MakeVector3(0.f, 0.f, 0.f));
renderer->SetFogDistance(128.f);
Player *localPlayer = world->GetLocalPlayer();
stmp::optional<Player &> localPlayer = world->GetLocalPlayer();
if (localPlayer == nullptr) {
if (!localPlayer) {
SPLog("HitTestDebugger failure: Local player is null");
return;
}
@ -100,7 +100,7 @@ namespace spades {
// fit FoV to include all possibly hit players
float range = 0.2f;
for (std::size_t i = 0; i < world->GetNumPlayerSlots(); i++) {
auto *p = world->GetPlayer(static_cast<unsigned int>(i));
auto p = world->GetPlayer(static_cast<unsigned int>(i));
if (!p)
continue;
if (p == localPlayer)
@ -148,9 +148,9 @@ namespace spades {
def.zFar = 200.f;
// start rendering
GameMap *map = world->GetMap();
const Handle<GameMap>& map = world->GetMap();
if (!def.skipWorld) {
renderer->SetGameMap(map);
renderer->SetGameMap(&*map);
}
renderer->StartScene(def);
@ -204,7 +204,7 @@ namespace spades {
};
for (std::size_t i = 0; i < numPlayers; i++) {
auto *p = world->GetPlayer(static_cast<unsigned int>(i));
auto p = world->GetPlayer(static_cast<unsigned int>(i));
if (!p)
continue;
if (p == localPlayer)
@ -271,7 +271,7 @@ namespace spades {
fileName = buf;
}
switch (localPlayer->GetWeapon()->GetWeaponType()) {
switch (localPlayer->GetWeapon().GetWeaponType()) {
case SMG_WEAPON: fileName += "-SMG"; break;
case RIFLE_WEAPON: fileName += "-Rifle"; break;
case SHOTGUN_WEAPON: fileName += "-Shotgun"; break;

View File

@ -74,8 +74,8 @@ namespace spades {
return;
}
Player *p = w->GetLocalPlayer();
if (p == NULL || !p->IsAlive()) {
auto p = w->GetLocalPlayer();
if (!p || !p->IsAlive()) {
ClearAll();
return;
}

View File

@ -21,6 +21,7 @@
#pragma once
#include <Core/Math.h>
#include <Core/TMPUtils.h>
#include "PhysicsConstants.h"
namespace spades {
@ -33,29 +34,29 @@ namespace spades {
class IWorldListener {
public:
virtual void PlayerObjectSet(int playerId) = 0;
virtual void PlayerMadeFootstep(Player *) = 0;
virtual void PlayerJumped(Player *) = 0;
virtual void PlayerLanded(Player *, bool hurt) = 0;
virtual void PlayerFiredWeapon(Player *) = 0;
virtual void PlayerDryFiredWeapon(Player *) = 0;
virtual void PlayerReloadingWeapon(Player *) = 0;
virtual void PlayerReloadedWeapon(Player *) = 0;
virtual void PlayerChangedTool(Player *) = 0;
virtual void PlayerThrownGrenade(Player *, Grenade *) = 0;
virtual void PlayerMissedSpade(Player *) = 0;
virtual void PlayerHitBlockWithSpade(Player *, Vector3 hitPos, IntVector3 blockPos,
virtual void PlayerMadeFootstep(Player &) = 0;
virtual void PlayerJumped(Player &) = 0;
virtual void PlayerLanded(Player &, bool hurt) = 0;
virtual void PlayerFiredWeapon(Player &) = 0;
virtual void PlayerDryFiredWeapon(Player &) = 0;
virtual void PlayerReloadingWeapon(Player &) = 0;
virtual void PlayerReloadedWeapon(Player &) = 0;
virtual void PlayerChangedTool(Player &) = 0;
virtual void PlayerThrewGrenade(Player &, stmp::optional<const Grenade &>) = 0;
virtual void PlayerMissedSpade(Player &) = 0;
virtual void PlayerHitBlockWithSpade(Player &, Vector3 hitPos, IntVector3 blockPos,
IntVector3 normal) = 0;
virtual void PlayerKilledPlayer(Player *killer, Player *victim, KillType) = 0;
virtual void PlayerRestocked(Player *) = 0;
virtual void PlayerKilledPlayer(Player &killer, Player &victim, KillType) = 0;
virtual void PlayerRestocked(Player &) = 0;
virtual void BulletHitPlayer(Player *hurtPlayer, HitType, Vector3 hitPos,
Player *by) = 0;
virtual void BulletHitPlayer(Player &hurtPlayer, HitType, Vector3 hitPos,
Player &by) = 0;
virtual void BulletHitBlock(Vector3 hitPos, IntVector3 blockPos, IntVector3 normal) = 0;
virtual void AddBulletTracer(Player *player, Vector3 muzzlePos, Vector3 hitPos) = 0;
virtual void AddBulletTracer(Player &player, Vector3 muzzlePos, Vector3 hitPos) = 0;
virtual void GrenadeExploded(Grenade *) = 0;
virtual void GrenadeBounced(Grenade *) = 0;
virtual void GrenadeDroppedIntoWater(Grenade *) = 0;
virtual void GrenadeExploded(const Grenade &) = 0;
virtual void GrenadeBounced(const Grenade &) = 0;
virtual void GrenadeDroppedIntoWater(const Grenade &) = 0;
virtual void BlocksFell(std::vector<IntVector3>) = 0;

View File

@ -242,7 +242,7 @@ namespace spades {
return;
// The player to focus on
Player *focusPlayerPtr = nullptr;
stmp::optional<Player &> focusPlayerPtr;
Vector3 focusPlayerPos;
float focusPlayerAngle;
@ -253,7 +253,7 @@ namespace spades {
focusPlayerPos = player.GetPosition();
focusPlayerAngle = atan2(front.x, -front.y);
focusPlayerPtr = &player;
focusPlayerPtr = player;
} else if (client->GetCameraMode() == ClientCameraMode::Free) {
focusPlayerPos = client->freeCameraState.position;
focusPlayerAngle =
@ -267,16 +267,16 @@ namespace spades {
if (!world->GetLocalPlayer()) {
return;
}
Player &localPlayer = *world->GetLocalPlayer();
Player &localPlayer = world->GetLocalPlayer().value();
SPAssert(focusPlayerPtr);
Player &focusPlayer = *focusPlayerPtr;
Player &focusPlayer = focusPlayerPtr.value();
if (largeMap)
if (zoomState < .0001f)
return;
GameMap *map = world->GetMap();
Handle<GameMap> map = world->GetMap();
SPAssert(map);
Vector2 mapSize = MakeVector2(map->Width(), map->Height());
Vector2 center = {focusPlayerPos.x, focusPlayerPos.y};
@ -477,44 +477,49 @@ namespace spades {
// draw player's icon
for (int i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *p = world->GetPlayer(i);
if (!p || !p->IsAlive()) {
auto maybePlayer = world->GetPlayer(i);
if (!maybePlayer) {
continue;
}
Player &p = maybePlayer.value();
if (!p.IsAlive()) {
// The player is non-existent or dead
continue;
}
if (!localPlayer.IsSpectator() && localPlayer.GetTeamId() != p->GetTeamId()) {
if (!localPlayer.IsSpectator() && localPlayer.GetTeamId() != p.GetTeamId()) {
// Duh
continue;
}
if (p->IsSpectator() && p == &localPlayer &&
if (p.IsSpectator() && &p == &localPlayer &&
HasTargetPlayer(client->GetCameraMode())) {
// Don't draw white icon when spectating a player
continue;
}
if (p->IsSpectator() && p != &localPlayer) {
if (p.IsSpectator() && &p != &localPlayer) {
// Don't draw other spectators
continue;
}
IntVector3 iconColor =
colorMode ? IntVector3::Make(palette[i][0], palette[i][1], palette[i][2])
: world->GetTeam(p->GetTeamId()).color;
if (p->GetTeamId() >= 2)
: world->GetTeam(p.GetTeamId()).color;
if (p.GetTeamId() >= 2)
iconColor =
IntVector3::Make(200, 200, 200); // colorMode doesn't matter here, right?
Vector4 iconColorF = ModifyColor(iconColor);
iconColorF *= alpha;
Vector3 front = p->GetFront2D();
Vector3 front = p.GetFront2D();
float ang = atan2(front.x, -front.y);
if (p->IsSpectator() && client->GetCameraMode() == ClientCameraMode::Free) {
if (p.IsSpectator() && client->GetCameraMode() == ClientCameraMode::Free) {
ang = focusPlayerAngle;
}
// Draw the focused player's view
if (p == &focusPlayer) {
if (&p == &focusPlayer) {
renderer->SetColorAlphaPremultiplied(iconColorF * 0.9f);
DrawIcon(p->IsSpectator() ? client->freeCameraState.position : p->GetPosition(),
DrawIcon(p.IsSpectator() ? client->freeCameraState.position : p.GetPosition(),
viewIcon, ang);
}
@ -523,35 +528,35 @@ namespace spades {
if (iconMode) {
WeaponType weapon = world->GetPlayer(i)->GetWeaponType();
if (weapon == WeaponType::SMG_WEAPON) {
DrawIcon(p->IsSpectator() ? client->freeCameraState.position
: p->GetPosition(),
DrawIcon(p.IsSpectator() ? client->freeCameraState.position
: p.GetPosition(),
playerSMG, ang);
}
else if (weapon == WeaponType::RIFLE_WEAPON) {
DrawIcon(p->IsSpectator() ? client->freeCameraState.position
: p->GetPosition(),
DrawIcon(p.IsSpectator() ? client->freeCameraState.position
: p.GetPosition(),
playerRifle, ang);
}
else if (weapon == WeaponType::SHOTGUN_WEAPON) {
DrawIcon(p->IsSpectator() ? client->freeCameraState.position
: p->GetPosition(),
DrawIcon(p.IsSpectator() ? client->freeCameraState.position
: p.GetPosition(),
playerShotgun, ang);
}
} else { // draw normal color
DrawIcon(p == &focusPlayer ? focusPlayerPos : p->GetPosition(), playerIcon,
DrawIcon(&p == &focusPlayer ? focusPlayerPos : p.GetPosition(), playerIcon,
ang);
}
}
IGameMode *mode = world->GetMode();
stmp::optional<IGameMode &> mode = world->GetMode();
if (mode && IGameMode::m_CTF == mode->ModeType()) {
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
CTFGameMode &ctf = dynamic_cast<CTFGameMode &>(*mode);
Handle<IImage> intelIcon = renderer->RegisterImage("Gfx/Map/Intel.png");
Handle<IImage> baseIcon = renderer->RegisterImage("Gfx/Map/CommandPost.png");
for (int tId = 0; tId < 2; tId++) {
CTFGameMode::Team &team = ctf->GetTeam(tId);
CTFGameMode::Team &team = ctf.GetTeam(tId);
IntVector3 teamColor = world->GetTeam(tId).color;
Vector4 teamColorF = ModifyColor(teamColor);
teamColorF *= alpha;
@ -561,16 +566,16 @@ namespace spades {
DrawIcon(team.basePos, baseIcon, 0.f);
// draw flag
if (!ctf->GetTeam(1 - tId).hasIntel) {
if (!ctf.GetTeam(1 - tId).hasIntel) {
renderer->SetColorAlphaPremultiplied(teamColorF);
DrawIcon(team.flagPos, intelIcon, 0.f);
} else if (world->GetLocalPlayer()->GetTeamId() == 1 - tId) {
// local player's team is carrying
int cId = ctf->GetTeam(1 - tId).carrier;
int cId = ctf.GetTeam(1 - tId).carrier;
// in some game modes, carrier becomes invalid
if (cId < world->GetNumPlayerSlots()) {
Player *carrier = world->GetPlayer(cId);
auto carrier = world->GetPlayer(cId);
if (carrier &&
carrier->GetTeamId() == world->GetLocalPlayer()->GetTeamId()) {
@ -583,21 +588,21 @@ namespace spades {
}
}
} else if (mode && IGameMode::m_TC == mode->ModeType()) {
TCGameMode *tc = static_cast<TCGameMode *>(mode);
TCGameMode &tc = dynamic_cast<TCGameMode &>(*mode);
Handle<IImage> icon = renderer->RegisterImage("Gfx/Map/CommandPost.png");
int cnt = tc->GetNumTerritories();
int cnt = tc.GetNumTerritories();
for (int i = 0; i < cnt; i++) {
TCGameMode::Territory *t = tc->GetTerritory(i);
TCGameMode::Territory &t = tc.GetTerritory(i);
IntVector3 teamColor = {128, 128, 128};
if (t->ownerTeamId < 2) {
teamColor = world->GetTeam(t->ownerTeamId).color;
if (t.ownerTeamId < 2) {
teamColor = world->GetTeam(t.ownerTeamId).color;
}
Vector4 teamColorF = ModifyColor(teamColor);
teamColorF *= alpha;
// draw base
renderer->SetColorAlphaPremultiplied(teamColorF);
DrawIcon(t->pos, icon, 0.f);
DrawIcon(t.pos, icon, 0.f);
}
}

View File

@ -29,15 +29,14 @@
#include "Client.h"
#include "GameMap.h"
#include "GameMapLoader.h"
#include "GameProperties.h"
#include "Grenade.h"
#include "NetClient.h"
#include "Player.h"
#include "TCGameMode.h"
#include "World.h"
#include "GameProperties.h"
#include <Core/CP437.h>
#include <Core/Debug.h>
#include <Core/Debug.h>
#include <Core/DeflateStream.h>
#include <Core/Exception.h>
#include <Core/Math.h>
@ -132,7 +131,7 @@ namespace spades {
}
return CP437::Decode(s);
}
}
} // namespace
class NetPacketReader {
std::vector<char> data;
@ -626,9 +625,9 @@ namespace spades {
}
}
World *NetClient::GetWorld() { return client->GetWorld(); }
stmp::optional<World &> NetClient::GetWorld() { return client->GetWorld(); }
Player *NetClient::GetPlayerOrNull(int pId) {
stmp::optional<Player &> NetClient::GetPlayerOrNull(int pId) {
SPADES_MARK_FUNCTION();
if (!GetWorld())
SPRaise("Invalid Player ID %d: No world", pId);
@ -636,7 +635,7 @@ namespace spades {
return NULL;
return GetWorld()->GetPlayer(pId);
}
Player *NetClient::GetPlayer(int pId) {
Player &NetClient::GetPlayer(int pId) {
SPADES_MARK_FUNCTION();
if (!GetWorld())
SPRaise("Invalid Player ID %d: No world", pId);
@ -644,19 +643,19 @@ namespace spades {
SPRaise("Invalid Player ID %d: Out of range", pId);
if (!GetWorld()->GetPlayer(pId))
SPRaise("Invalid Player ID %d: Doesn't exist", pId);
return GetWorld()->GetPlayer(pId);
return GetWorld()->GetPlayer(pId).value();
}
Player *NetClient::GetLocalPlayer() {
Player &NetClient::GetLocalPlayer() {
SPADES_MARK_FUNCTION();
if (!GetWorld())
SPRaise("Failed to get local player: no world");
if (!GetWorld()->GetLocalPlayer())
SPRaise("Failed to get local player: no local player");
return GetWorld()->GetLocalPlayer();
return GetWorld()->GetLocalPlayer().value();
}
Player *NetClient::GetLocalPlayerOrNull() {
stmp::optional<Player &> NetClient::GetLocalPlayerOrNull() {
SPADES_MARK_FUNCTION();
if (!GetWorld())
SPRaise("Failed to get local player: no world");
@ -744,7 +743,7 @@ namespace spades {
switch (reader.GetType()) {
case PacketTypePositionData: {
Player *p = GetLocalPlayer();
Player &p = GetLocalPlayer();
Vector3 pos;
if (reader.GetData().size() < 12) {
// sometimes 00 00 00 00 packet is sent.
@ -754,15 +753,15 @@ namespace spades {
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
p->SetPosition(pos);
p.SetPosition(pos);
} break;
case PacketTypeOrientationData: {
Player *p = GetLocalPlayer();
Player &p = GetLocalPlayer();
Vector3 pos;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
p->SetOrientation(pos);
p.SetOrientation(pos);
} break;
case PacketTypeWorldUpdate: {
// reader.DumpDebug();
@ -793,7 +792,6 @@ namespace spades {
savedPlayerFront[idx] = front;
if (pos.x != 0.f || pos.y != 0.f || pos.z != 0.f || front.x != 0.f ||
front.y != 0.f || front.z != 0.f) {
Player *p;
SPAssert(!std::isnan(pos.x));
SPAssert(!std::isnan(pos.y));
SPAssert(!std::isnan(pos.z));
@ -802,7 +800,7 @@ namespace spades {
SPAssert(!std::isnan(front.z));
SPAssert(front.GetLength() < 40.f);
if (GetWorld()) {
p = GetWorld()->GetPlayer(idx);
auto p = GetWorld()->GetPlayer(idx);
if (p) {
if (p != GetWorld()->GetLocalPlayer()) {
p->SetPosition(pos);
@ -832,22 +830,19 @@ namespace spades {
break;
{
int pId = reader.ReadByte();
Player *p = GetPlayer(pId);
Player &p = GetPlayer(pId);
PlayerInput inp = ParsePlayerInput(reader.ReadByte());
if (GetWorld()->GetLocalPlayer() == p) {
if (GetWorld()->GetLocalPlayer() == &p) {
// handle "/fly" jump
if (inp.jump) {
if (!p) {
SPRaise("Local player is null");
}
p->ForceJump();
p.ForceJump();
}
break;
}
p->SetInput(inp);
p.SetInput(inp);
}
break;
@ -856,27 +851,27 @@ namespace spades {
break;
{
int pId = reader.ReadByte();
Player *p = GetPlayer(pId);
Player &p = GetPlayer(pId);
WeaponInput inp = ParseWeaponInput(reader.ReadByte());
if (GetWorld()->GetLocalPlayer() == p)
break;
p->SetWeaponInput(inp);
p.SetWeaponInput(inp);
}
break;
// Hit Packet is Client-to-Server!
case PacketTypeSetHP: {
Player *p = GetLocalPlayer();
Player &p = GetLocalPlayer();
int hp = reader.ReadByte();
int type = reader.ReadByte(); // 0=fall, 1=weap
Vector3 hurtPos;
hurtPos.x = reader.ReadFloat();
hurtPos.y = reader.ReadFloat();
hurtPos.z = reader.ReadFloat();
p->SetHP(hp, type ? HurtTypeWeapon : HurtTypeFall, hurtPos);
p.SetHP(hp, type ? HurtTypeWeapon : HurtTypeFall, hurtPos);
} break;
case PacketTypeGrenadePacket:
@ -900,24 +895,24 @@ namespace spades {
break;
}*/
Grenade *g = new Grenade(GetWorld(), pos, vel, fuseLen);
GetWorld()->AddGrenade(g);
Grenade *g = new Grenade(*GetWorld(), pos, vel, fuseLen);
GetWorld()->AddGrenade(std::unique_ptr<Grenade>{g});
}
break;
case PacketTypeSetTool: {
Player *p = GetPlayer(reader.ReadByte());
Player &p = GetPlayer(reader.ReadByte());
int tool = reader.ReadByte();
switch (tool) {
case 0: p->SetTool(Player::ToolSpade); break;
case 1: p->SetTool(Player::ToolBlock); break;
case 2: p->SetTool(Player::ToolWeapon); break;
case 3: p->SetTool(Player::ToolGrenade); break;
case 0: p.SetTool(Player::ToolSpade); break;
case 1: p.SetTool(Player::ToolBlock); break;
case 2: p.SetTool(Player::ToolWeapon); break;
case 3: p.SetTool(Player::ToolGrenade); break;
default: SPRaise("Received invalid tool type: %d", tool);
}
} break;
case PacketTypeSetColour: {
Player *p = GetPlayerOrNull(reader.ReadByte());
stmp::optional<Player &> p = GetPlayerOrNull(reader.ReadByte());
IntVector3 col = reader.ReadIntColor();
if (p)
p->SetHeldBlockColor(col);
@ -945,12 +940,11 @@ namespace spades {
default: SPRaise("Received invalid weapon: %d", weapon);
}
Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId],
GetWorld()->GetTeam(team).color);
std::unique_ptr<Player> p{new Player(*GetWorld(), pId, wType, team,
savedPlayerPos[pId],
GetWorld()->GetTeam(team).color)};
p->SetHeldBlockColor(color);
// p->SetOrientation(savedPlayerFront[pId]);
GetWorld()->SetPlayer(pId, p);
switch (tool) {
case 0: p->SetTool(Player::ToolSpade); break;
case 1: p->SetTool(Player::ToolBlock); break;
@ -958,6 +952,7 @@ namespace spades {
case 3: p->SetTool(Player::ToolGrenade); break;
default: SPRaise("Received invalid tool type: %d", tool);
}
GetWorld()->SetPlayer(pId, std::move(p));
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
pers.name = name;
@ -978,20 +973,20 @@ namespace spades {
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
IGameMode *mode = GetWorld()->GetMode();
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (mode && IGameMode::m_CTF == mode->ModeType()) {
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
auto &ctf = dynamic_cast<CTFGameMode &>(mode.value());
switch (type) {
case BLUE_BASE: ctf->GetTeam(0).basePos = pos; break;
case BLUE_FLAG: ctf->GetTeam(0).flagPos = pos; break;
case GREEN_BASE: ctf->GetTeam(1).basePos = pos; break;
case GREEN_FLAG: ctf->GetTeam(1).flagPos = pos; break;
case BLUE_BASE: ctf.GetTeam(0).basePos = pos; break;
case BLUE_FLAG: ctf.GetTeam(0).flagPos = pos; break;
case GREEN_BASE: ctf.GetTeam(1).basePos = pos; break;
case GREEN_FLAG: ctf.GetTeam(1).flagPos = pos; break;
}
} else if (mode && IGameMode::m_TC == mode->ModeType()) {
TCGameMode *tc = static_cast<TCGameMode *>(mode);
if (type >= tc->GetNumTerritories()) {
auto &tc = dynamic_cast<TCGameMode &>(mode.value());
if (type >= tc.GetNumTerritories()) {
SPRaise("Invalid territory id specified: %d (max = %d)", (int)type,
tc->GetNumTerritories() - 1);
tc.GetNumTerritories() - 1);
}
if (state > 2) {
@ -999,9 +994,9 @@ namespace spades {
(int)state);
}
TCGameMode::Territory *t = tc->GetTerritory(type);
t->pos = pos;
t->ownerTeamId = state; /*
TCGameMode::Territory &t = tc.GetTerritory(type);
t.pos = pos;
t.ownerTeamId = state; /*
t->progressBasePos = 0.f;
t->progressRate = 0.f;
t->progressStartTime = 0.f;
@ -1035,11 +1030,14 @@ namespace spades {
default: SPRaise("Received invalid weapon: %d", weapon);
}
Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId],
std::unique_ptr<Player> p{new Player(*GetWorld(), pId, wType, team,
savedPlayerPos[pId],
GetWorld()->GetTeam(team).color);
GetWorld()->GetTeam(team).color)};
p->SetPosition(pos);
GetWorld()->SetPlayer(pId, p);
GetWorld()->SetPlayer(pId, std::move(p));
Player &pRef = GetWorld()->GetPlayer(pId).value();
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
@ -1062,17 +1060,16 @@ namespace spades {
rec.time = GetWorld()->GetTime();
}
if (savedPlayerTeam[pId] != team) {
client->PlayerJoinedTeam(p);
client->PlayerJoinedTeam(pRef);
savedPlayerTeam[pId] = team;
}
}
client->PlayerSpawned(p);
client->PlayerSpawned(pRef);
} break;
case PacketTypeBlockAction: {
Player *p = GetPlayerOrNull(reader.ReadByte());
stmp::optional<Player &> p = GetPlayerOrNull(reader.ReadByte());
int action = reader.ReadByte();
IntVector3 pos;
pos.x = reader.ReadInt();
@ -1086,7 +1083,7 @@ namespace spades {
GetWorld()->CreateBlock(pos, temporaryPlayerBlockColor);
} else {
GetWorld()->CreateBlock(pos, p->GetBlockColor());
client->PlayerCreatedBlock(p);
client->PlayerCreatedBlock(*p);
if (!replace) {
p->UsedBlocks(1);
}
@ -1117,7 +1114,7 @@ namespace spades {
}
} break;
case PacketTypeBlockLine: {
Player *p = GetPlayerOrNull(reader.ReadByte());
stmp::optional<Player &> p = GetPlayerOrNull(reader.ReadByte());
IntVector3 pos1, pos2;
pos1.x = reader.ReadInt();
pos1.y = reader.ReadInt();
@ -1138,7 +1135,7 @@ namespace spades {
if (p) {
p->UsedBlocks(static_cast<int>(cells.size()));
client->PlayerCreatedBlock(p);
client->PlayerCreatedBlock(*p);
}
} break;
case PacketTypeStateData:
@ -1169,84 +1166,74 @@ namespace spades {
int mode = reader.ReadByte();
if (mode == 0) {
// CTF
CTFGameMode *mode = new CTFGameMode();
try {
CTFGameMode::Team &mt1 = mode->GetTeam(0);
CTFGameMode::Team &mt2 = mode->GetTeam(1);
std::unique_ptr<CTFGameMode> mode{new CTFGameMode()};
mt1.score = reader.ReadByte();
mt2.score = reader.ReadByte();
mode->SetCaptureLimit(reader.ReadByte());
CTFGameMode::Team &mt1 = mode->GetTeam(0);
CTFGameMode::Team &mt2 = mode->GetTeam(1);
int intelFlags = reader.ReadByte();
mt1.hasIntel = (intelFlags & 1) != 0;
mt2.hasIntel = (intelFlags & 2) != 0;
mt1.score = reader.ReadByte();
mt2.score = reader.ReadByte();
mode->SetCaptureLimit(reader.ReadByte());
if (mt2.hasIntel) {
mt1.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt1.flagPos.x = reader.ReadFloat();
mt1.flagPos.y = reader.ReadFloat();
mt1.flagPos.z = reader.ReadFloat();
}
int intelFlags = reader.ReadByte();
mt1.hasIntel = (intelFlags & 1) != 0;
mt2.hasIntel = (intelFlags & 2) != 0;
if (mt1.hasIntel) {
mt2.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt2.flagPos.x = reader.ReadFloat();
mt2.flagPos.y = reader.ReadFloat();
mt2.flagPos.z = reader.ReadFloat();
}
mt1.basePos.x = reader.ReadFloat();
mt1.basePos.y = reader.ReadFloat();
mt1.basePos.z = reader.ReadFloat();
mt2.basePos.x = reader.ReadFloat();
mt2.basePos.y = reader.ReadFloat();
mt2.basePos.z = reader.ReadFloat();
GetWorld()->SetMode(mode);
} catch (...) {
delete mode;
throw;
if (mt2.hasIntel) {
mt1.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt1.flagPos.x = reader.ReadFloat();
mt1.flagPos.y = reader.ReadFloat();
mt1.flagPos.z = reader.ReadFloat();
}
if (mt1.hasIntel) {
mt2.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt2.flagPos.x = reader.ReadFloat();
mt2.flagPos.y = reader.ReadFloat();
mt2.flagPos.z = reader.ReadFloat();
}
mt1.basePos.x = reader.ReadFloat();
mt1.basePos.y = reader.ReadFloat();
mt1.basePos.z = reader.ReadFloat();
mt2.basePos.x = reader.ReadFloat();
mt2.basePos.y = reader.ReadFloat();
mt2.basePos.z = reader.ReadFloat();
GetWorld()->SetMode(std::move(mode));
} else {
// TC
TCGameMode *mode = new TCGameMode(GetWorld());
try {
int numTer = reader.ReadByte();
std::unique_ptr<TCGameMode> mode{new TCGameMode(*GetWorld())};
int numTer = reader.ReadByte();
for (int i = 0; i < numTer; i++) {
TCGameMode::Territory ter;
ter.pos.x = reader.ReadFloat();
ter.pos.y = reader.ReadFloat();
ter.pos.z = reader.ReadFloat();
for (int i = 0; i < numTer; i++) {
TCGameMode::Territory ter{*mode};
ter.pos.x = reader.ReadFloat();
ter.pos.y = reader.ReadFloat();
ter.pos.z = reader.ReadFloat();
int state = reader.ReadByte();
ter.ownerTeamId = state;
ter.progressBasePos = 0.f;
ter.progressStartTime = 0.f;
ter.progressRate = 0.f;
ter.capturingTeamId = -1;
ter.mode = mode;
mode->AddTerritory(ter);
}
GetWorld()->SetMode(mode);
} catch (...) {
delete mode;
throw;
int state = reader.ReadByte();
ter.ownerTeamId = state;
ter.progressBasePos = 0.f;
ter.progressStartTime = 0.f;
ter.progressRate = 0.f;
ter.capturingTeamId = -1;
mode->AddTerritory(ter);
}
GetWorld()->SetMode(std::move(mode));
}
client->JoinedGame();
}
break;
case PacketTypeKillAction: {
Player *p = GetPlayer(reader.ReadByte());
Player *killer = GetPlayer(reader.ReadByte());
Player &p = GetPlayer(reader.ReadByte());
Player *killer = &GetPlayer(reader.ReadByte());
int kt = reader.ReadByte();
KillType type;
switch (kt) {
@ -1264,27 +1251,27 @@ namespace spades {
switch (type) {
case KillTypeFall:
case KillTypeClassChange:
case KillTypeTeamChange: killer = p; break;
case KillTypeTeamChange: killer = &p; break;
default: break;
}
p->KilledBy(type, killer, respawnTime);
if (p != killer) {
p.KilledBy(type, *killer, respawnTime);
if (&p != killer) {
GetWorld()->GetPlayerPersistent(killer->GetId()).kills += 1;
}
} break;
case PacketTypeChatMessage: {
// might be wrong player id for server message
uint8_t pId = reader.ReadByte();
Player *p = GetPlayerOrNull(pId);
stmp::optional<Player &> p = GetPlayerOrNull(pId);
int type = reader.ReadByte();
std::string txt = reader.ReadRemainingString();
if (p) {
switch (type) {
case 0: // all
client->PlayerSentChatMessage(p, true, txt);
client->PlayerSentChatMessage(*p, true, txt);
break;
case 1: // team
client->PlayerSentChatMessage(p, false, txt);
client->PlayerSentChatMessage(*p, false, txt);
break;
case 2: // system???
client->ServerSentMessage(txt);
@ -1312,14 +1299,14 @@ namespace spades {
} break;
case PacketTypeMapChunk: SPRaise("Unexpected: received Map Chunk while game");
case PacketTypePlayerLeft: {
Player *p = GetPlayer(reader.ReadByte());
Player &p = GetPlayer(reader.ReadByte());
client->PlayerLeaving(p);
GetWorld()->GetPlayerPersistent(p->GetId()).kills = 0;
GetWorld()->GetPlayerPersistent(p.GetId()).kills = 0;
savedPlayerTeam[p->GetId()] = -1;
playerPosRecords[p->GetId()].valid = false;
GetWorld()->SetPlayer(p->GetId(), NULL);
savedPlayerTeam[p.GetId()] = -1;
playerPosRecords[p.GetId()].valid = false;
GetWorld()->SetPlayer(p.GetId(), NULL);
// TODO: message
} break;
case PacketTypeTerritoryCapture: {
@ -1327,28 +1314,32 @@ namespace spades {
bool winning = reader.ReadByte() != 0;
int state = reader.ReadByte();
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
// TODO: This piece is repeated for at least three times
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (!mode) {
SPLog("Ignoring PacketTypeTerritoryCapture because game mode isn't "
"specified yet");
break;
}
if (mode->ModeType() != IGameMode::m_TC) {
SPRaise("Received PacketTypeTerritoryCapture in non-TC gamemode");
}
TCGameMode *tc = static_cast<TCGameMode *>(mode);
TCGameMode &tc = dynamic_cast<TCGameMode &>(*mode);
if (territoryId >= tc->GetNumTerritories()) {
if (territoryId >= tc.GetNumTerritories()) {
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
tc->GetNumTerritories() - 1);
tc.GetNumTerritories() - 1);
}
client->TeamCapturedTerritory(state, territoryId);
TCGameMode::Territory *t = tc->GetTerritory(territoryId);
TCGameMode::Territory &t = tc.GetTerritory(territoryId);
t->ownerTeamId = state;
t->progressBasePos = 0.f;
t->progressRate = 0.f;
t->progressStartTime = 0.f;
t->capturingTeamId = -1;
t.ownerTeamId = state;
t.progressBasePos = 0.f;
t.progressRate = 0.f;
t.progressStartTime = 0.f;
t.capturingTeamId = -1;
if (winning)
client->TeamWon(state);
@ -1359,73 +1350,86 @@ namespace spades {
int rate = (int8_t)reader.ReadByte();
float progress = reader.ReadFloat();
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (!mode) {
SPLog(
"Ignoring PacketTypeProgressBar because game mode isn't specified yet");
break;
}
if (mode->ModeType() != IGameMode::m_TC) {
SPRaise("Received PacketTypeProgressBar in non-TC gamemode");
}
TCGameMode *tc = static_cast<TCGameMode *>(mode);
TCGameMode &tc = dynamic_cast<TCGameMode &>(*mode);
if (territoryId >= tc->GetNumTerritories()) {
if (territoryId >= tc.GetNumTerritories()) {
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
tc->GetNumTerritories() - 1);
tc.GetNumTerritories() - 1);
}
if (progress < -0.1f || progress > 1.1f)
SPRaise("Progress value out of range(%f)", progress);
TCGameMode::Territory *t = tc->GetTerritory(territoryId);
TCGameMode::Territory &t = tc.GetTerritory(territoryId);
t->progressBasePos = progress;
t->progressRate = (float)rate * TC_CAPTURE_RATE;
t->progressStartTime = GetWorld()->GetTime();
t->capturingTeamId = capturingTeam;
t.progressBasePos = progress;
t.progressRate = (float)rate * TC_CAPTURE_RATE;
t.progressStartTime = GetWorld()->GetTime();
t.capturingTeamId = capturingTeam;
} break;
case PacketTypeIntelCapture: {
if (!GetWorld())
SPRaise("No world");
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (!mode) {
SPLog(
"Ignoring PacketTypeIntelCapture because game mode isn't specified yet");
break;
}
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelCapture in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
Player *p = GetPlayer(reader.ReadByte());
CTFGameMode &ctf = dynamic_cast<CTFGameMode &>(mode.value());
Player &p = GetPlayer(reader.ReadByte());
client->PlayerCapturedIntel(p);
GetWorld()->GetPlayerPersistent(p->GetId()).kills += 10;
ctf->GetTeam(p->GetTeamId()).hasIntel = false;
ctf->GetTeam(p->GetTeamId()).score++;
GetWorld()->GetPlayerPersistent(p.GetId()).kills += 10;
ctf.GetTeam(p.GetTeamId()).hasIntel = false;
ctf.GetTeam(p.GetTeamId()).score++;
bool winning = reader.ReadByte() != 0;
if (winning)
client->TeamWon(p->GetTeamId());
client->TeamWon(p.GetTeamId());
} break;
case PacketTypeIntelPickup: {
Player *p = GetPlayer(reader.ReadByte());
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
Player &p = GetPlayer(reader.ReadByte());
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (!mode) {
SPLog(
"Ignoring PacketTypeIntelPickup because game mode isn't specified yet");
break;
}
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
CTFGameMode::Team &team = ctf->GetTeam(p->GetTeamId());
CTFGameMode &ctf = dynamic_cast<CTFGameMode &>(mode.value());
CTFGameMode::Team &team = ctf.GetTeam(p.GetTeamId());
team.hasIntel = true;
team.carrier = p->GetId();
team.carrier = p.GetId();
client->PlayerPickedIntel(p);
} break;
case PacketTypeIntelDrop: {
Player *p = GetPlayer(reader.ReadByte());
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
Player &p = GetPlayer(reader.ReadByte());
stmp::optional<IGameMode &> mode = GetWorld()->GetMode();
if (!mode) {
SPLog("Ignoring PacketTypeIntelDrop because game mode isn't specified yet");
break;
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
CTFGameMode::Team &team = ctf->GetTeam(p->GetTeamId());
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelDrop in non-TC gamemode");
}
CTFGameMode &ctf = dynamic_cast<CTFGameMode &>(mode.value());
CTFGameMode::Team &team = ctf.GetTeam(p.GetTeamId());
team.hasIntel = false;
Vector3 pos;
@ -1433,13 +1437,13 @@ namespace spades {
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
ctf->GetTeam(1 - p->GetTeamId()).flagPos = pos;
ctf.GetTeam(1 - p.GetTeamId()).flagPos = pos;
client->PlayerDropIntel(p);
} break;
case PacketTypeRestock: {
Player *p = GetLocalPlayer(); // GetPlayer(reader.ReadByte());
p->Restock();
Player &p = GetLocalPlayer(); // GetPlayer(reader.ReadByte());
p.Restock();
} break;
case PacketTypeFogColour: {
if (GetWorld()) {
@ -1448,24 +1452,24 @@ namespace spades {
}
} break;
case PacketTypeWeaponReload: {
Player *p = GetPlayer(reader.ReadByte());
if (p != GetLocalPlayerOrNull())
p->Reload();
Player &p = GetPlayer(reader.ReadByte());
if (&p != GetLocalPlayerOrNull())
p.Reload();
else {
int clip = reader.ReadByte();
int reserve = reader.ReadByte();
if (clip < 255 && reserve < 255 && p) {
p->ReloadDone(clip, reserve);
if (clip < 255 && reserve < 255) {
p.ReloadDone(clip, reserve);
}
}
// FIXME: use of "clip ammo" and "reserve ammo"?
} break;
case PacketTypeChangeTeam: {
Player *p = GetPlayer(reader.ReadByte());
Player &p = GetPlayer(reader.ReadByte());
int team = reader.ReadByte();
if (team < 0 || team > 2)
SPRaise("Received invalid team: %d", team);
p->SetTeam(team);
p.SetTeam(team);
}
case PacketTypeChangeWeapon: {
reader.ReadByte();
@ -1537,7 +1541,7 @@ namespace spades {
}
NetPacketWriter wri(PacketTypeExistingPlayer);
wri.Write((uint8_t)GetWorld()->GetLocalPlayerIndex());
wri.Write((uint8_t)0); // Player ID, but shouldn't matter here
wri.Write((uint8_t)team);
wri.Write((uint8_t)weapId);
wri.Write((uint8_t)2); // TODO: change tool
@ -1551,8 +1555,8 @@ namespace spades {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypePositionData);
// wri.Write((uint8_t)pId);
Player *p = GetLocalPlayer();
Vector3 v = p->GetPosition();
Player &p = GetLocalPlayer();
Vector3 v = p.GetPosition();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
@ -1597,7 +1601,7 @@ namespace spades {
lastPlayerInput = bits;
NetPacketWriter wri(PacketTypeInputData);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write(bits);
enet_peer_send(peer, 0, wri.CreatePacket());
@ -1616,7 +1620,7 @@ namespace spades {
lastWeaponInput = bits;
NetPacketWriter wri(PacketTypeWeaponInput);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write(bits);
enet_peer_send(peer, 0, wri.CreatePacket());
@ -1625,7 +1629,7 @@ namespace spades {
void NetClient::SendBlockAction(spades::IntVector3 v, BlockActionType type) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeBlockAction);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
switch (type) {
case BlockActionCreate: wri.Write((uint8_t)0); break;
@ -1645,7 +1649,7 @@ namespace spades {
void NetClient::SendBlockLine(spades::IntVector3 v1, spades::IntVector3 v2) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeBlockLine);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write((uint32_t)v1.x);
wri.Write((uint32_t)v1.y);
@ -1660,7 +1664,7 @@ namespace spades {
void NetClient::SendReload() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeWeaponReload);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
// these value should be 255, or
// NetClient will think reload was done when
@ -1674,8 +1678,8 @@ namespace spades {
void NetClient::SendHeldBlockColor() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeSetColour);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
IntVector3 v = GetLocalPlayer()->GetBlockColor();
wri.Write((uint8_t)GetLocalPlayer().GetId());
IntVector3 v = GetLocalPlayer().GetBlockColor();
wri.WriteColor(v);
enet_peer_send(peer, 0, wri.CreatePacket());
}
@ -1683,31 +1687,31 @@ namespace spades {
void NetClient::SendTool() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeSetTool);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
switch (GetLocalPlayer()->GetTool()) {
wri.Write((uint8_t)GetLocalPlayer().GetId());
switch (GetLocalPlayer().GetTool()) {
case Player::ToolSpade: wri.Write((uint8_t)0); break;
case Player::ToolBlock: wri.Write((uint8_t)1); break;
case Player::ToolWeapon: wri.Write((uint8_t)2); break;
case Player::ToolGrenade: wri.Write((uint8_t)3); break;
default: SPInvalidEnum("tool", GetLocalPlayer()->GetTool());
default: SPInvalidEnum("tool", GetLocalPlayer().GetTool());
}
enet_peer_send(peer, 0, wri.CreatePacket());
}
void NetClient::SendGrenade(spades::client::Grenade *g) {
void NetClient::SendGrenade(const Grenade &g) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeGrenadePacket);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write(g->GetFuse());
wri.Write(g.GetFuse());
Vector3 v = g->GetPosition();
Vector3 v = g.GetPosition();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
v = g->GetVelocity();
v = g.GetVelocity();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
@ -1733,7 +1737,7 @@ namespace spades {
void NetClient::SendChat(std::string text, bool global) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChatMessage);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write((uint8_t)(global ? 0 : 1));
wri.Write(text);
wri.Write((uint8_t)0);
@ -1743,7 +1747,7 @@ namespace spades {
void NetClient::SendWeaponChange(WeaponType wt) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChangeWeapon);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
switch (wt) {
case RIFLE_WEAPON: wri.Write((uint8_t)0); break;
case SMG_WEAPON: wri.Write((uint8_t)1); break;
@ -1755,7 +1759,7 @@ namespace spades {
void NetClient::SendTeamChange(int team) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChangeTeam);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)GetLocalPlayer().GetId());
wri.Write((uint8_t)team);
enet_peer_send(peer, 0, wri.CreatePacket());
}
@ -1921,5 +1925,5 @@ namespace spades {
return text;
}
}
}
} // namespace client
} // namespace spades

View File

@ -21,12 +21,12 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <set>
#include <cstdint>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "PhysicsConstants.h"
#include "Player.h"
@ -145,11 +145,11 @@ namespace spades {
bool HandleHandshakePackets(NetPacketReader &);
void HandleExtensionPacket(NetPacketReader &);
void HandleGamePacket(NetPacketReader &);
World *GetWorld();
Player *GetPlayer(int);
Player *GetPlayerOrNull(int);
Player *GetLocalPlayer();
Player *GetLocalPlayerOrNull();
stmp::optional<World &> GetWorld();
Player &GetPlayer(int);
stmp::optional<Player &> GetPlayerOrNull(int);
Player &GetLocalPlayer();
stmp::optional<Player &> GetLocalPlayerOrNull();
std::string DisconnectReasonString(uint32_t);
@ -200,7 +200,7 @@ namespace spades {
void SendBlockLine(IntVector3 v1, IntVector3 v2);
void SendReload();
void SendTool();
void SendGrenade(Grenade *);
void SendGrenade(const Grenade &);
void SendHeldBlockColor();
void SendHit(int targetPlayerId, HitType type);
void SendChat(std::string, bool global);
@ -211,5 +211,5 @@ namespace spades {
double GetDownlinkBps() { return bandwidthMonitor->GetDownlinkBps(); }
double GetUplinkBps() { return bandwidthMonitor->GetUplinkBps(); }
};
}
}
} // namespace client
} // namespace spades

View File

@ -20,11 +20,11 @@
#include <Core/Settings.h>
#include "PaletteView.h"
#include "Client.h"
#include "IImage.h"
#include "IRenderer.h"
#include "NetClient.h"
#include "PaletteView.h"
#include "Player.h"
#include "World.h"
@ -74,7 +74,7 @@ namespace spades {
if (!w)
return -1;
Player *p = w->GetLocalPlayer();
stmp::optional<Player &> p = w->GetLocalPlayer();
if (!p)
return -1;
@ -101,7 +101,7 @@ namespace spades {
if (!w)
return;
Player *p = w->GetLocalPlayer();
stmp::optional<Player &> p = w->GetLocalPlayer();
if (!p)
return;
@ -195,5 +195,5 @@ namespace spades {
}
}
}
}
}
} // namespace client
} // namespace spades

View File

@ -34,7 +34,7 @@ namespace spades {
private:
IRenderer *renderer;
GameMap *map;
Handle<GameMap> map;
IImage *image;
Vector4 color;

View File

@ -36,7 +36,7 @@
namespace spades {
namespace client {
Player::Player(World *w, int playerId, WeaponType wType, int teamId, Vector3 position,
Player::Player(World &w, int playerId, WeaponType wType, int teamId, Vector3 position,
IntVector3 color)
: world(w) {
SPADES_MARK_FUNCTION();
@ -57,7 +57,7 @@ namespace spades {
moveSteps = 0;
this->playerId = playerId;
this->weapon = Weapon::CreateWeapon(wType, this, *w->GetGameProperties());
this->weapon.reset(Weapon::CreateWeapon(wType, *this, *w.GetGameProperties()));
this->weaponType = wType;
this->teamId = teamId;
this->weapon->Reset();
@ -86,16 +86,9 @@ namespace spades {
canPending = false;
}
Player::~Player() {
SPADES_MARK_FUNCTION();
delete weapon;
}
Player::~Player() { SPADES_MARK_FUNCTION(); }
bool Player::IsLocalPlayer() {
if (!world)
return false;
return world->GetLocalPlayer() == this;
}
bool Player::IsLocalPlayer() { return world.GetLocalPlayer() == this; }
void Player::SetInput(PlayerInput newInput) {
SPADES_MARK_FUNCTION();
@ -114,7 +107,7 @@ namespace spades {
void Player::SetWeaponInput(WeaponInput newInput) {
SPADES_MARK_FUNCTION();
auto *listener = GetWorld()->GetListener();
auto *listener = GetWorld().GetListener();
if (!IsAlive())
return;
@ -129,12 +122,12 @@ namespace spades {
newInput.primary = false;
if (newInput.secondary != weapInput.secondary) {
if (newInput.secondary) {
nextDigTime = world->GetTime() + 1.f;
nextDigTime = world.GetTime() + 1.f;
firstDig = true;
}
}
} else if (tool == ToolGrenade) {
if (world->GetTime() < nextGrenadeTime) {
if (world.GetTime() < nextGrenadeTime) {
newInput.primary = false;
}
if (grenades == 0) {
@ -147,13 +140,13 @@ namespace spades {
if (newInput.primary != weapInput.primary) {
if (!newInput.primary) {
if (holdingGrenade) {
nextGrenadeTime = world->GetTime() + .5f;
nextGrenadeTime = world.GetTime() + .5f;
ThrowGrenade();
}
} else {
holdingGrenade = true;
grenadeTime = world->GetTime();
if (listener && this == world->GetLocalPlayer())
grenadeTime = world.GetTime();
if (listener && this == world.GetLocalPlayer())
// playing other's grenade sound
// is cheating
listener->LocalPlayerPulledGrenadePin();
@ -163,12 +156,12 @@ namespace spades {
// work-around for bug that placing block
// occasionally becomes impossible
if (nextBlockTime >
world->GetTime() + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay())) {
world.GetTime() + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay())) {
nextBlockTime =
world->GetTime() + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay());
world.GetTime() + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay());
}
if (world->GetTime() < nextBlockTime) {
if (world.GetTime() < nextBlockTime) {
newInput.primary = false;
newInput.secondary = false;
}
@ -181,7 +174,7 @@ namespace spades {
blockCursorDragPos = blockCursorPos;
} else {
// cannot build; invalid position.
if (listener && this == world->GetLocalPlayer()) {
if (listener && this == world.GetLocalPlayer()) {
listener->LocalPlayerBuildError(
BuildFailureReason::InvalidPosition);
}
@ -190,23 +183,23 @@ namespace spades {
if (IsBlockCursorDragging()) {
if (IsBlockCursorActive()) {
std::vector<IntVector3> blocks =
GetWorld()->CubeLine(blockCursorDragPos, blockCursorPos, 256);
GetWorld().CubeLine(blockCursorDragPos, blockCursorPos, 256);
if ((int)blocks.size() <= blockStocks) {
if (listener && this == world->GetLocalPlayer())
if (listener && this == world.GetLocalPlayer())
listener->LocalPlayerCreatedLineBlock(blockCursorDragPos,
blockCursorPos);
// blockStocks -= blocks.size(); decrease when created
} else {
// cannot build; insufficient blocks.
if (listener && this == world->GetLocalPlayer()) {
if (listener && this == world.GetLocalPlayer()) {
listener->LocalPlayerBuildError(
BuildFailureReason::InsufficientBlocks);
}
}
nextBlockTime = world->GetTime() + GetToolSecondaryDelay();
nextBlockTime = world.GetTime() + GetToolSecondaryDelay();
} else {
// cannot build; invalid position.
if (listener && this == world->GetLocalPlayer()) {
if (listener && this == world.GetLocalPlayer()) {
listener->LocalPlayerBuildError(
BuildFailureReason::InvalidPosition);
}
@ -223,15 +216,15 @@ namespace spades {
if (!weapInput.primary)
lastSingleBlockBuildSeqDone = false;
if (IsBlockCursorActive() && blockStocks > 0) {
if (listener && this == world->GetLocalPlayer())
if (listener && this == world.GetLocalPlayer())
listener->LocalPlayerBlockAction(blockCursorPos, BlockActionCreate);
lastSingleBlockBuildSeqDone = true;
// blockStocks--; decrease when created
nextBlockTime = world->GetTime() + GetToolPrimaryDelay();
nextBlockTime = world.GetTime() + GetToolPrimaryDelay();
} else if (blockStocks > 0 && airborne && canPending &&
this == world->GetLocalPlayer()) {
this == world.GetLocalPlayer()) {
pendingPlaceBlock = true;
pendingPlaceBlockPos = blockCursorPos;
} else if (!IsBlockCursorActive()) {
@ -243,7 +236,7 @@ namespace spades {
} else {
if (!lastSingleBlockBuildSeqDone) {
// cannot build; invalid position.
if (listener && this == world->GetLocalPlayer()) {
if (listener && this == world.GetLocalPlayer()) {
listener->LocalPlayerBuildError(
BuildFailureReason::InvalidPosition);
}
@ -274,7 +267,7 @@ namespace spades {
return;
}
weapon->Reload();
if (this == world->GetLocalPlayer() && weapon->IsReloading())
if (this == world.GetLocalPlayer() && weapon->IsReloading())
reloadingServerSide = true;
}
@ -295,8 +288,8 @@ namespace spades {
pendingRestockBlock = true;
health = 100;
if (world->GetListener())
world->GetListener()->PlayerRestocked(this);
if (world.GetListener())
world.GetListener()->PlayerRestocked(*this);
}
void Player::GotBlock() {
@ -321,8 +314,8 @@ namespace spades {
weapon->AbortReload();
if (world->GetListener())
world->GetListener()->PlayerChangedTool(this);
if (world.GetListener())
world.GetListener()->PlayerChangedTool(*this);
}
void Player::SetHeldBlockColor(spades::IntVector3 col) { blockColor = col; }
@ -369,16 +362,16 @@ namespace spades {
void Player::SetHP(int hp, HurtType type, spades::Vector3 p) {
health = hp;
if (this == world->GetLocalPlayer()) {
if (world->GetListener())
world->GetListener()->LocalPlayerHurt(
type, p.x != 0.f || p.y != 0.f || p.z != 0.f, p);
if (this == world.GetLocalPlayer()) {
if (world.GetListener())
world.GetListener()->LocalPlayerHurt(type,
p.x != 0.f || p.y != 0.f || p.z != 0.f, p);
}
}
void Player::Update(float dt) {
SPADES_MARK_FUNCTION();
auto *listener = world->GetListener();
auto *listener = world.GetListener();
MovePlayer(dt);
@ -389,20 +382,22 @@ namespace spades {
if (tool == ToolSpade) {
if (weapInput.primary) {
if (world->GetTime() > nextSpadeTime) {
if (world.GetTime() > nextSpadeTime) {
UseSpade();
nextSpadeTime = world->GetTime() + GetToolPrimaryDelay();
nextSpadeTime = world.GetTime() + GetToolPrimaryDelay();
}
} else if (weapInput.secondary) {
if (world->GetTime() > nextDigTime) {
if (world.GetTime() > nextDigTime) {
DigWithSpade();
nextDigTime = world->GetTime() + GetToolSecondaryDelay();
nextDigTime = world.GetTime() + GetToolSecondaryDelay();
firstDig = false;
}
}
} else if (tool == ToolBlock && IsLocalPlayer()) {
GameMap::RayCastResult result;
auto *map = GetWorld()->GetMap();
Handle<GameMap> map = GetWorld().GetMap();
SPAssert(map);
result = map->CastRay2(GetEye(), GetFront(), 12);
canPending = false;
@ -418,7 +413,7 @@ namespace spades {
// still okay
} else {
// cannot build; floating
if (listener && this == world->GetLocalPlayer()) {
if (listener && this == world.GetLocalPlayer()) {
listener->LocalPlayerBuildError(BuildFailureReason::InvalidPosition);
}
blockCursorDragging = false;
@ -428,8 +423,7 @@ namespace spades {
if (result.hit && (result.hitBlock + result.normal).z < 62 &&
(!OverlapsWithOneBlock(result.hitBlock + result.normal)) &&
BoxDistanceToBlock(result.hitBlock + result.normal) < 3.f &&
(result.hitBlock + result.normal).z >= 0 &&
!pendingPlaceBlock) {
(result.hitBlock + result.normal).z >= 0 && !pendingPlaceBlock) {
// Building is possible, and there's no delayed block placement.
blockCursorActive = true;
@ -452,17 +446,17 @@ namespace spades {
} else if ((!OverlapsWithOneBlock(pendingPlaceBlockPos)) &&
BoxDistanceToBlock(pendingPlaceBlockPos) < 3.f) {
// now building became possible.
SPAssert(this == world->GetLocalPlayer());
SPAssert(this == world.GetLocalPlayer());
if (GetWorld()->GetListener())
GetWorld()->GetListener()->LocalPlayerBlockAction(pendingPlaceBlockPos,
BlockActionCreate);
if (GetWorld().GetListener())
GetWorld().GetListener()->LocalPlayerBlockAction(pendingPlaceBlockPos,
BlockActionCreate);
pendingPlaceBlock = false;
lastSingleBlockBuildSeqDone = true;
// blockStocks--; decrease when created
nextBlockTime = world->GetTime() + GetToolPrimaryDelay();
nextBlockTime = world.GetTime() + GetToolPrimaryDelay();
}
} else {
@ -476,11 +470,11 @@ namespace spades {
int dist = 11;
for (; dist >= 1 && BoxDistanceToBlock(result.hitBlock + result.normal) > 3.f;
dist--) {
result = GetWorld()->GetMap()->CastRay2(GetEye(), GetFront(), dist);
result = GetWorld().GetMap()->CastRay2(GetEye(), GetFront(), dist);
}
for (; dist < 12 && BoxDistanceToBlock(result.hitBlock + result.normal) < 3.f;
dist++) {
result = GetWorld()->GetMap()->CastRay2(GetEye(), GetFront(), dist);
result = GetWorld().GetMap()->CastRay2(GetEye(), GetFront(), dist);
}
blockCursorPos = result.hitBlock + result.normal;
@ -489,7 +483,7 @@ namespace spades {
} else if (tool == ToolWeapon) {
} else if (tool == ToolGrenade) {
if (holdingGrenade) {
if (world->GetTime() - grenadeTime > 2.9f) {
if (world.GetTime() - grenadeTime > 2.9f) {
ThrowGrenade();
}
}
@ -502,11 +496,11 @@ namespace spades {
}
if (weapon->IsReloading()) {
lastReloadingTime = world->GetTime();
lastReloadingTime = world.GetTime();
} else if (reloadingServerSide) {
// for some reason a server didn't return
// WeaponReload packet.
if (world->GetTime() + lastReloadingTime + .8f) {
if (world.GetTime() + lastReloadingTime + .8f) {
reloadingServerSide = false;
weapon->ForceReloadDone();
}
@ -554,7 +548,9 @@ namespace spades {
int pellets = weapon->GetPelletSize();
float spread = weapon->GetSpread();
GameMap *map = world->GetMap();
Handle<GameMap> map = world.GetMap();
SPAssert(map);
if (weapInput.secondary) {
// vanilla behavior (confirmed by measurement)
@ -580,27 +576,31 @@ namespace spades {
GameMap::RayCastResult mapResult;
mapResult = map->CastRay2(muzzle, dir, 500);
Player *hitPlayer = NULL;
stmp::optional<Player &> hitPlayer;
float hitPlayerDistance = 0.f; // disregarding Z coordinate
float hitPlayerActualDistance = 0.f;
HitBodyPart hitPart = HitBodyPart::None;
for (int i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *other = world->GetPlayer(i);
if (other == this || other == NULL)
continue;
if (other == this || !other->IsAlive() || other->GetTeamId() >= 2)
continue;
// quickly reject players unlikely to be hit
if (!other->RayCastApprox(muzzle, dir))
for (int i = 0; i < world.GetNumPlayerSlots(); i++) {
// TODO: This is a repeated pattern, add something like
// `World::GetExistingPlayerRange()` returning a range
auto maybeOther = world.GetPlayer(i);
if (maybeOther == this || !maybeOther)
continue;
HitBoxes hb = other->GetHitBoxes();
Player &other = maybeOther.value();
if (!other.IsAlive() || other.GetTeamId() >= 2)
continue;
// quickly reject players unlikely to be hit
if (!other.RayCastApprox(muzzle, dir))
continue;
HitBoxes hb = other.GetHitBoxes();
Vector3 hitPos;
if (hb.head.RayCast(muzzle, dir, &hitPos)) {
float dist = GetHorizontalLength(hitPos - muzzle);
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (!hitPlayer || dist < hitPlayerDistance) {
hitPlayer = other;
hitPlayerDistance = dist;
hitPlayerActualDistance = (hitPos - muzzle).GetLength();
@ -609,7 +609,7 @@ namespace spades {
}
if (hb.torso.RayCast(muzzle, dir, &hitPos)) {
float dist = GetHorizontalLength(hitPos - muzzle);
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (!hitPlayer || dist < hitPlayerDistance) {
hitPlayer = other;
hitPlayerDistance = dist;
hitPlayerActualDistance = (hitPos - muzzle).GetLength();
@ -619,7 +619,7 @@ namespace spades {
for (int j = 0; j < 3; j++) {
if (hb.limbs[j].RayCast(muzzle, dir, &hitPos)) {
float dist = GetHorizontalLength(hitPos - muzzle);
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (!hitPlayer || dist < hitPlayerDistance) {
hitPlayer = other;
hitPlayerDistance = dist;
hitPlayerActualDistance = (hitPos - muzzle).GetLength();
@ -636,12 +636,12 @@ namespace spades {
Vector3 finalHitPos;
finalHitPos = muzzle + dir * 128.f;
if (hitPlayer == nullptr && !mapResult.hit) {
if (!hitPlayer && !mapResult.hit) {
// might hit water surface.
}
if (mapResult.hit && GetHorizontalLength(mapResult.hitPos - muzzle) < 128.f &&
(hitPlayer == NULL ||
(!hitPlayer ||
GetHorizontalLength(mapResult.hitPos - muzzle) < hitPlayerDistance)) {
IntVector3 outBlockCoord = mapResult.hitBlock;
// TODO: set correct ray distance
@ -653,13 +653,13 @@ namespace spades {
outBlockCoord.x < map->Width() && outBlockCoord.y < map->Height() &&
outBlockCoord.z < map->Depth()) {
if (outBlockCoord.z == 63) {
if (world->GetListener())
world->GetListener()->BulletHitBlock(
if (world.GetListener())
world.GetListener()->BulletHitBlock(
mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
} else if (outBlockCoord.z == 62) {
// blocks at this level cannot be damaged
if (world->GetListener())
world->GetListener()->BulletHitBlock(
if (world.GetListener())
world.GetListener()->BulletHitBlock(
mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
} else {
int x = outBlockCoord.x;
@ -677,22 +677,22 @@ namespace spades {
health = 0;
blockDestroyed = true;
// send destroy cmd
if (world->GetListener() && world->GetLocalPlayer() == this)
world->GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionTool);
if (world.GetListener() && world.GetLocalPlayer() == this)
world.GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionTool);
}
color = (color & 0xffffff) | ((uint32_t)health << 24);
if (map->IsSolid(x, y, z))
map->Set(x, y, z, true, color);
world->MarkBlockForRegeneration(outBlockCoord);
world.MarkBlockForRegeneration(outBlockCoord);
if (world->GetListener())
world->GetListener()->BulletHitBlock(
if (world.GetListener())
world.GetListener()->BulletHitBlock(
mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
}
}
} else if (hitPlayer != NULL) {
} else if (hitPlayer) {
if (hitPlayerDistance < 128.f) {
finalHitPos = muzzle + dir * hitPlayerActualDistance;
@ -716,28 +716,24 @@ namespace spades {
case HitBodyPart::None: SPAssert(false); break;
}
if (world->GetListener()) {
if (world.GetListener()) {
switch (hitPart) {
case HitBodyPart::Head:
world->GetListener()->BulletHitPlayer(
hitPlayer, HitTypeHead, finalHitPos,
this);
world.GetListener()->BulletHitPlayer(*hitPlayer, HitTypeHead,
finalHitPos, *this);
break;
case HitBodyPart::Torso:
world->GetListener()->BulletHitPlayer(
hitPlayer, HitTypeTorso, finalHitPos,
this);
world.GetListener()->BulletHitPlayer(*hitPlayer, HitTypeTorso,
finalHitPos, *this);
break;
case HitBodyPart::Limb1:
case HitBodyPart::Limb2:
world->GetListener()->BulletHitPlayer(
hitPlayer, HitTypeLegs, finalHitPos,
this);
world.GetListener()->BulletHitPlayer(*hitPlayer, HitTypeLegs,
finalHitPos, *this);
break;
case HitBodyPart::Arms:
world->GetListener()->BulletHitPlayer(
hitPlayer, HitTypeArms, finalHitPos,
this);
world.GetListener()->BulletHitPlayer(*hitPlayer, HitTypeArms,
finalHitPos, *this);
break;
case HitBodyPart::None: SPAssert(false); break;
}
@ -745,14 +741,14 @@ namespace spades {
}
}
if (world->GetListener() && this != world->GetLocalPlayer())
world->GetListener()->AddBulletTracer(this, muzzle, finalHitPos);
if (world.GetListener() && this != world.GetLocalPlayer())
world.GetListener()->AddBulletTracer(*this, muzzle, finalHitPos);
// one pellet done
}
// do hit test debugging
auto *debugger = world->GetHitTestDebugger();
auto *debugger = world.GetHitTestDebugger();
if (debugger && IsLocalPlayer()) {
debugger->SaveImage(playerHits, bulletVectors);
}
@ -762,11 +758,10 @@ namespace spades {
Vector3 rec = weapon->GetRecoil();
float upLimit = Vector3::Dot(GetFront2D(), o);
upLimit -= 0.03f; // ???
o += GetUp() * std::min(rec.y, std::max(0.f, upLimit)) *
(input.crouch ? 0.5f : 1.0f);
o += GetUp() * std::min(rec.y, std::max(0.f, upLimit)) * (input.crouch ? 0.5f : 1.0f);
// vanilla's horizontial recoil seems to driven by a triangular wave generator.
// the period was measured with SMG
float triWave = world->GetTime() * 0.9788f;
float triWave = world.GetTime() * 0.9788f;
triWave -= std::floor(triWave);
if (triWave < 0.5f) {
triWave = triWave * 4.0f - 1.0f;
@ -789,7 +784,7 @@ namespace spades {
Vector3 muzzle = GetEye() + GetFront() * 0.1f;
Vector3 vel = GetFront() * 1.f;
float fuse = world->GetTime() - grenadeTime;
float fuse = world.GetTime() - grenadeTime;
fuse = 3.f - fuse;
if (health <= 0) {
@ -799,15 +794,15 @@ namespace spades {
vel += GetVelocty();
if (this == world->GetLocalPlayer()) {
Grenade *gren = new Grenade(world, muzzle, vel, fuse);
world->AddGrenade(gren);
if (world->GetListener())
world->GetListener()->PlayerThrownGrenade(this, gren);
if (this == world.GetLocalPlayer()) {
std::unique_ptr<Grenade> gren{new Grenade(world, muzzle, vel, fuse)};
if (world.GetListener())
world.GetListener()->PlayerThrewGrenade(*this, *gren);
world.AddGrenade(std::move(gren));
} else {
// grenade packet will be sent by server
if (world->GetListener())
world->GetListener()->PlayerThrownGrenade(this, NULL);
if (world.GetListener())
world.GetListener()->PlayerThrewGrenade(*this, {});
}
holdingGrenade = false;
@ -817,9 +812,11 @@ namespace spades {
SPADES_MARK_FUNCTION();
IntVector3 outBlockCoord;
GameMap *map = world->GetMap();
Handle<GameMap> map = world.GetMap();
Vector3 muzzle = GetEye(), dir = GetFront();
SPAssert(map);
// TODO: set correct ray distance
// first do map raycast
GameMap::RayCastResult mapResult;
@ -836,20 +833,20 @@ namespace spades {
SPAssert(map->IsSolid(outBlockCoord.x, outBlockCoord.y, outBlockCoord.z));
// send destroy command only for local cmd
if (this == world->GetLocalPlayer()) {
if (this == world.GetLocalPlayer()) {
if (world->GetListener())
world->GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionDig);
if (world.GetListener())
world.GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionDig);
}
if (world->GetListener())
world->GetListener()->PlayerHitBlockWithSpade(
this, mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
if (world.GetListener())
world.GetListener()->PlayerHitBlockWithSpade(
*this, mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
}
} else {
if (world->GetListener())
world->GetListener()->PlayerMissedSpade(this);
if (world.GetListener())
world.GetListener()->PlayerMissedSpade(*this);
}
}
@ -861,27 +858,31 @@ namespace spades {
Vector3 muzzle = GetEye(), dir = GetFront();
IntVector3 outBlockCoord;
GameMap *map = world->GetMap();
Handle<GameMap> map = world.GetMap();
SPAssert(map);
// TODO: set correct ray distance
// first do map raycast
GameMap::RayCastResult mapResult;
mapResult = map->CastRay2(muzzle, dir, 256);
Player *hitPlayer = NULL;
stmp::optional<Player &> hitPlayer;
int hitFlag = 0;
for (int i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *other = world->GetPlayer(i);
if (other == this || other == NULL)
continue;
if (other == this || !other->IsAlive() || other->GetTeamId() >= 2)
continue;
if (!other->RayCastApprox(muzzle, dir))
continue;
if ((eye - other->GetEye()).GetChebyshevLength() >= MELEE_DISTANCE_F)
for (int i = 0; i < world.GetNumPlayerSlots(); i++) {
auto maybeOther = world.GetPlayer(i);
if (maybeOther == this || !maybeOther)
continue;
Vector3 diff = other->GetEye() - eye;
Player &other = maybeOther.value();
if (!other.IsAlive() || other.GetTeamId() >= 2)
continue;
if (!other.RayCastApprox(muzzle, dir))
continue;
if ((eye - other.GetEye()).GetChebyshevLength() >= MELEE_DISTANCE_F)
continue;
Vector3 diff = other.GetEye() - eye;
Vector3 view;
view.x = Vector3::Dot(diff, GetRight());
view.y = Vector3::Dot(diff, GetUp());
@ -903,7 +904,7 @@ namespace spades {
outBlockCoord = mapResult.hitBlock;
if (mapResult.hit && BoxDistanceToBlock(mapResult.hitBlock + mapResult.normal) < 3.f &&
(hitPlayer == NULL) && outBlockCoord.x >= 0 && outBlockCoord.y >= 0 &&
!hitPlayer && outBlockCoord.x >= 0 && outBlockCoord.y >= 0 &&
outBlockCoord.z >= 0 && outBlockCoord.x < map->Width() &&
outBlockCoord.y < map->Height() && outBlockCoord.z < map->Depth()) {
if (outBlockCoord.z < 62) {
@ -919,34 +920,33 @@ namespace spades {
if (health <= 0) {
health = 0;
// send destroy command only for local cmd
if (this == world->GetLocalPlayer()) {
if (world->GetListener())
world->GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionTool);
if (this == world.GetLocalPlayer()) {
if (world.GetListener())
world.GetListener()->LocalPlayerBlockAction(outBlockCoord,
BlockActionTool);
}
}
color = (color & 0xffffff) | ((uint32_t)health << 24);
if (map->IsSolid(x, y, z))
map->Set(x, y, z, true, color);
world->MarkBlockForRegeneration(outBlockCoord);
world.MarkBlockForRegeneration(outBlockCoord);
if (world->GetListener())
world->GetListener()->PlayerHitBlockWithSpade(
this, mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
if (world.GetListener())
world.GetListener()->PlayerHitBlockWithSpade(
*this, mapResult.hitPos, mapResult.hitBlock, mapResult.normal);
}
} else if (hitPlayer != NULL) {
if (world->GetListener()) {
} else if (hitPlayer) {
if (world.GetListener()) {
if (hitFlag)
world->GetListener()->BulletHitPlayer(hitPlayer, HitTypeMelee,
hitPlayer->GetEye(), this);
world.GetListener()->BulletHitPlayer(*hitPlayer, HitTypeMelee,
hitPlayer->GetEye(), *this);
}
}
if (missed) {
if (world->GetListener())
world->GetListener()->PlayerMissedSpade(this);
if (world.GetListener())
world.GetListener()->PlayerMissedSpade(*this);
}
}
@ -1007,7 +1007,9 @@ namespace spades {
float nz = position.z + offset;
float z;
GameMap *map = world->GetMap();
const Handle<GameMap> &map = world.GetMap();
SPAssert(map);
if (velocity.x < 0.f)
f = -0.45f;
@ -1066,7 +1068,7 @@ namespace spades {
if (climb) {
velocity.x *= .5f;
velocity.y *= .5f;
lastClimbTime = world->GetTime();
lastClimbTime = world.GetTime();
nz -= 1.f;
m = -1.35f;
} else {
@ -1099,9 +1101,9 @@ namespace spades {
void Player::ForceJump() {
velocity.z = -0.36f;
lastJump = true;
if (world->GetListener() && world->GetTime() > lastJumpTime + .1f) {
world->GetListener()->PlayerJumped(this);
lastJumpTime = world->GetTime();
if (world.GetListener() && world.GetTime() > lastJumpTime + .1f) {
world.GetListener()->PlayerJumped(*this);
lastJumpTime = world.GetTime();
}
}
@ -1109,9 +1111,9 @@ namespace spades {
if (input.jump && (!lastJump) && IsOnGroundOrWade()) {
velocity.z = -0.36f;
lastJump = true;
if (world->GetListener() && world->GetTime() > lastJumpTime + .1f) {
world->GetListener()->PlayerJumped(this);
lastJumpTime = world->GetTime();
if (world.GetListener() && world.GetTime() > lastJumpTime + .1f) {
world.GetListener()->PlayerJumped(*this);
lastJumpTime = world.GetTime();
}
} else if (!input.jump) {
lastJump = false;
@ -1178,12 +1180,12 @@ namespace spades {
velocity.y *= .5f;
if (f2 > FALL_DAMAGE_VELOCITY) {
if (world->GetListener()) {
world->GetListener()->PlayerLanded(this, true);
if (world.GetListener()) {
world.GetListener()->PlayerLanded(*this, true);
}
} else {
if (world->GetListener()) {
world->GetListener()->PlayerLanded(this, false);
if (world.GetListener()) {
world.GetListener()->PlayerLanded(*this, false);
}
}
}
@ -1202,8 +1204,8 @@ namespace spades {
moveSteps++;
moveDistance -= 1.f;
if (world->GetListener() && !madeFootstep) {
world->GetListener()->PlayerMadeFootstep(this);
if (world.GetListener() && !madeFootstep) {
world.GetListener()->PlayerMadeFootstep(*this);
madeFootstep = true;
}
}
@ -1220,12 +1222,13 @@ namespace spades {
float z1 = position.z + 2.25f;
float z2 = position.z - 1.35f;
GameMap *map = world->GetMap();
const Handle<GameMap> &map = world.GetMap();
SPAssert(map);
// lower feet
if (airborne &&
!(map->ClipBox(x1, y1, z1) || map->ClipBox(x2, y1, z1) ||
map->ClipBox(x1, y2, z1) || map->ClipBox(x2, y2, z1)))
if (airborne && !(map->ClipBox(x1, y1, z1) || map->ClipBox(x2, y1, z1) ||
map->ClipBox(x1, y2, z1) || map->ClipBox(x2, y2, z1)))
return true;
else if (!(map->ClipBox(x1, y1, z2) || map->ClipBox(x2, y1, z2) ||
map->ClipBox(x1, y2, z2) || map->ClipBox(x2, y2, z2))) {
@ -1242,7 +1245,7 @@ namespace spades {
SPADES_MARK_FUNCTION();
eye = position = pos2;
float f = lastClimbTime - world->GetTime();
float f = lastClimbTime - world.GetTime();
if (f > -.25f)
eye.z += (f + .25f) / .25f;
}
@ -1274,7 +1277,7 @@ namespace spades {
SPAssert(tool == ToolSpade);
SPAssert(weapInput.primary);
return 1.f - (nextSpadeTime - world->GetTime()) / GetToolPrimaryDelay();
return 1.f - (nextSpadeTime - world.GetTime()) / GetToolPrimaryDelay();
}
float Player::GetDigAnimationProgress() {
@ -1282,32 +1285,32 @@ namespace spades {
SPAssert(tool == ToolSpade);
SPAssert(weapInput.secondary);
return 1.f - (nextDigTime - world->GetTime()) / GetToolSecondaryDelay();
return 1.f - (nextDigTime - world.GetTime()) / GetToolSecondaryDelay();
}
float Player::GetTimeToNextGrenade() { return nextGrenadeTime - world->GetTime(); }
float Player::GetTimeToNextGrenade() { return nextGrenadeTime - world.GetTime(); }
void Player::KilledBy(KillType type, Player *killer, int respawnTime) {
void Player::KilledBy(KillType type, Player &killer, int respawnTime) {
SPADES_MARK_FUNCTION();
health = 0;
weapon->SetShooting(false);
// if local player is killed while cooking grenade,
// drop the live grenade.
if (this == world->GetLocalPlayer() && tool == ToolGrenade && holdingGrenade) {
if (this == world.GetLocalPlayer() && tool == ToolGrenade && holdingGrenade) {
ThrowGrenade();
}
if (world->GetListener())
world->GetListener()->PlayerKilledPlayer(killer, this, type);
if (world.GetListener())
world.GetListener()->PlayerKilledPlayer(killer, *this, type);
input = PlayerInput();
weapInput = WeaponInput();
this->respawnTime = world->GetTime() + respawnTime;
this->respawnTime = world.GetTime() + respawnTime;
}
bool Player::IsAlive() { return health > 0; }
std::string Player::GetName() { return world->GetPlayerPersistent(GetId()).name; }
std::string Player::GetName() { return world.GetPlayerPersistent(GetId()).name; }
float Player::GetWalkAnimationProgress() {
return moveDistance * .5f + (float)(moveSteps)*.5f;
@ -1379,17 +1382,22 @@ namespace spades {
return hb;
}
IntVector3 Player::GetColor() { return world->GetTeam(teamId).color; }
IntVector3 Player::GetColor() { return world.GetTeam(teamId).color; }
bool Player::IsCookingGrenade() { return tool == ToolGrenade && holdingGrenade; }
float Player::GetGrenadeCookTime() { return world->GetTime() - grenadeTime; }
float Player::GetGrenadeCookTime() { return world.GetTime() - grenadeTime; }
Weapon &Player::GetWeapon() {
SPADES_MARK_FUNCTION();
SPAssert(weapon);
return *weapon;
}
void Player::SetWeaponType(WeaponType weap) {
SPADES_MARK_FUNCTION_DEBUG();
if (this->weapon->GetWeaponType() == weap)
return;
delete this->weapon;
this->weapon = Weapon::CreateWeapon(weap, this, *world->GetGameProperties());
this->weapon.reset(Weapon::CreateWeapon(weap, *this, *world.GetGameProperties()));
this->weaponType = weap;
}
@ -1398,8 +1406,8 @@ namespace spades {
bool Player::IsReadyToUseTool() {
SPADES_MARK_FUNCTION_DEBUG();
switch (tool) {
case ToolBlock: return world->GetTime() > nextBlockTime && blockStocks > 0;
case ToolGrenade: return world->GetTime() > nextGrenadeTime && grenades > 0;
case ToolBlock: return world.GetTime() > nextBlockTime && blockStocks > 0;
case ToolGrenade: return world.GetTime() > nextGrenadeTime && grenades > 0;
case ToolSpade: return true;
case ToolWeapon: return weapon->IsReadyToShoot();
}
@ -1445,5 +1453,5 @@ namespace spades {
return (e - eye).GetChebyshevLength();
}
}
}
} // namespace client
} // namespace spades

View File

@ -21,8 +21,10 @@
#pragma once
#include <Core/Math.h>
#include <memory>
#include "PhysicsConstants.h"
#include <Core/Math.h>
namespace spades {
namespace client {
@ -66,7 +68,7 @@ namespace spades {
};
private:
World *world;
World &world;
Vector3 position;
Vector3 velocity;
@ -79,7 +81,7 @@ namespace spades {
ToolType tool;
WeaponType weaponType;
Weapon *weapon;
std::unique_ptr<Weapon> weapon;
int playerId;
int teamId;
IntVector3 color; // obsolete
@ -134,13 +136,16 @@ namespace spades {
void ThrowGrenade();
public:
Player(World *, int playerId, WeaponType weapon, int teamId, Vector3 position,
Player(World &, int playerId, WeaponType weapon, int teamId, Vector3 position,
IntVector3 color);
Player(const Player &) = delete;
void operator =(const Player &) = delete;
~Player();
int GetId() { return playerId; }
Weapon *GetWeapon() { return weapon; }
Weapon &GetWeapon();
WeaponType GetWeaponType() { return weaponType; }
int GetTeamId() { return teamId; }
bool IsSpectator() { return teamId >= 2; }
@ -188,7 +193,7 @@ namespace spades {
void UsedBlocks(int c) { blockStocks = std::max(blockStocks - c, 0); }
/** makes player's health 0. */
void KilledBy(KillType, Player *killer, int respawnTime);
void KilledBy(KillType, Player &killer, int respawnTime);
bool IsAlive();
/** @return world time to respawn */
@ -207,7 +212,7 @@ namespace spades {
Vector3 GetVelocty() { return velocity; }
int GetMoveSteps() { return moveSteps; }
World *GetWorld() { return world; }
World &GetWorld() { return world; }
bool GetWade();
bool IsOnGroundOrWade();
@ -241,5 +246,5 @@ namespace spades {
float BoxDistanceToBlock(IntVector3);
};
}
}
} // namespace client
} // namespace spades

View File

@ -50,7 +50,6 @@ namespace spades {
1}; // Goldish yellow
static const auto spectatorTeamId = 255; // Spectators have a team id of 255
ScoreboardView::ScoreboardView(Client *client)
: client(client), renderer(client->GetRenderer()) {
SPADES_MARK_FUNCTION();
@ -62,14 +61,12 @@ namespace spades {
// Use GUI font if spectator string has special chars
auto spectatorString = _TrN("Client", "Spectator{1}", "Spectators{1}", "", "");
auto has_special_char =
std::find_if(spectatorString.begin(), spectatorString.end(),
[](char ch) {
return !(isalnum(static_cast<unsigned char>(ch)) || ch == '_');
}) != spectatorString.end();
std::find_if(spectatorString.begin(), spectatorString.end(), [](char ch) {
return !(isalnum(static_cast<unsigned char>(ch)) || ch == '_');
}) != spectatorString.end();
spectatorFont = has_special_char ?
client->fontManager->GetMediumFont() :
client->fontManager->GetSquareDesignFont();
spectatorFont = has_special_char ? client->fontManager->GetMediumFont()
: client->fontManager->GetSquareDesignFont();
}
ScoreboardView::~ScoreboardView() {}
@ -81,7 +78,7 @@ namespace spades {
int cnt = tc->GetNumTerritories();
int num = 0;
for (int i = 0; i < cnt; i++)
if (tc->GetTerritory(i)->ownerTeamId == team)
if (tc->GetTerritory(i).ownerTeamId == team)
num++;
return num;
} else {
@ -94,7 +91,8 @@ namespace spades {
return MakeVector4(c.x / 255.f, c.y / 255.f, c.z / 255.f, 1.f);
}
Vector4 ScoreboardView::AdjustColor(spades::Vector4 col, float bright, float saturation) const {
Vector4 ScoreboardView::AdjustColor(spades::Vector4 col, float bright,
float saturation) const {
col.x *= bright;
col.y *= bright;
col.z *= bright;
@ -129,9 +127,15 @@ namespace spades {
return;
}
IGameMode *mode = world->GetMode();
ctf = IGameMode::m_CTF == mode->ModeType() ? static_cast<CTFGameMode *>(mode) : NULL;
tc = IGameMode::m_TC == mode->ModeType() ? static_cast<TCGameMode *>(mode) : NULL;
// TODO: `ctf` and `tc` are only valid throughout the method call's
// duration. Move them to a new context type
auto mode = world->GetMode();
ctf = IGameMode::m_CTF == mode->ModeType()
? dynamic_cast<CTFGameMode *>(mode.get_pointer())
: NULL;
tc = IGameMode::m_TC == mode->ModeType()
? dynamic_cast<TCGameMode *>(mode.get_pointer())
: NULL;
Handle<IImage> image;
IFont *font;
@ -249,16 +253,17 @@ namespace spades {
std::vector<ScoreboardEntry> entries;
for (int i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *p = world->GetPlayer(i);
if (!p)
auto maybePlayer = world->GetPlayer(i);
if (!maybePlayer)
continue;
if (p->GetTeamId() != team)
Player &player = maybePlayer.value();
if (player.GetTeamId() != team)
continue;
ScoreboardEntry ent;
ent.name = p->GetName();
ent.name = player.GetName();
ent.score = world->GetPlayerPersistent(i).kills;
ent.alive = p->IsAlive();
ent.alive = player.IsAlive();
ent.id = i;
entries.push_back(ent);
@ -297,7 +302,7 @@ namespace spades {
}
color = ent.alive ? white : gray;
if (ent.id == world->GetLocalPlayerIndex())
if (stmp::make_optional(ent.id) == world->GetLocalPlayerIndex())
color = GetTeamColor(team);
font->Draw(ent.name, MakeVector2(colX + 45.f, rowY), 1.f, color);
@ -326,14 +331,16 @@ namespace spades {
int numSpectators = 0;
float totalPixelWidth = 0;
for (int i = 0; i < world->GetNumPlayerSlots(); i++) {
Player *p = world->GetPlayer(i);
if (!p)
auto maybePlayer = world->GetPlayer(i);
if (!maybePlayer)
continue;
if (p->GetTeamId() != spectatorTeamId)
Player &player = maybePlayer.value();
if (player.GetTeamId() != spectatorTeamId)
continue;
ScoreboardEntry ent;
ent.name = p->GetName();
ent.name = player.GetName();
ent.id = i;
entries.push_back(ent);
@ -353,10 +360,9 @@ namespace spades {
auto isSquareFont = spectatorFont == client->fontManager->GetSquareDesignFont();
auto sizeSpecString = spectatorFont->Measure(buf);
spectatorFont->Draw(buf,
MakeVector2(centerX - sizeSpecString.x / 2, top + (isSquareFont ? 0 : 10)),
1.f,
spectatorTextColor);
spectatorFont->Draw(
buf, MakeVector2(centerX - sizeSpecString.x / 2, top + (isSquareFont ? 0 : 10)), 1.f,
spectatorTextColor);
auto yOffset = top + sizeSpecString.y;
auto halfTotalX = totalPixelWidth / 2;
@ -379,11 +385,11 @@ namespace spades {
bool ScoreboardView::areSpectatorsPresent() const {
for (auto i = 0; i < client->GetWorld()->GetNumPlayerSlots(); i++) {
auto *p = world->GetPlayer(i);
if (p && p->GetTeamId() == spectatorTeamId)
auto p = world->GetPlayer(i);
if (p && p.value().GetTeamId() == spectatorTeamId)
return true;
}
return false;
}
}
}
} // namespace client
} // namespace spades

View File

@ -25,7 +25,7 @@
namespace spades {
namespace client {
TCGameMode::TCGameMode(World *w) : IGameMode(m_TC), world(w) { SPADES_MARK_FUNCTION(); }
TCGameMode::TCGameMode(World &w) : IGameMode(m_TC), world(w) { SPADES_MARK_FUNCTION(); }
TCGameMode::~TCGameMode() { SPADES_MARK_FUNCTION(); }
TCGameMode::Team &TCGameMode::GetTeam(int t) {
@ -40,7 +40,7 @@ namespace spades {
}
float TCGameMode::Territory::GetProgress() {
float dt = mode->world->GetTime() - progressStartTime;
float dt = mode.world.GetTime() - progressStartTime;
float prog = progressBasePos;
prog += progressRate * dt;
if (prog < 0.f)

View File

@ -32,7 +32,7 @@ namespace spades {
class TCGameMode : public IGameMode {
public:
struct Territory {
TCGameMode *mode;
TCGameMode &mode;
Vector3 pos;
/** team that owns this territory, or 2 if this territory is currently neutral.*/
@ -45,6 +45,8 @@ namespace spades {
float progressRate;
float progressStartTime;
Territory(TCGameMode &mode) : mode{mode} {}
/** gets capture progress of this territory.
* 0 = ownerTeamId is capturing, 1 = 1-ownerTeamId has captured this. */
float GetProgress();
@ -53,22 +55,25 @@ namespace spades {
int captureLimit;
private:
World *world;
World &world;
Team teams[2];
std::vector<Territory> territories;
public:
TCGameMode(World *);
TCGameMode(World &);
~TCGameMode();
TCGameMode(const TCGameMode &) = delete;
void operator=(const TCGameMode &) = delete;
Team &GetTeam(int t);
int GetNumTerritories() const { return (int)territories.size(); }
Territory *GetTerritory(int index) {
Territory &GetTerritory(int index) {
SPADES_MARK_FUNCTION();
SPAssert(index >= 0);
SPAssert(index < GetNumTerritories());
return &(territories[index]);
return territories[index];
}
void AddTerritory(const Territory &);

View File

@ -40,16 +40,16 @@ namespace spades {
TCProgressView::~TCProgressView() {}
static TCProgressState StateForTerritory(TCGameMode::Territory *t, int myTeam) {
static TCProgressState StateForTerritory(TCGameMode::Territory &t, int myTeam) {
TCProgressState state;
if (t->capturingTeamId == -1) {
state.team1 = t->ownerTeamId;
if (t.capturingTeamId == -1) {
state.team1 = t.ownerTeamId;
state.team2 = 2;
state.progress = 0.f;
} else {
float prg = t->GetProgress();
state.team1 = t->ownerTeamId;
state.team2 = t->capturingTeamId;
float prg = t.GetProgress();
state.team1 = t.ownerTeamId;
state.team2 = t.capturingTeamId;
state.progress = prg;
if (state.team2 == myTeam) {
@ -66,11 +66,11 @@ namespace spades {
lastTerritoryId = -1;
return;
}
IGameMode *mode = w->GetMode();
stmp::optional<IGameMode &> mode = w->GetMode();
if (!mode || IGameMode::m_TC != mode->ModeType()) {
return;
}
TCGameMode *tc = static_cast<TCGameMode *>(mode);
TCGameMode &tc = dynamic_cast<TCGameMode &>(mode.value());
float scrW = renderer->ScreenWidth();
float scrH = renderer->ScreenHeight();
@ -78,22 +78,25 @@ namespace spades {
Handle<IImage> prgBg = renderer->RegisterImage("Gfx/TC/ProgressBg.png");
Handle<IImage> prgBar = renderer->RegisterImage("Gfx/TC/ProgressBar.png");
Player *p = w->GetLocalPlayer();
if (p && p->GetTeamId() < 2 && p->IsAlive()) {
stmp::optional<Player &> maybePlayer = w->GetLocalPlayer();
if (maybePlayer && maybePlayer.value().GetTeamId() < 2 &&
maybePlayer.value().IsAlive()) {
Player &p = maybePlayer.value();
// show approaching territory
TCGameMode::Territory *nearTerritory = NULL;
stmp::optional<TCGameMode::Territory &> nearTerritory;
int nearTerId = 0;
float distance = 0.f;
int myTeam = p->GetTeamId();
int myTeam = p.GetTeamId();
int cnt = tc->GetNumTerritories();
int cnt = tc.GetNumTerritories();
for (int i = 0; i < cnt; i++) {
TCGameMode::Territory *t = tc->GetTerritory(i);
Vector3 diff = t->pos - p->GetEye();
TCGameMode::Territory &t = tc.GetTerritory(i);
Vector3 diff = t.pos - p.GetEye();
if (fabsf(diff.x) < 18.f && fabsf(diff.y) < 18.f && fabsf(diff.z) < 18.f) {
float dist = diff.GetPoweredLength();
if (nearTerritory == NULL || dist < distance) {
nearTerritory = t;
if (!nearTerritory || dist < distance) {
nearTerritory = &t;
nearTerId = i;
distance = dist;
}
@ -106,11 +109,11 @@ namespace spades {
lastTerritoryTime = w->GetTime();
} else if (lastTerritoryId != -1 && w->GetTime() < lastTerritoryTime + 2.f) {
fade = 1.f - (w->GetTime() - lastTerritoryTime) / 2.f;
nearTerritory = tc->GetTerritory(lastTerritoryId);
nearTerritory = &tc.GetTerritory(lastTerritoryId);
}
if (nearTerritory) {
TCProgressState state = StateForTerritory(nearTerritory, myTeam);
TCProgressState state = StateForTerritory(*nearTerritory, myTeam);
float x = (scrW - 256.f) * .5f;
float y = scrH * 0.7f;
@ -166,5 +169,5 @@ namespace spades {
lastTerritoryId = -1;
}
}
}
}
} // namespace client
} // namespace spades

View File

@ -28,7 +28,7 @@
namespace spades {
namespace client {
Weapon::Weapon(World *w, Player *p)
Weapon::Weapon(World &w, Player &p)
: world(w),
owner(p),
time(0),
@ -59,7 +59,7 @@ namespace spades {
void Weapon::SetShooting(bool b) { shooting = b; }
bool Weapon::IsReadyToShoot() {
return (ammo > 0 || !owner->IsLocalPlayer()) && time >= nextShotTime &&
return (ammo > 0 || !owner.IsLocalPlayer()) && time >= nextShotTime &&
(!reloading || IsReloadSlow());
}
@ -72,7 +72,7 @@ namespace spades {
bool Weapon::FrameNext(float dt) {
SPADES_MARK_FUNCTION();
bool ownerIsLocalPlayer = owner->IsLocalPlayer();
bool ownerIsLocalPlayer = owner.IsLocalPlayer();
bool fired = false;
bool dryFire = false;
@ -93,8 +93,8 @@ namespace spades {
ammo--;
}
if (world->GetListener()) {
world->GetListener()->PlayerFiredWeapon(owner);
if (world.GetListener()) {
world.GetListener()->PlayerFiredWeapon(owner);
}
nextShotTime += GetDelay();
} else if (time >= nextShotTime) {
@ -128,22 +128,22 @@ namespace spades {
slowReloadLeftCount--;
if (slowReloadLeftCount > 0)
Reload(false);
else if (world->GetListener())
world->GetListener()->PlayerReloadedWeapon(owner);
else if (world.GetListener())
world.GetListener()->PlayerReloadedWeapon(owner);
} else {
if (!ownerIsLocalPlayer) {
ammo = GetClipSize();
}
if (world->GetListener())
world->GetListener()->PlayerReloadedWeapon(owner);
if (world.GetListener())
world.GetListener()->PlayerReloadedWeapon(owner);
}
}
}
time += dt;
if (dryFire && !lastDryFire) {
if (world->GetListener())
world->GetListener()->PlayerDryFiredWeapon(owner);
if (world.GetListener())
world.GetListener()->PlayerDryFiredWeapon(owner);
}
lastDryFire = dryFire;
return fired;
@ -163,7 +163,7 @@ namespace spades {
void Weapon::Reload(bool initial) {
SPADES_MARK_FUNCTION();
bool ownerIsLocalPlayer = owner->IsLocalPlayer();
bool ownerIsLocalPlayer = owner.IsLocalPlayer();
if (reloading)
return;
@ -171,7 +171,7 @@ namespace spades {
// Is the clip already full?
if (ammo >= GetClipSize())
return;
if (ownerIsLocalPlayer) {
if (stock == 0)
return;
@ -186,8 +186,8 @@ namespace spades {
reloadStartTime = time;
reloadEndTime = time + GetReloadTime();
if (world->GetListener())
world->GetListener()->PlayerReloadingWeapon(owner);
if (world.GetListener())
world.GetListener()->PlayerReloadingWeapon(owner);
}
void Weapon::ForceReloadDone() {
@ -199,7 +199,7 @@ namespace spades {
class RifleWeapon3 : public Weapon {
public:
RifleWeapon3(World *w, Player *p) : Weapon(w, p) {}
RifleWeapon3(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "Rifle"; }
float GetDelay() override { return 0.5f; }
int GetClipSize() override { return 10; }
@ -226,7 +226,7 @@ namespace spades {
class SMGWeapon3 : public Weapon {
public:
SMGWeapon3(World *w, Player *p) : Weapon(w, p) {}
SMGWeapon3(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "SMG"; }
float GetDelay() override { return 0.11f; }
int GetClipSize() override { return 30; }
@ -253,7 +253,7 @@ namespace spades {
class ShotgunWeapon3 : public Weapon {
public:
ShotgunWeapon3(World *w, Player *p) : Weapon(w, p) {}
ShotgunWeapon3(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "Shotgun"; }
float GetDelay() override { return 1.f; }
int GetClipSize() override { return 6; }
@ -283,7 +283,7 @@ namespace spades {
class RifleWeapon4 : public Weapon {
public:
RifleWeapon4(World *w, Player *p) : Weapon(w, p) {}
RifleWeapon4(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "Rifle"; }
float GetDelay() override { return 0.6f; }
int GetClipSize() override { return 8; }
@ -316,7 +316,7 @@ namespace spades {
class SMGWeapon4 : public Weapon {
public:
SMGWeapon4(World *w, Player *p) : Weapon(w, p) {}
SMGWeapon4(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "SMG"; }
float GetDelay() override { return 0.1f; }
int GetClipSize() override { return 30; }
@ -344,7 +344,7 @@ namespace spades {
class ShotgunWeapon4 : public Weapon {
public:
ShotgunWeapon4(World *w, Player *p) : Weapon(w, p) {}
ShotgunWeapon4(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "Shotgun"; }
float GetDelay() override { return 0.8f; }
int GetClipSize() override { return 8; }
@ -370,22 +370,22 @@ namespace spades {
int GetPelletSize() override { return 8; }
};
Weapon *Weapon::CreateWeapon(WeaponType type, Player *p, const GameProperties &gp) {
Weapon *Weapon::CreateWeapon(WeaponType type, Player &p, const GameProperties &gp) {
SPADES_MARK_FUNCTION();
switch (gp.protocolVersion) {
case ProtocolVersion::v075:
switch (type) {
case RIFLE_WEAPON: return new RifleWeapon3(p->GetWorld(), p);
case SMG_WEAPON: return new SMGWeapon3(p->GetWorld(), p);
case SHOTGUN_WEAPON: return new ShotgunWeapon3(p->GetWorld(), p);
case RIFLE_WEAPON: return new RifleWeapon3(p.GetWorld(), p);
case SMG_WEAPON: return new SMGWeapon3(p.GetWorld(), p);
case SHOTGUN_WEAPON: return new ShotgunWeapon3(p.GetWorld(), p);
default: SPInvalidEnum("type", type);
}
case ProtocolVersion::v076:
switch (type) {
case RIFLE_WEAPON: return new RifleWeapon4(p->GetWorld(), p);
case SMG_WEAPON: return new SMGWeapon4(p->GetWorld(), p);
case SHOTGUN_WEAPON: return new ShotgunWeapon4(p->GetWorld(), p);
case RIFLE_WEAPON: return new RifleWeapon4(p.GetWorld(), p);
case SMG_WEAPON: return new SMGWeapon4(p.GetWorld(), p);
case SHOTGUN_WEAPON: return new ShotgunWeapon4(p.GetWorld(), p);
default: SPInvalidEnum("type", type);
}
default:

View File

@ -31,8 +31,8 @@ namespace spades {
struct GameProperties;
class Weapon {
World *world;
Player *owner;
World &world;
Player &owner;
float time;
bool shooting;
bool shootingPreviously;
@ -49,7 +49,7 @@ namespace spades {
int stock;
public:
Weapon(World *, Player *);
Weapon(World &, Player &);
virtual ~Weapon();
virtual std::string GetName() = 0;
virtual float GetDelay() = 0;
@ -65,7 +65,7 @@ namespace spades {
virtual int GetPelletSize() = 0;
static Weapon *CreateWeapon(WeaponType index, Player *, const GameProperties &);
static Weapon *CreateWeapon(WeaponType index, Player &owner, const GameProperties &);
void Restock();
void Reset();
@ -95,5 +95,5 @@ namespace spades {
bool IsReadyToShoot();
};
}
}
} // namespace client
} // namespace spades

View File

@ -23,10 +23,6 @@
#include <cstdlib>
#include <deque>
#include <Core/Debug.h>
#include <Core/Debug.h>
#include <Core/FileManager.h>
#include <Core/IStream.h>
#include "GameMap.h"
#include "GameMapWrapper.h"
#include "GameProperties.h"
@ -37,6 +33,9 @@
#include "Player.h"
#include "Weapon.h"
#include "World.h"
#include <Core/Debug.h>
#include <Core/FileManager.h>
#include <Core/IStream.h>
#include <Core/Settings.h>
DEFINE_SPADES_SETTING(cg_debugHitTest, "0");
@ -47,43 +46,12 @@ namespace spades {
World::World(const std::shared_ptr<GameProperties> &gameProperties)
: gameProperties{gameProperties} {
SPADES_MARK_FUNCTION();
listener = NULL;
map = NULL;
mapWrapper = NULL;
localPlayerIndex = -1;
for (int i = 0; i < 128; i++) {
players.push_back((Player *)NULL);
playerPersistents.push_back(PlayerPersistent());
}
localPlayerIndex = 0;
time = 0.f;
mode = NULL;
}
World::~World() {
SPADES_MARK_FUNCTION();
for (std::list<Grenade *>::iterator it = grenades.begin(); it != grenades.end(); it++)
delete *it;
for (size_t i = 0; i < players.size(); i++)
if (players[i])
delete players[i];
if (mode) {
delete mode;
}
if (map) {
delete mapWrapper;
map->Release();
}
}
World::~World() { SPADES_MARK_FUNCTION(); }
size_t World::GetNumPlayers() {
size_t numPlayers = 0;
for (auto *p : players) {
for (const auto &p : players) {
if (p)
++numPlayers;
}
@ -95,9 +63,9 @@ namespace spades {
ApplyBlockActions();
for (size_t i = 0; i < players.size(); i++)
if (players[i])
players[i]->Update(dt);
for (const auto &player : players)
if (player)
player->Update(dt);
while (!blockRegenerationQueue.empty()) {
auto it = blockRegenerationQueue.begin();
@ -118,74 +86,52 @@ namespace spades {
blockRegenerationQueue.erase(it);
}
std::vector<std::list<Grenade *>::iterator> removedGrenades;
for (std::list<Grenade *>::iterator it = grenades.begin(); it != grenades.end(); it++) {
Grenade *g = *it;
if (g->Update(dt)) {
std::vector<decltype(grenades.begin())> removedGrenades;
for (auto it = grenades.begin(); it != grenades.end(); it++) {
Grenade &g = **it;
if (g.Update(dt)) {
removedGrenades.push_back(it);
}
}
for (size_t i = 0; i < removedGrenades.size(); i++)
grenades.erase(removedGrenades[i]);
for (auto it : removedGrenades)
grenades.erase(it);
time += dt;
}
void World::SetMap(spades::client::GameMap *newMap) {
void World::SetMap(Handle<GameMap> newMap) {
if (map == newMap)
return;
hitTestDebugger.reset();
if (map) {
map->Release();
delete mapWrapper;
mapWrapper.reset();
}
map = newMap;
if (map) {
map->AddRef();
mapWrapper = new GameMapWrapper(*map);
mapWrapper.reset(new GameMapWrapper(*map));
mapWrapper->Rebuild();
}
}
void World::AddGrenade(spades::client::Grenade *g) {
void World::AddGrenade(std::unique_ptr<Grenade> g) {
SPADES_MARK_FUNCTION_DEBUG();
grenades.push_back(g);
grenades.push_back(std::move(g));
}
std::vector<Grenade *> World::GetAllGrenades() {
SPADES_MARK_FUNCTION_DEBUG();
std::vector<Grenade *> g;
for (std::list<Grenade *>::iterator it = grenades.begin(); it != grenades.end(); it++) {
g.push_back(*it);
}
return g;
}
void World::SetPlayer(int i, spades::client::Player *p) {
void World::SetPlayer(int i, std::unique_ptr<Player> p) {
SPADES_MARK_FUNCTION();
SPAssert(i >= 0);
SPAssert(i < (int)players.size());
if (players[i] == p)
return;
if (players[i])
delete players[i];
players[i] = p;
if (listener)
players.at(i) = std::move(p);
if (listener) {
listener->PlayerObjectSet(i);
}
}
void World::SetMode(spades::client::IGameMode *m) {
if (mode == m)
return;
if (mode)
delete mode;
mode = m;
}
void World::SetMode(std::unique_ptr<IGameMode> m) { mode = std::move(m); }
void World::MarkBlockForRegeneration(const IntVector3 &blockLocation) {
UnmarkBlockForRegeneration(blockLocation);
@ -345,7 +291,7 @@ namespace spades {
World::PlayerPersistent &World::GetPlayerPersistent(int index) {
SPAssert(index >= 0);
SPAssert(index < players.size());
return playerPersistents[index];
return playerPersistents.at(index);
}
std::vector<IntVector3> World::CubeLine(spades::IntVector3 v1, spades::IntVector3 v2,
@ -437,15 +383,16 @@ namespace spades {
}
World::WeaponRayCastResult World::WeaponRayCast(spades::Vector3 startPos,
spades::Vector3 dir, Player *exclude) {
spades::Vector3 dir,
stmp::optional<int> excludePlayerId) {
WeaponRayCastResult result;
Player *hitPlayer = NULL;
stmp::optional<int> hitPlayer;
float hitPlayerDistance = 0.f;
hitTag_t hitFlag = hit_None;
for (int i = 0; i < (int)players.size(); i++) {
Player *p = players[i];
if (p == NULL || p == exclude)
const auto &p = players[i];
if (!p || (excludePlayerId && *excludePlayerId == i))
continue;
if (p->GetTeamId() >= 2 || !p->IsAlive())
continue;
@ -457,9 +404,9 @@ namespace spades {
if (hb.head.RayCast(startPos, dir, &hitPos)) {
float dist = (hitPos - startPos).GetLength();
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (hitPlayer != p) {
hitPlayer = p;
if (!hitPlayer || dist < hitPlayerDistance) {
if (hitPlayer != i) {
hitPlayer = i;
hitFlag = hit_None;
}
hitPlayerDistance = dist;
@ -468,9 +415,9 @@ namespace spades {
}
if (hb.torso.RayCast(startPos, dir, &hitPos)) {
float dist = (hitPos - startPos).GetLength();
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (hitPlayer != p) {
hitPlayer = p;
if (!hitPlayer || dist < hitPlayerDistance) {
if (hitPlayer != i) {
hitPlayer = i;
hitFlag = hit_None;
}
hitPlayerDistance = dist;
@ -480,9 +427,9 @@ namespace spades {
for (int j = 0; j < 3; j++) {
if (hb.limbs[j].RayCast(startPos, dir, &hitPos)) {
float dist = (hitPos - startPos).GetLength();
if (hitPlayer == NULL || dist < hitPlayerDistance) {
if (hitPlayer != p) {
hitPlayer = p;
if (!hitPlayer || dist < hitPlayerDistance) {
if (hitPlayer != i) {
hitPlayer = i;
hitFlag = hit_None;
}
hitPlayerDistance = dist;
@ -501,17 +448,16 @@ namespace spades {
res2 = map->CastRay2(startPos, dir, 256);
if (res2.hit &&
(hitPlayer == NULL || (res2.hitPos - startPos).GetLength() < hitPlayerDistance)) {
(!hitPlayer || (res2.hitPos - startPos).GetLength() < hitPlayerDistance)) {
result.hit = true;
result.startSolid = res2.startSolid;
result.player = NULL;
result.hitFlag = hit_None;
result.blockPos = res2.hitBlock;
result.hitPos = res2.hitPos;
} else if (hitPlayer) {
result.hit = true;
result.startSolid = false; // FIXME: startSolid for player
result.player = hitPlayer;
result.playerId = hitPlayer;
result.hitPos = startPos + dir * hitPlayerDistance;
result.hitFlag = hitFlag;
} else {
@ -530,5 +476,5 @@ namespace spades {
}
return nullptr;
}
}
}
} // namespace client
} // namespace spades

View File

@ -21,17 +21,20 @@
#pragma once
#include <array>
#include <list>
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <map>
#include "GameMapWrapper.h"
#include "PhysicsConstants.h"
#include <Core/Debug.h>
#include <Core/Math.h>
#include <Core/RefCountedObject.h>
#include <Core/TMPUtils.h>
namespace spades {
namespace client {
@ -44,6 +47,9 @@ namespace spades {
class Client; // FIXME: for debug
class HitTestDebugger;
struct GameProperties;
constexpr std::size_t NumPlayerSlots = 128;
class World {
friend class Client; // FIXME: for debug
public:
@ -58,23 +64,23 @@ namespace spades {
};
private:
IWorldListener *listener;
IWorldListener *listener = nullptr;
IGameMode *mode;
std::unique_ptr<IGameMode> mode;
GameMap *map;
GameMapWrapper *mapWrapper;
float time;
Handle<GameMap> map;
std::unique_ptr<GameMapWrapper> mapWrapper;
float time = 0.0f;
IntVector3 fogColor;
Team teams[3];
std::shared_ptr<GameProperties> gameProperties;
std::vector<Player *> players;
std::vector<PlayerPersistent> playerPersistents;
int localPlayerIndex;
std::array<std::unique_ptr<Player>, NumPlayerSlots> players;
std::array<PlayerPersistent, NumPlayerSlots> playerPersistents;
stmp::optional<int> localPlayerIndex;
std::list<Grenade *> grenades;
std::list<std::unique_ptr<Grenade>> grenades;
std::unique_ptr<HitTestDebugger> hitTestDebugger;
std::unordered_map<CellPos, spades::IntVector3, CellPosHash> createdBlocks;
@ -87,40 +93,43 @@ namespace spades {
void ApplyBlockActions();
public:
World(const std::shared_ptr<GameProperties>&);
World(const std::shared_ptr<GameProperties> &);
~World();
GameMap *GetMap() { return map; }
GameMapWrapper *GetMapWrapper() { return mapWrapper; }
const Handle<GameMap> &GetMap() { return map; }
GameMapWrapper &GetMapWrapper() { return *mapWrapper; }
float GetTime() { return time; }
/** Returns a non-null reference to `GameProperties`. */
const std::shared_ptr<GameProperties> &GetGameProperties() { return gameProperties; }
void SetMap(GameMap *);
void SetMap(Handle<GameMap>);
IntVector3 GetFogColor() { return fogColor; }
void SetFogColor(IntVector3 v) { fogColor = v; }
void Advance(float dt);
void AddGrenade(Grenade *);
std::vector<Grenade *> GetAllGrenades();
void AddGrenade(std::unique_ptr<Grenade>);
const std::list<std::unique_ptr<Grenade>> &GetAllGrenades() { return grenades; }
void MarkBlockForRegeneration(const IntVector3 &blockLocation);
void UnmarkBlockForRegeneration(const IntVector3 &blockLocation);
std::vector<IntVector3> CubeLine(IntVector3 v1, IntVector3 v2, int maxLength);
Player *GetPlayer(unsigned int i) {
// SPAssert(i >= 0); lm: unsigned cannot be smaller than 0 :)
stmp::optional<Player &> GetPlayer(unsigned int i) {
SPAssert(i < players.size());
return players[i];
return players[i].get();
}
void SetPlayer(int i, Player *p);
void SetPlayer(int i, std::unique_ptr<Player> p);
IGameMode *GetMode() { return mode; }
void SetMode(IGameMode *);
/**
* Get the object containing data specific to the current game mode.
* Can be `{}` if the game mode is not specified yet.
*/
stmp::optional<IGameMode &> GetMode() { return mode.get(); }
void SetMode(std::unique_ptr<IGameMode>);
Team &GetTeam(int t) {
if (t >= 2 || t < 0) // spectator
@ -135,32 +144,33 @@ namespace spades {
struct WeaponRayCastResult {
bool hit, startSolid;
Player *player;
stmp::optional<int> playerId;
IntVector3 blockPos;
Vector3 hitPos;
hitTag_t hitFlag;
};
WeaponRayCastResult WeaponRayCast(Vector3 startPos, Vector3 dir, Player *exclude);
WeaponRayCastResult WeaponRayCast(Vector3 startPos, Vector3 dir,
stmp::optional<int> excludePlayerId);
size_t GetNumPlayerSlots() { return players.size(); }
size_t GetNumPlayers();
int GetLocalPlayerIndex() { return localPlayerIndex; }
stmp::optional<int> GetLocalPlayerIndex() { return localPlayerIndex; }
void SetLocalPlayerIndex(stmp::optional<int> p) { localPlayerIndex = p; }
void SetLocalPlayerIndex(int p) { localPlayerIndex = p; }
Player *GetLocalPlayer() {
if (GetLocalPlayerIndex() == -1)
return NULL;
return GetPlayer(GetLocalPlayerIndex());
/** Get the local player. Can be `nullptr`. */
stmp::optional<Player &> GetLocalPlayer() {
if (!GetLocalPlayerIndex())
return {};
return GetPlayer(*GetLocalPlayerIndex());
}
/** Can be `nullptr`. */
HitTestDebugger *GetHitTestDebugger();
void SetListener(IWorldListener *l) { listener = l; }
void SetListener(IWorldListener *newListener) { listener = newListener; }
IWorldListener *GetListener() { return listener; }
};
}
}
} // namespace client
} // namespace spades

View File

@ -83,19 +83,11 @@ namespace spades {
return {ptr, false};
}
T *operator->() {
T *operator->() const {
SPAssert(ptr != NULL);
return ptr;
}
const T *operator->() const {
SPAssert(ptr != NULL);
return ptr;
}
T &operator*() {
SPAssert(ptr != NULL);
return *ptr;
}
const T &operator*() const {
T &operator*() const {
SPAssert(ptr != NULL);
return *ptr;
}
@ -126,7 +118,7 @@ namespace spades {
ptr = NULL;
return p;
}
operator bool() { return ptr != NULL; }
operator bool() const { return ptr != NULL; }
bool operator==(const Handle &rhs) const { return ptr == rhs.ptr; }

View File

@ -115,13 +115,13 @@ namespace stmp {
if (!has_some) {
throw bad_optional_access{};
}
return *get_pointer();
return std::move(*get_pointer());
}
const T &&value() const && {
if (!has_some) {
throw bad_optional_access{};
}
return *get_pointer();
return std::move(*get_pointer());
}
template <class U> T value_or(U &&default_value) const & {
@ -131,14 +131,8 @@ namespace stmp {
return *this ? std::move(get()) : static_cast<T>(std::forward<U>(default_value));
}
T &operator->() {
assert(has_some);
return get();
}
const T &operator->() const {
assert(has_some);
return get();
}
T *operator->() { return &get(); }
const T *operator->() const { return &get(); }
T &operator*() {
assert(has_some);
@ -157,8 +151,141 @@ namespace stmp {
bool operator!=(const optional &rhs) const {
return has_some != rhs.has_some || (has_some && **this != *rhs);
}
template <class U> bool operator==(const U &rhs) const { return has_some && **this == rhs; }
template <class U> bool operator!=(const U &rhs) const { return !has_some || **this != rhs; }
};
template <class T, class U>
typename std::enable_if<!std::is_reference<T>::value, bool>::type
operator==(const U &lhs, const optional<T> rhs) {
return rhs && lhs == *rhs;
}
template <class T, class U>
typename std::enable_if<!std::is_reference<T>::value, bool>::type
operator!=(const U &lhs, const optional<T> rhs) {
return !rhs || lhs != *rhs;
}
/**
* Specialization of `optional` for references. Works very similarly to
* pointers, but it's better at communicating the nullability.
*
* Boost's `optional` has this, while C++17's `optional` doesn't.
*/
template <class T> class optional<T &> {
T *ptr;
public:
optional() : ptr(nullptr) {}
optional(T *v) : ptr(v) {}
optional(T &v) : ptr(&v) {}
optional(const optional &o) : ptr(o.ptr) {}
void reset() { ptr = nullptr; }
void operator=(const optional &o) { ptr = o.ptr; }
T *get_pointer() { return ptr; }
const T *get_pointer() const { return ptr; }
T &get() {
assert(ptr);
return *get_pointer();
}
const T &get() const {
assert(ptr);
return *get_pointer();
}
T &value() {
if (!ptr) {
throw bad_optional_access{};
}
return *get_pointer();
}
const T &value() const {
if (!ptr) {
throw bad_optional_access{};
}
return *get_pointer();
}
template <class U> T &value_or(U &&default_value) const & {
return *this ? get() : static_cast<T>(std::forward<U>(default_value));
}
template <class U> T &value_or(U &&default_value) && {
return *this ? std::move(get()) : static_cast<T>(std::forward<U>(default_value));
}
T *operator->() { return &get(); }
const T *operator->() const { return &get(); }
T &operator*() { return get(); }
const T &operator*() const { return get(); }
explicit operator bool() const { return !!ptr; }
bool operator==(const optional &rhs) const { return ptr == rhs.ptr; }
bool operator!=(const optional &rhs) const { return ptr != rhs.ptr; }
bool operator==(const T *rhs) const { return ptr == rhs; }
bool operator!=(const T *rhs) const { return ptr != rhs; }
};
template <class T> bool operator==(const T *lhs, const optional<T &> rhs) {
return lhs == rhs.get_pointer();
}
template <class T> bool operator!=(const T *lhs, const optional<T &> rhs) {
return lhs != rhs.get_pointer();
}
template <class T> class optional<const T &> {
const T *ptr;
public:
optional() : ptr(nullptr) {}
optional(const T *v) : ptr(v) {}
optional(const T &v) : ptr(&v) {}
optional(const optional &o) : ptr(o.ptr) {}
void reset() { ptr = nullptr; }
void operator=(const optional &o) { ptr = o.ptr; }
const T *get_pointer() const { return ptr; }
const T &get() const {
assert(ptr);
return *get_pointer();
}
const T &value() const {
if (!ptr) {
throw bad_optional_access{};
}
return *get_pointer();
}
template <class U> T &value_or(U &&default_value) const & {
return *this ? get() : static_cast<T>(std::forward<U>(default_value));
}
const T *operator->() const { return &get(); }
const T &operator*() const { return get(); }
explicit operator bool() const { return !!ptr; }
bool operator==(const optional &rhs) const { return ptr == rhs.ptr; }
bool operator!=(const optional &rhs) const { return ptr != rhs.ptr; }
bool operator==(const T *rhs) const { return ptr == rhs; }
bool operator!=(const T *rhs) const { return ptr != rhs; }
};
template <class T> bool operator==(const T *lhs, const optional<const T &> rhs) {
return lhs == rhs.get_pointer();
}
template <class T> bool operator!=(const T *lhs, const optional<const T &> rhs) {
return lhs != rhs.get_pointer();
}
template <class T> optional<typename std::decay<T>::type> make_optional(T &&value) {
return {std::forward<T>(value)};
}

View File

@ -194,22 +194,22 @@ namespace spades {
manager->CheckError(r);
r = eng->RegisterObjectMethod("GameMap",
"bool ClipBox(int, int, int)",
asMETHODPR(GameMap, ClipBox, (int,int,int), bool),
asMETHODPR(GameMap, ClipBox, (int,int,int) const, bool),
asCALL_THISCALL);
manager->CheckError(r);
r = eng->RegisterObjectMethod("GameMap",
"bool ClipWorld(int, int, int)",
asMETHODPR(GameMap, ClipBox, (int,int,int), bool),
asMETHODPR(GameMap, ClipBox, (int,int,int) const, bool),
asCALL_THISCALL);
manager->CheckError(r);
r = eng->RegisterObjectMethod("GameMap",
"bool ClipBox(float, float, float)",
asMETHODPR(GameMap, ClipBox, (float,float,float), bool),
asMETHODPR(GameMap, ClipBox, (float,float,float) const, bool),
asCALL_THISCALL);
manager->CheckError(r);
r = eng->RegisterObjectMethod("GameMap",
"bool ClipWorld(float, float, float)",
asMETHODPR(GameMap, ClipBox, (float,float,float), bool),
asMETHODPR(GameMap, ClipBox, (float,float,float) const, bool),
asCALL_THISCALL);
manager->CheckError(r);
r = eng->RegisterObjectMethod("GameMap",