diff options
Diffstat (limited to 'src/control/Pickups.cpp')
-rw-r--r-- | src/control/Pickups.cpp | 2098 |
1 files changed, 1049 insertions, 1049 deletions
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 3e3c2a48..774abd8c 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -1,1049 +1,1049 @@ -#include "common.h"
-#include "patcher.h"
-#include "main.h"
-
-#include "Camera.h"
-#include "Coronas.h"
-#include "Darkel.h"
-#include "Entity.h"
-#include "Explosion.h"
-#include "Font.h"
-#include "Garages.h"
-#include "General.h"
-#include "ModelIndices.h"
-#include "Object.h"
-#include "Pad.h"
-#include "Pickups.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "DMAudio.h"
-#include "Fire.h"
-#include "PointLights.h"
-#include "Pools.h"
-#ifdef FIX_BUGS
-#include "Replay.h"
-#endif
-#include "Script.h"
-#include "Shadows.h"
-#include "SpecialFX.h"
-#include "Sprite.h"
-#include "Timer.h"
-#include "WaterLevel.h"
-#include "World.h"
-
-CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98;
-int16 CPickups::NumMessages;// = *(int16*)0x95CC98;
-int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538;
-int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A;
-
-// unused
-bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71;
-CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8;
-CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8;
-uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C;
-
-tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
-
-// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4)
-uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
-uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 };
-uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
-
-uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 };
-uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 };
-uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 };
-float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f };
-
-WRAPPER void CPacManPickups::Init(void) { EAXJMP(0x432760); }
-WRAPPER void CPacManPickups::Update(void) { EAXJMP(0x432800); }
-WRAPPER void CPacManPickups::GeneratePMPickUps(CVector, float, int16, uint8) { EAXJMP(0x432AE0); }
-WRAPPER void CPacManPickups::GeneratePMPickUpsForRace(int32) { EAXJMP(0x432D50); }
-WRAPPER void CPacManPickups::GenerateOnePMPickUp(CVector) { EAXJMP(0x432F20); }
-WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); }
-WRAPPER void CPacManPickups::DoCleanUpPacManStuff(void) { EAXJMP(0x433150); }
-WRAPPER void CPacManPickups::StartPacManRace(int32) { EAXJMP(0x433340); }
-WRAPPER void CPacManPickups::StartPacManRecord(void) { EAXJMP(0x433360); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsEatenInRace(void) { EAXJMP(0x4333A0); }
-WRAPPER void CPacManPickups::ResetPowerPillsEatenInRace(void) { EAXJMP(0x4333B0); }
-WRAPPER void CPacManPickups::CleanUpPacManStuff(void) { EAXJMP(0x4333C0); }
-WRAPPER void CPacManPickups::StartPacManScramble(CVector, float, int16) { EAXJMP(0x4333D0); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsCarriedByPlayer(void) { EAXJMP(0x4333F0); }
-WRAPPER void CPacManPickups::ResetPowerPillsCarriedByPlayer(void) { EAXJMP(0x433410); }
-
-
-void
-CPickup::RemoveKeepType()
-{
- CWorld::Remove(m_pObject);
- delete m_pObject;
-
- m_bRemoved = true;
- m_pObject = nil;
-}
-
-void
-CPickup::Remove()
-{
- RemoveKeepType();
- m_eType = PICKUP_NONE;
-}
-
-CObject *
-CPickup::GiveUsAPickUpObject(int32 handle)
-{
- CObject *object;
-
- if (handle <= 0) object = new CObject(m_eModelIndex, false);
- else {
- CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
- object = new(handle) CObject(m_eModelIndex, false);
- }
-
- if (object == nil) return nil;
- object->ObjectCreatedBy = MISSION_OBJECT;
- object->GetPosition() = m_vecPos;
- object->SetOrientation(0.0f, 0.0f, -HALFPI);
- object->GetMatrix().UpdateRW();
- object->UpdateRwFrame();
-
- object->bAffectedByGravity = false;
- object->bExplosionProof = true;
- object->bUsesCollision = false;
- object->bIsPickup = true;
-
- object->field_172 = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
-
- switch (m_eType)
- {
- case PICKUP_IN_SHOP:
- object->m_obj_flag2 = true;
- object->bOutOfStock = false;
- break;
- case PICKUP_ON_STREET:
- case PICKUP_ONCE:
- case PICKUP_ONCE_TIMEOUT:
- case PICKUP_COLLECTABLE1:
- case PICKUP_MONEY:
- case PICKUP_MINE_INACTIVE:
- case PICKUP_MINE_ARMED:
- case PICKUP_NAUTICAL_MINE_INACTIVE:
- case PICKUP_NAUTICAL_MINE_ARMED:
- case PICKUP_FLOATINGPACKAGE:
- case PICKUP_ON_STREET_SLOW:
- object->m_obj_flag2 = false;
- object->bOutOfStock = false;
- break;
- case PICKUP_IN_SHOP_OUT_OF_STOCK:
- object->m_obj_flag2 = false;
- object->bOutOfStock = true;
- object->bRenderScorched = true;
- break;
- case PICKUP_FLOATINGPACKAGE_FLOATING:
- default:
- break;
- }
- return object;
-}
-
-bool
-CPickup::CanBePickedUp(CPlayerPed *player)
-{
- assert(m_pObject != nil);
- bool cannotBePickedUp =
- (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f)
- || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f)
- || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0)
- || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame));
- return !cannotBePickedUp;
-}
-
-bool
-CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
-{
- float waterLevel;
-
- if (m_bRemoved) {
- if (CTimer::GetTimeInMilliseconds() > m_nTimer) {
- // respawn pickup if we're far enough
- float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y);
- if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) {
- m_pObject = GiveUsAPickUpObject(-1);
- if (m_pObject) {
- CWorld::Add(m_pObject);
- m_bRemoved = false;
- }
- }
- }
- return false;
- }
-
- if (!m_pObject) return false;
-
- if (!IsMine()) {
- // let's check if we touched the pickup
- bool isPickupTouched = false;
- if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) {
- if (vehicle != nil) {
- if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f))
- isPickupTouched = true;
- }
- else {
- if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
- if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
- (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
- isPickupTouched = true;
- }
- }
- } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) {
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- isPickupTouched = true;
- }
- } else if (vehicle == nil) {
- if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
- if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
- (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
- isPickupTouched = true;
- }
- }
-
- // if we didn't then we've got nothing to do
- if (isPickupTouched && CanBePickedUp(player)) {
- CPad::GetPad(0)->StartShake(120, 100);
- switch (m_eType)
- {
- case PICKUP_IN_SHOP:
- if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) {
- CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
- } else {
- CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())];
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
- }
- RemoveKeepType();
- m_nTimer = CTimer::GetTimeInMilliseconds() + 5000;
- return true;
- }
- break;
- case PICKUP_ON_STREET:
- case PICKUP_ON_STREET_SLOW:
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) {
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- }
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
- } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- CPickups::bPickUpcamActivated = true;
- CPickups::pPlayerVehicle = FindPlayerVehicle();
- CPickups::StaticCamCoors = m_pObject->GetPosition();
- CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds();
- }
- }
- if (m_eType == PICKUP_ON_STREET) {
- m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
- } else if (m_eType == PICKUP_ON_STREET_SLOW) {
- if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex)
- m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
- else
- m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
- }
-
- RemoveKeepType();
- return true;
- case PICKUP_ONCE:
- case PICKUP_ONCE_TIMEOUT:
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- }
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
- }
- Remove();
- return true;
- case PICKUP_COLLECTABLE1:
- CWorld::Players[playerId].m_nCollectedPackages++;
- CWorld::Players[playerId].m_nMoney += 1000;
-
- if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) {
- printf("All collectables have been picked up\n");
- CGarages::TriggerMessage("CO_ALL", -1, 5000, -1);
- CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000;
- } else
- CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
-
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
- return true;
- case PICKUP_MONEY:
- CWorld::Players[playerId].m_nMoney += m_nQuantity;
- sprintf(gString, "$%d", m_nQuantity);
-#ifdef MONEY_MESSAGES
- CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f);
-#endif
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
- return true;
- //case PICKUP_IN_SHOP_OUT_OF_STOCK:
- //case PICKUP_MINE_INACTIVE:
- //case PICKUP_MINE_ARMED:
- //case PICKUP_NAUTICAL_MINE_INACTIVE:
- //case PICKUP_NAUTICAL_MINE_ARMED:
- //case PICKUP_FLOATINGPACKAGE:
- //case PICKUP_FLOATINGPACKAGE_FLOATING:
- default:
- break;
- }
- }
- } else {
- switch (m_eType)
- {
- case PICKUP_MINE_INACTIVE:
- if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- m_eType = PICKUP_MINE_ARMED;
- m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
- }
- break;
- case PICKUP_NAUTICAL_MINE_INACTIVE:
- {
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
- m_pObject->GetPosition().z = waterLevel + 0.6f;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
-
- bool touched = false;
- for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
- CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
- touched = true;
- break; // added break here
- }
- }
-
- if (!touched) {
- m_eType = PICKUP_NAUTICAL_MINE_ARMED;
- m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
- }
- break;
- }
- case PICKUP_NAUTICAL_MINE_ARMED:
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
- m_pObject->GetPosition().z = waterLevel + 0.6f;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- // no break here
- case PICKUP_MINE_ARMED:
- {
- bool explode = false;
- if (CTimer::GetTimeInMilliseconds() > m_nTimer)
- explode = true;
- else {// added else here since vehicle lookup is useless
- for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
- CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
- explode = true;
- break; // added break here
- }
- }
- }
- if (explode) {
- CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
- Remove();
- }
- break;
- }
- case PICKUP_FLOATINGPACKAGE:
- m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
- m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep();
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z)
- m_eType = PICKUP_FLOATINGPACKAGE_FLOATING;
- break;
- case PICKUP_FLOATINGPACKAGE_FLOATING:
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0))
- m_pObject->GetPosition().z = waterLevel;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
- return true;
- }
- break;
- }
- }
- if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
- Remove();
- return false;
-}
-
-void
-CPickups::Init(void)
-{
- NumMessages = 0;
- for (int i = 0; i < NUMPICKUPS; i++) {
- aPickUps[i].m_eType = PICKUP_NONE;
- aPickUps[i].m_nIndex = 1;
- aPickUps[i].m_pObject = nil;
- }
-
- for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- aPickUpsCollected[i] = 0;
-
- CollectedPickUpIndex = 0;
-}
-
-bool
-CPickups::IsPickUpPickedUp(int32 pickupId)
-{
- for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) {
- if (pickupId == aPickUpsCollected[i]) {
- aPickUpsCollected[i] = 0;
- return true;
- }
- }
- return false;
-}
-
-void
-CPickups::PassTime(uint32 time)
-{
- for (int i = 0; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE) {
- if (aPickUps[i].m_nTimer <= time)
- aPickUps[i].m_nTimer = 0;
- else
- aPickUps[i].m_nTimer -= time;
- }
- }
-}
-
-int32
-CPickups::GetActualPickupIndex(int32 index)
-{
- if (index == -1) return -1;
-
- // doesn't look nice
- if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1;
- return (uint16)index;
-}
-
-bool
-CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
-{
- CPlayerPed *player;
-
- if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
- else player = CWorld::Players[playerIndex].m_pPed;
-
- if (modelIndex == MI_PICKUP_ADRENALINE) {
- player->m_bAdrenalineActive = true;
- player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000;
- player->m_fCurrentStamina = player->m_fMaxStamina;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BODYARMOUR) {
- player->m_fArmour = 100.0f;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_INFO) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_HEALTH) {
- player->m_fHealth = 100.0f;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BONUS) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BRIBE) {
- int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1;
- if (level < 0) level = 0;
- player->SetWantedLevel(level);
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_KILLFRENZY) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- }
- return false;
-}
-
-void
-CPickups::RemoveAllFloatingPickups()
-{
- for (int i = 0; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) {
- if (aPickUps[i].m_pObject) {
- CWorld::Remove(aPickUps[i].m_pObject);
- delete aPickUps[i].m_pObject;
- aPickUps[i].m_pObject = nil;
- }
- }
- }
-}
-
-void
-CPickups::RemovePickUp(int32 pickupIndex)
-{
- int32 index = CPickups::GetActualPickupIndex(pickupIndex);
- if (index == -1) return;
-
- if (aPickUps[index].m_pObject) {
- CWorld::Remove(aPickUps[index].m_pObject);
- delete aPickUps[index].m_pObject;
- aPickUps[index].m_pObject = nil;
- }
- aPickUps[index].m_eType = PICKUP_NONE;
- aPickUps[index].m_bRemoved = true;
-}
-
-int32
-CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity)
-{
- bool bFreeFound = false;
- int32 slot = 0;
-
- if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) {
- for (slot = NUMPICKUPS; slot >= 0; slot--) {
- if (aPickUps[slot].m_eType == PICKUP_NONE) {
- bFreeFound = true;
- break;
- }
- }
- } else {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_NONE) {
- bFreeFound = true;
- break;
- }
- }
- }
-
- if (!bFreeFound)
- {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_MONEY) break;
- }
-
- if (slot >= NUMGENERALPICKUPS)
- {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break;
- }
-
- if (slot >= NUMGENERALPICKUPS) return -1;
- }
- }
-
- if (slot >= NUMPICKUPS) return -1;
-
- aPickUps[slot].m_eType = (ePickupType)type;
- aPickUps[slot].m_bRemoved = false;
- aPickUps[slot].m_nQuantity = quantity;
- if (type == PICKUP_ONCE_TIMEOUT)
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
- else if (type == PICKUP_MONEY)
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
- else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) {
- aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE;
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
- } else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) {
- aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE;
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
- }
- aPickUps[slot].m_eModelIndex = modelIndex;
- aPickUps[slot].m_vecPos = pos;
- aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
- if (aPickUps[slot].m_pObject)
- CWorld::Add(aPickUps[slot].m_pObject);
- return GetNewUniquePickupIndex(slot);
-}
-
-int32
-CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
-{
- return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
-}
-
-int32
-CPickups::GetNewUniquePickupIndex(int32 slot)
-{
- if (aPickUps[slot].m_nIndex >= 0xFFFE)
- aPickUps[slot].m_nIndex = 1;
- else
- aPickUps[slot].m_nIndex++;
- return slot | (aPickUps[slot].m_nIndex << 16);
-}
-
-int32
-CPickups::ModelForWeapon(eWeaponType weaponType)
-{
- switch (weaponType)
- {
- case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT;
- case WEAPONTYPE_COLT45: return MI_COLT;
- case WEAPONTYPE_UZI: return MI_UZI;
- case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN;
- case WEAPONTYPE_AK47: return MI_AK47;
- case WEAPONTYPE_M16: return MI_M16;
- case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER;
- case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER;
- case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER;
- case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV;
- case WEAPONTYPE_GRENADE: return MI_GRENADE;
- }
- return 0;
-}
-
-eWeaponType
-CPickups::WeaponForModel(int32 model)
-{
- if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
- switch (model)
- {
- case MI_GRENADE: return WEAPONTYPE_GRENADE;
- case MI_AK47: return WEAPONTYPE_AK47;
- case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT;
- case MI_COLT: return WEAPONTYPE_COLT45;
- case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV;
- case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER;
- case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN;
- case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE;
- case MI_UZI: return WEAPONTYPE_UZI;
- case MI_MISSILE: return WEAPONTYPE_UNARMED;
- case MI_M16: return WEAPONTYPE_M16;
- case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER;
- }
- return WEAPONTYPE_UNARMED;
-}
-
-int32
-CPickups::FindColourIndexForWeaponMI(int32 model)
-{
- return WeaponForModel(model) - 1;
-}
-
-void
-CPickups::AddToCollectedPickupsArray(int32 index)
-{
- aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16);
- if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS)
- CollectedPickUpIndex = 0;
-}
-
-void
-CPickups::Update()
-{
-#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
- if (CReplay::IsPlayingBack())
- return;
-#endif
-#define PICKUPS_FRAME_SPAN (6)
-#ifdef FIX_BUGS
- for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
-#else // BUG: this code can only reach 318 out of 320 pickups
- for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
-#endif
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-#undef PICKUPS_FRAME_SPAN
- for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-}
-
-void
-CPickups::DoPickUpEffects(CEntity *entity)
-{
- if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
- entity->m_flagD80 = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
-
- if (!entity->m_flagD80) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
- float modifiedSin = 0.3f * (s + 1.0f);
-
-
- int16 colorId;
-
- if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA)
- colorId = 11;
- else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE)
- colorId = 12;
- else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
- colorId = 13;
- else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS)
- colorId = 14;
- else
- colorId = FindColourIndexForWeaponMI(entity->GetModelIndex());
-
- assert(colorId >= 0);
-
- CVector &pos = entity->GetPosition();
-
- float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f;
- CShadows::StoreStaticShadow(
- (uintptr)entity,
- SHADOWTYPE_ADDITIVE,
- gpShadowExplosionTex,
- &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
-
- float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f;
- CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true);
- float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f;
- CCoronas::RegisterCorona( (uintptr)entity,
- aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f,
- 255,
- pos,
- size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-
- CObject *object = (CObject*)entity;
- if (object->m_obj_flag2 || object->bOutOfStock || object->field_172) {
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 12.0f;
-
- if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
- RwV3d vecOut;
- float fDistX, fDistY;
- if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) {
- aMessages[NumMessages].m_pos.x = vecOut.x;
- aMessages[NumMessages].m_pos.y = vecOut.y;
- aMessages[NumMessages].m_dist.x = fDistX;
- aMessages[NumMessages].m_dist.y = fDistY;
- aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex());
- aMessages[NumMessages].m_color.red = aWeaponReds[colorId];
- aMessages[NumMessages].m_color.green = aWeaponGreens[colorId];
- aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId];
- aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
- aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
- aMessages[NumMessages].m_quantity = object->field_172;
- NumMessages++;
- }
- }
- }
-
- entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]);
- }
-}
-
-void
-CPickups::DoMineEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 20.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200));
-
- int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- red, 0, 0,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
-}
-
-void
-CPickups::DoMoneyEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 20.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400));
-
- int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- 0, green, 0,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
-}
-
-void
-CPickups::DoCollectableEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 14.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
-
- int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- color, color, color,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
-}
-
-void
-CPickups::RenderPickUpText()
-{
- wchar *strToPrint;
- for (int32 i = 0; i < NumMessages; i++) {
- if (aMessages[i].m_quantity <= 39) {
- switch (aMessages[i].m_quantity) // could use some enum maybe
- {
- case 0:
- if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code?
- // what is this??
- sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
- } else {
- if (aMessages[i].m_bOutOfStock)
- strToPrint = TheText.Get("STOCK");
- else {
- sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]);
- AsciiToUnicode(gString, gUString);
- strToPrint = gUString;
- }
- }
- break;
- case 1:
- strToPrint = TheText.Get("SECURI");
- break;
- case 2:
- strToPrint = TheText.Get("MOONBM");
- break;
- case 3:
- strToPrint = TheText.Get("COACH");
- break;
- case 4:
- strToPrint = TheText.Get("FLATBED");
- break;
- case 5:
- strToPrint = TheText.Get("LINERUN");
- break;
- case 6:
- strToPrint = TheText.Get("TRASHM");
- break;
- case 7:
- strToPrint = TheText.Get("PATRIOT");
- break;
- case 8:
- strToPrint = TheText.Get("WHOOPEE");
- break;
- case 9:
- strToPrint = TheText.Get("BLISTA");
- break;
- case 10:
- strToPrint = TheText.Get("MULE");
- break;
- case 11:
- strToPrint = TheText.Get("YANKEE");
- break;
- case 12:
- strToPrint = TheText.Get("BOBCAT");
- break;
- case 13:
- strToPrint = TheText.Get("DODO");
- break;
- case 14:
- strToPrint = TheText.Get("BUS");
- break;
- case 15:
- strToPrint = TheText.Get("RUMPO");
- break;
- case 16:
- strToPrint = TheText.Get("PONY");
- break;
- case 17:
- strToPrint = TheText.Get("SENTINL");
- break;
- case 18:
- strToPrint = TheText.Get("CHEETAH");
- break;
- case 19:
- strToPrint = TheText.Get("BANSHEE");
- break;
- case 20:
- strToPrint = TheText.Get("IDAHO");
- break;
- case 21:
- strToPrint = TheText.Get("INFERNS");
- break;
- case 22:
- strToPrint = TheText.Get("TAXI");
- break;
- case 23:
- strToPrint = TheText.Get("KURUMA");
- break;
- case 24:
- strToPrint = TheText.Get("STRETCH");
- break;
- case 25:
- strToPrint = TheText.Get("PEREN");
- break;
- case 26:
- strToPrint = TheText.Get("STINGER");
- break;
- case 27:
- strToPrint = TheText.Get("MANANA");
- break;
- case 28:
- strToPrint = TheText.Get("LANDSTK");
- break;
- case 29:
- strToPrint = TheText.Get("STALION");
- break;
- case 30:
- strToPrint = TheText.Get("BFINJC");
- break;
- case 31:
- strToPrint = TheText.Get("CABBIE");
- break;
- case 32:
- strToPrint = TheText.Get("ESPERAN");
- break;
- case 33:
- strToPrint = TheText.Get("FIRETRK");
- break;
- case 34:
- strToPrint = TheText.Get("AMBULAN");
- break;
- case 35:
- strToPrint = TheText.Get("ENFORCR");
- break;
- case 36:
- strToPrint = TheText.Get("FBICAR");
- break;
- case 37:
- strToPrint = TheText.Get("RHINO");
- break;
- case 38:
- strToPrint = TheText.Get("BARRCKS");
- break;
- case 39:
- strToPrint = TheText.Get("POLICAR");
- break;
- default:
- break;
- }
- }
- CFont::SetPropOn();
- CFont::SetBackgroundOff();
-
- const float MAX_SCALE = 1.0f;
-
- float fScaleY = aMessages[i].m_dist.y / 100.0f;
- if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
-
- float fScaleX = aMessages[i].m_dist.x / 100.0f;
- if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
-
- CFont::SetScale(fScaleX, fScaleY);
- CFont::SetCentreOn();
- CFont::SetCentreSize(SCREEN_WIDTH);
- CFont::SetJustifyOff();
-
- CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha));
- CFont::SetBackGroundOnlyTextOff();
- CFont::SetFontStyle(FONT_BANK);
- CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
- }
- NumMessages = 0;
-}
-
-void
-CPickups::Load(uint8 *buf, uint32 size)
-{
-INITSAVEBUF
-
- for (int32 i = 0; i < NUMPICKUPS; i++) {
- aPickUps[i] = ReadSaveBuf<CPickup>(buf);
-
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil)
- aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1);
- }
-
- CollectedPickUpIndex = ReadSaveBuf<uint16>(buf);
- ReadSaveBuf<uint16>(buf);
- NumMessages = 0;
-
- for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- aPickUpsCollected[i] = ReadSaveBuf<int32>(buf);
-
-VALIDATESAVEBUF(size)
-}
-
-void
-CPickups::Save(uint8 *buf, uint32 *size)
-{
- *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
-
-INITSAVEBUF
-
- for (int32 i = 0; i < NUMPICKUPS; i++) {
- CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
- if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil)
- buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
- }
-
- WriteSaveBuf(buf, CollectedPickUpIndex);
- WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
-
- for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- WriteSaveBuf(buf, aPickUpsCollected[i]);
-
-VALIDATESAVEBUF(*size)
-}
-
-STARTPATCHES
- InjectHook(0x430220, CPickups::Init, PATCH_JUMP);
- InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP);
- InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP);
- InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP);
- InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP);
- InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP);
- InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP);
- InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP);
- InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP);
- InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP);
- InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP);
- InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP);
- InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP);
- InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP);
- InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP);
- InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/
- InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP);
- InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP);
- InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP);
- InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP);
- InjectHook(0x433F60, CPickups::Load, PATCH_JUMP);
- InjectHook(0x433E40, CPickups::Save, PATCH_JUMP);
- InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP);
- InjectHook(0x430860, &CPickup::Update, PATCH_JUMP);
-ENDPATCHES
+#include "common.h" +#include "patcher.h" +#include "main.h" + +#include "Camera.h" +#include "Coronas.h" +#include "Darkel.h" +#include "Entity.h" +#include "Explosion.h" +#include "Font.h" +#include "Garages.h" +#include "General.h" +#include "ModelIndices.h" +#include "Object.h" +#include "Pad.h" +#include "Pickups.h" +#include "PlayerPed.h" +#include "Wanted.h" +#include "DMAudio.h" +#include "Fire.h" +#include "PointLights.h" +#include "Pools.h" +#ifdef FIX_BUGS +#include "Replay.h" +#endif +#include "Script.h" +#include "Shadows.h" +#include "SpecialFX.h" +#include "Sprite.h" +#include "Timer.h" +#include "WaterLevel.h" +#include "World.h" + +CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98; +int16 CPickups::NumMessages;// = *(int16*)0x95CC98; +int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538; +int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A; + +// unused +bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71; +CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8; +CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8; +uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C; + +tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES]; + +// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4) +uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 }; +uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 }; +uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 }; + +uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 }; +uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 }; +uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 }; +float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f }; + +WRAPPER void CPacManPickups::Init(void) { EAXJMP(0x432760); } +WRAPPER void CPacManPickups::Update(void) { EAXJMP(0x432800); } +WRAPPER void CPacManPickups::GeneratePMPickUps(CVector, float, int16, uint8) { EAXJMP(0x432AE0); } +WRAPPER void CPacManPickups::GeneratePMPickUpsForRace(int32) { EAXJMP(0x432D50); } +WRAPPER void CPacManPickups::GenerateOnePMPickUp(CVector) { EAXJMP(0x432F20); } +WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); } +WRAPPER void CPacManPickups::DoCleanUpPacManStuff(void) { EAXJMP(0x433150); } +WRAPPER void CPacManPickups::StartPacManRace(int32) { EAXJMP(0x433340); } +WRAPPER void CPacManPickups::StartPacManRecord(void) { EAXJMP(0x433360); } +WRAPPER uint32 CPacManPickups::QueryPowerPillsEatenInRace(void) { EAXJMP(0x4333A0); } +WRAPPER void CPacManPickups::ResetPowerPillsEatenInRace(void) { EAXJMP(0x4333B0); } +WRAPPER void CPacManPickups::CleanUpPacManStuff(void) { EAXJMP(0x4333C0); } +WRAPPER void CPacManPickups::StartPacManScramble(CVector, float, int16) { EAXJMP(0x4333D0); } +WRAPPER uint32 CPacManPickups::QueryPowerPillsCarriedByPlayer(void) { EAXJMP(0x4333F0); } +WRAPPER void CPacManPickups::ResetPowerPillsCarriedByPlayer(void) { EAXJMP(0x433410); } + + +void +CPickup::RemoveKeepType() +{ + CWorld::Remove(m_pObject); + delete m_pObject; + + m_bRemoved = true; + m_pObject = nil; +} + +void +CPickup::Remove() +{ + RemoveKeepType(); + m_eType = PICKUP_NONE; +} + +CObject * +CPickup::GiveUsAPickUpObject(int32 handle) +{ + CObject *object; + + if (handle <= 0) object = new CObject(m_eModelIndex, false); + else { + CPools::MakeSureSlotInObjectPoolIsEmpty(handle); + object = new(handle) CObject(m_eModelIndex, false); + } + + if (object == nil) return nil; + object->ObjectCreatedBy = MISSION_OBJECT; + object->GetPosition() = m_vecPos; + object->SetOrientation(0.0f, 0.0f, -HALFPI); + object->GetMatrix().UpdateRW(); + object->UpdateRwFrame(); + + object->bAffectedByGravity = false; + object->bExplosionProof = true; + object->bUsesCollision = false; + object->bIsPickup = true; + + object->field_172 = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0; + + switch (m_eType) + { + case PICKUP_IN_SHOP: + object->m_obj_flag2 = true; + object->bOutOfStock = false; + break; + case PICKUP_ON_STREET: + case PICKUP_ONCE: + case PICKUP_ONCE_TIMEOUT: + case PICKUP_COLLECTABLE1: + case PICKUP_MONEY: + case PICKUP_MINE_INACTIVE: + case PICKUP_MINE_ARMED: + case PICKUP_NAUTICAL_MINE_INACTIVE: + case PICKUP_NAUTICAL_MINE_ARMED: + case PICKUP_FLOATINGPACKAGE: + case PICKUP_ON_STREET_SLOW: + object->m_obj_flag2 = false; + object->bOutOfStock = false; + break; + case PICKUP_IN_SHOP_OUT_OF_STOCK: + object->m_obj_flag2 = false; + object->bOutOfStock = true; + object->bRenderScorched = true; + break; + case PICKUP_FLOATINGPACKAGE_FLOATING: + default: + break; + } + return object; +} + +bool +CPickup::CanBePickedUp(CPlayerPed *player) +{ + assert(m_pObject != nil); + bool cannotBePickedUp = + (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f) + || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f) + || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0) + || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame)); + return !cannotBePickedUp; +} + +bool +CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId) +{ + float waterLevel; + + if (m_bRemoved) { + if (CTimer::GetTimeInMilliseconds() > m_nTimer) { + // respawn pickup if we're far enough + float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y); + if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) { + m_pObject = GiveUsAPickUpObject(-1); + if (m_pObject) { + CWorld::Add(m_pObject); + m_bRemoved = false; + } + } + } + return false; + } + + if (!m_pObject) return false; + + if (!IsMine()) { + // let's check if we touched the pickup + bool isPickupTouched = false; + if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) { + if (vehicle != nil) { + if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) + isPickupTouched = true; + } + else { + if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) { + if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) + + (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f) + isPickupTouched = true; + } + } + } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) { + if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) { + isPickupTouched = true; + } + } else if (vehicle == nil) { + if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) { + if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) + + (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f) + isPickupTouched = true; + } + } + + // if we didn't then we've got nothing to do + if (isPickupTouched && CanBePickedUp(player)) { + CPad::GetPad(0)->StartShake(120, 100); + switch (m_eType) + { + case PICKUP_IN_SHOP: + if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) { + CGarages::TriggerMessage("PU_MONY", -1, 6000, -1); + } else { + CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]; + if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) { + player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]); + player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex())); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE); + } + RemoveKeepType(); + m_nTimer = CTimer::GetTimeInMilliseconds() + 5000; + return true; + } + break; + case PICKUP_ON_STREET: + case PICKUP_ON_STREET_SLOW: + if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) { + if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) { + player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]); + if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) { + player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex())); + } + DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE); + } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) { + DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); + CPickups::bPickUpcamActivated = true; + CPickups::pPlayerVehicle = FindPlayerVehicle(); + CPickups::StaticCamCoors = m_pObject->GetPosition(); + CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds(); + } + } + if (m_eType == PICKUP_ON_STREET) { + m_nTimer = CTimer::GetTimeInMilliseconds() + 30000; + } else if (m_eType == PICKUP_ON_STREET_SLOW) { + if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex) + m_nTimer = CTimer::GetTimeInMilliseconds() + 300000; + else + m_nTimer = CTimer::GetTimeInMilliseconds() + 720000; + } + + RemoveKeepType(); + return true; + case PICKUP_ONCE: + case PICKUP_ONCE_TIMEOUT: + if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) { + if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) { + player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]); + if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) + player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex())); + } + DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE); + } + Remove(); + return true; + case PICKUP_COLLECTABLE1: + CWorld::Players[playerId].m_nCollectedPackages++; + CWorld::Players[playerId].m_nMoney += 1000; + + if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) { + printf("All collectables have been picked up\n"); + CGarages::TriggerMessage("CO_ALL", -1, 5000, -1); + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000; + } else + CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages); + + Remove(); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0); + return true; + case PICKUP_MONEY: + CWorld::Players[playerId].m_nMoney += m_nQuantity; + sprintf(gString, "$%d", m_nQuantity); +#ifdef MONEY_MESSAGES + CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f); +#endif + Remove(); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0); + return true; + //case PICKUP_IN_SHOP_OUT_OF_STOCK: + //case PICKUP_MINE_INACTIVE: + //case PICKUP_MINE_ARMED: + //case PICKUP_NAUTICAL_MINE_INACTIVE: + //case PICKUP_NAUTICAL_MINE_ARMED: + //case PICKUP_FLOATINGPACKAGE: + //case PICKUP_FLOATINGPACKAGE_FLOATING: + default: + break; + } + } + } else { + switch (m_eType) + { + case PICKUP_MINE_INACTIVE: + if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) { + m_eType = PICKUP_MINE_ARMED; + m_nTimer = CTimer::GetTimeInMilliseconds() + 10000; + } + break; + case PICKUP_NAUTICAL_MINE_INACTIVE: + { + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false)) + m_pObject->GetPosition().z = waterLevel + 0.6f; + + m_pObject->GetMatrix().UpdateRW(); + m_pObject->UpdateRwFrame(); + + bool touched = false; + for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) { + CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i); + if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) { + touched = true; + break; // added break here + } + } + + if (!touched) { + m_eType = PICKUP_NAUTICAL_MINE_ARMED; + m_nTimer = CTimer::GetTimeInMilliseconds() + 10000; + } + break; + } + case PICKUP_NAUTICAL_MINE_ARMED: + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false)) + m_pObject->GetPosition().z = waterLevel + 0.6f; + + m_pObject->GetMatrix().UpdateRW(); + m_pObject->UpdateRwFrame(); + // no break here + case PICKUP_MINE_ARMED: + { + bool explode = false; + if (CTimer::GetTimeInMilliseconds() > m_nTimer) + explode = true; + else {// added else here since vehicle lookup is useless + for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) { + CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i); + if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) { + explode = true; + break; // added break here + } + } + } + if (explode) { + CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0); + Remove(); + } + break; + } + case PICKUP_FLOATINGPACKAGE: + m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep(); + m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep(); + + m_pObject->GetMatrix().UpdateRW(); + m_pObject->UpdateRwFrame(); + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z) + m_eType = PICKUP_FLOATINGPACKAGE_FLOATING; + break; + case PICKUP_FLOATINGPACKAGE_FLOATING: + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0)) + m_pObject->GetPosition().z = waterLevel; + + m_pObject->GetMatrix().UpdateRW(); + m_pObject->UpdateRwFrame(); + if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) { + Remove(); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0); + return true; + } + break; + } + } + if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer) + Remove(); + return false; +} + +void +CPickups::Init(void) +{ + NumMessages = 0; + for (int i = 0; i < NUMPICKUPS; i++) { + aPickUps[i].m_eType = PICKUP_NONE; + aPickUps[i].m_nIndex = 1; + aPickUps[i].m_pObject = nil; + } + + for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) + aPickUpsCollected[i] = 0; + + CollectedPickUpIndex = 0; +} + +bool +CPickups::IsPickUpPickedUp(int32 pickupId) +{ + for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) { + if (pickupId == aPickUpsCollected[i]) { + aPickUpsCollected[i] = 0; + return true; + } + } + return false; +} + +void +CPickups::PassTime(uint32 time) +{ + for (int i = 0; i < NUMPICKUPS; i++) { + if (aPickUps[i].m_eType != PICKUP_NONE) { + if (aPickUps[i].m_nTimer <= time) + aPickUps[i].m_nTimer = 0; + else + aPickUps[i].m_nTimer -= time; + } + } +} + +int32 +CPickups::GetActualPickupIndex(int32 index) +{ + if (index == -1) return -1; + + // doesn't look nice + if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1; + return (uint16)index; +} + +bool +CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex) +{ + CPlayerPed *player; + + if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + else player = CWorld::Players[playerIndex].m_pPed; + + if (modelIndex == MI_PICKUP_ADRENALINE) { + player->m_bAdrenalineActive = true; + player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000; + player->m_fCurrentStamina = player->m_fMaxStamina; + DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0); + return true; + } else if (modelIndex == MI_PICKUP_BODYARMOUR) { + player->m_fArmour = 100.0f; + DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0); + return true; + } else if (modelIndex == MI_PICKUP_INFO) { + DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); + return true; + } else if (modelIndex == MI_PICKUP_HEALTH) { + player->m_fHealth = 100.0f; + DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0); + return true; + } else if (modelIndex == MI_PICKUP_BONUS) { + DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); + return true; + } else if (modelIndex == MI_PICKUP_BRIBE) { + int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1; + if (level < 0) level = 0; + player->SetWantedLevel(level); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); + return true; + } else if (modelIndex == MI_PICKUP_KILLFRENZY) { + DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); + return true; + } + return false; +} + +void +CPickups::RemoveAllFloatingPickups() +{ + for (int i = 0; i < NUMPICKUPS; i++) { + if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) { + if (aPickUps[i].m_pObject) { + CWorld::Remove(aPickUps[i].m_pObject); + delete aPickUps[i].m_pObject; + aPickUps[i].m_pObject = nil; + } + } + } +} + +void +CPickups::RemovePickUp(int32 pickupIndex) +{ + int32 index = CPickups::GetActualPickupIndex(pickupIndex); + if (index == -1) return; + + if (aPickUps[index].m_pObject) { + CWorld::Remove(aPickUps[index].m_pObject); + delete aPickUps[index].m_pObject; + aPickUps[index].m_pObject = nil; + } + aPickUps[index].m_eType = PICKUP_NONE; + aPickUps[index].m_bRemoved = true; +} + +int32 +CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity) +{ + bool bFreeFound = false; + int32 slot = 0; + + if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) { + for (slot = NUMPICKUPS; slot >= 0; slot--) { + if (aPickUps[slot].m_eType == PICKUP_NONE) { + bFreeFound = true; + break; + } + } + } else { + for (slot = 0; slot < NUMGENERALPICKUPS; slot++) { + if (aPickUps[slot].m_eType == PICKUP_NONE) { + bFreeFound = true; + break; + } + } + } + + if (!bFreeFound) + { + for (slot = 0; slot < NUMGENERALPICKUPS; slot++) { + if (aPickUps[slot].m_eType == PICKUP_MONEY) break; + } + + if (slot >= NUMGENERALPICKUPS) + { + for (slot = 0; slot < NUMGENERALPICKUPS; slot++) { + if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break; + } + + if (slot >= NUMGENERALPICKUPS) return -1; + } + } + + if (slot >= NUMPICKUPS) return -1; + + aPickUps[slot].m_eType = (ePickupType)type; + aPickUps[slot].m_bRemoved = false; + aPickUps[slot].m_nQuantity = quantity; + if (type == PICKUP_ONCE_TIMEOUT) + aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000; + else if (type == PICKUP_MONEY) + aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000; + else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) { + aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE; + aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500; + } else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) { + aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE; + aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500; + } + aPickUps[slot].m_eModelIndex = modelIndex; + aPickUps[slot].m_vecPos = pos; + aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1); + if (aPickUps[slot].m_pObject) + CWorld::Add(aPickUps[slot].m_pObject); + return GetNewUniquePickupIndex(slot); +} + +int32 +CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity) +{ + return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity); +} + +int32 +CPickups::GetNewUniquePickupIndex(int32 slot) +{ + if (aPickUps[slot].m_nIndex >= 0xFFFE) + aPickUps[slot].m_nIndex = 1; + else + aPickUps[slot].m_nIndex++; + return slot | (aPickUps[slot].m_nIndex << 16); +} + +int32 +CPickups::ModelForWeapon(eWeaponType weaponType) +{ + switch (weaponType) + { + case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT; + case WEAPONTYPE_COLT45: return MI_COLT; + case WEAPONTYPE_UZI: return MI_UZI; + case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN; + case WEAPONTYPE_AK47: return MI_AK47; + case WEAPONTYPE_M16: return MI_M16; + case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER; + case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER; + case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER; + case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV; + case WEAPONTYPE_GRENADE: return MI_GRENADE; + } + return 0; +} + +eWeaponType +CPickups::WeaponForModel(int32 model) +{ + if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR; + switch (model) + { + case MI_GRENADE: return WEAPONTYPE_GRENADE; + case MI_AK47: return WEAPONTYPE_AK47; + case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT; + case MI_COLT: return WEAPONTYPE_COLT45; + case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV; + case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER; + case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN; + case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE; + case MI_UZI: return WEAPONTYPE_UZI; + case MI_MISSILE: return WEAPONTYPE_UNARMED; + case MI_M16: return WEAPONTYPE_M16; + case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER; + } + return WEAPONTYPE_UNARMED; +} + +int32 +CPickups::FindColourIndexForWeaponMI(int32 model) +{ + return WeaponForModel(model) - 1; +} + +void +CPickups::AddToCollectedPickupsArray(int32 index) +{ + aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16); + if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS) + CollectedPickUpIndex = 0; +} + +void +CPickups::Update() +{ +#ifdef FIX_BUGS // RIP speedrunning (solution from SA) + if (CReplay::IsPlayingBack()) + return; +#endif +#define PICKUPS_FRAME_SPAN (6) +#ifdef FIX_BUGS + for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) { +#else // BUG: this code can only reach 318 out of 320 pickups + for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) { +#endif + if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) { + AddToCollectedPickupsArray(i); + } + } +#undef PICKUPS_FRAME_SPAN + for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) { + if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) { + AddToCollectedPickupsArray(i); + } + } +} + +void +CPickups::DoPickUpEffects(CEntity *entity) +{ + if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY) + entity->m_flagD80 = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame; + + if (!entity->m_flagD80) { + float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800)); + float modifiedSin = 0.3f * (s + 1.0f); + + + int16 colorId; + + if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA) + colorId = 11; + else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE) + colorId = 12; + else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY) + colorId = 13; + else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS) + colorId = 14; + else + colorId = FindColourIndexForWeaponMI(entity->GetModelIndex()); + + assert(colorId >= 0); + + CVector &pos = entity->GetPosition(); + + float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f; + CShadows::StoreStaticShadow( + (uintptr)entity, + SHADOWTYPE_ADDITIVE, + gpShadowExplosionTex, + &pos, + 2.0f, 0.0f, 0.0f, -2.0f, + 255, // this is 0 on PC which results in no shadow + aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier, + 4.0f, 1.0f, 40.0f, false, 0.0f); + + float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f; + CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true); + float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f; + CCoronas::RegisterCorona( (uintptr)entity, + aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f, + 255, + pos, + size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + + CObject *object = (CObject*)entity; + if (object->m_obj_flag2 || object->bOutOfStock || object->field_172) { + float dist = (TheCamera.GetPosition() - pos).Magnitude(); + const float MAXDIST = 12.0f; + + if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) { + RwV3d vecOut; + float fDistX, fDistY; + if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) { + aMessages[NumMessages].m_pos.x = vecOut.x; + aMessages[NumMessages].m_pos.y = vecOut.y; + aMessages[NumMessages].m_dist.x = fDistX; + aMessages[NumMessages].m_dist.y = fDistY; + aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex()); + aMessages[NumMessages].m_color.red = aWeaponReds[colorId]; + aMessages[NumMessages].m_color.green = aWeaponGreens[colorId]; + aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId]; + aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f; + aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock; + aMessages[NumMessages].m_quantity = object->field_172; + NumMessages++; + } + } + } + + entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]); + } +} + +void +CPickups::DoMineEffects(CEntity *entity) +{ + CVector &pos = entity->GetPosition(); + float dist = (TheCamera.GetPosition() - pos).Magnitude(); + const float MAXDIST = 20.0f; + + if (dist < MAXDIST) { + float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200)); + + int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f; + CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos, + 2.0f, 0.0f, 0.0f, -2.0f, + 255, // this is 0 on PC which results in no shadow + red, 0, 0, + 4.0f, 1.0f, 40.0f, false, 0.0f); + CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + } + + entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400)); +} + +void +CPickups::DoMoneyEffects(CEntity *entity) +{ + CVector &pos = entity->GetPosition(); + float dist = (TheCamera.GetPosition() - pos).Magnitude(); + const float MAXDIST = 20.0f; + + if (dist < MAXDIST) { + float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400)); + + int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f; + CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos, + 2.0f, 0.0f, 0.0f, -2.0f, + 255, // this is 0 on PC which results in no shadow + 0, green, 0, + 4.0f, 1.0f, 40.0f, false, 0.0f); + CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + } + + entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800)); +} + +void +CPickups::DoCollectableEffects(CEntity *entity) +{ + CVector &pos = entity->GetPosition(); + float dist = (TheCamera.GetPosition() - pos).Magnitude(); + const float MAXDIST = 14.0f; + + if (dist < MAXDIST) { + float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800)); + + int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f; + CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos, + 2.0f, 0.0f, 0.0f, -2.0f, + 255, // this is 0 on PC which results in no shadow + color, color, color, + 4.0f, 1.0f, 40.0f, false, 0.0f); + CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + } + + entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000)); +} + +void +CPickups::RenderPickUpText() +{ + wchar *strToPrint; + for (int32 i = 0; i < NumMessages; i++) { + if (aMessages[i].m_quantity <= 39) { + switch (aMessages[i].m_quantity) // could use some enum maybe + { + case 0: + if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code? + // what is this?? + sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903); + } else { + if (aMessages[i].m_bOutOfStock) + strToPrint = TheText.Get("STOCK"); + else { + sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]); + AsciiToUnicode(gString, gUString); + strToPrint = gUString; + } + } + break; + case 1: + strToPrint = TheText.Get("SECURI"); + break; + case 2: + strToPrint = TheText.Get("MOONBM"); + break; + case 3: + strToPrint = TheText.Get("COACH"); + break; + case 4: + strToPrint = TheText.Get("FLATBED"); + break; + case 5: + strToPrint = TheText.Get("LINERUN"); + break; + case 6: + strToPrint = TheText.Get("TRASHM"); + break; + case 7: + strToPrint = TheText.Get("PATRIOT"); + break; + case 8: + strToPrint = TheText.Get("WHOOPEE"); + break; + case 9: + strToPrint = TheText.Get("BLISTA"); + break; + case 10: + strToPrint = TheText.Get("MULE"); + break; + case 11: + strToPrint = TheText.Get("YANKEE"); + break; + case 12: + strToPrint = TheText.Get("BOBCAT"); + break; + case 13: + strToPrint = TheText.Get("DODO"); + break; + case 14: + strToPrint = TheText.Get("BUS"); + break; + case 15: + strToPrint = TheText.Get("RUMPO"); + break; + case 16: + strToPrint = TheText.Get("PONY"); + break; + case 17: + strToPrint = TheText.Get("SENTINL"); + break; + case 18: + strToPrint = TheText.Get("CHEETAH"); + break; + case 19: + strToPrint = TheText.Get("BANSHEE"); + break; + case 20: + strToPrint = TheText.Get("IDAHO"); + break; + case 21: + strToPrint = TheText.Get("INFERNS"); + break; + case 22: + strToPrint = TheText.Get("TAXI"); + break; + case 23: + strToPrint = TheText.Get("KURUMA"); + break; + case 24: + strToPrint = TheText.Get("STRETCH"); + break; + case 25: + strToPrint = TheText.Get("PEREN"); + break; + case 26: + strToPrint = TheText.Get("STINGER"); + break; + case 27: + strToPrint = TheText.Get("MANANA"); + break; + case 28: + strToPrint = TheText.Get("LANDSTK"); + break; + case 29: + strToPrint = TheText.Get("STALION"); + break; + case 30: + strToPrint = TheText.Get("BFINJC"); + break; + case 31: + strToPrint = TheText.Get("CABBIE"); + break; + case 32: + strToPrint = TheText.Get("ESPERAN"); + break; + case 33: + strToPrint = TheText.Get("FIRETRK"); + break; + case 34: + strToPrint = TheText.Get("AMBULAN"); + break; + case 35: + strToPrint = TheText.Get("ENFORCR"); + break; + case 36: + strToPrint = TheText.Get("FBICAR"); + break; + case 37: + strToPrint = TheText.Get("RHINO"); + break; + case 38: + strToPrint = TheText.Get("BARRCKS"); + break; + case 39: + strToPrint = TheText.Get("POLICAR"); + break; + default: + break; + } + } + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + + const float MAX_SCALE = 1.0f; + + float fScaleY = aMessages[i].m_dist.y / 100.0f; + if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE; + + float fScaleX = aMessages[i].m_dist.x / 100.0f; + if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE; + + CFont::SetScale(fScaleX, fScaleY); + CFont::SetCentreOn(); + CFont::SetCentreSize(SCREEN_WIDTH); + CFont::SetJustifyOff(); + + CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha)); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); + CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint); + } + NumMessages = 0; +} + +void +CPickups::Load(uint8 *buf, uint32 size) +{ +INITSAVEBUF + + for (int32 i = 0; i < NUMPICKUPS; i++) { + aPickUps[i] = ReadSaveBuf<CPickup>(buf); + + if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil) + aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1); + } + + CollectedPickUpIndex = ReadSaveBuf<uint16>(buf); + ReadSaveBuf<uint16>(buf); + NumMessages = 0; + + for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++) + aPickUpsCollected[i] = ReadSaveBuf<int32>(buf); + +VALIDATESAVEBUF(size) +} + +void +CPickups::Save(uint8 *buf, uint32 *size) +{ + *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected); + +INITSAVEBUF + + for (int32 i = 0; i < NUMPICKUPS; i++) { + CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]); + if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil) + buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1); + } + + WriteSaveBuf(buf, CollectedPickUpIndex); + WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages + + for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++) + WriteSaveBuf(buf, aPickUpsCollected[i]); + +VALIDATESAVEBUF(*size) +} + +STARTPATCHES + InjectHook(0x430220, CPickups::Init, PATCH_JUMP); + InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP); + InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP); + InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP); + InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP); + InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP); + InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP); + InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP); + InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP); + InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP); + InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP); + InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP); + InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP); + InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP); + InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP); + InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/ + InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP); + InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP); + InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP); + InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP); + InjectHook(0x433F60, CPickups::Load, PATCH_JUMP); + InjectHook(0x433E40, CPickups::Save, PATCH_JUMP); + InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP); + InjectHook(0x430860, &CPickup::Update, PATCH_JUMP); +ENDPATCHES |