Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 125 additions & 41 deletions examples/PedSpawner/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,135 @@
*/
#include "plugin.h"
#include "common.h"
#include "CTimer.h"
#include "CPopulation.h"
#include "CCivilianPed.h"
#include "CWorld.h"
#ifdef GTASA
#include "CMessages.h"
#include "CStreaming.h"
#include "CTaskComplexWanderStandard.h"
#include "CTheScripts.h"
#include "CTimer.h"
#include "CWorld.h"

#ifdef GTA3
#include "RpAnimBlend.h"
#endif
#include "CHud.h"

int pedModelIds[] = { 0, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 57, 58, 59, 60, 61, 62, 66, 67, 68, 70, 71, 72, 73, 78, 79, 80, 81, 82, 83, 84, 94, 95, 96, 97, 98, 99, 100, 101,
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127, 128, 132,
133, 134, 135, 136, 137, 142, 143, 144, 146, 147, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170, 171,
173, 174, 175, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 200, 202, 203, 204, 206, 209, 210, 212, 213, 217, 220,
221, 222, 223, 227, 228, 229, 230, 234, 235, 236, 239, 240, 241, 242, 247, 248, 249, 250, 252, 253, 254, 255, 258, 259, 260, 261, 262,
9, 10, 11, 12, 13, 31, 38, 39, 40, 41, 53, 54, 55, 56, 63, 64, 69, 75, 76, 77, 85, 87, 88, 89, 90, 91, 92, 93, 129, 130, 131, 138, 139,
140, 141, 145, 148, 150, 151, 152, 157, 169, 172, 178, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 201, 205, 207, 211, 214, 215,
216, 218, 219, 224, 225, 226, 231, 232, 233, 237, 238, 243, 244, 245, 246, 251, 256, 257, 263 };

using namespace plugin;

class PedSpawner {
public:
PedSpawner() {
static int keyPressTime = 0;
Events::gameProcessEvent += [] {
if (FindPlayerPed() && KeyPressed(VK_F9) && CTimer::m_snTimeInMilliseconds - keyPressTime > 500) {
#ifdef GTASA
keyPressTime = CTimer::m_snTimeInMilliseconds;
int modelID = pedModelIds[rand() % 250];
CStreaming::RequestModel(modelID, 0);
CStreaming::LoadAllRequestedModels(false);
CPed *ped = new CCivilianPed(CPopulation::IsFemale(modelID) ? PED_TYPE_CIVFEMALE : PED_TYPE_CIVMALE, modelID);
if (ped) {
ped->SetPosn(FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 3.0f)));
ped->SetOrientation(0.0f, 0.0f, 0.0f);
CWorld::Add(ped);
ped->PositionAnyPedOutOfCollision();
ped->m_pIntelligence->m_TaskMgr.SetTask(new CTaskComplexWanderStandard(4, rand() % 8, true), 4, false);
}
#else
CHud::SetHelpMessage(L"Not done yet!", true, false);
#endif
}
};
struct Main
{
char messageBuffer[128] = { 0 }; // it must exist as long, as it is printed on the screen

bool tipDisplayed = false;
int modelId = eModelID::MODEL_INVALID;
bool keyPedSpawnPrevPressed = false;
bool keyPedSpawnNextPressed = false;

Main()
{
// register event callbacks
Events::restartGameEvent += [this]{ OnGameRestart(); };
Events::gameProcessEvent += [this]{ OnGameProcess(); };
}

void OnGameRestart()
{
tipDisplayed = false;
modelId = eModelID::MODEL_INVALID;
}

void OnGameProcess()
{
if (!tipDisplayed)
{
CMessages::AddMessageJumpQ("Press ~h~.~s~ or ~h~,~s~ to spawn ped. Hold SHIFT for fast browsing.", 10000, 0);
tipDisplayed = true;
}

bool pressed;

// handle prev ped spawning hotkey
pressed = KeyPressed(VK_OEM_COMMA); // < key
if (pressed && !keyPedSpawnPrevPressed) // just pressed
{
int skip = KeyPressed(VK_SHIFT) ? 9 : 0; // fast browse key
SpawnNextPed(modelId - skip, false);
}
keyPedSpawnPrevPressed = pressed;

pressed = KeyPressed(VK_OEM_PERIOD); // > key
if (pressed && !keyPedSpawnNextPressed) // just pressed
{
int skip = KeyPressed(VK_SHIFT) ? 9 : 0; // fast browse key
SpawnNextPed(modelId + skip, true);
}
keyPedSpawnNextPressed = pressed;
}

void SpawnNextPed(int searchStartId, bool searchForward)
{
auto player = FindPlayerPed();
if (!player)
{
return; // player not found
}

// ground level position in front of the player
CVector position = player->TransformFromObjectSpace({0.0f, 4.0f, -1.0f});
float heading = player->GetHeading() + DegToRad(180.0f); // face the player

// find next model id
modelId = searchStartId;
while (true)
{
modelId = CModelInfo::FindNextModel(MODEL_INFO_PED, modelId, searchForward);

if (modelId == MODEL_INVALID)
return; // error: not found

if (modelId >= MODEL_SPECIAL_FIRST && modelId <= MODEL_SPECIAL_LAST) // ped special character slots
continue; // keep searching

break; // found
}

// load model
CStreaming::RequestModel(modelId, 0);
CStreaming::LoadAllRequestedModels(false);
if (!CStreaming::HasModelLoaded(modelId))
{
sprintf_s(messageBuffer, "~r~~h~Failed to load ped model: %d", modelId);
CMessages::AddMessageJumpQ(messageBuffer, 10000, 0);
return; // failed to load model
}

CWorld::ClearExcitingStuffFromArea(position, 2.0f, false); // clear non-mission entities in the radius

auto ped = new CCivilianPed(PED_TYPE_CIVMALE, modelId);
if (!ped)
{
sprintf_s(messageBuffer, "~r~~h~Failed to spawn ped model: %d", modelId);
CMessages::AddMessageJumpQ(messageBuffer, 10000, 0);
return; // failed to spawn
}

sprintf_s(messageBuffer, "Ped model: %d", modelId);
CMessages::AddMessageJumpQ(messageBuffer, 3000, 0);

position.z += 1.0f; // offset from the ground to the ped center
ped->SetPosition(position.x, position.y, position.z);
ped->SetHeading(heading);
ped->m_fHeadingCurrent = ped->m_fHeadingGoal = heading;
ped->GetMatrix().UpdateRW();

if (ped->m_pRwClump)
{
RpAnimBlendClumpUpdateAnimations(ped->m_pRwClump, CTimer::ms_fTimeStep);
}

#if defined(GTASA)
ped->m_fContactSurfaceBrightness = 0.5f;
#endif

CTheScripts::ClearSpaceForMissionEntity(ped->GetPosition(), ped); // clear non-mission entities colliding with the ped
CWorld::Add(ped);
}
} pedSpawner;
} gInstance;
16 changes: 11 additions & 5 deletions examples/PedSpawner/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
## Random Ped Spawner
Spawns random male and female pedestrians in front of the player when F9 is pressed.
## Ped Spawner
Showcase browsing and creation of all (non-cutscene) ped models.
Supports new model IDs added with limit adjusters.

![Img1](http://i.imgur.com/J1m0lHH.png) ![Img2](http://i.imgur.com/BrkDKbn.png)
### Controls (keyboard)
* **<** - find previous ped model ID and spawn it
* **>** - find next ped model ID and spawn it
* **SHIFT** - hold for faster model browising

#### Controls (keyboard)
* F9 - Spawn Ped
### Target platforms
* Classic GTA 3
* Classic GTA Vice City
* Classic GTA San Andreas
2 changes: 1 addition & 1 deletion examples/examples.csv
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ HandSignals, ASI, ---, ---, ---, YES, ---, ---, ---, ---, ---
Neon, ASI, ---, ---, ---, YES, ---, ---, ---, ---, ---
OpenDoorExample, ASI, ---, ---, ---, YES, ---, ---, ---, ---, ---
PedPainting, ASI, ---, ---, YES, YES, ---, ---, ---, ---, ---
PedSpawner, ASI, ---, ---, YES, YES, ---, ---, ---, ---, ---
PedSpawner, ASI, ---, YES, YES, YES, ---, ---, ---, ---, ---
PlayerWeapon, ASI, ---, ---, ---, YES, ---, ---, ---, ---, ---
RotateDoor, ASI, ---, ---, ---, YES, ---, ---, ---, ---, ---
ScriptCommands, ASI, ---, YES, YES, YES, ---, ---, ---, ---, ---
Expand Down
12 changes: 12 additions & 0 deletions plugin_III/game_III/CCivilianPed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,21 @@ int dtor_gaddr(CCivilianPed) = GLOBAL_ADDRESS_BY_VERSION(0x4BFFC0, 0x4C00B0, 0x4
int del_dtor_addr(CCivilianPed) = ADDRESS_BY_VERSION(0x4C1170, 0x4C1260, 0x4C11F0);
int del_dtor_gaddr(CCivilianPed) = GLOBAL_ADDRESS_BY_VERSION(0x4C1170, 0x4C1260, 0x4C11F0);

void* CCivilianPed::operator new(size_t size) {
return plugin::CallAndReturnDynGlobal<void*, size_t>(op_new_gaddr(CPed), size);
}

void CCivilianPed::operator delete(void* data) {
return plugin::CallDynGlobal<void*>(op_delete_gaddr(CPed), data);
}

int addrof(CCivilianPed::ProcessControl) = ADDRESS_BY_VERSION(0x4BFFE0, 0x4C00D0, 0x4C0060);
int gaddrof(CCivilianPed::ProcessControl) = GLOBAL_ADDRESS_BY_VERSION(0x4BFFE0, 0x4C00D0, 0x4C0060);

CCivilianPed::CCivilianPed(ePedType pedType, unsigned int modelIndex) {
plugin::CallMethodDynGlobal<CCivilianPed*, ePedType, unsigned int>(ctor_gaddr_o(CCivilianPed, void(ePedType, unsigned int)), this, pedType, modelIndex);
}

void CCivilianPed::ProcessControl() {
plugin::CallVirtualMethod<8, CCivilianPed *>(this);
}
Expand Down
7 changes: 5 additions & 2 deletions plugin_III/game_III/CCivilianPed.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
#include "PluginBase.h"
#include "CPed.h"

class PLUGIN_API CCivilianPed {
class PLUGIN_API CCivilianPed : public CPed
{
PLUGIN_NO_DEFAULT_CONSTRUCTION(CCivilianPed)
static void* operator new(size_t size);
static void operator delete(void* data);

public:
CPed ped; //!< isbase:true
SUPPORTED_10EN_11EN_STEAM CCivilianPed(ePedType pedType, unsigned int modelIndex);

// virtual function #0 (destructor)

Expand Down
8 changes: 4 additions & 4 deletions plugin_III/game_III/CPed.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,10 @@ class PLUGIN_API CPed : public CPhysical {
short m_nRoutePointsPassed;
short m_nRouteType; //!< see ePedRouteType
short m_nRoutePointsBeingPassed;
CVector2D m_vec2dMoved;
float m_fRotationCur;
float m_fRotationDest;
float m_fHeadingRate;
CVector2D m_vecAnimMovingShift; // velocity from walk animations
float m_fHeadingCurrent; // current heading angle
float m_fHeadingGoal; // desired heading angle
float m_fHeadingChangeRate; // speed of turing to m_fHeadingGoal
unsigned short m_nVehicleDoor;
short m_nWalkAroundType;
CPhysical *m_pCurrentPhysSurface;
Expand Down
11 changes: 2 additions & 9 deletions plugin_III/game_III/CPlaceable.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,8 @@ class PLUGIN_API CPlaceable {
SUPPORTED_10EN_11EN_STEAM bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2);
SUPPORTED_10EN_11EN_STEAM void SetHeading(float angle);
SUPPORTED_10EN_11EN_STEAM void SetPosition(float x, float y, float z);

inline float GetHeading() {
float angle = atan2f(-m_matrix.up.x, m_matrix.up.y) * 57.295776f;
if (angle < 0.0f)
angle += 360.0f;
if (angle > 360.0f)
angle -= 360.0f;
return angle;
}

inline float GetHeading() { return GetForward().Heading(); }

inline void SetPos(CVector &pos) {
this->m_matrix.pos = pos;
Expand Down
6 changes: 5 additions & 1 deletion plugin_III/game_III/CStreaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ int &CStreaming::ms_oldSectorX = *(int *)0x8F2C84;
int &CStreaming::ms_oldSectorY = *(int *)0x8F2C88;
int &CStreaming::ms_vehiclesLoaded = *(int *)0x773560;

CStreamingInfo *CStreaming::ms_aInfoForModel = (CStreamingInfo *)0x6C7088;
CStreamingInfo *CStreaming::ms_aInfoForModel = *(CStreamingInfo**)0x40A4AD; // limit adjusters support - get from reference in CStreaming::LoadAllRequestedModels
CStreamingInfo *CStreaming::ms_endRequestedList = (CStreamingInfo *)0x940738;
CStreamingInfo *CStreaming::ms_startLoadedList = (CStreamingInfo *)0x942F60;
CStreamingInfo *CStreaming::ms_startRequestedList = (CStreamingInfo *)0x8F1B3C;
Expand Down Expand Up @@ -236,6 +236,10 @@ int CStreaming::GetNextFileOnCd(int arg0, bool arg1) {
return plugin::CallAndReturn<int, 0x409E50, int, bool>(arg0, arg1);
}

bool CStreaming::HasModelLoaded(int modelIndex) {
return ms_aInfoForModel[modelIndex].m_nLoadState == LOADSTATE_LOADED;
}

// Converted from cdecl bool CStreaming::HasSpecialCharLoaded(int modelIndex) 0x40ADC0
bool CStreaming::HasSpecialCharLoaded(int modelIndex) {
return plugin::CallAndReturn<bool, 0x40ADC0, int>(modelIndex);
Expand Down
3 changes: 3 additions & 0 deletions plugin_III/game_III/CStreaming.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ class CStreaming {
static bool FinishLoadingLargeFile(char* FileName, int modelIndex);
static unsigned int GetCdImageOffset(int arg0);
static int GetNextFileOnCd(int arg0, bool arg1);

static bool HasModelLoaded(int modelIndex);
static bool HasSpecialCharLoaded(int modelIndex);

static void HaveAllBigBuildingsLoaded(eLevelName levelName);
static void IHaveUsedStreamingMemory();
// empty function
Expand Down
8 changes: 4 additions & 4 deletions plugin_sa/game_sa/CPed.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,10 @@ class PLUGIN_API CPed : public CPhysical {
float m_fMaxHealth;
float m_fArmour;
unsigned int m_nTimeTillWeNeedThisPed;
CVector2D m_vecAnimMovingShift;
float m_fCurrentRotation;
float m_fAimingRotation;
float m_fHeadingChangeRate;
CVector2D m_vecAnimMovingShift; // velocity from walk animations
float m_fHeadingCurrent; // current heading angle
float m_fHeadingGoal; // desired heading angle
float m_fHeadingChangeRate; // speed of turing to m_fHeadingGoal
int m_fMoveAnim;
CEntity* m_standingOnEntity;
CVector field_56C;
Expand Down
4 changes: 2 additions & 2 deletions plugin_sa/game_sa/CPlaceable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ void CPlaceable::SetMatrix(CMatrix const& matrix)
((void (__thiscall *)(CPlaceable *, CMatrix const&))0x54F610)(this, matrix);
}

CMatrixLink *CPlaceable::GetMatrix() {
return ((CMatrixLink *(__thiscall *)(CPlaceable *))0x411990)(this);
CMatrixLink& CPlaceable::GetMatrix() {
return *((CMatrixLink *(__thiscall *)(CPlaceable *))0x411990)(this);
}

void CPlaceable::ShutdownMatrixArray() {
Expand Down
8 changes: 6 additions & 2 deletions plugin_sa/game_sa/CPlaceable.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class PLUGIN_API CPlaceable {

virtual ~CPlaceable() {};

CMatrixLink *GetMatrix();
CMatrixLink& GetMatrix();

static void ShutdownMatrixArray();
static void InitMatrixArray();
Expand All @@ -30,8 +30,12 @@ class PLUGIN_API CPlaceable {
CVector GetAtDirection();

void FreeStaticMatrix();

void SetPosn(float x, float y, float z);
void SetPosn(CVector const& posn);
void SetPosn(CVector const& pos);
inline void SetPosition(float x, float y, float z) { SetPosn(x, y, z); }
inline void SetPosition(CVector const& pos) { SetPosn(pos); }

void SetOrientation(float x, float y, float z);
void GetOrientation(float& x, float& y, float& z);
void SetHeading(float heading);
Expand Down
4 changes: 4 additions & 0 deletions plugin_sa/game_sa/CStreaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ int CStreaming::GetNextFileOnCd(int pos, bool bNotPriority) {
return plugin::CallAndReturnDynGlobal<int, int, bool>(gaddrof(CStreaming::GetNextFileOnCd), pos, bNotPriority);
}

bool CStreaming::HasModelLoaded(int modelIndex) {
return ms_aInfoForModel[modelIndex].m_nLoadState == LOADSTATE_LOADED;
}

int addrof(CStreaming::HasSpecialCharLoaded) = ADDRESS_BY_VERSION(0x407F00, 0, 0, 0, 0, 0);
int gaddrof(CStreaming::HasSpecialCharLoaded) = GLOBAL_ADDRESS_BY_VERSION(0x407F00, 0, 0, 0, 0, 0);

Expand Down
3 changes: 3 additions & 0 deletions plugin_sa/game_sa/CStreaming.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ class PLUGIN_API CStreaming {
SUPPORTED_10US static signed int GetDiscInDrive();
//! return modelIndex
SUPPORTED_10US static int GetNextFileOnCd(int pos, bool bNotPriority);

static bool HasModelLoaded(int modelIndex);
SUPPORTED_10US static bool HasSpecialCharLoaded(int slot);
SUPPORTED_10US static bool HasVehicleUpgradeLoaded(int ModelIndex);

//! does nothing (NOP)
SUPPORTED_10US static void IHaveUsedStreamingMemory();
//! does nothing (NOP)
Expand Down
2 changes: 1 addition & 1 deletion plugin_sa/game_sa/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void RpAnimBlendClumpRemoveAllAssociations(RpClump* clump);
void RpAnimBlendClumpRemoveAssociations(RpClump* clump, unsigned int flags);
void RpAnimBlendClumpSetBlendDeltas(RpClump* clump, unsigned int flags, float delta);
void RpAnimBlendClumpUnPauseAllAnimations(RpClump* clump);
void RpAnimBlendClumpUpdateAnimations(RpClump* clump, float step, bool onScreen);
void RpAnimBlendClumpUpdateAnimations(RpClump* clump, float step, bool onScreen = true);
RtAnimAnimation* RpAnimBlendCreateAnimationForHierarchy(RpHAnimHierarchy* hierarchy);
char* RpAnimBlendFrameGetName(RwFrame* frame);
void RpAnimBlendFrameSetName(RwFrame* frame, char* name);
Expand Down
Loading