Kill Alerts + New Sound functions from Lua

ximboliex

Pirate
Registered
LV
0
 
Joined
Jan 29, 2026
Messages
21
Reaction score
17
Points
8
Location
Panama
Today I bring you a bonus to spice up PK with multi-kill announcements and auxiliary functions to play sounds from Lua, by party, ChaID or global map

OK let's Start

Src/Libraries/common/include/NetCommnad.h add this:
C++:
#define CMD_MC_PLAYSOUND  CMD_MC_BASE + 118


Now we work on GS

Src/GameServer/src/SubMap.h add this:
C++:
void     PlaySoundMap(short sSoundID);

Src/GameServer/src/SubMap.cpp add this:
C++:
void SubMap::PlaySoundMap(short soundID)
{
    WPACKET WtPk = GETWPACKET();

    WRITE_CMD(WtPk, CMD_MC_PLAYSOUND);
    WRITE_SHORT(WtPk, soundID);

    CPlayer* pHeadPlayer = 0;
    CPlayer* pLastPlayer = 0;

    CEyeshotCell* pCEyeCell;
    CCharacter* pCCha;
    Long lChaCount, lChaNum;

    m_CEyeshotCellL.BeginGet();

    while (pCEyeCell = m_CEyeshotCellL.GetNext())
    {
        lChaCount = 0;
        lChaNum = pCEyeCell->GetChaNum();
        pCCha = pCEyeCell->m_pCChaL;

        while (pCCha)
        {
            if (++lChaCount > lChaNum)
                break;

            if (pCCha->IsPlayerFocusCha())
            {
                if (!pHeadPlayer)
                {
                    pHeadPlayer = pCCha->GetPlayer();
                    pLastPlayer = pHeadPlayer;
                }
                else
                {
                    pLastPlayer->GetNextPlayer() =
                        pCCha->GetPlayer();

                    pLastPlayer =
                        (CPlayer*)pLastPlayer->GetNextPlayer();
                }
            }

            if (pCCha->m_pCEyeshotCellNext)
                pCCha =
                    pCCha->m_pCEyeshotCellNext->IsCharacter();
            else
                pCCha = 0;
        }
    }

    if (pLastPlayer)
        pLastPlayer->GetNextPlayer() = NULL;

    SENDTOCLIENT(WtPk, pHeadPlayer);
}


Src/GameServer/src/Character.h add this:
C++:
int                 AddMultiKill();
int                 GetMultiKill();
DWORD                 m_dwLastPvPKill;
BYTE                  m_btMultiKill;


Now search chatColour(0xFFFFFFFF), in Src/GameServer/Character.cpp and right below it adds
C++:
m_dwLastPvPKill(0),
m_btMultiKill(0),



Src/Gameserver/src/Character.cpp add this:
C++:
int CCharacter::AddMultiKill()
{
    DWORD now = GetTickCount();

    DWORD window = 10000;

    switch (m_btMultiKill)
    {
    case 1: window = 10000; break; // secs to Double
    case 2: window = 10000;  break; // secs to Triple
    case 3: window = 10000;  break; // secs to Quadra
    case 4: window = 10000;  break; // secs to Penta
    }

    if (now - m_dwLastPvPKill > window)
    {
        m_btMultiKill = 0;
        m_dwLastPvPKill = 0;
    }

    m_btMultiKill++;

    if (m_btMultiKill > 5)
        m_btMultiKill = 5;

    m_dwLastPvPKill = now;

    return m_btMultiKill;
}


Now we will explain the functions in Lua

Src/GameServer/src/Expand.h :
C++:
inline int lua_PlaySoundCha(lua_State* L)
{
    CCharacter* pCha =
        (CCharacter*)lua_touserdata(L, 1);

    short soundID =
        (short)lua_tonumber(L, 2);

    if (!pCha)
        return 0;

    WPACKET pk = GETWPACKET();

    WRITE_CMD(pk, CMD_MC_PLAYSOUND);
    WRITE_SHORT(pk, soundID);

    pCha->ReflectINFof(pCha, pk);

    return 0;
}



inline int lua_PlaySoundToParty(lua_State* L)
{
    CCharacter* pCha =
        (CCharacter*)lua_touserdata(L, 1);

    short soundID =
        (short)lua_tonumber(L, 2);

    if (!pCha)
        return 0;

    CPlayer* cPly = pCha->GetPlayer();

    if (!cPly || !cPly->HasTeam())
        return 0;

    WPACKET pk = GETWPACKET();

    WRITE_CMD(pk, CMD_MC_PLAYSOUND);
    WRITE_SHORT(pk, soundID);

    pCha->ReflectINFof(pCha, pk);

    int partyCnt = cPly->GetTeamMemberCnt();

    for (int i = 0; i < partyCnt; i++)
    {
        CPlayer* pMember =
            g_pGameApp->GetPlayerByDBID(
                cPly->GetTeamMemberDBID(i)
            );

        if (!pMember)
            continue;

        CCharacter* pMemberCha =
            pMember->GetCtrlCha();

        if (!pMemberCha)
            continue;

        pMemberCha->ReflectINFof(
            pMemberCha,
            pk
        );
    }

    return 0;
}

inline int lua_PlayMapSound(lua_State* L)
{
    CCharacter* pCha =
        (CCharacter*)lua_touserdata(L, 1);

    short soundID =
        (short)lua_tonumber(L, 2);

    if (pCha && pCha->GetSubMap())
    {
        pCha->GetSubMap()->PlaySoundMap(soundID);
    }

    return 0;
}

inline int lua_AddMultiKill(lua_State* L)
{
    CCharacter* pCha =
        (CCharacter*)lua_touserdata(L, 1);

    lua_pushnumber(
        L,
        pCha->AddMultiKill()
    );

    return 1;
}

And records the functions:
C++:
REGFN(PlaySoundCha);
REGFN(PlaySoundToParty);
REGFN(PlayMapSound);
REGFN(AddMultiKill);

Now let's start with the client

Src/Client/src/NetIF.cpp search CMD_MC_VOLUNTER_ASK and add this just below:
C++:
    case CMD_MC_PLAYSOUND:
    {
        SC_ServerPlaySound(pk);
        return TRUE;
    }

Src/Client/src/PacketCmd.h add this just before #endif
C++:
extern void SC_ServerPlaySound(LPRPACKET pk);

Src/Client/src/PacketCmd_SC.cpp add this
C++:
void SC_ServerPlaySound(LPRPACKET pk)
{
    short SoundID = pk.ReadShort();

    g_pGameApp->PlaySound(SoundID);
}


We're going to configure it on the server

scripts/calculate/function.lua search after_player_kill_player(ATKER, DEFER) and just below local DEFER_Get1_Ry = 0 add this
C++:
    local MultiKill = AddMultiKill(ATKER)

    if MultiKill == 2 then

        Notice("[DOUBLE KILL] "..GetChaDefaultName(ATKER).." has achieved a Double Kill!")
        PlayMapSound(ATKER, 457)

    elseif MultiKill == 3 then

        Notice("[TRIPLE KILL] "..GetChaDefaultName(ATKER).." has achieved a Triple Kill!")
        PlayMapSound(ATKER, 458)

    elseif MultiKill == 4 then

        Notice("[QUADRA KILL] "..GetChaDefaultName(ATKER).." has achieved a Quadra Kill!")
        PlayMapSound(ATKER, 459)

    elseif MultiKill == 5 then

        Notice("[PENTA KILL] "..GetChaDefaultName(ATKER).." has achieved a P-P-P Penta Kill!")
        PlayMapSound(ATKER, 460)

    end


Now we're going to add sound to the client

music/sound/combat/ Add the sounds here, which I will attach for download

To finish let's just add the sounds to musicinfo.txt
Code:
457    music/sound/combat/doublek.wav    1
458    music/sound/combat/triplek.wav    1
459    music/sound/combat/quadrak.wav    1
460    music/sound/combat/pentak.wav    1
461    music/sound/combat/sysnoti.wav    1


The new features work as follows
PlaySoundCha(role, soundID)
- Plays a sound for a specific player only.

PlaySoundToParty(role, soundID)
- Plays a sound for all members of the player's party.

PlayMapSound(role, soundID)
- Plays a sound for all players within the current map. It can be the ID of the attacker or the victim, it is only used to obtain the map.

AddMultiKill(role)
- Returns the player's current PvP kill streak level.

Example Usage:
C++:
local MultiKill = AddMultiKill(ATKER)



if MultiKill == 2 then

    Notice(GetChaDefaultName(ATKER).." achieved DOUBLE KILL!")

    PlayMapSound(ATKER, 457)



elseif MultiKill == 3 then

    Notice(GetChaDefaultName(ATKER).." achieved TRIPLE KILL!")

    PlayMapSound(ATKER, 458)



elseif MultiKill == 4 then

    Notice(GetChaDefaultName(ATKER).." achieved QUADRA KILL!")

    PlayMapSound(ATKER, 459)



elseif MultiKill == 5 then

    Notice(GetChaDefaultName(ATKER).." achieved PENTA KILL!")

    PlayMapSound(ATKER, 460)

end



Besides alerts, a range of options now opens up with sound playback from Lua. Ejoy!
 

Attachments