diff --git a/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.cpp index 3b8f90b1078..1b0c5f95d6f 100644 --- a/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.cpp @@ -18,6 +18,7 @@ void CWeaponRPCs::LoadFunctions() { AddHandler(GIVE_WEAPON, GiveWeapon, "GiveWeapon"); AddHandler(TAKE_WEAPON, TakeWeapon, "TakeWeapon"); + AddHandler(TAKE_WEAPONS, TakeWeapons, "TakeWeapons"); AddHandler(TAKE_ALL_WEAPONS, TakeAllWeapons, "TakeAllWeapons"); AddHandler(SET_WEAPON_AMMO, SetWeaponAmmo, "SetWeaponAmmo"); AddHandler(SET_WEAPON_SLOT, SetWeaponSlot, "SetWeaponSlot"); @@ -185,6 +186,41 @@ void CWeaponRPCs::TakeWeapon(CClientEntity* pSource, NetBitStreamInterface& bitS } } +void CWeaponRPCs::TakeWeapons(CClientEntity* pSource, NetBitStreamInterface& bitStream) +{ + std::uint32_t count = 0; + if (!bitStream.Read(count)) + return; + + CClientPed* ped = m_pPedManager->Get(pSource->GetID(), true); + if (!ped) + return; + + for (std::uint32_t i = 0; i < count; i++) + { + unsigned char weaponID; + if (!bitStream.Read(weaponID)) + return; + + if (!CClientPickupManager::IsValidWeaponID(weaponID)) + continue; + + if (ped->IsLocalPlayer()) + { + ped->RemoveWeapon(static_cast(weaponID)); + } + else + { + CWeapon* playerWeapon = ped->GetWeapon(static_cast(weaponID)); + if (playerWeapon) + { + playerWeapon->SetAmmoInClip(0); + playerWeapon->SetAmmoTotal(0); + } + } + } +} + void CWeaponRPCs::TakeAllWeapons(CClientEntity* pSource, NetBitStreamInterface& bitStream) { CClientPed* pPed = m_pPedManager->Get(pSource->GetID(), true); diff --git a/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.h b/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.h index 8bc3437fe47..2f63b27b6c6 100644 --- a/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.h +++ b/Client/mods/deathmatch/logic/rpc/CWeaponRPCs.h @@ -20,6 +20,7 @@ class CWeaponRPCs : public CRPCFunctions DECLARE_ELEMENT_RPC(GiveWeapon); DECLARE_ELEMENT_RPC(TakeWeapon); + DECLARE_ELEMENT_RPC(TakeWeapons); DECLARE_ELEMENT_RPC(TakeAllWeapons); DECLARE_ELEMENT_RPC(GiveWeaponAmmo); DECLARE_ELEMENT_RPC(TakeWeaponAmmo); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 5cef09925e4..04b0841bb5f 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1655,6 +1655,8 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPlayerChangesProtectedData", "element, key, value", nullptr, false); m_Events.AddEvent("onPlayerChangesWorldSpecialProperty", "property, enabled", nullptr, false); m_Events.AddEvent("onPlayerTeleport", "previousX, previousY, previousZ, currentX, currentY, currentZ", nullptr, false); + m_Events.AddEvent("onPlayerWeaponGiven", "weaponID, weaponAmmo, weaponSlot", nullptr, false); + m_Events.AddEvent("onPlayerWeaponTaken", "weaponID, weaponAmmo, weaponSlot", nullptr, false); // Ped events m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false); @@ -1663,6 +1665,8 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPedWeaponSwitch", "previous, current", NULL, false); m_Events.AddEvent("onPedWeaponReload", "weapon, clip, ammo", nullptr, false); m_Events.AddEvent("onPedDamage", "loss", NULL, false); + m_Events.AddEvent("onPedWeaponGiven", "weaponID, weaponAmmo, weaponSlot", nullptr, false); + m_Events.AddEvent("onPedWeaponTaken", "weaponID, weaponAmmo, weaponSlot", nullptr, false); // Element events m_Events.AddEvent("onElementColShapeHit", "colshape, matchingDimension", NULL, false); diff --git a/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp b/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp index cdebcedcc24..1b462a95bc2 100644 --- a/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp +++ b/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp @@ -92,6 +92,7 @@ ADD_ENUM1(SET_VEHICLE_HEADLIGHT_COLOR) ADD_ENUM1(SET_VEHICLE_DOOR_OPEN_RATIO) ADD_ENUM1(GIVE_WEAPON) ADD_ENUM1(TAKE_WEAPON) +ADD_ENUM1(TAKE_WEAPONS) ADD_ENUM1(TAKE_ALL_WEAPONS) ADD_ENUM1(SET_WEAPON_AMMO) ADD_ENUM1(SET_WEAPON_SLOT) diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index cb1971e31b3..bc103da96c4 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -4807,6 +4807,15 @@ bool CStaticFunctionDefinitions::GiveWeapon(CElement* pElement, unsigned char uc if (pPed->IsSpawned()) { unsigned char ucCurrentWeapon = pPed->GetWeaponType(); + unsigned char ucWeaponSlot = CWeaponNames::GetSlotFromWeapon(ucWeaponID); + + CLuaArguments arguments; + arguments.PushNumber(ucWeaponID); + arguments.PushNumber(usAmmo); + arguments.PushNumber(ucWeaponSlot); + if (!pPed->CallEvent(IS_PLAYER(pElement) ? "onPlayerWeaponGiven" : "onPedWeaponGiven", arguments)) + return false; + if (ucCurrentWeapon != ucWeaponID && bSetAsCurrent) { // Call our weapon switch command @@ -4823,8 +4832,8 @@ bool CStaticFunctionDefinitions::GiveWeapon(CElement* pElement, unsigned char uc bSetAsCurrent = false; } - unsigned char ucWeaponSlot = CWeaponNames::GetSlotFromWeapon(ucWeaponID); unsigned char ucPreviousWeaponID = pPed->GetWeaponType(ucWeaponSlot); + pPed->SetWeaponType(ucWeaponID, ucWeaponSlot); if (bSetAsCurrent) pPed->SetWeaponSlot(ucWeaponSlot); @@ -4878,8 +4887,14 @@ bool CStaticFunctionDefinitions::TakeWeapon(CElement* pElement, unsigned char uc // Just because it's the same slot doesn't mean it's the same weapon -_- - Caz if (pPed->IsSpawned() && pPed->GetWeapon(ucWeaponSlot) && pPed->GetWeaponType(ucWeaponSlot) == ucWeaponID) { + CLuaArguments arguments; + arguments.PushNumber(ucWeaponID); + arguments.PushNumber(usAmmo); + arguments.PushNumber(ucWeaponSlot); + if (!pPed->CallEvent(IS_PLAYER(pElement) ? "onPlayerWeaponTaken" : "onPedWeaponTaken", arguments)) + return false; + CBitStream BitStream; - SWeaponTypeSync weaponType; weaponType.data.ucWeaponType = ucWeaponID; BitStream.pBitStream->Write(&weaponType); @@ -4930,14 +4945,48 @@ bool CStaticFunctionDefinitions::TakeAllWeapons(CElement* pElement) CPed* pPed = static_cast(pElement); if (pPed->IsSpawned()) { - CBitStream BitStream; - m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, TAKE_ALL_WEAPONS, *BitStream.pBitStream)); + std::vector weapons; for (unsigned char ucWeaponSlot = 0; ucWeaponSlot < WEAPON_SLOTS; ++ucWeaponSlot) { - pPed->SetWeaponType(0, ucWeaponSlot); - pPed->SetWeaponAmmoInClip(0, ucWeaponSlot); - pPed->SetWeaponTotalAmmo(0, ucWeaponSlot); + unsigned char ucWeaponID = pPed->GetWeaponType(ucWeaponSlot); + unsigned char ucAmmo = pPed->GetWeaponTotalAmmo(ucWeaponSlot); + + if (ucWeaponID > 0) + { + CLuaArguments arguments; + arguments.PushNumber(ucWeaponID); + arguments.PushNumber(ucAmmo); + arguments.PushNumber(ucWeaponSlot); + + bool shouldTake = true; + if (!pPed->CallEvent(IS_PLAYER(pElement) ? "onPlayerWeaponTaken" : "onPedWeaponTaken", arguments)) + shouldTake = false; + + if (shouldTake) + { + weapons.push_back(ucWeaponID); + + pPed->SetWeaponType(0, ucWeaponSlot); + pPed->SetWeaponAmmoInClip(0, ucWeaponSlot); + pPed->SetWeaponTotalAmmo(0, ucWeaponSlot); + } + } + } + + if (!weapons.empty()) + { + CBitStream BitStream; + std::uint32_t weaponsTaken = static_cast(weapons.size()); + + BitStream.pBitStream->Write(weaponsTaken); + + for (auto& weaponID : weapons) + { + BitStream.pBitStream->Write(weaponID); + } + + m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, TAKE_WEAPONS, *BitStream.pBitStream)); } return true; diff --git a/Shared/sdk/net/rpc_enums.h b/Shared/sdk/net/rpc_enums.h index 84c7518bc45..7a779e2ee58 100644 --- a/Shared/sdk/net/rpc_enums.h +++ b/Shared/sdk/net/rpc_enums.h @@ -293,5 +293,7 @@ enum eElementRPCFunctions SET_ELEMENT_ON_FIRE, + TAKE_WEAPONS, + NUM_RPC_FUNCS // Add above this line };