diff --git a/src/game/features/players/teleport/TpToPlayerCamp.cpp b/src/game/features/players/teleport/TpToPlayerCamp.cpp new file mode 100644 index 00000000..bd79fed2 --- /dev/null +++ b/src/game/features/players/teleport/TpToPlayerCamp.cpp @@ -0,0 +1,47 @@ +#include "game/backend/Players.hpp" +#include "game/backend/Self.hpp" +#include "game/commands/PlayerCommand.hpp" +#include "game/features/Features.hpp" +#include "game/rdr/Natives.hpp" +#include "game/rdr/ScriptGlobal.hpp" +#include "util/teleport.hpp" + +namespace YimMenu::Features +{ + class TpToPlayerCamp: public PlayerCommand + { + using PlayerCommand::PlayerCommand; + static constexpr auto PlayerList = ScriptGlobal(1141332); + + virtual void OnCall(Player player) override + { + if (!PlayerList.CanAccess()) + return; + + for (int i = 0; i < 32; i++) + { + if (*PlayerList.At(i, 27).At(9).As() == player.GetId()) + { + auto Camp = ScriptGlobal(1141332).At(i, 27).At(20); + + if (!Camp.CanAccess()) + return; + + Vector3 CampCoords = *Camp.As(); + if (CampCoords != Vector3(0.f, 0.f, 0.f)) + { + if(YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), CampCoords + Vector3(1, 0, 0), true)) + g_Spectating = false; + } + else + { + Notifications::Show("Camp", "Unable to find player's camp", NotificationType::Error); + } + break; + } + } + } + }; + + static TpToPlayerCamp _TpToPlayerCamp{"tptoplayercamp", "Teleport To Player's Camp", "Teleport to the player's camp"}; +} \ No newline at end of file diff --git a/src/game/features/self/TpToMoonshineShack.cpp b/src/game/features/self/TpToMoonshineShack.cpp index 0d863bb6..c937de09 100644 --- a/src/game/features/self/TpToMoonshineShack.cpp +++ b/src/game/features/self/TpToMoonshineShack.cpp @@ -10,17 +10,24 @@ namespace YimMenu::Features class TpToMoonshineShack : public Command { using Command::Command; - static constexpr auto ShackBlip = ScriptGlobal(1297441).At(128); + static constexpr auto MoonshineShack = ScriptGlobal(1297441).At(128).At(1); virtual void OnCall() override { - if (ShackBlip.CanAccess()) + if (MoonshineShack.CanAccess()) { - Blip Shack = *ShackBlip.As(); - if (MAP::DOES_BLIP_EXIST(Shack)) + Vector3 ShackCoords; + switch (*MoonshineShack.As()) { - Vector3 ShackCoords = MAP::GET_BLIP_COORDS(Shack); - YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), ShackCoords, true); + case 0: ShackCoords = Vector3(1785.3f, -813.4f, 43.f); break; + case 1: ShackCoords = Vector3(-1088.43f, 706.8f, 104.5f); break; + case 2: ShackCoords = Vector3(-2777.04, -3051.f, 11.581f); break; + case 3: ShackCoords = Vector3(1627.f, 821.f, 145.f); break; + case 4: ShackCoords = Vector3(-1859.7f, -1730.3f, 109.5f); break; + } + if (ShackCoords != Vector3(0.f, 0.f, 0.f)) + { + YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), ShackCoords, false); } else { diff --git a/src/game/frontend/submenus/Players.cpp b/src/game/frontend/submenus/Players.cpp index b541a0a6..9f4d579e 100644 --- a/src/game/frontend/submenus/Players.cpp +++ b/src/game/frontend/submenus/Players.cpp @@ -287,6 +287,7 @@ namespace YimMenu::Submenus })); teleportGroup->AddItem(std::make_shared("tptoplayer"_J)); + teleportGroup->AddItem(std::make_shared("tptoplayercamp"_J)); teleportGroup->AddItem(std::make_shared("tpbehindplayer"_J)); teleportGroup->AddItem(std::make_shared("tpintovehicle"_J)); teleportGroup->AddItem(std::make_shared("bring"_J)); diff --git a/src/game/frontend/submenus/Recovery.cpp b/src/game/frontend/submenus/Recovery.cpp index f722733c..3de6cfe9 100644 --- a/src/game/frontend/submenus/Recovery.cpp +++ b/src/game/frontend/submenus/Recovery.cpp @@ -1,17 +1,22 @@ #include "Recovery.hpp" + +#include "core/commands/BoolCommand.hpp" +#include "core/commands/Commands.hpp" #include "game/backend/FiberPool.hpp" #include "game/frontend/items/Items.hpp" -#include "core/commands/Commands.hpp" -#include "core/commands/BoolCommand.hpp" +#include "game/rdr/ScriptFunction.hpp" +#include "game/rdr/Scripts.hpp" #include "util/Rewards.hpp" namespace YimMenu::Submenus { + Recovery::Recovery() : Submenu::Submenu("Recovery") { auto recovery = std::make_shared("Recovery"); auto spawnCollectiblesGroup = std::make_shared("Spawn Collectibles"); + auto spawnHerbsGroup = std::make_shared("Spawn Herbs"); auto recoveryOptions = std::make_shared("Options"); static auto recoveryCommand = Commands::GetCommand("recoveryenabled"_J); @@ -35,7 +40,6 @@ namespace YimMenu::Submenus {Rewards::eRewardType::TAROTCARDS_WANDS, "Tarot Cards - Wands"}, {Rewards::eRewardType::FOSSILS, "Fossils"}, {Rewards::eRewardType::EGGS, "Eggs"}, - {Rewards::eRewardType::HERBS, "Herbs"}, {Rewards::eRewardType::TREASURE, "Treasure Reward"}, {Rewards::eRewardType::CAPITALE, "Capitale"}, {Rewards::eRewardType::XP, "25K XP"}, @@ -44,6 +48,7 @@ namespace YimMenu::Submenus {Rewards::eRewardType::COLLECTORXP, "200 Collector XP"}, {Rewards::eRewardType::NATURALISTXP, "300 Naturalist XP"}, {Rewards::eRewardType::BOUNTYHUNTERXP, "200 Bounty Hunter XP"}, + {Rewards::eRewardType::TRADERGOODS, "Max Trader Goods"}, }; if (ImGui::BeginCombo("Rewards", reward_translations[selected].c_str())) @@ -81,9 +86,42 @@ namespace YimMenu::Submenus } } })); + spawnHerbsGroup->AddItem(std::make_shared([=] { + if (recoveryCommand->GetState()) + { + static joaat_t selectedHerb; + std::map herb_translations = {{"HERB_LOOT_ALASKAN_GINSENG"_J, "Alaskan Ginseng"},{"HERB_LOOT_AMERICAN_GINSENG"_J, "American Ginseng"},{"HERB_LOOT_BAY_BOLETE"_J, "Bay Bolete"},{"HERB_LOOT_BLACK_BERRY"_J, "Black Berry"},{"HERB_LOOT_BLACK_CURRANT"_J, "Black Currant"},{"HERB_LOOT_BURDOCK_ROOT"_J, "Burdock Root"},{"HERB_LOOT_CHANTERELLES"_J, "Chanterelles"},{"HERB_LOOT_COMMON_BULRUSH"_J, "Common Bulrush"},{"HERB_LOOT_CREEPING_THYME"_J, "Creeping Thyme"},{"HERB_LOOT_DESERT_SAGE"_J, "Desert Sage"},{"HERB_LOOT_ENGLISH_MACE"_J, "English Mace"},{"HERB_LOOT_EVERGREEN_HUCKLEBERRY"_J, "Evergreen Huckleberry"},{"HERB_LOOT_GOLDEN_CURRANT"_J, "Golden Currant"},{"HERB_LOOT_HUMMINGBIRD_SAGE"_J, "Hummingbird Sage"},{"HERB_LOOT_INDIAN_TOBACCO"_J, "Indian Tobacco"},{"HERB_LOOT_MILKWEED"_J, "Milkweed"},{"HERB_LOOT_OLEANDER_SAGE"_J, "Oleander Sage"},{"HERB_LOOT_OREGANO"_J, "Oregano"},{"HERB_LOOT_PARASOL_MUSHROOM"_J, "Parasol Mushroom"},{"HERB_LOOT_PRAIRIE_POPPY"_J, "Prairie Poppy"},{"HERB_LOOT_RAMS_HEAD"_J, "Rams Head"},{"HERB_LOOT_RED_RASPBERRY"_J, "Red Raspberry"},{"HERB_LOOT_RED_SAGE"_J, "Red Sage"},{"HERB_LOOT_VANILLA_FLOWER"_J, "Vanilla Flower"},{"HERB_LOOT_VIOLET_SNOWDROP"_J, "Violet Snowdrop"},{"HERB_LOOT_WILD_CARROTS"_J, "Wild Carrots"},{"HERB_LOOT_WILD_FEVERFEW"_J, "Wild Feverfew"},{"HERB_LOOT_WILD_MINT"_J, "Wild Mint"},{"HERB_LOOT_WINTERGREEN_BERRY"_J, "Wintergreen Berry"},{"HERB_LOOT_YARROW"_J, "Yarrow"},{"HERB_LOOT_AGARITA"_J, "Agarita"},{"HERB_LOOT_BITTERWEED"_J, "Bitterweed"},{"HERB_LOOT_BLUE_BONNET"_J, "Blue Bonnet"},{"HERB_LOOT_BLOOD_FLOWER"_J, "Blood Flower"},{"HERB_LOOT_CARDINAL_FLOWER"_J, "Cardinal Flower"},{"HERB_LOOT_CHOCOLATE_DAISY"_J, "Chocolate Daisy"},{"HERB_LOOT_CREEK_PLUM"_J, "Creek Plum"},{"HERB_LOOT_RHUBARB"_J, "Rhubarb"},{"HERB_LOOT_WISTERIA"_J, "Wisteria"},{"HERB_LOOT_HARRIETUM"_J, "Harrietum"},}; + if (ImGui::BeginCombo("Herbs", herb_translations[selectedHerb].c_str())) + { + for (auto& [herb, translation] : herb_translations) + { + if (ImGui::Selectable(std::string(translation).c_str(), herb == selectedHerb)) + { + selectedHerb = herb; + } + } + ImGui::EndCombo(); + } + + static int amount = 1; + ImGui::SliderInt("Amount", &amount, 1, 10); + + if (ImGui::Button("Give Selected")) + { + FiberPool::Push([] { + if (!Scripts::RequestScript("interactive_campfire"_J)) + return; + + for (int i = 0; i < amount; i++) + ScriptFunctions::GiveLootTableAward.StaticCall(selectedHerb, 0); + }); + } + } + })); recoveryOptions->AddItem(std::make_shared("unlimiteditems"_J)); recoveryOptions->AddItem(std::make_shared("fastmoonshine"_J)); recovery->AddItem(spawnCollectiblesGroup); + recovery->AddItem(spawnHerbsGroup); recovery->AddItem(recoveryOptions); AddCategory(std::move(recovery)); diff --git a/src/game/rdr/ScriptFunction.cpp b/src/game/rdr/ScriptFunction.cpp index 4db13f04..f639ac81 100644 --- a/src/game/rdr/ScriptFunction.cpp +++ b/src/game/rdr/ScriptFunction.cpp @@ -61,7 +61,7 @@ namespace YimMenu { } - void ScriptFunction::RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector& args) + void ScriptFunction::RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector& args, void* returnValue, uint32_t returnSize) { const auto globals_initialized = std::vector(50, true); // std::vector does weird stuff so we aren't using that @@ -69,6 +69,7 @@ namespace YimMenu auto old_thread_running = rage::tlsContext::Get()->m_RunningScript; auto stack = reinterpret_cast(thread->m_Stack); auto context = thread->m_Context; + auto top = context.m_StackPointer; for (auto& arg : args) stack[context.m_StackPointer++] = arg; @@ -85,9 +86,12 @@ namespace YimMenu rage::tlsContext::Get()->m_RunningScript = old_thread_running; *Pointers.CurrentScriptThread = old_thread; + + if (returnValue) + memcpy(returnValue, stack + top, returnSize); } - void ScriptFunction::StaticCall(const std::vector& args) + void ScriptFunction::StaticCallImpl(const std::vector& args, void* returnValue, uint32_t returnSize) { auto pc = GetPC(); auto program = Scripts::FindScriptProgram(m_Hash); @@ -103,13 +107,13 @@ namespace YimMenu thread->m_Context.m_StackSize = 25000; thread->m_Context.m_StackPointer = 1; - RunScript(thread, program, args); + RunScript(thread, program, args, returnValue, returnSize); delete[] stack; delete[] (uint8_t*)thread; } - void ScriptFunction::Call(const std::vector& args) + void ScriptFunction::CallImpl(const std::vector& args, void* returnValue, uint32_t returnSize) { auto pc = GetPC(); auto thread = Scripts::FindScriptThread(m_Hash); @@ -118,6 +122,6 @@ namespace YimMenu if (!pc || !thread || !program) return; - RunScript(thread, program, args); + RunScript(thread, program, args, returnValue, returnSize); } } \ No newline at end of file diff --git a/src/game/rdr/ScriptFunction.hpp b/src/game/rdr/ScriptFunction.hpp index acfd81c6..e0cac368 100644 --- a/src/game/rdr/ScriptFunction.hpp +++ b/src/game/rdr/ScriptFunction.hpp @@ -2,6 +2,8 @@ #include "core/memory/Pattern.hpp" #include "util/Joaat.hpp" +#include + namespace rage { class scrThread; @@ -19,22 +21,48 @@ namespace YimMenu std::optional GetPC(); - void RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector& args); + void RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector& args, void* returnValue, uint32_t returnSize); - void Call(const std::vector& args); + void CallImpl(const std::vector& args, void* returnValue = 0, uint32_t returnSize = 0); - void StaticCall(const std::vector& args); + void StaticCallImpl(const std::vector& args, void* returnValue = 0, uint32_t returnSize = 0); public: ScriptFunction(joaat_t hash, SimplePattern pattern); - // TODO: return value support + template + Ret StaticCall(Args... args) + { + std::vector params; + (params.push_back(static_cast(args)), ...); + + if constexpr (!std::is_same_v) + { + Ret returnValue; + StaticCallImpl(params, &returnValue, sizeof(returnValue)); + return returnValue; + } + else + { + StaticCallImpl(params); + } + } - template - void StaticCall(Args... args) + template + Ret Call(Args... args) { std::vector params; (params.push_back(static_cast(args)), ...); - StaticCall(params); + + if constexpr (!std::is_same_v) + { + Ret returnValue; + CallImpl(params, &returnValue, sizeof(returnValue)); + return returnValue; + } + else + { + CallImpl(params); + } } template @@ -42,7 +70,7 @@ namespace YimMenu { std::vector params; (params.push_back(static_cast(args)), ...); - Call(params); + CallImpl(params); } }; diff --git a/src/game/rdr/Scripts.cpp b/src/game/rdr/Scripts.cpp index 9222ae95..1d4d4395 100644 --- a/src/game/rdr/Scripts.cpp +++ b/src/game/rdr/Scripts.cpp @@ -4,6 +4,7 @@ #include