mirror of
https://github.com/YimMenu/YimMenuV2.git
synced 2026-10-10 03:43:15 +08:00
feat: Shoot Animals Photography (#427)
* feat: Shoot Animals Photography * Fix ptr name
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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.";
|
||||
|
||||
Reference in New Issue
Block a user