6437: Make team kills condensed in killfeed r=heinrich5991 a=VoxelDoesCode

For those who still have the killfeed on, I wanted to modernize it, by having team kills become one line instead of a bunch!

![image](https://user-images.githubusercontent.com/95713843/226060109-ed74c2f6-1289-4247-81dc-1725428ddf59.png)
## Checklist

- [x] Tested the change ingame
- [x] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: VoxelDoesCode <dante_n_cedroni@hotmail.com>
This commit is contained in:
bors[bot] 2023-04-21 10:37:40 +00:00 committed by GitHub
commit cdd19beee4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 32 deletions

View file

@ -513,4 +513,9 @@ Messages = [
NetIntAny("m_ServerTimeBest"), NetIntAny("m_ServerTimeBest"),
NetIntAny("m_PlayerTimeBest"), NetIntAny("m_PlayerTimeBest"),
]), ]),
NetMessageEx("Sv_KillMsgTeam", "killmsgteam@netmsg.ddnet.tw", [
NetIntRange("m_Team", 0, 'MAX_CLIENTS-1'),
NetIntRange("m_First", -1, 'MAX_CLIENTS-1'),
]),
] ]

View file

@ -6,10 +6,13 @@
#include <engine/textrender.h> #include <engine/textrender.h>
#include <game/generated/client_data.h> #include <game/generated/client_data.h>
#include <game/generated/protocol.h> #include <game/generated/protocol.h>
#include <game/localization.h>
#include "killmessages.h" #include "killmessages.h"
#include <game/client/animstate.h> #include <game/client/animstate.h>
#include <game/client/gameclient.h> #include <game/client/gameclient.h>
#include <game/client/prediction/entities/character.h>
#include <game/client/prediction/gameworld.h>
void CKillMessages::OnWindowResize() void CKillMessages::OnWindowResize()
{ {
@ -23,6 +26,7 @@ void CKillMessages::OnWindowResize()
void CKillMessages::OnReset() void CKillMessages::OnReset()
{ {
m_KillmsgCurrent = 0; m_KillmsgCurrent = 0;
for(auto &Killmsg : m_aKillmsgs) for(auto &Killmsg : m_aKillmsgs)
{ {
Killmsg.m_Tick = -100000; Killmsg.m_Tick = -100000;
@ -103,6 +107,83 @@ void CKillMessages::OnMessage(int MsgType, void *pRawMsg)
if(m_pClient->m_SuppressEvents) if(m_pClient->m_SuppressEvents)
return; return;
if(MsgType == NETMSGTYPE_SV_KILLMSGTEAM)
{
CNetMsg_Sv_KillMsgTeam *pMsg = (CNetMsg_Sv_KillMsgTeam *)pRawMsg;
// unpack messages
CKillMsg Kill;
Kill.m_aVictimName[0] = '\0';
Kill.m_aKillerName[0] = '\0';
std::vector<std::pair<int, int>> vStrongWeakSorted;
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_pClient->m_Teams.Team(i) == pMsg->m_Team)
{
CCharacter *pChr = m_pClient->m_GameWorld.GetCharacterByID(i);
vStrongWeakSorted.emplace_back(i, pMsg->m_First == i ? MAX_CLIENTS : pChr ? pChr->GetStrongWeakID() : 0);
}
}
std::stable_sort(vStrongWeakSorted.begin(), vStrongWeakSorted.end(), [](auto &Left, auto &Right) { return Left.second > Right.second; });
Kill.m_TeamSize = vStrongWeakSorted.size();
if(Kill.m_TeamSize > MAX_KILLMSG_TEAM_MEMBERS)
Kill.m_TeamSize = MAX_KILLMSG_TEAM_MEMBERS;
Kill.m_VictimID = vStrongWeakSorted[0].first;
if(Kill.m_VictimID >= 0 && Kill.m_VictimID < MAX_CLIENTS)
{
Kill.m_VictimTeam = m_pClient->m_aClients[Kill.m_VictimID].m_Team;
Kill.m_VictimDDTeam = pMsg->m_Team;
Kill.m_VictimRenderInfo[0] = m_pClient->m_aClients[Kill.m_VictimID].m_RenderInfo;
for(int i = 1; i < Kill.m_TeamSize; i++)
Kill.m_VictimRenderInfo[i] = m_pClient->m_aClients[vStrongWeakSorted[i].first].m_RenderInfo;
str_format(Kill.m_aVictimName, sizeof(Kill.m_aVictimName), Localize("Team %d"), Kill.m_VictimDDTeam);
}
Kill.m_KillerID = Kill.m_VictimID;
Kill.m_Weapon = -1;
Kill.m_ModeSpecial = 0;
Kill.m_Tick = Client()->GameTick(g_Config.m_ClDummy);
Kill.m_VitctimTextWidth = Kill.m_KillerTextWidth = 0.f;
float Width = 400 * 3.0f * Graphics()->ScreenAspect();
float Height = 400 * 3.0f;
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
Graphics()->MapScreen(0, 0, Width * 1.5f, Height * 1.5f);
CreateKillmessageNamesIfNotCreated(Kill);
int VictimSkinsValid = 0;
for(int i = 0; i < Kill.m_TeamSize; i++)
{
if((Kill.m_VictimRenderInfo[i].m_CustomColoredSkin && Kill.m_VictimRenderInfo[i].m_ColorableRenderSkin.m_Body.IsValid()) || (!Kill.m_VictimRenderInfo[i].m_CustomColoredSkin && Kill.m_VictimRenderInfo[i].m_OriginalRenderSkin.m_Body.IsValid()))
VictimSkinsValid++;
}
bool KillMsgValid = VictimSkinsValid == Kill.m_TeamSize;
if(KillMsgValid)
{
// add the message
m_KillmsgCurrent = (m_KillmsgCurrent + 1) % MAX_KILLMSGS;
TextRender()->DeleteTextContainer(m_aKillmsgs[m_KillmsgCurrent].m_VictimTextContainerIndex);
TextRender()->DeleteTextContainer(m_aKillmsgs[m_KillmsgCurrent].m_KillerTextContainerIndex);
m_aKillmsgs[m_KillmsgCurrent] = Kill;
}
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
}
if(MsgType == NETMSGTYPE_SV_KILLMSG) if(MsgType == NETMSGTYPE_SV_KILLMSG)
{ {
CNetMsg_Sv_KillMsg *pMsg = (CNetMsg_Sv_KillMsg *)pRawMsg; CNetMsg_Sv_KillMsg *pMsg = (CNetMsg_Sv_KillMsg *)pRawMsg;
@ -112,13 +193,15 @@ void CKillMessages::OnMessage(int MsgType, void *pRawMsg)
Kill.m_aVictimName[0] = '\0'; Kill.m_aVictimName[0] = '\0';
Kill.m_aKillerName[0] = '\0'; Kill.m_aKillerName[0] = '\0';
Kill.m_TeamSize = 1;
Kill.m_VictimID = pMsg->m_Victim; Kill.m_VictimID = pMsg->m_Victim;
if(Kill.m_VictimID >= 0 && Kill.m_VictimID < MAX_CLIENTS) if(Kill.m_VictimID >= 0 && Kill.m_VictimID < MAX_CLIENTS)
{ {
Kill.m_VictimTeam = m_pClient->m_aClients[Kill.m_VictimID].m_Team; Kill.m_VictimTeam = m_pClient->m_aClients[Kill.m_VictimID].m_Team;
Kill.m_VictimDDTeam = m_pClient->m_Teams.Team(Kill.m_VictimID); Kill.m_VictimDDTeam = m_pClient->m_Teams.Team(Kill.m_VictimID);
str_copy(Kill.m_aVictimName, m_pClient->m_aClients[Kill.m_VictimID].m_aName); str_copy(Kill.m_aVictimName, m_pClient->m_aClients[Kill.m_VictimID].m_aName);
Kill.m_VictimRenderInfo = m_pClient->m_aClients[Kill.m_VictimID].m_RenderInfo; Kill.m_VictimRenderInfo[0] = m_pClient->m_aClients[Kill.m_VictimID].m_RenderInfo;
} }
Kill.m_KillerID = pMsg->m_Killer; Kill.m_KillerID = pMsg->m_Killer;
@ -146,7 +229,7 @@ void CKillMessages::OnMessage(int MsgType, void *pRawMsg)
CreateKillmessageNamesIfNotCreated(Kill); CreateKillmessageNamesIfNotCreated(Kill);
bool KillMsgValid = (Kill.m_VictimRenderInfo.m_CustomColoredSkin && Kill.m_VictimRenderInfo.m_ColorableRenderSkin.m_Body.IsValid()) || (!Kill.m_VictimRenderInfo.m_CustomColoredSkin && Kill.m_VictimRenderInfo.m_OriginalRenderSkin.m_Body.IsValid()); bool KillMsgValid = (Kill.m_VictimRenderInfo[0].m_CustomColoredSkin && Kill.m_VictimRenderInfo[0].m_ColorableRenderSkin.m_Body.IsValid()) || (!Kill.m_VictimRenderInfo[0].m_CustomColoredSkin && Kill.m_VictimRenderInfo[0].m_OriginalRenderSkin.m_Body.IsValid());
// if killer != victim, killer must be valid too // if killer != victim, killer must be valid too
KillMsgValid &= Kill.m_KillerID == Kill.m_VictimID || ((Kill.m_KillerRenderInfo.m_CustomColoredSkin && Kill.m_KillerRenderInfo.m_ColorableRenderSkin.m_Body.IsValid()) || (!Kill.m_KillerRenderInfo.m_CustomColoredSkin && Kill.m_KillerRenderInfo.m_OriginalRenderSkin.m_Body.IsValid())); KillMsgValid &= Kill.m_KillerID == Kill.m_VictimID || ((Kill.m_KillerRenderInfo.m_CustomColoredSkin && Kill.m_KillerRenderInfo.m_ColorableRenderSkin.m_Body.IsValid()) || (!Kill.m_KillerRenderInfo.m_CustomColoredSkin && Kill.m_KillerRenderInfo.m_OriginalRenderSkin.m_Body.IsValid()));
if(KillMsgValid) if(KillMsgValid)
@ -224,7 +307,9 @@ void CKillMessages::OnRender()
if(m_aKillmsgs[r].m_VictimID >= 0) if(m_aKillmsgs[r].m_VictimID >= 0)
{ {
CTeeRenderInfo TeeInfo = m_aKillmsgs[r].m_VictimRenderInfo; for(int j = (m_aKillmsgs[r].m_TeamSize - 1); j >= 0; j--)
{
CTeeRenderInfo TeeInfo = m_aKillmsgs[r].m_VictimRenderInfo[j];
CAnimState *pIdleState = CAnimState::GetIdle(); CAnimState *pIdleState = CAnimState::GetIdle();
vec2 OffsetToMid; vec2 OffsetToMid;
@ -232,12 +317,13 @@ void CKillMessages::OnRender()
vec2 TeeRenderPos(x, y + 46.0f / 2.0f + OffsetToMid.y); vec2 TeeRenderPos(x, y + 46.0f / 2.0f + OffsetToMid.y);
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_PAIN, vec2(-1, 0), TeeRenderPos); RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_PAIN, vec2(-1, 0), TeeRenderPos);
x -= 44.0f;
}
} }
x -= 32.0f;
// render weapon // render weapon
x -= 44.0f; x -= 32.0f;
if(m_aKillmsgs[r].m_Weapon >= 0) if(m_aKillmsgs[r].m_Weapon >= 0)
{ {
Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeapons[m_aKillmsgs[r].m_Weapon]); Graphics()->TextureSet(GameClient()->m_GameSkin.m_aSpriteWeapons[m_aKillmsgs[r].m_Weapon]);
@ -313,7 +399,7 @@ void CKillMessages::RefindSkins()
{ {
const CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID]; const CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID];
if(Client.m_aSkinName[0] != '\0') if(Client.m_aSkinName[0] != '\0')
m_aKillmsgs[r].m_VictimRenderInfo = Client.m_RenderInfo; m_aKillmsgs[r].m_VictimRenderInfo[0] = Client.m_RenderInfo;
else else
m_aKillmsgs[r].m_VictimID = -1; m_aKillmsgs[r].m_VictimID = -1;
} }

View file

@ -5,10 +5,14 @@
#include <game/client/component.h> #include <game/client/component.h>
#include <game/client/render.h> #include <game/client/render.h>
class CKillMessages : public CComponent class CKillMessages : public CComponent
{ {
int m_SpriteQuadContainerIndex; int m_SpriteQuadContainerIndex;
enum
{
MAX_KILLMSGS = 5,
MAX_KILLMSG_TEAM_MEMBERS = 4,
};
public: public:
// kill messages // kill messages
@ -27,8 +31,7 @@ public:
char m_aVictimName[64]; char m_aVictimName[64];
int m_VictimTextContainerIndex; int m_VictimTextContainerIndex;
float m_VitctimTextWidth; float m_VitctimTextWidth;
CTeeRenderInfo m_VictimRenderInfo; CTeeRenderInfo m_VictimRenderInfo[MAX_KILLMSG_TEAM_MEMBERS];
int m_KillerID; int m_KillerID;
int m_KillerTeam; int m_KillerTeam;
char m_aKillerName[64]; char m_aKillerName[64];
@ -39,11 +42,7 @@ public:
int m_ModeSpecial; // for CTF, if the guy is carrying a flag for example int m_ModeSpecial; // for CTF, if the guy is carrying a flag for example
int m_Tick; int m_Tick;
int m_FlagCarrierBlue; int m_FlagCarrierBlue;
}; int m_TeamSize;
enum
{
MAX_KILLMSGS = 5,
}; };
private: private:

View file

@ -906,7 +906,7 @@ bool CCharacter::IncreaseArmor(int Amount)
return true; return true;
} }
void CCharacter::Die(int Killer, int Weapon) void CCharacter::Die(int Killer, int Weapon, bool SendKillMsg)
{ {
if(Server()->IsRecording(m_pPlayer->GetCID())) if(Server()->IsRecording(m_pPlayer->GetCID()))
Server()->StopRecord(m_pPlayer->GetCID()); Server()->StopRecord(m_pPlayer->GetCID());
@ -920,12 +920,15 @@ void CCharacter::Die(int Killer, int Weapon)
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
// send the kill message // send the kill message
if(SendKillMsg && (Team() == TEAM_FLOCK || Teams()->Count(Team()) == 1 || Teams()->GetTeamState(Team()) == CGameTeams::TEAMSTATE_OPEN))
{
CNetMsg_Sv_KillMsg Msg; CNetMsg_Sv_KillMsg Msg;
Msg.m_Killer = Killer; Msg.m_Killer = Killer;
Msg.m_Victim = m_pPlayer->GetCID(); Msg.m_Victim = m_pPlayer->GetCID();
Msg.m_Weapon = Weapon; Msg.m_Weapon = Weapon;
Msg.m_ModeSpecial = ModeSpecial; Msg.m_ModeSpecial = ModeSpecial;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1); Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
}
// a nice sound // a nice sound
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE, TeamMask()); GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE, TeamMask());

View file

@ -63,7 +63,7 @@ public:
void ResetInput(); void ResetInput();
void FireWeapon(); void FireWeapon();
void Die(int Killer, int Weapon); void Die(int Killer, int Weapon, bool SendKillMsg = true);
bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon); bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
bool Spawn(class CPlayer *pPlayer, vec2 Pos); bool Spawn(class CPlayer *pPlayer, vec2 Pos);

View file

@ -559,11 +559,11 @@ CCharacter *CPlayer::GetCharacter()
return 0; return 0;
} }
void CPlayer::KillCharacter(int Weapon) void CPlayer::KillCharacter(int Weapon, bool SendKillMsg)
{ {
if(m_pCharacter) if(m_pCharacter)
{ {
m_pCharacter->Die(m_ClientID, Weapon); m_pCharacter->Die(m_ClientID, Weapon, SendKillMsg);
delete m_pCharacter; delete m_pCharacter;
m_pCharacter = 0; m_pCharacter = 0;

View file

@ -59,7 +59,7 @@ public:
void OnPredictedEarlyInput(CNetObj_PlayerInput *pNewInput); void OnPredictedEarlyInput(CNetObj_PlayerInput *pNewInput);
void OnDisconnect(); void OnDisconnect();
void KillCharacter(int Weapon = WEAPON_GAME); void KillCharacter(int Weapon = WEAPON_GAME, bool SendKillMsg = true);
CCharacter *GetCharacter(); CCharacter *GetCharacter();
void SpectatePlayerName(const char *pName); void SpectatePlayerName(const char *pName);

View file

@ -453,7 +453,7 @@ void CGameTeams::KillTeam(int Team, int NewStrongID, int ExceptID)
GameServer()->m_apPlayers[i]->m_VotedForPractice = false; GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
if(i != ExceptID) if(i != ExceptID)
{ {
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF); GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF, false);
if(NewStrongID != -1 && i != NewStrongID) if(NewStrongID != -1 && i != NewStrongID)
{ {
GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer
@ -461,6 +461,12 @@ void CGameTeams::KillTeam(int Team, int NewStrongID, int ExceptID)
} }
} }
} }
// send the team kill message
CNetMsg_Sv_KillMsgTeam Msg;
Msg.m_Team = Team;
Msg.m_First = NewStrongID;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
} }
bool CGameTeams::TeamFinished(int Team) bool CGameTeams::TeamFinished(int Team)