feat(world): improve ped spawner

This commit is contained in:
maybegreat48
2025-06-23 02:57:26 -04:00
parent 2abf551ccc
commit 41fdc31681
11 changed files with 1442 additions and 55 deletions
-26
View File
@@ -6,34 +6,9 @@
namespace YimMenu::Features
{
static StringCommand _VehicleModelName{"vehmodelname", "Vehicle Model", "The model name of the vehicle you wish to spawn."};
static StringCommand _PedModelName{"pedmodelname", "Ped Model", "The model name of the ped you wish to spawn."};
static StringCommand _ObjectModelName{"objectmodelname", "Object Model", "The model name of the object you wish to spawn."};
class SpawnVehicle : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto model = _VehicleModelName.GetString();
if (!model.length())
{
Notifications::Show("Spawn Vehicle", "No model name provided.", NotificationType::Error);
return;
}
auto modelHash = Joaat(model);
if (STREAMING::IS_MODEL_IN_CDIMAGE(modelHash))
{
Vehicle::Create(modelHash, Self::GetPed().GetPosition(), Self::GetPed().GetHeading());
}
else
{
Notifications::Show("Spawn Vehicle", "Invalid model name provided.", NotificationType::Error);
}
}
};
class SpawnPed : public Command
{
@@ -85,7 +60,6 @@ namespace YimMenu::Features
}
};
static SpawnVehicle _SpawnVehicle{"spawnvehicle", "Spawn Vehicle", "Spawns a vehicle at your current location."};
static SpawnPed _SpawnPed{"spawnped", "Spawn Ped", "Spawns a ped at your current location."};
static SpawnObject _SpawnObject{"spawnobject", "Spawn Object", "Spawns an object at your current location."};
}
+8 -22
View File
@@ -1,5 +1,6 @@
#include "World.hpp"
#include "game/frontend/items/Items.hpp"
#include "World/SpawnPed.hpp"
namespace YimMenu::Submenus
{
@@ -8,7 +9,6 @@ namespace YimMenu::Submenus
Submenu::Submenu("World", ICON_FA_GLOBE)
{
auto main = std::make_shared<Category>("Main");
auto spawnersGroup = std::make_shared<Category>("Spawners");
auto iplsGroup = std::make_shared<Category>("IPLs");
auto killPeds = std::make_shared<Group>("Kill", 1);
@@ -29,11 +29,13 @@ namespace YimMenu::Submenus
weatherOpts->AddItem(std::make_shared<ConditionalItem>("forceweather"_J, std::make_shared<CommandItem>("setweather"_J), true));
weatherOpts->AddItem(std::make_shared<BoolCommandItem>("forceweather"_J));
auto timeGroup = std::make_shared<Group>("Time Control");
auto timeGroup = std::make_shared<Group>("Time");
timeGroup->AddItem(std::make_shared<IntCommandItem>("networktimehour"_J, "Hour"));
timeGroup->AddItem(std::make_shared<IntCommandItem>("networktimeminute"_J, "Minute"));
timeGroup->AddItem(std::make_shared<IntCommandItem>("networktimesecond"_J, "Second"));
auto hms = std::make_shared<Group>("", 1);
hms->AddItem(std::make_shared<IntCommandItem>("networktimehour"_J, "Hour"));
hms->AddItem(std::make_shared<IntCommandItem>("networktimeminute"_J, "Minute"));
hms->AddItem(std::make_shared<IntCommandItem>("networktimesecond"_J, "Second"));
timeGroup->AddItem(std::move(hms));
timeGroup->AddItem(std::make_shared<CommandItem>("setnetworktime"_J, "Set"));
timeGroup->AddItem(std::make_shared<BoolCommandItem>("freezenetworktime"_J, "Freeze"));
@@ -51,29 +53,13 @@ namespace YimMenu::Submenus
main->AddItem(std::move(otherOpts));
main->AddItem(timeGroup);
auto spawnVehicle = std::make_shared<Group>("Vehicle");
spawnVehicle->AddItem(std::make_shared<StringCommandItem>("vehmodelname"_J));
spawnVehicle->AddItem(std::make_shared<CommandItem>("spawnvehicle"_J));
auto spawnPed = std::make_shared<Group>("Ped");
spawnPed->AddItem(std::make_shared<StringCommandItem>("pedmodelname"_J));
spawnPed->AddItem(std::make_shared<CommandItem>("spawnped"_J));
auto spawnObject = std::make_shared<Group>("Object");
spawnObject->AddItem(std::make_shared<StringCommandItem>("objectmodelname"_J));
spawnObject->AddItem(std::make_shared<CommandItem>("spawnobject"_J));
spawnersGroup->AddItem(spawnVehicle);
spawnersGroup->AddItem(spawnPed);
spawnersGroup->AddItem(spawnObject);
iplsGroup->AddItem(std::make_shared<ListCommandItem>("iplselector"_J));
iplsGroup->AddItem(std::make_shared<CommandItem>("loadipl"_J));
iplsGroup->AddItem(std::make_shared<CommandItem>("unloadipl"_J));
iplsGroup->AddItem(std::make_shared<CommandItem>("ipltp"_J));
AddCategory(std::move(main));
AddCategory(std::move(spawnersGroup));
AddCategory(std::move(BuildSpawnPedMenu()));
AddCategory(std::move(iplsGroup));
}
};
@@ -0,0 +1,141 @@
#include "SpawnPed.hpp"
#include "core/backend/ScriptMgr.hpp"
#include "core/backend/FiberPool.hpp"
#include "game/backend/Self.hpp"
#include "game/gta/data/PedModels.hpp"
#include "game/gta/Ped.hpp"
#include "game/gta/Natives.hpp"
#include "types/ped/PedCombatAttribute.hpp"
#include "game/gta/data/Weapons.hpp"
#include "game/gta/Scripts.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<Category> BuildSpawnPedMenu()
{
auto menu = std::make_shared<Category>("Spawn Ped");
static bool invincible;
static bool spawnDead;
static bool spawnAsBodyguard;
static bool spawnAsCop;
static bool giveAllWeapons;
static bool spawnAsProstitute;
static std::vector<Ped> spawnedPeds;
menu->AddItem(std::make_unique<ImGuiItem>([] {
static char search[64];
ImGui::SetNextItemWidth(300.f);
ImGui::InputTextWithHint("Name", "Search", search, sizeof(search));
const int visible = std::min(20, static_cast<int>(g_PedModels.size()));
const float height = visible * ImGui::GetTextLineHeightWithSpacing();
if (ImGui::BeginListBox("##vehicles", {300.f, height}))
{
std::string lower = search;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
for (int veh = 0; veh < g_PedModels.size(); veh++)
{
auto name = g_PedModels[veh];
auto lowerName = std::string(name);
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
bool matchesSearch = lowerName.find(lower) != std::string::npos;
if (matchesSearch)
{
ImGui::PushID(name);
if (ImGui::Selectable(name))
{
FiberPool::Push([name] {
auto hash = Joaat(name);
auto handle = Ped::Create(hash, Self::GetPed().GetPosition(), Self::GetPed().GetHeading());
handle.SetCombatAttribute(PedCombatAttribute::AlwaysFight, true);
handle.SetCombatAttribute(PedCombatAttribute::DisableAllRandomsFlee, true);
handle.SetCombatAttribute(PedCombatAttribute::DisableFleeFromCombat, true);
handle.SetCombatAttribute(PedCombatAttribute::CanUseVehicles, true);
handle.SetCombatAttribute(PedCombatAttribute::CanLeaveVehicle, true);
if (invincible)
handle.SetInvincible(true);
if (spawnDead)
handle.Kill();
if (spawnAsBodyguard)
{
handle.SetCombatAttribute(PedCombatAttribute::CanCharge, true);
handle.SetCombatAttribute(PedCombatAttribute::CanCommandeerVehicles, true);
handle.SetCombatAttribute(PedCombatAttribute::DisableInjuredOnGround, true);
handle.SetCombatAttribute(PedCombatAttribute::AllowDogFighting, true);
handle.SetCombatAttribute(PedCombatAttribute::PerfectAccuracy, true);
handle.SetCombatAttribute(PedCombatAttribute::UseVehicleAttack, true);
handle.SetCombatAttribute(PedCombatAttribute::CanDoDrivebys, true);
handle.SetCombatAttribute(PedCombatAttribute::FleesFromInvincibleOpponents, false);
handle.SetCombatAttribute(PedCombatAttribute::CanThrowSmokeGrenade, true);
handle.SetCombatAttribute(PedCombatAttribute::CanSeeUnderwaterPeds, true);
auto group = Self::GetPlayer().GetGroup();
handle.AddToGroup(group);
PED::SET_GROUP_SEPARATION_RANGE(group, 9999.9f);
PED::SET_PED_CAN_TELEPORT_TO_GROUP_LEADER(handle.GetHandle(), group, true);
PED::SET_GROUP_FORMATION_SPACING(group, 10.0f, 0.0f, 0.0f);
}
if (spawnAsCop)
{
handle.SetAsCop();
}
if (giveAllWeapons)
{
for (auto hash : g_WeaponHashes)
handle.GiveWeapon(hash);
}
if (spawnAsProstitute)
{
handle.StartScenario("WORLD_HUMAN_PROSTITUTE_HIGH_CLASS");
handle.SetKeepTask(true);
if (!*Pointers.IsSessionStarted)
{
PED_INDEX ped = handle.GetHandle();
Scripts::StartScript("pb_prostitute"_J, eStackSizes::FRIEND, &ped, 1);
}
}
spawnedPeds.push_back(handle);
});
}
ImGui::PopID();
}
}
ImGui::EndListBox();
}
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("Invincible", &invincible);
ImGui::Checkbox("Spawn Dead", &spawnDead);
ImGui::Checkbox("Spawn As Bodyguard", &spawnAsBodyguard);
ImGui::Checkbox("Spawn As Cop", &spawnAsCop);
ImGui::Checkbox("Give All Weapons", &giveAllWeapons);
ImGui::Checkbox("Spawn As Prostitute", &spawnAsProstitute);
if (ImGui::Button("Remove All"))
{
FiberPool::Push([] {
for (auto& ped : spawnedPeds)
if (ped)
ped.Delete();
spawnedPeds.clear();
});
}
ImGui::EndGroup();
}));
return menu;
}
}
@@ -0,0 +1,8 @@
#pragma once
#include "core/frontend/manager/Category.hpp"
#include "game/frontend/items/Items.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<Category> BuildSpawnPedMenu();
}
+53
View File
@@ -116,6 +116,13 @@ namespace YimMenu
PED::SET_PED_CONFIG_FLAG(GetHandle(), (int)flag, value);
}
void Ped::SetCombatAttribute(PedCombatAttribute attribute, bool value)
{
ENTITY_ASSERT_VALID();
ENTITY_ASSERT_CONTROL();
PED::SET_PED_COMBAT_ATTRIBUTES(GetHandle(), (int)attribute, value);
}
bool Ped::IsEnemy()
{
ENTITY_ASSERT_VALID();
@@ -224,12 +231,50 @@ namespace YimMenu
void Ped::SetArmour(int amount)
{
ENTITY_ASSERT_VALID();
ENTITY_ASSERT_CONTROL();
PED::SET_PED_ARMOUR(GetHandle(), amount);
}
void Ped::SetLeaderOfGroup(int group)
{
ENTITY_ASSERT_VALID();
PED::SET_PED_AS_GROUP_LEADER(GetHandle(), group);
}
void Ped::AddToGroup(int group)
{
ENTITY_ASSERT_VALID();
PED::SET_PED_AS_GROUP_MEMBER(GetHandle(), group);
}
void Ped::RemoveFromGroup()
{
ENTITY_ASSERT_VALID();
PED::REMOVE_PED_FROM_GROUP(GetHandle());
}
bool Ped::IsMemberOfGroup(int group)
{
ENTITY_ASSERT_VALID();
return PED::IS_PED_GROUP_MEMBER(GetHandle(), group);
}
void Ped::StartScenario(std::string_view name, int duration, bool entry_anim)
{
ENTITY_ASSERT_VALID();
TASK::TASK_START_SCENARIO_IN_PLACE(GetHandle(), name.data(), duration, entry_anim);
}
void Ped::SetKeepTask(bool keep)
{
ENTITY_ASSERT_VALID();
PED::SET_PED_KEEP_TASK(GetHandle(), keep);
}
void Ped::ClearDamage()
{
ENTITY_ASSERT_VALID();
ENTITY_ASSERT_CONTROL();
PED::CLEAR_PED_BLOOD_DAMAGE(GetHandle());
PED::CLEAR_PED_WETNESS(GetHandle());
PED::CLEAR_PED_ENV_DIRT(GetHandle());
@@ -239,9 +284,17 @@ namespace YimMenu
void Ped::SetMaxTimeUnderwater(int time)
{
ENTITY_ASSERT_VALID();
ENTITY_ASSERT_CONTROL();
PED::SET_PED_MAX_TIME_UNDERWATER(GetHandle(), time);
}
void Ped::SetAsCop()
{
ENTITY_ASSERT_VALID();
ENTITY_ASSERT_CONTROL();
PED::SET_PED_AS_COP(GetHandle(), true);
}
void Ped::SetMaxAmmoForWeapon(std::uint32_t hash)
{
int maxAmmo;
+15
View File
@@ -3,6 +3,7 @@
#include "Vehicle.hpp"
enum class PedConfigFlag : std::uint32_t;
enum class PedCombatAttribute : std::uint32_t;
namespace YimMenu
{
@@ -30,6 +31,9 @@ namespace YimMenu
bool GetConfigFlag(PedConfigFlag flag);
void SetConfigFlag(PedConfigFlag flag, bool value);
// combat attributes
void SetCombatAttribute(PedCombatAttribute attribute, bool value);
// relationships
bool IsEnemy();
@@ -57,8 +61,19 @@ namespace YimMenu
int GetArmour();
void SetArmour(int amount);
// groups
void SetLeaderOfGroup(int group);
void AddToGroup(int group);
void RemoveFromGroup();
bool IsMemberOfGroup(int group);
// tasks
void StartScenario(std::string_view name, int duration = -1, bool entry_anim = true);
void SetKeepTask(bool keep);
// misc
void ClearDamage();
void SetMaxTimeUnderwater(int time);
void SetAsCop();
};
}
+5
View File
@@ -352,6 +352,11 @@ namespace YimMenu
return PLAYER::GET_PLAYER_MAX_ARMOUR(GetId()); // Not checking IsValid to let GetId return 0 in SP
}
int Player::GetGroup()
{
return PLAYER::GET_PLAYER_GROUP(GetId());
}
bool Player::operator==(Player other)
{
return m_Handle == other.m_Handle;
+2
View File
@@ -83,6 +83,8 @@ namespace YimMenu
int GetMaxArmour();
int GetGroup();
bool operator==(Player other);
inline operator bool()
File diff suppressed because it is too large Load Diff
+10 -7
View File
@@ -28,13 +28,16 @@ namespace YimMenu::Hooks
LOGF(WARNING, "Player {} changed their player index from {} to {}", player->GetName(), player->m_PlayerIndex, index);
BaseHook::Get<Info::AssignPhysicalIndex, DetourHook<decltype(&Info::AssignPhysicalIndex)>>()->Original()(mgr, player, index);
Players::OnPlayerJoin(player);
std::string name = player->GetName();
FiberPool::Push([name] {
HUD::SET_TEXT_OUTLINE();
HUD::BEGIN_TEXT_COMMAND_THEFEED_POST("STRING");
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(std::format("<C>{}</C> joined.", name).data());
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
});
if (Features::_NotifyOnPlayerJoin.GetState() && !player->IsLocal())
{
std::string name = player->GetName();
FiberPool::Push([name] {
HUD::SET_TEXT_OUTLINE();
HUD::BEGIN_TEXT_COMMAND_THEFEED_POST("STRING");
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(std::format("<C>{}</C> joined.", name).data());
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
});
}
}
else
{
+96
View File
@@ -0,0 +1,96 @@
#pragma once
enum class PedCombatAttribute : std::uint32_t
{
CanUseCover,
CanUseVehicles,
CanDoDrivebys,
CanLeaveVehicle,
CanUseDynamicStrafeDecisions,
AlwaysFight,
FleeWhilstInVehicle,
JustFollowInVehicle,
Unused_3,
WillScanForDeadPeds,
Unused_1,
JustSeekCover,
BlindFireWhenInCover,
Aggressive,
CanInvestigate,
HasRadio,
Unused_2,
AlwaysFlee,
ForceInjuredOnGround,
DisableInjuredOnGround,
CanTauntInVehicle,
CanChaseTargetOnFoot,
WillDragInjuredPedsToSafety,
RequiresLosToShoot,
UseProximityFiringRate,
DisableSecondaryTarget,
DisableEntryReactions,
PerfectAccuracy,
CanUseFrustratedAdvance,
MoveToLocationBeforeCoverSearch,
CanShootWithoutLOS,
MaintainMinDistanceToTarget,
IgnoreHatedPedsInFastMovingVehicles,
UseProximityAccuracy,
CanUsePeekingVariations,
DisablePinnedDown,
DisablePinDownOthers,
ClearAreaSetDefensiveIfDefensiveAreaReached,
DisableBulletReactions,
CanBust,
IgnoredByOtherPedsWhenWanted,
CanCommandeerVehicles,
CanFlank,
SwitchToAdvanceIfCantFindCover,
SwitchToDefensiveIfInCover,
ClearPrimaryDefensiveAreaWhenReached,
CanFightArmedPedsWhenNotArmed,
EnableTacticalPointsWhenDefensive,
DisableCoverArcAdjustments,
UseEnemyAccuracyScaling,
CanCharge,
ClearAreaSetAdvanceIfDefensiveAreaReached,
UseVehicleAttack,
UseVehicleAttackIfVehicleHasMountedGuns,
AlwaysEquipBestWeapon,
CanSeeUnderwaterPeds,
DisableAimAtAITargetsInHelis,
DisableSeekDueToLineOfSight,
DisableFleeFromCombat,
DisableTargetChangesDuringVehiclePursuit,
CanThrowSmokeGrenade,
NonMissionPedsFleeFromThisPedUnlessArmed,
ClearAreaSetDefensiveIfDefensiveCannotBeReached,
FleesFromInvincibleOpponents,
DisableBlockFromPursueDuringVehicleChase,
DisableSpinOutDuringVehicleChase,
DisableCruiseInFrontDuringBlockDuringVehicleChase,
CanIgnoreBlockedLosWeighting,
DisableReactToBuddyShot,
PreferNavmeshDuringVehicleChase,
AllowedToAvoidOffroadDuringVehicleChase,
PermitChargeBeyondDefensiveArea,
UseRocketsAgainstVehiclesOnly,
DisableTacticalPointsWithoutClearLos,
DisablePullAlongsideDuringVehicleChase,
DisableShoutTargetPosition,
SetDisableShoutTargetPositionOnCombatStart,
DisableRespondedToThreatBroadcast,
DisableAllRandomsFlee,
WillGenerateDeadPedSeenScriptEvents,
UseMaxSenseRangeWhenReceivingEvents,
RestrictInVehicleAimingToCurrentSide,
UseDefaultBlockedLosPositionAndDirection,
RequiresLosToAim,
CruiseAndBlockInVehicle,
PreferAirCombatWhenInAircraft,
AllowDogFighting,
PreferNonAircraftTargets,
PreferKnownTargetsWhenCombatClosestTarget,
ForceCheckAttackAngleForMountedGuns,
BlockFireForVehiclePassengerMountedGuns,
};