feat: Shoot Animals Photography (#427)

* feat: Shoot Animals Photography

* Fix ptr name
This commit is contained in:
Arthur
2025-06-14 21:48:41 +03:00
committed by GitHub
parent 1e62d31001
commit 0e36f887d7
4 changed files with 157 additions and 16 deletions
@@ -6,6 +6,7 @@
#include "game/backend/Self.hpp"
#include "game/backend/ScriptPatches.hpp"
#include "game/backend/Tunables.hpp"
#include "game/gta/Ped.hpp"
#include "game/gta/Natives.hpp"
#include "game/gta/Scripts.hpp"
#include "game/gta/Stats.hpp"
@@ -79,6 +80,36 @@ namespace YimMenu::Features
{{0, "LS Tag 1"}, {1, "LS Tag 2"}, {2, "LS Tag 3"}, {3, "LS Tag 4"}, {4, "LS Tag 5"}}
};
static ListCommand animalIndex = {
"animalindex",
"Animal",
"Selected Animal",
{{0, "Animal 1"}, {1, "Animal 2"}, {2, "Animal 3"}}
};
static constexpr auto wildlifePhotographyAnimalHashes = std::to_array({
"A_C_Boar"_J,
"A_C_Cat_01"_J,
"A_C_Cow"_J,
"A_C_Coyote"_J,
"A_C_Deer"_J,
"A_C_Husky"_J,
"A_C_MtLion"_J,
"A_C_Pig"_J,
"A_C_Poodle"_J,
"A_C_Pug"_J,
"A_C_Rabbit_01"_J,
"A_C_Retriever"_J,
"A_C_Rottweiler"_J,
"A_C_shepherd"_J,
"A_C_Westy"_J,
"A_C_Chickenhawk"_J,
"A_C_Cormorant"_J,
"A_C_Crow"_J,
"A_C_Hen"_J,
"A_C_Seagull"_J
});
static void SetAllDailyActivitiesCompleted(bool completed)
{
Stats::SetPackedBool(36628, completed); // G's Cache
@@ -934,6 +965,56 @@ namespace YimMenu::Features
}
};
class SpawnAnimal : public Command
{
using Command::Command;
virtual void OnCall() override
{
if (!*Pointers.IsSessionStarted)
return;
if (!Stats::GetPackedBool(42059 + animalIndex.GetState()))
{
int index = Stats::GetPackedInt(28091 + animalIndex.GetState());
if (index < 0 || index >= wildlifePhotographyAnimalHashes.size())
return;
Ped::Create(wildlifePhotographyAnimalHashes[index], Self::GetPed().GetPosition());
}
else
{
Notifications::Show("Shoot Animals Photography", "This animal has already been photographed.", NotificationType::Error);
}
}
};
class PhotographAnimal : public Command
{
using Command::Command;
virtual void OnCall() override
{
if (!*Pointers.IsSessionStarted)
return;
if (!Stats::GetPackedBool(42059 + animalIndex.GetState()))
{
int index = Stats::GetPackedInt(28091 + animalIndex.GetState());
if (index < 0 || index >= wildlifePhotographyAnimalHashes.size())
return;
ScriptGlobal(2708543).At(544).As<SCR_BITSET<uint64_t>*>()->Set(6);
*ScriptGlobal(2708543).At(547).As<joaat_t*>() = wildlifePhotographyAnimalHashes[index];
*ScriptGlobal(2708543).At(548).As<int*>() = *Pointers.GameTimer - 1; // bypass 2 sec delay
}
else
{
Notifications::Show("Shoot Animals Photography", "This animal has already been photographed.", NotificationType::Error);
}
}
};
static SetAllActivitiesCompleted _SetAllActivitiesCompleted{"setallactivitiescompleted", "Set All Activities Completed", "Switch session to apply the changes."};
static ResetAllActivities _ResetAllActivities{"resetallactivities", "Reset All Activities", "Switch session to apply the changes."};
@@ -976,4 +1057,7 @@ namespace YimMenu::Features
static TeleportToMadrazoHit _TeleportToMadrazoHit{"tptomadrazohit", "Teleport to Madrazo Hit", "Teleports to Madrazo Hit."};
static TeleportToMadrazoHitTarget _TeleportToMadrazoHitTarget{"tptomadrazohittarget", "Teleport to Madrazo Hit Target", "Teleports to Madrazo Hit Target."};
static SpawnAnimal _SpawnAnimal{"spawnanimal", "Spawn Animal", "Spawns the selected animal."};
static PhotographAnimal _PhotographAnimal{"photographanimal", "Photograph Animal", "Photographs the selected animal."};
}
@@ -6,19 +6,20 @@ namespace YimMenu::Submenus
{
auto dailyActivities = std::make_shared<Category>("Daily Activities");
auto challengesTab = std::make_shared<CollapsingHeaderItem>("Challenges");
auto hiddenCacheTab = std::make_shared<CollapsingHeaderItem>("Hidden Caches");
auto treasureChestTab = std::make_shared<CollapsingHeaderItem>("Treasure Chests");
auto shipwreckedTab = std::make_shared<CollapsingHeaderItem>("Shipwreck");
auto buriedStashTab = std::make_shared<CollapsingHeaderItem>("Buried Stashes");
auto skydiveTab = std::make_shared<CollapsingHeaderItem>("Junk Energy Skydives");
auto timeTrialsTab = std::make_shared<CollapsingHeaderItem>("Time Trials");
auto exoticExportsTab = std::make_shared<CollapsingHeaderItem>("Exotic Exports");
auto deadDropTab = std::make_shared<CollapsingHeaderItem>("G's Cache");
auto stashHouseTab = std::make_shared<CollapsingHeaderItem>("Stash House");
auto streetDealerTab = std::make_shared<CollapsingHeaderItem>("Street Dealers");
auto lsTagsTab = std::make_shared<CollapsingHeaderItem>("LS Tags");
auto madrazoHitsTab = std::make_shared<CollapsingHeaderItem>("Madrazo Hits");
auto challengesTab = std::make_shared<CollapsingHeaderItem>("Challenges");
auto hiddenCacheTab = std::make_shared<CollapsingHeaderItem>("Hidden Caches");
auto treasureChestTab = std::make_shared<CollapsingHeaderItem>("Treasure Chests");
auto shipwreckedTab = std::make_shared<CollapsingHeaderItem>("Shipwreck");
auto buriedStashTab = std::make_shared<CollapsingHeaderItem>("Buried Stashes");
auto skydiveTab = std::make_shared<CollapsingHeaderItem>("Junk Energy Skydives");
auto timeTrialsTab = std::make_shared<CollapsingHeaderItem>("Time Trials");
auto exoticExportsTab = std::make_shared<CollapsingHeaderItem>("Exotic Exports");
auto deadDropTab = std::make_shared<CollapsingHeaderItem>("G's Cache");
auto stashHouseTab = std::make_shared<CollapsingHeaderItem>("Stash House");
auto streetDealerTab = std::make_shared<CollapsingHeaderItem>("Street Dealers");
auto lsTagsTab = std::make_shared<CollapsingHeaderItem>("LS Tags");
auto madrazoHitsTab = std::make_shared<CollapsingHeaderItem>("Madrazo Hits");
auto wildlifePhotography = std::make_shared<CollapsingHeaderItem>("Shoot Animals Photography");
dailyActivities->AddItem(std::make_shared<CommandItem>("setallactivitiescompleted"_J));
dailyActivities->AddItem(std::make_shared<CommandItem>("resetallactivities"_J));
@@ -71,6 +72,10 @@ namespace YimMenu::Submenus
madrazoHitsTab->AddItem(std::make_shared<CommandItem>("tptomadrazohit"_J));
madrazoHitsTab->AddItem(std::make_shared<CommandItem>("tptomadrazohittarget"_J));
wildlifePhotography->AddItem(std::make_shared<ListCommandItem>("animalindex"_J));
wildlifePhotography->AddItem(std::make_shared<CommandItem>("spawnanimal"_J));
wildlifePhotography->AddItem(std::make_shared<CommandItem>("photographanimal"_J));
dailyActivities->AddItem(std::move(challengesTab));
dailyActivities->AddItem(std::move(hiddenCacheTab));
dailyActivities->AddItem(std::move(treasureChestTab));
@@ -84,6 +89,7 @@ namespace YimMenu::Submenus
dailyActivities->AddItem(std::move(streetDealerTab));
dailyActivities->AddItem(std::move(lsTagsTab));
dailyActivities->AddItem(std::move(madrazoHitsTab));
dailyActivities->AddItem(std::move(wildlifePhotography));
return dailyActivities;
}
}
+49 -3
View File
@@ -17,6 +17,33 @@ namespace YimMenu::Submenus
joaat_t hash;
};
static void FetchWeaponStats(joaat_t weaponHash, int& kills, int& deaths, float& kd, int& headshots, int& accuracy)
{
uint64_t garbage[4]{};
if (auto id = Scripts::StartScript("mp_weapons"_J, eStackSizes::PAUSE_MENU_SCRIPT, &garbage, 4))
{
if (auto thread = Scripts::FindScriptThreadByID(id))
{
thread->m_Context.m_State = rage::scrThread::State::PAUSED;
static ScriptFunction getWeaponKills("mp_weapons"_J, ScriptPointer("GetWeaponKills", "5D ? ? ? 39 0F 38 00").Add(1).Rip());
static ScriptFunction getWeaponDeaths("mp_weapons"_J, ScriptPointer("GetWeaponDeaths", "5D ? ? ? 39 10").Add(1).Rip());
static ScriptFunction getWeaponKDRatio("mp_weapons"_J, ScriptPointer("GetWeaponKDRatio", "5D ? ? ? 39 12").Add(1).Rip());
static ScriptFunction getWeaponHeadshots("mp_weapons"_J, ScriptPointer("GetWeaponHeadshots", "5D ? ? ? 39 11").Add(1).Rip());
static ScriptFunction getWeaponAccuracy("mp_weapons"_J, ScriptPointer("GetWeaponAccuracy", "2D 01 09 00 00"));
kills = getWeaponKills.Call<int>(weaponHash, -1);
deaths = getWeaponDeaths.Call<int>(weaponHash, -1);
kd = getWeaponKDRatio.Call<float>(weaponHash, -1);
headshots = getWeaponHeadshots.Call<int>(weaponHash, -1);
accuracy = static_cast<int>(getWeaponAccuracy.Call<float>(weaponHash));
thread->Kill();
thread->m_Context.m_State = rage::scrThread::State::KILLED;
}
}
}
static void RenderAmmuNationMenu()
{
static std::vector<WeaponDisplay> weaponDisplays;
@@ -24,12 +51,19 @@ namespace YimMenu::Submenus
static joaat_t selectedWeaponHash{};
static char searchWeapon[64];
static int kills{};
static int deaths{};
static float kdRatio{};
static int headshots{};
static int accuracy{};
static bool init = [] {
FiberPool::Push([] {
while (Scripts::IsScriptActive("startup"_J))
ScriptMgr::Yield();
if (auto id = Scripts::StartScript("mp_weapons"_J))
uint64_t garbage[4]{};
if (auto id = Scripts::StartScript("mp_weapons"_J, eStackSizes::PAUSE_MENU_SCRIPT, &garbage, 4))
{
if (auto thread = Scripts::FindScriptThreadByID(id))
{
@@ -85,8 +119,11 @@ namespace YimMenu::Submenus
ImGui::PushID(weap.hash);
if (ImGui::Selectable(weap.name.c_str()))
{
selectedWeapon = weap.name;
selectedWeaponHash = weap.hash;
FiberPool::Push([weap] {
selectedWeapon = weap.name;
selectedWeaponHash = weap.hash;
FetchWeaponStats(selectedWeaponHash, kills, deaths, kdRatio, headshots, accuracy);
});
}
ImGui::PopID();
if (ImGui::IsItemHovered() && !weap.desc.empty())
@@ -115,6 +152,15 @@ namespace YimMenu::Submenus
Self::GetPed().RemoveWeapon(selectedWeaponHash);
});
}
if (*Pointers.IsSessionStarted && selectedWeaponHash != NULL)
{
ImGui::Text("Kills With: %d", kills);
ImGui::Text("Deaths By: %d", deaths);
ImGui::Text("K/D Ratio: %.2f", kdRatio);
ImGui::Text("Headshots: %d", headshots);
ImGui::Text("Accuracy: %d%%", accuracy);
}
}
std::shared_ptr<Category> BuildWeaponsMenu()
+5
View File
@@ -395,6 +395,11 @@ namespace YimMenu
GameSkeleton = ptr.Add(0x9).Add(3).Rip().As<rage::gameSkeleton*>();
});
constexpr auto SetExplosiveAmmoOnlinePatchPtrn = Pattern<"48 83 EC 28 80 3D ? ? ? ? 00 0F 85 ? ? ? ? E9 ? ? ? ? 48 8B 45 28">("SetExplosiveAmmoOnlinePatch");
scanner.Add(SetExplosiveAmmoOnlinePatchPtrn, [this](PointerCalculator ptr) {
BytePatches::Add(ptr.Add(0xB).As<std::uint16_t*>(), 0x04EB)->Apply();
});
if (!scanner.Scan())
{
LOG(FATAL) << "Some patterns could not be found, unloading.";