From 77d61dcdd229bf155a4c2d262ec3af12ac13be46 Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 19 Aug 2014 12:57:35 +0200 Subject: [PATCH] Refined weapon rendering --- SAFix/GeneralSA.cpp | 2 + SAFix/GeneralSA.h | 181 +++++++++++++++++++++ SAFix/PedSA.cpp | 77 +++++++++ SAFix/PedSA.h | 305 ++++++++++++++++++++++++++++++++++++ SAFix/SAFix.vcxproj | 2 + SAFix/SAFix.vcxproj.filters | 6 + SAFix/SilentPatchSA.cpp | 107 +++++++++---- SAFix/StdAfxSA.h | 2 + 8 files changed, 653 insertions(+), 29 deletions(-) create mode 100644 SAFix/PedSA.cpp create mode 100644 SAFix/PedSA.h diff --git a/SAFix/GeneralSA.cpp b/SAFix/GeneralSA.cpp index 4e557b2..b9242e2 100644 --- a/SAFix/GeneralSA.cpp +++ b/SAFix/GeneralSA.cpp @@ -5,6 +5,8 @@ static void* EntityRender = AddressByVersion(0x534310, 0, 0); WRAPPER void CEntity::Render() { VARJMP(EntityRender); } +CWeaponInfo* (*CWeaponInfo::GetWeaponInfo)(eWeaponType, signed char) = AddressByVersion(0x743C60, 0, 0); + static RwTexture*& ms_pRemapTexture = **AddressByVersion(0x59F1BD, 0, 0); static unsigned char* ms_currentCol = *AddressByVersion(0x4C84C8, 0, 0); diff --git a/SAFix/GeneralSA.h b/SAFix/GeneralSA.h index 0888b0f..0f1f0a1 100644 --- a/SAFix/GeneralSA.h +++ b/SAFix/GeneralSA.h @@ -368,6 +368,187 @@ public: unsigned char flags; }; +enum eWeaponSkill +{ + WEAPONSKILL_POOR = 0, + WEAPONSKILL_STD, + WEAPONSKILL_PRO, + WEAPONSKILL_SPECIAL, // for cops using pistols differently for example + WEAPONSKILL_MAX_NUMBER +}; + +enum eFireType +{ + FIRETYPE_MELEE, + FIRETYPE_INSTANT_HIT, + FIRETYPE_PROJECTILE, + FIRETYPE_AREA_EFFECT, + FIRETYPE_CAMERA, + FIRETYPE_USE, + + FIRETYPE_LAST_FIRETYPE +}; + +enum eWeaponSlot +{ + WEAPONSLOT_TYPE_UNARMED = 0, + WEAPONSLOT_TYPE_MELEE, + WEAPONSLOT_TYPE_HANDGUN, + WEAPONSLOT_TYPE_SHOTGUN, + WEAPONSLOT_TYPE_SMG, //4 + WEAPONSLOT_TYPE_MG, + WEAPONSLOT_TYPE_RIFLE, + WEAPONSLOT_TYPE_HEAVY, + WEAPONSLOT_TYPE_THROWN, + WEAPONSLOT_TYPE_SPECIAL, //9 + WEAPONSLOT_TYPE_GIFT, //10 + WEAPONSLOT_TYPE_PARACHUTE, //11 + WEAPONSLOT_TYPE_DETONATOR, //12 + + WEAPONSLOT_MAX +}; + +enum eWeaponState +{ + WEAPONSTATE_READY, + WEAPONSTATE_FIRING, + WEAPONSTATE_RELOADING, + WEAPONSTATE_OUT_OF_AMMO, + WEAPONSTATE_MELEE_MADECONTACT +}; + +/** + * Contains the weapon types/models + */ +enum eWeaponType +{ + WEAPONTYPE_UNARMED=0, + WEAPONTYPE_BRASSKNUCKLE, + WEAPONTYPE_GOLFCLUB, + WEAPONTYPE_NIGHTSTICK, + WEAPONTYPE_KNIFE, + WEAPONTYPE_BASEBALLBAT, + WEAPONTYPE_SHOVEL, + WEAPONTYPE_POOL_CUE, + WEAPONTYPE_KATANA, + WEAPONTYPE_CHAINSAW, + + // gifts + WEAPONTYPE_DILDO1, // 10 + WEAPONTYPE_DILDO2, + WEAPONTYPE_VIBE1, + WEAPONTYPE_VIBE2, + WEAPONTYPE_FLOWERS, + WEAPONTYPE_CANE, + + WEAPONTYPE_GRENADE, + WEAPONTYPE_TEARGAS, + WEAPONTYPE_MOLOTOV, + WEAPONTYPE_ROCKET, + WEAPONTYPE_ROCKET_HS, // 20 + WEAPONTYPE_FREEFALL_BOMB, + + // FIRST SKILL WEAPON + WEAPONTYPE_PISTOL, // handguns + WEAPONTYPE_PISTOL_SILENCED, + WEAPONTYPE_DESERT_EAGLE, + WEAPONTYPE_SHOTGUN, // shotguns + WEAPONTYPE_SAWNOFF_SHOTGUN, // one handed + WEAPONTYPE_SPAS12_SHOTGUN, + WEAPONTYPE_MICRO_UZI, // submachine guns + WEAPONTYPE_MP5, + WEAPONTYPE_AK47, // 30 // machine guns + WEAPONTYPE_M4, + WEAPONTYPE_TEC9, // this uses stat from the micro_uzi + // END SKILL WEAPONS + + WEAPONTYPE_COUNTRYRIFLE, // rifles + WEAPONTYPE_SNIPERRIFLE, + WEAPONTYPE_ROCKETLAUNCHER, // specials + WEAPONTYPE_ROCKETLAUNCHER_HS, + WEAPONTYPE_FLAMETHROWER, + WEAPONTYPE_MINIGUN, + WEAPONTYPE_REMOTE_SATCHEL_CHARGE, + WEAPONTYPE_DETONATOR, // 40 // plastic explosive + WEAPONTYPE_SPRAYCAN, + WEAPONTYPE_EXTINGUISHER, + WEAPONTYPE_CAMERA, + WEAPONTYPE_NIGHTVISION, + WEAPONTYPE_INFRARED, + WEAPONTYPE_PARACHUTE, + WEAPONTYPE_LAST_WEAPONTYPE, + + WEAPONTYPE_ARMOUR, + // these are possible ways to die + WEAPONTYPE_RAMMEDBYCAR, + WEAPONTYPE_RUNOVERBYCAR, // 50 + WEAPONTYPE_EXPLOSION, + WEAPONTYPE_UZI_DRIVEBY, + WEAPONTYPE_DROWNING, + WEAPONTYPE_FALL, + WEAPONTYPE_UNIDENTIFIED, // Used for damage being done + WEAPONTYPE_ANYMELEE, + WEAPONTYPE_ANYWEAPON, + WEAPONTYPE_FLARE, +}; + +class CWeapon +{ +public: + eWeaponType m_eWeaponType; + eWeaponState m_eState; + int m_nAmmoInClip; + int m_nAmmoTotal; + int m_nTimer; + int m_Unknown; + void* m_pParticle; +}; + +class CWeaponInfo +{ +public: + DWORD weaponType; + DWORD targetRange; + DWORD weaponRange; + int dwModelID; + int dwModelID2; + int nSlot; + DWORD hexFlags; + DWORD animStyle; + WORD ammoClip; + DWORD fireOffsetX; + DWORD fireOffsetY; + DWORD fireOffsetZ; + DWORD skillLevel; + DWORD reqStatLevel; + float accuracy; + DWORD moveSpeed; + DWORD animLoopStart; + DWORD animLoopEnd; + DWORD animLoopFire; + DWORD animLoop2Start; + DWORD animLoop2End; + DWORD animLoop2Fire; + DWORD breakoutTime; + DWORD speed; + DWORD radius; + DWORD lifespan; + DWORD spread; + DWORD animStyle2; + +public: + inline float GetAccuracy() + { return accuracy; }; + inline DWORD GetWeaponType() + { return weaponType; }; + inline DWORD GetClipSize() + { return ammoClip; }; + inline DWORD GetWeaponSlot() + { return nSlot; }; + + static CWeaponInfo* (*GetWeaponInfo)(eWeaponType weaponID, signed char bType); +}; + static_assert(sizeof(CEntity) == 0x38, "Wrong size: CEntity"); static_assert(sizeof(CPhysical) == 0x138, "Wrong size: CPhysical"); static_assert(sizeof(CObject) == 0x17C, "Wrong size: CObject"); diff --git a/SAFix/PedSA.cpp b/SAFix/PedSA.cpp new file mode 100644 index 0000000..65212b0 --- /dev/null +++ b/SAFix/PedSA.cpp @@ -0,0 +1,77 @@ +#include "StdAfxSA.h" +#include "PedSA.h" + +static void* varGetWeaponSkill = AddressByVersion(0x5E6580, 0, 0); +WRAPPER unsigned char CPed::GetWeaponSkill() { VARJMP(varGetWeaponSkill); } +static void* varResetGunFlashAlpha = AddressByVersion(0x5DF4E0, 0, 0); +WRAPPER void CPed::ResetGunFlashAlpha() { VARJMP(varResetGunFlashAlpha); } +static void* varSetGunFlashAlpha = AddressByVersion(0x5DF400, 0, 0); +WRAPPER void CPed::SetGunFlashAlpha(bool bSecondWeapon) { WRAPARG(bSecondWeapon); VARJMP(varSetGunFlashAlpha); } + +static RwObject* GetFirstObjectCallback(RwObject* pObject, void* pData) +{ + *static_cast(pData) = pObject; + return nullptr; +} + +RwObject* GetFirstObject(RwFrame* pFrame) +{ + RwObject* pObject = nullptr; + RwFrameForAllObjects(pFrame, GetFirstObjectCallback, &pObject); + return pObject; +} + +void CPed::RenderWeapon(bool bMuzzleFlash) +{ + if ( m_pWeaponObject ) + { + RpHAnimHierarchy* pAnimHierarchy = GetAnimHierarchyFromSkinClump(m_pRwObject); + bool bHasParachute = weaponSlots[m_bActiveWeapon].m_eWeaponType == WEAPONTYPE_PARACHUTE; + + RwFrame* pFrame = RpClumpGetFrame(reinterpret_cast(m_pWeaponObject)); + *RwFrameGetMatrix(pFrame) = RpHAnimHierarchyGetMatrixArray(pAnimHierarchy)[RpHAnimIDGetIndex(pAnimHierarchy, bHasParachute ? 3 : 24)]; + + if ( bHasParachute ) + { + const RwV3d vecParachuteTranslation = { 0.1f, -0.15f, 0.0f }; + const RwV3d vecParachuteRotation = { 0.0f, 1.0f, 0.0f }; + RwMatrixTranslate(RwFrameGetMatrix(pFrame), &vecParachuteTranslation, rwCOMBINEPRECONCAT); + RwMatrixRotate(RwFrameGetMatrix(pFrame), &vecParachuteRotation, 90.0f, rwCOMBINEPRECONCAT); + } + + RwFrameUpdateObjects(pFrame); + if ( !bMuzzleFlash ) + { + RpClumpRender(reinterpret_cast(m_pWeaponObject)); + } + else if ( m_pMuzzleFlashFrame ) + { + SetGunFlashAlpha(false); + RpAtomicRender(reinterpret_cast(GetFirstObject(m_pMuzzleFlashFrame))); + } + + // Dual weapons + if ( CWeaponInfo::GetWeaponInfo(weaponSlots[m_bActiveWeapon].m_eWeaponType, GetWeaponSkill())->hexFlags >> 11 & 1 ) + { + *RwFrameGetMatrix(pFrame) = RpHAnimHierarchyGetMatrixArray(pAnimHierarchy)[RpHAnimIDGetIndex(pAnimHierarchy, 34)]; + + const RwV3d vecParachuteRotation = { 1.0f, 0.0f, 0.0f }; + const RwV3d vecParachuteTranslation = { 0.04f, -0.05f, 0.0f }; + RwMatrixRotate(RwFrameGetMatrix(pFrame), &vecParachuteRotation, 180.0f, rwCOMBINEPRECONCAT); + RwMatrixTranslate(RwFrameGetMatrix(pFrame), &vecParachuteTranslation, rwCOMBINEPRECONCAT); + + RwFrameUpdateObjects(pFrame); + if ( !bMuzzleFlash ) + { + RpClumpRender(reinterpret_cast(m_pWeaponObject)); + } + else if ( m_pMuzzleFlashFrame ) + { + SetGunFlashAlpha(true); + RpAtomicRender(reinterpret_cast(GetFirstObject(m_pMuzzleFlashFrame))); + } + } + if ( bMuzzleFlash ) + ResetGunFlashAlpha(); + } +} \ No newline at end of file diff --git a/SAFix/PedSA.h b/SAFix/PedSA.h new file mode 100644 index 0000000..2ef18fb --- /dev/null +++ b/SAFix/PedSA.h @@ -0,0 +1,305 @@ +#ifndef __PEDSA +#define __PEDSA + +#include "GeneralSA.h" + +class CEntryExit; + +class CPedFlags +{ +public: + unsigned int bIsStanding : 1; // is ped standing on something + unsigned int bWasStanding : 1; // was ped standing on something + unsigned int bIsLooking : 1; // is ped looking at something or in a direction + unsigned int bIsRestoringLook : 1; // is ped restoring head postion from a look + unsigned int bIsAimingGun : 1; // is ped aiming gun + unsigned int bIsRestoringGun : 1; // is ped moving gun back to default posn + unsigned int bCanPointGunAtTarget : 1; // can ped point gun at target + unsigned int bIsTalking : 1; // is ped talking(see Chat()) + + unsigned int bInVehicle : 1; // is in a vehicle + unsigned int bIsInTheAir : 1; // is in the air + unsigned int bIsLanding : 1; // is landing after being in the air + unsigned int bHitSomethingLastFrame : 1; // has been in a collision last fram + unsigned int bIsNearCar : 1; // has been in a collision last fram + unsigned int bRenderPedInCar : 1; // has been in a collision last fram + unsigned int bUpdateAnimHeading : 1; // update ped heading due to heading change during anim sequence + unsigned int bRemoveHead : 1; // waiting on AntiSpazTimer to remove head + + unsigned int bFiringWeapon : 1; // is pulling trigger + unsigned int bHasACamera : 1; // does ped possess a camera to document accidents + unsigned int bPedIsBleeding : 1; // Ped loses a lot of blood if true + unsigned int bStopAndShoot : 1; // Ped cannot reach target to attack with fist, need to use gun + unsigned int bIsPedDieAnimPlaying : 1; // is ped die animation finished so can dead now + unsigned int bStayInSamePlace :1; // when set, ped stays put + unsigned int bKindaStayInSamePlace :1; // when set, ped doesn't seek out opponent or cover large distances. Will still shuffle and look for cover + unsigned int bBeingChasedByPolice :1; // use nodes for routefind + + unsigned int bNotAllowedToDuck :1; // Is this ped allowed to duck at all? + unsigned int bCrouchWhenShooting :1; // duck behind cars etc + unsigned int bIsDucking :1; // duck behind cars etc + unsigned int bGetUpAnimStarted :1; // don't want to play getup anim if under something + unsigned int bDoBloodyFootprints :1; // unsigned int bIsLeader :1; + unsigned int bDontDragMeOutCar :1; + unsigned int bStillOnValidPoly :1; // set if the polygon the ped is on is still valid for collision + unsigned int bAllowMedicsToReviveMe :1; + + unsigned int bResetWalkAnims :1; + unsigned int bOnBoat :1; // flee but only using nodes + unsigned int bBusJacked :1; // flee but only using nodes + unsigned int bFadeOut :1; // set if you want ped to fade out + unsigned int bKnockedUpIntoAir :1; // has ped been knocked up into the air by a car collision + unsigned int bHitSteepSlope :1; // has ped collided/is standing on a steep slope (surface type) + unsigned int bCullExtraFarAway :1; // special ped only gets culled if it's extra far away (for roadblocks) + unsigned int bTryingToReachDryLand :1; // has ped just exited boat and trying to get to dry land + + unsigned int bCollidedWithMyVehicle :1; + unsigned int bRichFromMugging :1; // ped has lots of cash cause they've been mugging people + unsigned int bChrisCriminal :1; // Is a criminal as killed during Chris' police mission (should be counted as such) + unsigned int bShakeFist :1; // test shake hand at look entity + unsigned int bNoCriticalHits : 1; // ped cannot be killed by a single bullet + unsigned int bHasAlreadyBeenRecorded : 1; // Used for replays + unsigned int bUpdateMatricesRequired : 1; // if PedIK has altered bones so matrices need updated this frame + unsigned int bFleeWhenStanding :1; // + + unsigned int bMiamiViceCop :1; // + unsigned int bMoneyHasBeenGivenByScript :1; // + unsigned int bHasBeenPhotographed :1; // + unsigned int bIsDrowning : 1; + unsigned int bDrownsInWater : 1; + unsigned int bHeadStuckInCollision : 1; + unsigned int bDeadPedInFrontOfCar :1; + unsigned int bStayInCarOnJack :1; + + unsigned int bDontFight :1; + unsigned int bDoomAim :1; + unsigned int bCanBeShotInVehicle : 1; + unsigned int bPushedAlongByCar :1; // ped is getting pushed along by car collision (so don't take damage from horz velocity) + unsigned int bNeverEverTargetThisPed :1; + unsigned int bThisPedIsATargetPriority :1; + unsigned int bCrouchWhenScared :1; + unsigned int bKnockedOffBike :1; + + unsigned int bDonePositionOutOfCollision :1; + unsigned int bDontRender : 1; + unsigned int bHasBeenAddedToPopulation :1; + unsigned int bHasJustLeftCar :1; + unsigned int bIsInDisguise :1; + unsigned int bDoesntListenToPlayerGroupCommands :1; + unsigned int bIsBeingArrested :1; + unsigned int bHasJustSoughtCover :1; + + unsigned int bKilledByStealth :1; + unsigned int bDoesntDropWeaponsWhenDead :1; + unsigned int bCalledPreRender :1; + unsigned int bBloodPuddleCreated : 1; // Has a static puddle of blood been created yet + unsigned int bPartOfAttackWave :1; + unsigned int bClearRadarBlipOnDeath :1; + unsigned int bNeverLeavesGroup :1; // flag that we want to test 3 extra spheres on col model + unsigned int bTestForBlockedPositions :1; // this sets these indicator flags for various posisions on the front of the ped + + unsigned int bRightArmBlocked :1; + unsigned int bLeftArmBlocked :1; + unsigned int bDuckRightArmBlocked :1; + unsigned int bMidriffBlockedForJump :1; + unsigned int bFallenDown :1; + unsigned int bUseAttractorInstantly :1; + unsigned int bDontAcceptIKLookAts :1; + unsigned int bHasAScriptBrain : 1; + + unsigned int bWaitingForScriptBrainToLoad : 1; + unsigned int bHasGroupDriveTask :1; + unsigned int bCanExitCar :1; + unsigned int CantBeKnockedOffBike :2; // 0=Default(harder for mission peds) 1=Never 2=Always normal(also for mission peds) + unsigned int bHasBeenRendered : 1; + unsigned int bIsCached :1; + unsigned int bPushOtherPeds :1; // GETS RESET EVERY FRAME - SET IN TASK: want to push other peds around (eg. leader of a group or ped trying to get in a car) + unsigned int bHasBulletProofVest :1; + + unsigned int bUsingMobilePhone :1; + unsigned int bUpperBodyDamageAnimsOnly :1; + unsigned int bStuckUnderCar :1; + unsigned int bKeepTasksAfterCleanUp :1; // If true ped will carry on with task even after cleanup + unsigned int bIsDyingStuck :1; + unsigned int bIgnoreHeightCheckOnGotoPointTask :1; // set when walking round buildings, reset when task quits + unsigned int bForceDieInCar:1; + unsigned int bCheckColAboveHead:1; + + unsigned int bIgnoreWeaponRange : 1; + unsigned int bDruggedUp : 1; + unsigned int bWantedByPolice : 1; // if this is set, the cops will always go after this ped when they are doing a KillCriminal task + unsigned int bSignalAfterKill: 1; + unsigned int bCanClimbOntoBoat :1; + unsigned int bPedHitWallLastFrame: 1; // useful to store this so that AI knows (normal will still be available) + unsigned int bIgnoreHeightDifferenceFollowingNodes: 1; + unsigned int bMoveAnimSpeedHasBeenSetByTask: 1; + + unsigned int bGetOutUpsideDownCar :1; + unsigned int bJustGotOffTrain :1; + unsigned int bDeathPickupsPersist :1; + unsigned int bTestForShotInVehicle :1; + unsigned int bUsedForReplay : 1; // This ped is controlled by replay and should be removed when replay is done. +}; + +class CVehicle; +class CPed; + +class CPlayerPedData +{ +public: + class CWanted* m_Wanted; // 0x0 + void* m_pClothes; // 0x4 + CPed* m_ArrestingOfficer; // 0x8 + CVector2D m_vecFightMovement; // 0xC + float m_moveBlendRatio; // 0x14 + float m_fSprintEnergy; // 0x18 + float m_fSprintControlCounter; // 0x1C + BYTE m_nChosenWeapon; // 0x20 + BYTE m_nCarDangerCounter; // 0x21 + DWORD m_nStandStillTimer; // 0x24 + DWORD m_nHitAnimDelayTimer; // 0x28 + float m_fAttackButtonCounter; // 0x2C + void *m_pDangerCar; // 0x30 + + DWORD m_bStoppedMoving : 1; // 0x34 + DWORD m_bAdrenaline : 1; + DWORD m_bHaveTargetSelected : 1; + DWORD m_bFreeAiming : 1; + DWORD bCanBeDamaged : 1; + DWORD bAllMeleeAttackPtsBlocked : 1; + DWORD m_JustBeenSnacking : 1; + DWORD m_bRequireHandleBreath : 1; + + DWORD m_GroupStuffDisabled : 1; // 0x35 + DWORD m_GroupAlwaysFollow : 1; + DWORD m_GroupNeverFollow : 1; + DWORD m_bInVehicleDontAllowWeaponChange : 1; + DWORD m_bRenderWeapon : 1; + DWORD m_bUnused1 : 1; + DWORD m_bUnused2 : 1; + DWORD m_bUnused3 : 1; + + DWORD m_bCopMode : 1; // 0x36 + + DWORD m_PlayerGroup; // 0x38 + + DWORD m_AdrenalineEndTime; // 0x3C + BYTE m_nDrunkenness; // 0x40 + BYTE m_bFadeDrunkenness; // 0x41 + BYTE m_nDrugLevel; // 0x42 + BYTE m_nScriptLimitToGangSize; // 0x43 + float m_fBreath; // 0x44 + DWORD m_MeleeWeaponAnimReferenced; // 0x48 + DWORD m_MeleeWeaponAnimReferencedExtra; // 0x4C + float m_fFPSMoveHeading; // 0x50 + float m_fLookPitch; // 0x54 + float m_fSkateBoardSpeed; // 0x58 + float m_fSkateBoardLean; // 0x5C + + void *m_pSpecialAtomic; // 0x60 + float m_fGunSpinSpeed; // 0x64 + float m_fGunSpinAngle; // 0x68 + + DWORD m_LastTimeFiring; // 0x6C + DWORD m_nTargetBone; // 0x70 + CVector m_vecTargetBoneOffset; // 0x74 + DWORD m_busFaresCollected; // 0x80 + BYTE m_bPlayerSprintDisabled; // 0x84 + BYTE m_bDontAllowWeaponChange; // 0x85 + BYTE m_bForceInteriorLighting; // 0x86 + WORD m_DPadDownPressedInMilliseconds; // 0x88 + WORD m_DPadUpPressedInMilliseconds; // 0x8A + BYTE m_wetness; // 0x8C + BYTE m_playersGangActive; // 0x8D + BYTE m_waterCoverPerc; // 0x8E + FLOAT m_waterHeight; // 0x90 + DWORD m_FireHSMissilePressedTime; // 0x94 + void* m_LastHSMissileTarget; + DWORD m_nModelIndexOfLastBuildingShot; + DWORD m_LastHSMissileLOSTime :31; + DWORD m_bLastHSMissileLOS :1; + void* m_pCurrentProstitutePed; + void* m_pLastProstituteShagged; +}; + +class NOVMT CPed : public CPhysical +{ +public: + BYTE __pad1[820]; + CPedFlags pedFlags; + class CPedIntelligence* pPedIntelligence; + CPlayerPedData* pPlayerData; + unsigned char PedCreatedBy; + BYTE __pad7[76]; + int iMoveAnimGroup; + BYTE __pad2[28]; + RwObject* m_pWeaponObject; + RwFrame* m_pMuzzleFlashFrame; + BYTE __pad10[68]; + float fHealth; + float fMaxHealth; + float fArmour; + BYTE __pad8[12]; + float m_fCurrentRotation; + float m_fTargetRotation; + BYTE __pad3[44]; + CVehicle* pVehicle; + BYTE __pad9[8]; + DWORD pedType; + BYTE __pad4[4]; + CWeapon weaponSlots[13]; + BYTE __pad5[12]; + BYTE m_bActiveWeapon; + BYTE __pad65[20]; + unsigned char bFightingStyle, bFightingStyleExtra; + BYTE __pad6[92]; + CEntryExit* pCurrentEntryExit; + BYTE __pad64[12]; + +public: + inline bool Save_Stub() + { return CPed::Save(); } + inline bool Load_Stub() + { return CPed::Load(); } + + virtual bool Save(); + virtual bool Load(); + + inline DWORD GetPedType() + { return pedType; }; + inline CPedFlags& GetPedFlags() + { return pedFlags; }; + inline CVehicle* GetVehiclePtr() + { return pVehicle; }; + inline CWeapon* GetWeaponSlots() + { return weaponSlots; }; + inline int GetMoveAnimGroup() + { return iMoveAnimGroup; }; + inline void SetMoveAnimGroup(int a) + { iMoveAnimGroup = a; }; + inline CPedIntelligence* GetPedIntelligencePtr() + { return pPedIntelligence; }; + inline float GetHealth() + { return fHealth; }; + inline float GetArmour() + { return fArmour; }; + inline CPlayerPedData* GetPlayerData() + { return pPlayerData; }; + inline BYTE GetActiveWeapon() + { return m_bActiveWeapon; }; + + inline void SetCurrentHeading(float fVal) + { m_fCurrentRotation = fVal; } + inline void SetTargetHeading(float fVal) + { m_fTargetRotation = fVal; } + + unsigned char GetWeaponSkill(); + void ResetGunFlashAlpha(); + void SetGunFlashAlpha(bool bSecondWeapon); + + void RenderWeapon(bool bMuzzleFlash); +}; + +static_assert(sizeof(CPed) == 0x79C, "Wrong size: CPed"); + +#endif \ No newline at end of file diff --git a/SAFix/SAFix.vcxproj b/SAFix/SAFix.vcxproj index 56ca927..22b83ab 100644 --- a/SAFix/SAFix.vcxproj +++ b/SAFix/SAFix.vcxproj @@ -95,6 +95,7 @@ + @@ -131,6 +132,7 @@ + diff --git a/SAFix/SAFix.vcxproj.filters b/SAFix/SAFix.vcxproj.filters index 835c086..0d17689 100644 --- a/SAFix/SAFix.vcxproj.filters +++ b/SAFix/SAFix.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + @@ -109,6 +112,9 @@ Header Files + + Header Files + diff --git a/SAFix/SilentPatchSA.cpp b/SAFix/SilentPatchSA.cpp index 92c4675..ff488cc 100644 --- a/SAFix/SilentPatchSA.cpp +++ b/SAFix/SilentPatchSA.cpp @@ -4,6 +4,7 @@ #include "GeneralSA.h" #include "ModelInfoSA.h" #include "VehicleSA.h" +#include "PedSA.h" #include "AudioHardwareSA.h" #include "LinkListSA.h" #include "PNGFile.h" @@ -23,6 +24,10 @@ static void* varRpMaterialSetTexture = AddressByVersion(0x74DBC0, 0, 0); WRAPPER RpMaterial *RpMaterialSetTexture(RpMaterial *material, RwTexture *texture) { VARJMP(varRpMaterialSetTexture); } static void* varRwFrameGetLTM = AddressByVersion(0x7F0990, 0, 0); WRAPPER RwMatrix* RwFrameGetLTM(RwFrame* frame) { VARJMP(varRwFrameGetLTM); } +static void* varRwMatrixTranslate = AddressByVersion(0x7F2450, 0, 0); +WRAPPER RwMatrix* RwMatrixTranslate(RwMatrix* matrix, const RwV3d* translation, RwOpCombineType combineOp) { WRAPARG(matrix); WRAPARG(translation); WRAPARG(combineOp); VARJMP(varRwMatrixTranslate); } +static void* varRwMatrixRotate = AddressByVersion(0x7F1FD0, 0, 0); +WRAPPER RwMatrix* RwMatrixRotate(RwMatrix* matrix, const RwV3d* axis, RwReal angle, RwOpCombineType combineOp) { WRAPARG(matrix); WRAPARG(axis); WRAPARG(angle); WRAPARG(combineOp); VARJMP(varRwMatrixRotate); } static void* varRwD3D9SetRenderState = AddressByVersion(0x7FC2D0, 0, 0); WRAPPER void RwD3D9SetRenderState(RwUInt32 state, RwUInt32 value) { WRAPARG(state); WRAPARG(value); VARJMP(varRwD3D9SetRenderState); } static void* var_rwD3D9SetVertexShader = AddressByVersion(0x7F9FB0, 0, 0); @@ -67,6 +72,16 @@ RwFrame* RwFrameForAllObjects(RwFrame* frame, RwObjectCallBack callBack, void* d return frame; } +RwFrame* RwFrameUpdateObjects(RwFrame* frame) +{ + if ( !rwObjectTestPrivateFlags(&frame->root->object, rwFRAMEPRIVATEHIERARCHYSYNCLTM|rwFRAMEPRIVATEHIERARCHYSYNCOBJ) ) + rwLinkListAddLLLink(&RWSRCGLOBAL(dirtyFrameList), &frame->root->inDirtyListLink); + + rwObjectSetPrivateFlags(&frame->root->object, rwObjectGetPrivateFlags(&frame->root->object) | (rwFRAMEPRIVATEHIERARCHYSYNCLTM|rwFRAMEPRIVATEHIERARCHYSYNCOBJ)); + rwObjectSetPrivateFlags(&frame->object, rwObjectGetPrivateFlags(&frame->object) | (rwFRAMEPRIVATESUBTREESYNCLTM|rwFRAMEPRIVATESUBTREESYNCOBJ)); + return frame; +} + RwMatrix* RwMatrixUpdate(RwMatrix* matrix) { matrix->flags &= ~(rwMATRIXTYPEMASK|rwMATRIXINTERNALIDENTITY); @@ -108,6 +123,23 @@ RpClump* RpClumpForAllAtomics(RpClump* clump, RpAtomicCallBack callback, void* p return clump; } +RpClump* RpClumpRender(RpClump* clump) +{ + for ( RwLLLink* link = rwLinkListGetFirstLLLink(&clump->atomicList); link != rwLinkListGetTerminator(&clump->atomicList); link = rwLLLinkGetNext(link) ) + { + RpAtomic* curAtomic = rwLLLinkGetData(link, RpAtomic, inClumpLink); + if ( RpAtomicGetFlags(curAtomic) & rpATOMICRENDER ) + { + // Not sure why they need this + RwFrameGetLTM(RpAtomicGetFrame(curAtomic)); + if ( !RpAtomicRender(curAtomic) ) + return NULL; + } + } + return clump; + +} + RpGeometry* RpGeometryForAllMaterials(RpGeometry* geometry, RpMaterialCallBack fpCallBack, void* pData) { for ( RwInt32 i = 0, j = geometry->matList.numMaterials; i < j; i++ ) @@ -118,9 +150,32 @@ RpGeometry* RpGeometryForAllMaterials(RpGeometry* geometry, RpMaterialCallBack f return geometry; } +RwInt32 RpHAnimIDGetIndex(RpHAnimHierarchy* hierarchy, RwInt32 ID) +{ + RpHAnimNodeInfo* curNodeInfo = hierarchy->pNodeInfo; + RwInt32 curNumNodes = hierarchy->numNodes; + + if ( curNumNodes > 0 ) + { + for ( RwInt32 i = 0; i < curNumNodes; i++ ) + { + if ( ID == curNodeInfo->nodeID ) + return i; + curNodeInfo++; + } + } + return -1; +} + +RwMatrix* RpHAnimHierarchyGetMatrixArray(RpHAnimHierarchy* hierarchy) +{ + return hierarchy->pMatrixArray; +} + // Other wrappers void (*GTAdelete)(void*) = AddressByVersion(0x82413F, 0, 0); const char* (*GetFrameNodeName)(RwFrame*) = AddressByVersion(0x72FB30, 0, 0); +RpHAnimHierarchy* (*GetAnimHierarchyFromSkinClump)(RpClump*) = AddressByVersion(0x734A40, 0, 0); auto SetVolume = AddressByVersion(0x4D7C60, 0, 0); auto InitializeUtrax = AddressByVersion(0x4F35B0, 0, 0); auto CanSeeOutSideFromCurrArea = AddressByVersion(0x53C4A0, 0, 0); @@ -128,9 +183,6 @@ auto CanSeeOutSideFromCurrArea = AddressByVersion(0x53C4A0, 0, 0) auto __rwD3D9TextureHasAlpha = AddressByVersion(0x4C9EA0, 0, 0); auto RenderOneXLUSprite = AddressByVersion(0x70D000, 0, 0); -// That function is fake -auto RenderWeaponHooked = AddressByVersion(0x732F95, 0, 0); - static BOOL (*IsAlreadyRunning)(); static void (*TheScriptsLoad)(); static void (*WipeLocalVariableMemoryForMissionScript)(); @@ -162,7 +214,7 @@ unsigned char* ZonesVisited = *AddressByVersion(0x57216A, 0, float& m_fDNBalanceParam = **AddressByVersion(0x4A9062, 0, 0); RpLight*& pAmbient = **AddressByVersion(0x5BA53A, 0, 0); -CLinkListSA& ms_weaponPedsForPC = **AddressByVersion**>(0x53EACA, 0, 0); +CLinkListSA& ms_weaponPedsForPC = **AddressByVersion**>(0x53EACA, 0, 0); CLinkListSA& m_alphaList = **AddressByVersion**>(0x733A4D, 0, 0); @@ -398,31 +450,26 @@ void SetRendererForAtomic(RpAtomic* pAtomic) RpAtomicSetRenderCallBack(pAtomic, renderer); } -void RenderWeapon(CEntity* pEntity) +void RenderWeapon(CPed* pPed) { - int nPushedAlpha, nAlphaFunction; - - RwRenderStateGet(rwRENDERSTATEALPHATESTFUNCTIONREF, &nPushedAlpha); - RwRenderStateGet(rwRENDERSTATEALPHATESTFUNCTION, &nAlphaFunction); - - if ( nPushedAlpha != 255 ) - RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTIONREF, reinterpret_cast(255)); - - if ( nAlphaFunction != rwALPHATESTFUNCTIONEQUAL ) - RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTION, reinterpret_cast(rwALPHATESTFUNCTIONEQUAL)); - - RenderWeaponHooked(pEntity); - - if ( nPushedAlpha != 255 ) - RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTIONREF, reinterpret_cast(nPushedAlpha)); - - if ( nAlphaFunction != rwALPHATESTFUNCTIONEQUAL ) - RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTION, reinterpret_cast(nAlphaFunction)); - - ms_weaponPedsForPC.Insert(pEntity); + pPed->RenderWeapon(false); + ms_weaponPedsForPC.Insert(pPed); } -void RenderWeaponsList() +void RenderWeaponPedsForPC() +{ + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(TRUE)); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); + + for ( auto it = ms_weaponPedsForPC.m_lnListHead.m_pNext; it != &ms_weaponPedsForPC.m_lnListTail; it = it->m_pNext ) + { + it->V()->SetupLighting(); + it->V()->RenderWeapon(true); + it->V()->RemoveLighting(); + } +} + +/*void RenderWeaponsList() { int nPushedAlpha, nAlphaFunction; int nZWrite; @@ -449,7 +496,7 @@ void RenderWeaponsList() RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTION, reinterpret_cast(nAlphaFunction)); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, reinterpret_cast(nZWrite)); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(nAlphaBlending)); -} +}*/ RpAtomic* RenderPedCB(RpAtomic* pAtomic) { @@ -1350,7 +1397,7 @@ __forceinline void Patch_SA_10() Patch(AddressByRegion_10(0x7469A0), 0x909000B0); // Weapons rendering - InjectHook(0x5E7859, RenderWeapon); + /*InjectHook(0x5E7859, RenderWeapon); InjectHook(0x732F30, RenderWeaponsList, PATCH_JUMP); //Patch(0x53EAC4, 0x0DEB); //Patch(0x705322, 0x0DEB); @@ -1364,7 +1411,9 @@ __forceinline void Patch_SA_10() //Nop(0x732F93, 6); //Nop(0x733144, 6); Nop(0x732FA6, 6); - //Nop(0x5E46DA, 2); + //Nop(0x5E46DA, 2);*/ + InjectHook(0x5E7859, RenderWeapon); + InjectHook(0x732F30, RenderWeaponPedsForPC, PATCH_JUMP); // Hunter interior & static_rotor for helis InjectHook(0x4C78F2, HunterTest, PATCH_JUMP); diff --git a/SAFix/StdAfxSA.h b/SAFix/StdAfxSA.h index c932a39..ef519f3 100644 --- a/SAFix/StdAfxSA.h +++ b/SAFix/StdAfxSA.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -50,6 +51,7 @@ struct AlphaObjectInfo // SA operator delete extern void (*GTAdelete)(void* data); extern const char* (*GetFrameNodeName)(RwFrame*); +extern RpHAnimHierarchy* (*GetAnimHierarchyFromSkinClump)(RpClump*); extern unsigned char& nGameClockDays; extern unsigned char& nGameClockMonths;