void Client::PlayerKilledPlayer(spades::client::Player *killer, spades::client::Player *victim, KillType kt) { // play hit sound if (kt == KillTypeWeapon || kt == KillTypeHeadshot) { // don't play on local: see BullethitPlayer if (victim != world->GetLocalPlayer()) { if (!IsMuted()) { Handle<IAudioChunk> c; switch (SampleRandomInt(0, 2)) { case 0: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus"); break; case 1: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh2.opus"); break; case 2: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh3.opus"); break; } AudioParam param; param.volume = 4.f; audioDevice->Play(c, victim->GetEye(), param); } } } // The local player is dead; initialize the look-you-are-dead cam if (victim == world->GetLocalPlayer()) { followCameraState.enabled = false; Vector3 v = -victim->GetFront(); followAndFreeCameraState.yaw = atan2(v.y, v.x); followAndFreeCameraState.pitch = 30.f * M_PI / 180.f; } // emit blood (also for local player) // FIXME: emiting blood for either // client-side or server-side hit? switch (kt) { case KillTypeGrenade: case KillTypeHeadshot: case KillTypeMelee: case KillTypeWeapon: Bleed(victim->GetEye()); break; default: break; } // create ragdoll corpse if (cg_ragdoll && victim->GetTeamId() < 2) { Corpse *corp; corp = new Corpse(renderer, map, victim); if (victim == world->GetLocalPlayer()) lastMyCorpse = corp; if (killer != victim && kt != KillTypeGrenade) { Vector3 dir = victim->GetPosition() - killer->GetPosition(); dir = dir.Normalize(); if (kt == KillTypeMelee) { dir *= 6.f; } else { if (killer->GetWeapon()->GetWeaponType() == SMG_WEAPON) { dir *= 2.8f; } else if (killer->GetWeapon()->GetWeaponType() == SHOTGUN_WEAPON) { dir *= 4.5f; } else { dir *= 3.5f; } } corp->AddImpulse(dir); } else if (kt == KillTypeGrenade) { corp->AddImpulse(MakeVector3(0, 0, -4.f - SampleRandomFloat() * 4.f)); } corp->AddImpulse(victim->GetVelocty() * 32.f); corpses.emplace_back(corp); if (corpses.size() > corpseHardLimit) { corpses.pop_front(); } else if (corpses.size() > corpseSoftLimit) { RemoveInvisibleCorpses(); } } // add chat message std::string s; s = ChatWindow::TeamColorMessage(killer->GetName(), killer->GetTeamId()); std::string cause; bool isFriendlyFire = killer->GetTeamId() == victim->GetTeamId(); if (killer == victim) isFriendlyFire = false; Weapon *w = killer ? killer->GetWeapon() : nullptr; // only used in case of KillTypeWeapon switch (kt) { case KillTypeWeapon: switch (w ? w->GetWeaponType() : RIFLE_WEAPON) { case RIFLE_WEAPON: cause += _Tr("Client", "Rifle"); break; case SMG_WEAPON: cause += _Tr("Client", "SMG"); break; case SHOTGUN_WEAPON: cause += _Tr("Client", "Shotgun"); break; } break; case KillTypeFall: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Fall"); break; case KillTypeMelee: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Melee"); break; case KillTypeGrenade: cause += _Tr("Client", "Grenade"); break; case KillTypeHeadshot: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Headshot"); break; case KillTypeTeamChange: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Team Change"); break; case KillTypeClassChange: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Weapon Change"); break; default: cause += "???"; break; } s += " ["; if (isFriendlyFire) s += ChatWindow::ColoredMessage(cause, MsgColorFriendlyFire); 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()); } 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()); } else { 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) { std::string msg; if (killer == local) { if ((int)cg_centerMessage == 2) msg = _Tr("Client", "You have killed {0}", victim->GetName()); } else { msg = _Tr("Client", "You were killed by {0}", killer->GetName()); } centerMessageView->AddMessage(msg); } } }