Skip to content

Commit

Permalink
CTheScripts (#654)
Browse files Browse the repository at this point in the history
Co-authored-by: Pirulax <patrikjankovics7@gmail.com>
  • Loading branch information
yukani and Pirulax authored Jul 14, 2024
1 parent 787d79e commit 4a7fdc0
Show file tree
Hide file tree
Showing 30 changed files with 1,850 additions and 279 deletions.
22 changes: 22 additions & 0 deletions source/extensions/EntityRef.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ struct EntityRef {
}
}

// No need for moving/copying the class itself, but just the pointer directly to it's new address
// (This way we avoid extra calls to `CleanUpOld/RegisterReference`...)
EntityRef<T>& operator=(EntityRef&&) = delete;
EntityRef<T>& operator=(const EntityRef&) = delete;
EntityRef(EntityRef<T>&&) = delete;
EntityRef(const EntityRef<T>&) = delete;

// This is the only magic we need
EntityRef<T>& operator=(T* ptr) {
if (m_Ptr) {
m_Ptr->CleanUpOldReference(reinterpret_cast<CEntity**>(&m_Ptr));
}
m_Ptr = ptr;
if (m_Ptr) {
m_Ptr->RegisterReference(reinterpret_cast<CEntity**>(&m_Ptr));
}
return *this;
}

T* Get() { return m_Ptr; }
const T* Get() const { return m_Ptr; }

operator T*() const { return m_Ptr; }
operator T*() { return m_Ptr; }

Expand Down
34 changes: 34 additions & 0 deletions source/extensions/File.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once
#include <span>
#include "FileMgr.h"

namespace notsa {
// RAII-wrapper for CFileMgr files.
class File {
public:
File(const char* path, const char* mode) :
m_file(CFileMgr::OpenFile(path, mode))
{}

~File()
{
if (m_file)
CloseFile();
}

operator bool() const { return m_file != nullptr; }

auto Read(void* buf, size_t size) { return CFileMgr::Read(m_file, buf, size); }
auto Write(const void* buf, size_t size) { return CFileMgr::Write(m_file, buf, size); }
auto Seek(long offset, int32 origin) { return CFileMgr::Seek(m_file, offset, origin); }
auto ReadLine(char* str, int32 num) { return CFileMgr::ReadLine(m_file, str, num); }
auto CloseFile() { return CFileMgr::CloseFile(std::exchange(m_file, nullptr)); }
auto GetTotalSize() const { return CFileMgr::GetTotalSize(m_file); }
auto Tell() const { return CFileMgr::Tell(m_file); }
auto GetErrorReadWrite() const { return CFileMgr::GetErrorReadWrite(m_file); }
void SeekNextLine() { CFileMgr::SeekNextLine(m_file); }

private:
FILESTREAM m_file{};
};
};
8 changes: 6 additions & 2 deletions source/extensions/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,15 @@ inline constexpr bool is_standard_integer = std::is_integral_v<T> && !is_any_of_
//! NOTE: Not a complete replacement for std::format_to,
//! e.g. it doesn't use output iterators. i don't care.
template<size_t N, class... Args>
void format_to_sz(char (&out)[N], std::string_view fmt, Args&&... args) {
void format_to_sz(char(&out)[N], std::string_view fmt, Args&&... args) {
*std::vformat_to(out, fmt, std::make_format_args(args...)) = '\0';
}

//! Reads a pointer as specified type.
template<typename T> requires std::is_trivially_constructible_v<T>
T ReadAs(void* ptr) {
return *static_cast<T*>(ptr);
}
//! Safe C string copying, use this instead of strcpy.
inline void string_copy(char* out, const char* from, size_t size) {
std::snprintf(out, size, "%s", from);
Expand All @@ -372,5 +377,4 @@ template<size_t N>
void string_copy(char (&out)[N], const char* from) {
std::snprintf(out, N, "%s", from);
}

};
27 changes: 14 additions & 13 deletions source/game_sa/Checkpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ enum class eCheckpointType : uint32 {
NUM = 0x9, ///< Count of different checkpoint types
NA = 0x101, ///< Sentinel value (Used for markers not in use)
};
using eCheckpointTypeU16 = notsa::WEnumU16<eCheckpointType>;

class CCheckpoint {
public:
Expand Down Expand Up @@ -66,19 +67,19 @@ class CCheckpoint {
void SetHeading(float headingDeg);

public:
notsa::WEnumU16<eCheckpointType> m_Type{eCheckpointType::NA};
bool m_IsUsed{false};
bool m_RotFlag{true};
int32 m_ID{0};
CRGBA m_Colour{255, 255, 255, 255};
uint16 m_PulsePeriod{1'024};
int16 m_RotateRate{5};
CVector m_Pos{};
CVector m_Fwd{}; ///< Pointing direction
float m_PulseFraction{0.25f};
float m_Size{1.f};
float m_DistToCam2D{0.f}; ///< (AKA CameraRange) - Distance to player's camera at the moment it's placed
float m_MultiSize{0.f};
eCheckpointTypeU16 m_Type{ eCheckpointType::NA };
bool m_IsUsed{ false };
bool m_RotFlag{ true };
int32 m_ID{ 0 };
CRGBA m_Colour{ 255, 255, 255, 255 };
uint16 m_PulsePeriod{ 1'024 };
int16 m_RotateRate{ 5 };
CVector m_Pos{};
CVector m_Fwd{}; ///< Pointing direction
float m_PulseFraction{ 0.25f };
float m_Size{ 1.f };
float m_DistToCam2D{ 0.f }; ///< (AKA CameraRange) - Distance to player's camera at the moment it's placed
float m_MultiSize{ 0.f };

};
VALIDATE_SIZE(CCheckpoint, 0x38);
6 changes: 3 additions & 3 deletions source/game_sa/Checkpoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ void CCheckpoints::Update() {
// 0x722C40
CCheckpoint* CCheckpoints::PlaceMarker(
uint32 id,
notsa::WEnumU16<eCheckpointType> type,
eCheckpointTypeU16 type,
const CVector& pos,
const CVector& direction,
float size,
uint8 red, uint8 green, uint8 blue, uint8 alpha,
CRGBA color,
uint16 pulsePeriod,
float pulseFraction,
int16 rotateRate
Expand Down Expand Up @@ -108,7 +108,7 @@ CCheckpoint* CCheckpoints::PlaceMarker(

if (cp) { // 0x722F07
cp->m_DistToCam2D = cpDistToPlayer2D;
cp->m_Colour = {red, green, blue, alpha};
cp->m_Colour = color;
cp->m_Size = size;
cp->m_RotateRate = rotateRate;
cp->m_Pos = pos;
Expand Down
2 changes: 1 addition & 1 deletion source/game_sa/Checkpoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CCheckpoints {
static void Shutdown();
static void SetHeading(uint32 id, float angle);
static void Update();
static CCheckpoint* PlaceMarker(uint32 id, notsa::WEnumU16<eCheckpointType> type, const CVector& posn, const CVector& direction, float size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
static CCheckpoint* PlaceMarker(uint32 id, eCheckpointTypeU16 type, const CVector& posn, const CVector& direction, float size, CRGBA color, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
/*!
* @brief Set the position of a checkpoint with the given `id`
* @param id ID of the checkpoint
Expand Down
5 changes: 4 additions & 1 deletion source/game_sa/DecisionMakerTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ class CDecisionMakerTypesFileLoader {

class CDecisionMakerTypes {
public:
static inline std::array<uint16, 20>& ScriptReferenceIndex = *(std::array<uint16, 20>*)0xC0AFF4;
static constexpr auto NUM_TYPES = 20u;

static inline auto& ScriptReferenceIndex = *(std::array<uint16, NUM_TYPES>*)0xC0AFF4;
static inline auto& m_bIsActive = *(std::array<bool, NUM_TYPES>*)0xC0B01C;

static void InjectHooks();

Expand Down
13 changes: 6 additions & 7 deletions source/game_sa/Entity/Object/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,12 @@ CObject::CObject(CDummyObject* dummyObj) : CPhysical() {

// 0x59F660
CObject::~CObject() {
if (objectFlags.b0x200000 || objectFlags.b0x100000) {
const auto iIndex = SCMToModelId(CTheScripts::ScriptsForBrains.m_aScriptForBrains[m_wScriptTriggerIndex].m_nIMGindex);
if (objectFlags.b0x100000_0x200000) {
const auto iIndex = SCMToModelId(CTheScripts::ScriptsForBrains.m_aScriptForBrains[m_nStreamedScriptBrainToLoad].m_StreamedScriptIndex);
CStreaming::SetMissionDoesntRequireModel(iIndex);
objectFlags.b0x100000 = false;
objectFlags.b0x200000 = false;
CTheScripts::RemoveFromWaitingForScriptBrainArray(this, m_wScriptTriggerIndex);
m_wScriptTriggerIndex = -1;
objectFlags.b0x100000_0x200000 = 0;
CTheScripts::RemoveFromWaitingForScriptBrainArray(this, m_nStreamedScriptBrainToLoad);
m_nStreamedScriptBrainToLoad = -1;
}

if (objectFlags.bHasNoModel) {
Expand Down Expand Up @@ -865,7 +864,7 @@ void CObject::Init() {

m_nColLighting.day = 0x8;
m_nColLighting.night = 0x4;
m_wScriptTriggerIndex = -1;
m_nStreamedScriptBrainToLoad = -1;
}

// 0x59FB50
Expand Down
5 changes: 2 additions & 3 deletions source/game_sa/Entity/Object/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ class NOTSA_EXPORT_VTABLE CObject : public CPhysical {
uint32 bIsScaled : 1;
uint32 bCanBeAttachedToMagnet : 1;
uint32 bDamaged : 1;
uint32 b0x100000 : 1;
uint32 b0x200000 : 1;
uint32 b0x100000_0x200000 : 2; // something something scripts for brains
uint32 bFadingIn : 1; // works only for objects with type 2 (OBJECT_MISSION)
uint32 bAffectedByColBrightness : 1;

Expand Down Expand Up @@ -82,7 +81,7 @@ class NOTSA_EXPORT_VTABLE CObject : public CPhysical {
float m_fScale;
CObjectData* m_pObjectInfo;
CFire* m_pFire;
int16 m_wScriptTriggerIndex;
int16 m_nStreamedScriptBrainToLoad;
int16 m_wRemapTxd; // this is used for detached car parts
RwTexture* m_pRemapTexture; // this is used for detached car parts
CDummyObject* m_pDummyObject; // used for dynamic objects like garage doors, train crossings etc.
Expand Down
8 changes: 4 additions & 4 deletions source/game_sa/Entity/Ped/Ped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ CPed::CPed(ePedType pedType) : CPhysical(), m_pedIK{CPedIK(this)} {

field_758 = 0;
m_fRemovalDistMultiplier = 1.0f;
m_nSpecialModelIndex = -1;
m_StreamedScriptBrainToLoad = -1;

CPopulation::UpdatePedCount(this, 0);

Expand All @@ -318,10 +318,10 @@ CPed::~CPed() {

// Remove script brain
if (bWaitingForScriptBrainToLoad) {
CStreaming::SetMissionDoesntRequireModel(SCMToModelId(CTheScripts::ScriptsForBrains.m_aScriptForBrains[m_nSpecialModelIndex].m_nIMGindex));
CStreaming::SetMissionDoesntRequireModel(SCMToModelId(CTheScripts::ScriptsForBrains.m_aScriptForBrains[m_StreamedScriptBrainToLoad].m_StreamedScriptIndex));
bWaitingForScriptBrainToLoad = false;
CTheScripts::RemoveFromWaitingForScriptBrainArray(this, m_nSpecialModelIndex);
m_nSpecialModelIndex = -1;
CTheScripts::RemoveFromWaitingForScriptBrainArray(this, m_StreamedScriptBrainToLoad);
m_StreamedScriptBrainToLoad = -1;
}

CWorld::Remove(this);
Expand Down
2 changes: 1 addition & 1 deletion source/game_sa/Entity/Ped/Ped.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ class NOTSA_EXPORT_VTABLE CPed : public CPhysical {
CCoverPoint* m_pCoverPoint;
CEntryExit* m_pEnex; // CEnEx *
float m_fRemovalDistMultiplier;
int16 m_nSpecialModelIndex;
int16 m_StreamedScriptBrainToLoad;
int32 field_798;

public:
Expand Down
5 changes: 5 additions & 0 deletions source/game_sa/Entity/Vehicle/Automobile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,11 @@ void CAutomobile::ProcessControl()
}

for (auto& collisionEntity : m_apWheelCollisionEntity) {
// FIXME(yukani): I need this to test anything outside, do not remove
// until game doesn't crash on me here.
if (collisionEntity == (CPhysical*)0xffffffff) {
collisionEntity = nullptr;
}
if (collisionEntity) {
vehicleFlags.bRestingOnPhysical = true;
if (!CWorld::bForceProcessControl && collisionEntity->m_bIsInSafePosition) {
Expand Down
24 changes: 16 additions & 8 deletions source/game_sa/Entity/Vehicle/Heli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,22 @@ void CHeli::SwitchPoliceHelis(bool enable) {

// 0x6C58E0
void CHeli::SearchLightCone(int32 coronaIndex,
CVector origin, CVector target,
CVector origin,
CVector target,
float targetRadius,
float power,
uint8 unknownFlag, uint8 drawShadow,
CVector* useless0, CVector* useless1, CVector* useless2,
bool a11, float baseRadius, float a13,float a14,float a15
uint8 unknownFlag,
uint8 drawShadow,
CVector& useless0,
CVector& useless1,
CVector& useless2,
bool a11,
float baseRadius,
float a13,
float a14,
float a15
) {
((void(__cdecl*)(int32, CVector, CVector, float, float, uint8, uint8, CVector*, CVector*, CVector*, bool, float, float, float, float))0x6C58E0)(coronaIndex, origin, target, targetRadius, power, unknownFlag, drawShadow, useless0, useless1, useless2, a11, baseRadius, a13, a14, a15);
((void(__cdecl*)(int32, CVector, CVector, float, float, uint8, uint8, CVector&, CVector&, CVector&, bool, float, float, float, float))0x6C58E0)(coronaIndex, origin, target, targetRadius, power, unknownFlag, drawShadow, useless0, useless1, useless2, a11, baseRadius, a13, a14, a15);
}

// 0x6C6520
Expand Down Expand Up @@ -245,9 +253,9 @@ void CHeli::RenderAllHeliSearchLights() {
light.m_fPower,
light.field_24,
light.m_bDrawShadow,
light.m_vecUseless,
&light.m_vecUseless[1],
&light.m_vecUseless[2],
light.m_vecUseless[0],
light.m_vecUseless[1],
light.m_vecUseless[2],
false,
0.05f,
0.0f,
Expand Down
16 changes: 12 additions & 4 deletions source/game_sa/Entity/Vehicle/Heli.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,20 @@ class NOTSA_EXPORT_VTABLE CHeli : public CAutomobile {
static void SpecialHeliPreRender(); // dummy function
static void SwitchPoliceHelis(bool enable);
static void SearchLightCone(int32 coronaIndex,
CVector origin, CVector target,
CVector origin,
CVector target,
float targetRadius,
float power,
uint8 unknownFlag, uint8 drawShadow,
CVector* useless0, CVector* useless1, CVector* useless2,
bool a11, float baseRadius, float a13, float a14, float a15);
uint8 clipIfColliding,
uint8 drawShadow,
CVector& useless0,
CVector& useless1,
CVector& useless2,
bool a11,
float baseRadius,
float a13,
float a14,
float a15);
static CHeli* GenerateHeli(CPed* target, bool newsHeli);
static void TestSniperCollision(CVector* origin, CVector* target);
static void UpdateHelis();
Expand Down
4 changes: 2 additions & 2 deletions source/game_sa/Entity/Vehicle/Vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3080,7 +3080,7 @@ void CVehicle::SetupRender() {
vehicleFlags.bDontSetColourWhenRemapping = false;
} else {
// Make sure it's loaded, if not, request it to be loaded
if (CStreaming::IsModelLoaded(ModelIdToTXD(m_nRemapTxd))) {
if (CStreaming::IsModelLoaded(TXDToModelId(m_nRemapTxd))) {
// If there was a remap texture set, remove it
if (m_pRemapTexture) {
m_pRemapTexture = nullptr;
Expand All @@ -3105,7 +3105,7 @@ void CVehicle::SetupRender() {
m_nPrimaryColor = 1;
}
} else {
CStreaming::RequestModel(ModelIdToTXD(m_nRemapTxd), STREAMING_KEEP_IN_MEMORY);
CStreaming::RequestModel(TXDToModelId(m_nRemapTxd), STREAMING_KEEP_IN_MEMORY);
}
}

Expand Down
13 changes: 8 additions & 5 deletions source/game_sa/FireManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CEntity;

class CFireManager {
public:
CFire m_aFires[MAX_NUM_FIRES];
std::array<CFire, MAX_NUM_FIRES> m_aFires;
uint32 m_nMaxFireGenerationsAllowed;

public:
Expand Down Expand Up @@ -57,16 +57,19 @@ class CFireManager {
uint32 GetNumOfFires();
CFire& GetRandomFire();

// NOTSA
CFire& Get(size_t idx)
{
assert(m_aFires[idx].IsActive());
return m_aFires[idx];
}
auto GetIndexOf(const CFire* fire) const { return std::distance(m_aFires.data(), fire); }
private:
friend void InjectHooksMain();
static void InjectHooks();

CFireManager* Constructor();
CFireManager* Destructor();

// NOTSA
CFire& Get(size_t idx) { return m_aFires[idx]; }
auto GetIndexOf(const CFire* fire) const { return std::distance(std::begin(m_aFires), fire); }
};

VALIDATE_SIZE(CFireManager, 0x964);
Expand Down
Loading

0 comments on commit 4a7fdc0

Please sign in to comment.