#include "common.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"
#include "Hud.h"
#include "Messages.h"
#include "Streaming.h"
CPickup CPickups::aPickUps[NUMPICKUPS];
int16 CPickups::NumMessages;
int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];
int16 CPickups::CollectedPickUpIndex;
int32 CPickups::PlayerOnWeaponPickup;
int32 CollectPickupBuffer;
// unused
bool CPickups::bPickUpcamActivated;
CVehicle *CPickups::pPlayerVehicle;
CVector CPickups::StaticCamCoors;
uint32 CPickups::StaticCamStartTime;
tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
uint16 AmmoForWeapon[WEAPONTYPE_TOTALWEAPONS + 1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 68, 24,
32, 28, 20, 200, 120, 120, 120, 120, 120, 40, 28, 8, 300, 200, 1000, 1, 400, 36, 0 };
uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS + 1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 34, 12,
16, 14, 10, 100, 60, 60, 60, 60, 60, 20, 14, 4, 150, 100, 500, 1, 400, 36, 0 };
uint16 CostOfWeapon[WEAPONTYPE_TOTALWEAPONS + 3] = { 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1000, 1000,
1000, 500, 8000, 250, 400, 1200, 1250, 1250, 800, 800, 650, 1200, 5000, 400,
10000, 10000, 8000, 8000, 8000, 10000, 1000, 11000, 500, 20, 10, 0 };
struct
{
uint8 r,g,b;
float unk;
} aPickupColors[] = {
{ 128, 128, 128, 1.0f },
{ 128, 128, 128, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 97, 194, 247, 1.0f },
{ 27, 89, 130, 1.0f },
{ 27, 89, 130, 1.0f },
{ 27, 89, 130, 1.0f },
{ 27, 89, 130, 1.0f },
{ 27, 89, 130, 1.0f },
{ 149, 194, 24, 1.0f },
{ 149, 194, 24, 1.0f },
{ 45, 155, 90, 1.0f },
{ 45, 155, 90, 1.0f },
{ 45, 155, 90, 1.0f },
{ 255, 227, 79, 1.0f },
{ 255, 227, 79, 1.0f },
{ 255, 227, 79, 1.0f },
{ 255, 227, 79, 1.0f },
{ 254, 137, 0, 1.0f },
{ 254, 137, 0, 1.0f },
{ 249, 131, 215, 1.0f },
{ 249, 131, 215, 1.0f },
{ 164, 40, 178, 1.0f },
{ 164, 40, 178, 1.0f },
{ 164, 40, 178, 1.0f },
{ 164, 40, 178, 1.0f },
{ 69, 69, 69, 1.0f },
{ 69, 69, 69, 1.0f },
{ 69, 69, 69, 1.0f },
{ 255, 100, 100, 1.0f },
{ 128, 255, 128, 1.0f },
{ 100, 100, 255, 1.0f },
{ 255, 255, 100, 1.0f },
{ 255, 100, 100, 1.0f },
{ 100, 255, 100, 1.0f },
{ 255, 255, 255, 1.0f }
};
void
ModifyStringLabelForControlSetting(char *str)
{
int len = (int)strlen(str);
if (len <= 2)
return;
if (str[len - 2] != '_')
return;
switch (CPad::GetPad(0)->Mode) {
case 0:
case 1:
str[len - 1] = 'L';
break;
case 2:
str[len - 1] = 'T';
break;
case 3:
str[len - 1] = 'C';
break;
default:
return;
}
}
void
CPickup::ExtractAmmoFromPickup(CPlayerPed *player)
{
eWeaponType weaponType = CPickups::WeaponForModel(m_pObject->GetModelIndex());
if (m_eType == PICKUP_IN_SHOP || !CWeaponInfo::IsWeaponSlotAmmoMergeable(CWeaponInfo::GetWeaponInfo(weaponType)->m_nWeaponSlot))
return;
uint32 ammo = m_nQuantity;
if (ammo == 0) {
if (!m_bWasAmmoCollected)
ammo = AmmoForWeapon_OnStreet[weaponType];
else
goto removeAmmo;
}
player->GrantAmmo(weaponType, ammo);
DMAudio.PlayOneShot(player->m_audioEntityId, SOUND_WEAPON_RELOAD, weaponType); // BUG? weapon type as volume, wtf?
removeAmmo:
m_nQuantity = 0;
m_bWasAmmoCollected = true;
}
void
CPickup::Remove()
{
GetRidOfObjects();
m_bRemoved = true;
m_eType = PICKUP_NONE;
}
CObject *
CPickup::GiveUsAPickUpObject(CObject **ppObject, CObject **ppExtraObject, int32 handle, int32 extraHandle)
{
CObject *&object = *ppObject;
CObject *&extraObject = *ppExtraObject;
object = extraObject = nil;
int32 modelId = -1;
if (CModelInfo::GetModelInfo(m_eModelIndex)->GetModelType() == MITYPE_WEAPON) {
CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(((CWeaponModelInfo*)CModelInfo::GetModelInfo(m_eModelIndex))->GetWeaponInfo());
modelId = weaponInfo->m_nModelId;
if (modelId == m_eModelIndex)
modelId = weaponInfo->m_nModel2Id;
}
if (handle >= 0) {
CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
if (extraHandle >= 0)
CPools::MakeSureSlotInObjectPoolIsEmpty(extraHandle);
if (object == nil)
object = new(handle) CObject(m_eModelIndex, false);
if (extraHandle >= 0 && modelId != -1 && extraObject == nil)
extraObject = new(extraHandle) CObject(modelId, false);
} else {
object = new CObject(m_eModelIndex, false);
if (modelId != -1)
extraObject = new CObject(modelId, false);
}
if (object == nil) return nil;
object->ObjectCreatedBy = MISSION_OBJECT;
object->SetPosition(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->bAmmoCollected = m_bWasAmmoCollected;
object->bHasPreRenderEffects = true;
if (extraObject) {
extraObject->ObjectCreatedBy = MISSION_OBJECT;
extraObject->SetPosition(m_vecPos);
extraObject->SetOrientation(0.0f, 0.0f, -HALFPI);
extraObject->GetMatrix().UpdateRW();
extraObject->UpdateRwFrame();
extraObject->bAffectedByGravity = false;
extraObject->bExplosionProof = true;
extraObject->bUsesCollision = false;
extraObject->bIsPickup = true;
extraObject->bAmmoCollected = true;
extraObject->bHasPreRenderEffects = true;
extraObject->m_nBonusValue = 0;
extraObject->bPickupObjWithMessage = false;
extraObject->bOutOfStock = false;
}
object->m_nBonusValue = (m_eModelIndex == MI_PICKUP_BONUS || m_eModelIndex == MI_PICKUP_CLOTHES) ? m_nQuantity : 0;
switch (m_eType)
{
case PICKUP_IN_SHOP:
object->bPickupObjWithMessage = true;
object->bOutOfStock = false;
if (m_eModelIndex == MI_PICKUP_HEALTH || m_eModelIndex == MI_PICKUP_ADRENALINE)
object->m_nCostValue = 0;
else
object->m_nCostValue = CostOfWeapon[CPickups::WeaponForModel(m_eModelIndex)];
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->bPickupObjWithMessage = false;
object->bOutOfStock = false;
break;
case PICKUP_IN_SHOP_OUT_OF_STOCK:
object->bPickupObjWithMessage = false;
object->bOutOfStock = true;
object->bRenderScorched = true;
break;
case PICKUP_FLOATINGPACKAGE_FLOATING:
default:
break;
}
return object;
}
bool
CPickup::CanBePickedUp(CPlayerPed *player, int playerId)
{
assert(m_pObject != nil);
bool cannotBePickedUp =
(m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > CWorld::Players[playerId].m_nMaxArmour - 0.2f)
|| (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > CWorld::Players[playerId].m_nMaxHealth - 0.2f)
|| (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->GetWantedLevel() == 0)
|| (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame))
|| (m_eType == PICKUP_ASSET_REVENUE && m_fRevenue < 10.0f);
return !cannotBePickedUp;
}
bool
CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
{
bool result = false;
float waterLevel;
if (m_pObject) {
m_pObject->GetMatrix().GetPosition() = m_vecPos;
if (m_pExtraObject)
m_pExtraObject->GetMatrix().GetPosition() = m_vecPos;
}
if (m_eType == PICKUP_ASSET_REVENUE) {
uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nTimer;
m_nTimer = CTimer::GetTimeInMilliseconds();
if (Distance(FindPlayerCoors(), m_vecPos) > 10.0f)
m_fRevenue += float(timePassed * m_nMoneySpeed) / SQR(1200.0f);
m_fRevenue = Min(m_fRevenue, m_nQuantity);
m_pObject->m_nCostValue = m_fRevenue < 10 ? 0 : m_fRevenue;
}
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(&m_pObject, &m_pExtraObject, -1, -1);
if (m_pObject) {
CWorld::Add(m_pObject);
m_bRemoved = false;
}
}
}
return false;
}
if (!m_pObject) {
GiveUsAPickUpObject(&m_pObject, &m_pExtraObject, -1, -1);
if (m_pObject)
CWorld::Add(m_pObject);
if (m_pExtraObject)
CWorld::Add(m_pExtraObject);
}
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 (isPickupTouched) {
eWeaponType weaponType = CPickups::WeaponForModel(m_pObject->GetModelIndex());
if (weaponType < WEAPONTYPE_TOTALWEAPONS && CDarkel::FrenzyOnGoing()) {
isPickupTouched = false;
m_bWasControlMessageShown = false;
} else if (weaponType < WEAPONTYPE_TOTALWEAPONS && weaponType != WEAPONTYPE_UNARMED) {
uint32 slot = CWeaponInfo::GetWeaponInfo(weaponType)->m_nWeaponSlot;
eWeaponType plrWeaponSlot = FindPlayerPed()->GetWeapon(slot).m_eWeaponType;
if (plrWeaponSlot != weaponType) {
if (CStreaming::ms_aInfoForModel[m_pObject->GetModelIndex()].m_loadState == STREAMSTATE_LOADED) {
if (plrWeaponSlot == WEAPONTYPE_UNARMED || (FindPlayerPed()->GetWeapon(slot).m_nAmmoTotal == 0 && !CWeaponInfo::IsWeaponSlotAmmoMergeable(slot))) {
if (CTimer::GetTimeInMilliseconds() - FindPlayerPed()->m_nPadDownPressedInMilliseconds < 1500) {
CPickups::PlayerOnWeaponPickup = 6;
isPickupTouched = false;
}
} else {
CPickups::PlayerOnWeaponPickup = 6;
if (CWeaponInfo::IsWeaponSlotAmmoMergeable(slot)) {
if (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_ONCE || m_eType == PICKUP_ON_STREET) {
ExtractAmmoFromPickup(player);
FindPlayerPed()->GetWeapon(slot).Reload();
}
}
if (!m_bWasControlMessageShown) {
switch (CPad::GetPad(0)->Mode)
{
case 0:
case 1:
CHud::SetHelpMessage(TheText.Get("PU_CF1"), false);
break;
case 2:
CHud::SetHelpMessage(TheText.Get("PU_CF3"), false);
break;
case 3:
CHud::SetHelpMessage(TheText.Get("PU_CF4"), false);
break;
default:
break;
}
m_bWasControlMessageShown = true;
}
if (CollectPickupBuffer == 0)
isPickupTouched = false;
if (CTimer::GetTimeInMilliseconds() - FindPlayerPed()->m_nPadDownPressedInMilliseconds < 1500)
isPickupTouched = false;
}
} else
isPickupTouched = false;
}
}
} else
m_bWasControlMessageShown = false;
// if we didn't then we've got nothing to do
if (isPickupTouched && CanBePickedUp(player, playerId)) {
if (m_pObject->GetModelIndex() != MI_PICKUP_PROPERTY && m_pObject->GetModelIndex() != MI_PICKUP_PROPERTY_FORSALE)
CPad::GetPad(0)->StartShake(120, 100);
eWeaponType weaponType = CPickups::WeaponForModel(m_pObject->GetModelIndex());
switch (m_eType)
{
case PICKUP_IN_SHOP:
if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[weaponType])
CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
else {
CWorld::Players[playerId].m_nMoney -= CostOfWeapon[weaponType];
if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
if (!player->DoesPlayerWantNewWeapon(weaponType, false))
break;
player->GiveWeapon(weaponType, AmmoForWeapon[weaponType]);
player->m_nSelectedWepSlot = player->GetWeaponSlot(weaponType);
DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
}
result = true;
Remove();
}
break;
case PICKUP_ON_STREET:
case PICKUP_ON_STREET_SLOW:
if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
if (!player->DoesPlayerWantNewWeapon(weaponType, false))
break;
if (weaponType != WEAPONTYPE_UNARMED) {
player->GiveWeapon(weaponType, m_nQuantity != 0 ? m_nQuantity : (m_bWasAmmoCollected ? 0 : AmmoForWeapon_OnStreet[weaponType]), true);
if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
player->m_nSelectedWepSlot = player->GetWeaponSlot(weaponType);
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->GetModelIndex())
m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
else
m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
}
result = true;
GetRidOfObjects();
m_bRemoved = true;
break;
case PICKUP_ONCE:
case PICKUP_ONCE_TIMEOUT:
case PICKUP_ONCE_TIMEOUT_SLOW:
if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
if (!player->DoesPlayerWantNewWeapon(weaponType, false)) {
ExtractAmmoFromPickup(player);
break;
}
if (weaponType != WEAPONTYPE_UNARMED) {
player->GiveWeapon(weaponType, m_nQuantity != 0 ? m_nQuantity : (m_bWasAmmoCollected ? 0 : AmmoForWeapon[weaponType]), true);
if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
player->m_nSelectedWepSlot = player->GetWeaponSlot(weaponType);
}
if (MI_PICKUP_SAVEGAME != m_pObject->GetModelIndex())
DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
}
result = true;
Remove();
break;
case PICKUP_COLLECTABLE1:
CWorld::Players[playerId].m_nCollectedPackages++;
CWorld::Players[playerId].m_nMoney += 100;
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 += 100000;
} else
CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
result = true;
Remove();
DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
break;
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
result = true;
Remove();
DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
player->Say(SOUND_PED_MUGGING);
break;
case PICKUP_ASSET_REVENUE:
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += m_fRevenue;
m_fRevenue = 0.0f;
DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
break;
case PICKUP_PROPERTY_LOCKED:
if (!m_bWasControlMessageShown) {
m_bWasControlMessageShown = true;
CHud::SetHelpMessage(TheText.Get(m_sTextKey), false);
}
break;
case PICKUP_PROPERTY_FORSALE:
ModifyStringLabelForControlSetting(m_sTextKey);
CMessages::InsertNumberInString(TheText.Get(m_sTextKey), m_nQuantity,
0, 0, 0, 0, 0, gUString);
if (!CHud::IsHelpMessageBeingDisplayed())
CHud::SetHelpMessage(gUString, false);
if (CollectPickupBuffer == 0)
break;
if (CTheScripts::IsPlayerOnAMission())
CHud::SetHelpMessage(TheText.Get("PROP_2"), true);
else {
if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney >= m_nQuantity) {
CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= m_nQuantity;
CHud::SetHelpMessage(nil, true);
result = true;
Remove();
break;
}
CHud::SetHelpMessage(TheText.Get("PROP_1"), true);
}
break;
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->GetMatrix().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;
#ifdef FIX_BUGS
break; // added break here
#endif
}
}
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->GetMatrix().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;
#ifdef FIX_BUGS
else// added else here since vehicle lookup is useless
#endif
{
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;
#ifdef FIX_BUGS
break; // added break here
#endif
}
}
}
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->GetMatrix().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, false) && 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, false))
m_pObject->GetMatrix().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();
result = true;
DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
}
break;
default: break;
}
}
if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_ONCE_TIMEOUT_SLOW || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
Remove();
return result;
}
void
CPickup::ProcessGunShot(CVector *vec1, CVector *vec2)
{
CColLine line(*vec1, *vec2);
if (m_pObject) {
CColSphere sphere;
sphere.radius = 4.0f;
sphere.center = m_pObject->GetPosition();
if (CCollision::TestLineSphere(line, sphere)) {
CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
CWorld::Remove(m_pObject);
delete m_pObject;
m_pObject = nil;
m_bRemoved = true;
m_eType = PICKUP_NONE;
}
}
}
void
CPickup::GetRidOfObjects()
{
if (m_pObject) {
CWorld::Remove(m_pObject);
delete m_pObject;
m_pObject = nil;
}
if (m_pExtraObject) {
CWorld::Remove(m_pExtraObject);
delete m_pExtraObject;
m_pExtraObject = nil;
}
}
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;
aPickUps[i].m_pExtraObject = nil;
}
for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
aPickUpsCollected[i] = 0;
CollectedPickUpIndex = 0;
}
bool
CPickups::TestForPickupsInBubble(CVector pos, float range)
{
for (int i = 0; i < NUMPICKUPS; i++) {
if ((aPickUps[i].m_vecPos - pos).Magnitude() < range)
return true;
}
return false;
}
bool
CPickups::TryToMerge_WeaponType(CVector pos, eWeaponType weapon, uint8 type, uint32 quantity, bool unused) {
for (int i = 0; i < NUMPICKUPS; i++) {
if (aPickUps[i].m_eType == type && aPickUps[i].m_eModelIndex == ModelForWeapon(weapon))
if ((aPickUps[i].m_vecPos - pos).Magnitude() < 7.5f) {
aPickUps[i].m_nQuantity += quantity;
return true;
}
}
return false;
}
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 && aPickUps[i].m_eType != PICKUP_ASSET_REVENUE) {
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 = CWorld::Players[playerIndex].m_nMaxArmour;
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 = CWorld::Players[playerIndex].m_nMaxHealth;
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 = Max(FindPlayerPed()->m_pWanted->GetWantedLevel() - 1, 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::RemovePickUp(int32 pickupIndex)
{
int32 index = 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;
}
if (aPickUps[index].m_pExtraObject) {
CWorld::Remove(aPickUps[index].m_pExtraObject);
delete aPickUps[index].m_pExtraObject;
aPickUps[index].m_pExtraObject = nil;
}
aPickUps[index].m_eType = PICKUP_NONE;
aPickUps[index].m_bRemoved = true;
}
int32
CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity, uint32 rate, bool highPriority, char* pText)
{
bool bFreeFound = false;
int32 slot = 0;
if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE || highPriority) {
for (slot = NUMPICKUPS-1; slot >= 0; 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_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 || aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT_SLOW) break;
}
if (slot >= NUMGENERALPICKUPS) return -1;
aPickUps[slot].GetRidOfObjects();
}
}
if (slot >= NUMPICKUPS) return -1;
aPickUps[slot].m_eType = type;
aPickUps[slot].m_bRemoved = false;
aPickUps[slot].m_nQuantity = quantity;
aPickUps[slot].m_nMoneySpeed = rate;
aPickUps[slot].m_fRevenue = 0.0f;
aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds();
aPickUps[slot].m_bWasAmmoCollected = highPriority;
aPickUps[slot].m_bWasControlMessageShown = false;
if (type == PICKUP_ONCE_TIMEOUT)
aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
else if (type == PICKUP_ONCE_TIMEOUT_SLOW)
aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 120000;
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;
if (pText)
strncpy(aPickUps[slot].m_sTextKey, pText, 8);
else
aPickUps[slot].m_sTextKey[0] = '\0';
aPickUps[slot].m_vecPos = pos;
aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(&aPickUps[slot].m_pObject, &aPickUps[slot].m_pExtraObject, -1, -1);
if (aPickUps[slot].m_pObject)
CWorld::Add(aPickUps[slot].m_pObject);
if (aPickUps[slot].m_pExtraObject)
CWorld::Add(aPickUps[slot].m_pExtraObject);
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)
{
return CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId;
}
eWeaponType
CPickups::WeaponForModel(int32 model)
{
if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
if (model == MI_PICKUP_HEALTH) return WEAPONTYPE_HEALTH;
if (model == MI_PICKUP_ADRENALINE) return WEAPONTYPE_ARMOUR;
if (model == -1) return WEAPONTYPE_UNARMED;
return ((CWeaponModelInfo*)CModelInfo::GetModelInfo(model))->GetWeaponInfo();
}
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
#ifdef CAMERA_PICKUP
if ( bPickUpcamActivated ) // taken from PS2
{
float dist = Distance2D(StaticCamCoors, FindPlayerCoors());
float mult;
if ( dist < 10.0f )
mult = 1.0f - (dist / 10.0f );
else
mult = 0.0f;
CVector pos = StaticCamCoors;
pos.z += (pPlayerVehicle->GetColModel()->boundingBox.GetSize().z + 2.0f) * mult;
if ( (CTimer::GetTimeInMilliseconds() - StaticCamStartTime) > 750 )
{
TheCamera.SetCamPositionForFixedMode(pos, CVector(0.0f, 0.0f, 0.0f));
TheCamera.TakeControl(FindPlayerVehicle(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_SCRIPT);
}
if ( FindPlayerVehicle() != pPlayerVehicle || Distance(StaticCamCoors, FindPlayerCoors()) > 40.0f
|| ((CTimer::GetTimeInMilliseconds() - StaticCamStartTime) > 60000) )
{
TheCamera.RestoreWithJumpCut();
bPickUpcamActivated = false;
}
}
#endif
if (CPad::GetPad(0)->CollectPickupJustDown())
CollectPickupBuffer = 6;
else
CollectPickupBuffer = Max(0, CollectPickupBuffer - 1);
if (PlayerOnWeaponPickup)
PlayerOnWeaponPickup = Max(0, PlayerOnWeaponPickup - 1);
#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);
}
}
CPickup*
CPickups::FindPickUpForThisObject(CEntity *object)
{
for (uint32 i = 0; i < NUMPICKUPS; i++) {
if (aPickUps[i].m_eType != PICKUP_NONE && (aPickUps[i].m_pObject == object || aPickUps[i].m_pExtraObject == object)) {
return &aPickUps[i];
}
}
return &aPickUps[0];
}
void
CPickups::DoPickUpEffects(CEntity *entity)
{
CPickup *pickup = FindPickUpForThisObject(entity);
if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
entity->bDoNotRender = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
if (!entity->bDoNotRender) {
float modifiedSin = 0.3f * (Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800)) + 1.0f);
#ifdef FIX_BUGS
int16 colorId = 0;
#else
int16 colorId;
#endif
bool doInnerGlow = false;
bool doOuterGlow = true;
if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA) {
colorId = WEAPONTYPE_TOTALWEAPONS;
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR) {
colorId = WEAPONTYPE_ARMOUR;
} else if (entity->GetModelIndex() == MI_PICKUP_BRIBE) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS) {
colorId = WEAPONTYPE_HEALTH;
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_PROPERTY) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_PROPERTY_FORSALE) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_REVENUE) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_SAVEGAME) {
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_CLOTHES) {
colorId = WEAPONTYPE_TOTALWEAPONS;
doOuterGlow = false;
doInnerGlow = true;
} else
colorId = WeaponForModel(entity->GetModelIndex());
const CVector& pos = pickup->m_vecPos;
if (doOuterGlow) {
bool corona1 = false;
bool corona2 = false;
int timerVal = (CTimer::GetTimeInMilliseconds() >> 9) & 7;
if (timerVal < 3)
corona1 = false;
else if (timerVal == 3)
corona1 = (CGeneral::GetRandomNumber() & 3) != 0;
else
corona1 = true;
timerVal = (timerVal - 1) & 7;
if (timerVal < 3)
corona2 = false;
else if (timerVal == 3)
corona2 = (CGeneral::GetRandomNumber() & 3) != 0;
else
corona2 = true;
if (((CObject*)entity)->bAmmoCollected) {
corona2 = false;
corona1 = false;
}
if (corona1) {
CCoronas::RegisterCorona((uintptr)entity,
aPickupColors[colorId].r * 0.45f, aPickupColors[colorId].g * 0.45f, aPickupColors[colorId].b * 0.45f,
255, pos, 0.76f, 65.0f,
CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF,
0.0f, false, -0.4f);
CShadows::StoreStaticShadow((uintptr)entity,
SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos, 2.0f, 0.0f, 0.0f, -2.0f, 0,
aPickupColors[colorId].r * 0.3f, aPickupColors[colorId].g * 0.3f, aPickupColors[colorId].b * 0.3f,
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, aPickupColors[colorId].r / 256.0f, aPickupColors[colorId].g / 256.0f, aPickupColors[colorId].b / 256.0f, CPointLights::FOG_NONE, true);
} else
CCoronas::RegisterCorona((uintptr)entity, 0, 0, 0, 255, pos, 0.57f, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
if (corona2) {
CCoronas::RegisterCorona(
(uintptr)entity + 1,
aPickupColors[colorId].r * 0.55f, aPickupColors[colorId].g * 0.55f, aPickupColors[colorId].b * 0.55f,
255,
pos,
0.6f,
65.0f,
CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF,
0.0f, false, -0.4f);
if (!corona1)
CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos, 2.0f, 0.0f, 0.0f, -2.0f, 0,
aPickupColors[colorId].r * 0.25f, aPickupColors[colorId].g * 0.25f, aPickupColors[colorId].b * 0.25f,
4.0f, 1.0f, 40.0f, false, 0.0f);
} else
CCoronas::RegisterCorona((uintptr)entity + 1, 0, 0, 0, 255, pos, 0.45f, 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->bPickupObjWithMessage || object->bOutOfStock || object->m_nBonusValue || object->m_nCostValue) {
float dist = Distance2D(pos, TheCamera.GetPosition());
const float MAXDIST = 14.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 = aPickupColors[colorId].r;
aMessages[NumMessages].m_color.green = aPickupColors[colorId].g;
aMessages[NumMessages].m_color.blue = aPickupColors[colorId].b;
aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
aMessages[NumMessages].m_quantity = object->m_nBonusValue;
aMessages[NumMessages].money = object->m_nCostValue;
NumMessages++;
}
}
}
uint32 model = entity->GetModelIndex();
CColModel *colModel = entity->GetColModel();
CVector colLength = colModel->boundingBox.max - colModel->boundingBox.min;
float maxDimension = Max(colLength.x, Max(colLength.y, colLength.z));
float scale = (Max(1.f, 1.2f / maxDimension) - 1.0f) * 0.6f + 1.0f;
if (model == MI_MINIGUN || model == MI_MINIGUN2)
scale = 1.2f;
float angle = (float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800);
float c = Cos(angle) * scale;
float s = Sin(angle) * scale;
// we know from SA they were setting each field manually like this
entity->GetMatrix().rx = c;
entity->GetMatrix().ry = s;
entity->GetMatrix().rz = 0.0f;
entity->GetMatrix().fx = -s;
entity->GetMatrix().fy = c;
entity->GetMatrix().fz = 0.0f;
entity->GetMatrix().ux = 0.0f;
entity->GetMatrix().uy = 0.0f;
entity->GetMatrix().uz = scale;
if (entity->GetModelIndex() == MI_MINIGUN2) {
CMatrix matrix1;
CMatrix matrix2; // unused
entity->SetPosition(pickup->m_vecPos);
matrix1.SetRotateX(0.0f);
matrix1.Rotate(DEGTORAD(4.477f), DEGTORAD(-29.731f), DEGTORAD(-1.064f));
matrix1.Translate(CVector(0.829f, -0.001f, 0.226f));
entity->GetMatrix() *= matrix1;
}
if (doOuterGlow) {
CVector scale(0.0f, 0.0f, 0.0f);
if (colLength.x == maxDimension)
scale.x = colLength.x;
else if (colLength.y == maxDimension)
scale.y = colLength.y;
else
scale.z = colLength.z;
for (int i = 0; i < 4; i++) {
CVector pos = entity->GetMatrix() * (scale * ((float)i / 3.0f));
CCoronas::RegisterCorona(
(uintptr)entity + 8 + i,
aPickupColors[colorId].r * 0.15f,
aPickupColors[colorId].g * 0.15f,
aPickupColors[colorId].b * 0.15f,
255,
pos,
1.0f,
65.0f,
CCoronas::TYPE_STAR, CCoronas::FLARE_NONE,
CCoronas::REFLECTION_OFF,
CCoronas::LOSCHECK_OFF,
CCoronas::STREAK_OFF,
0.0f,
false,
-0.5f);
}
}
if (doInnerGlow)
CCoronas::RegisterCorona(
#ifdef FIX_BUGS
(uintptr)entity + 8 + 4,
#else
(uintptr)entity + 9,
#endif
126, 69, 121, 255, entity->GetPosition(), 1.2f, 50.0f,
CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
}
}
void
CPickups::DoMineEffects(CEntity *entity)
{
const CVector &pos = entity->GetPosition();
float dist = Distance(pos, TheCamera.GetPosition());
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, 0, 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)
{
const CVector &pos = entity->GetPosition();
float dist = Distance(pos, TheCamera.GetPosition());
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, 0, 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)
{
const CVector &pos = entity->GetPosition();
float dist = Distance(pos, TheCamera.GetPosition());
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, 0, 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_HEX, 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].money != 0) {
sprintf(gString, "$%d", aMessages[i].money);
AsciiToUnicode(gString, gUString);
strToPrint = gUString;
} else {
switch (aMessages[i].m_quantity) // could use some enum maybe
{
case 0:
if (aMessages[i].m_weaponType == WEAPONTYPE_HEALTH || aMessages[i].m_weaponType == WEAPONTYPE_ARMOUR) {
strToPrint = nil;
} 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("OUTFT1");
break;
case 2:
strToPrint = TheText.Get("OUTFT2");
break;
case 3:
strToPrint = TheText.Get("OUTFT3");
break;
case 4:
strToPrint = TheText.Get("OUTFT4");
break;
case 5:
strToPrint = TheText.Get("OUTFT5");
break;
case 6:
strToPrint = TheText.Get("OUTFT6");
break;
case 7:
strToPrint = TheText.Get("OUTFT7");
break;
case 8:
strToPrint = TheText.Get("OUTFT8");
break;
case 9:
strToPrint = TheText.Get("OUTFT9");
break;
case 10:
strToPrint = TheText.Get("OUTFT10");
break;
case 11:
strToPrint = TheText.Get("OUTFT11");
break;
case 12:
strToPrint = TheText.Get("OUTFT12");
break;
case 13:
strToPrint = TheText.Get("OUTFT13");
break;
default:
break;
}
}
if (strToPrint == nil)
continue;
CFont::SetPropOn();
CFont::SetBackgroundOff();
#ifdef FIX_BUGS
const float MAX_SCALE = SCREEN_WIDTH / DEFAULT_SCREEN_WIDTH;
#else
float MAX_SCALE = RsGlobal.width / DEFAULT_SCREEN_WIDTH;
#endif
float fScaleY = aMessages[i].m_dist.y / 30.0f;
if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
float fScaleX = aMessages[i].m_dist.x / 30.0f;
if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
CFont::SetScale(fScaleX, fScaleY); // this shouldn't be scaled
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_STANDARD);
CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
}
NumMessages = 0;
}
void
CPickups::CreateSomeMoney(CVector pos, int money)
{
bool found;
int pickupCount = Min(money / 20 + 1, 7);
int moneyPerPickup = money / pickupCount;
for (int i = 0; i < pickupCount; i++) {
// (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish.
pos.x += 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128);
pos.y += 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128);
pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &found) + 0.5f;
if (found) {
CPickups::GenerateNewOne(CVector(pos.x, pos.y, pos.z), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 3));
}
}
}
void
CPickups::RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType weaponType)
{
uint32 weaponSlot = CWeaponInfo::GetWeaponInfo(weaponType)->m_nWeaponSlot;
if (CWeaponInfo::IsWeaponSlotAmmoMergeable(weaponSlot)) {
for (int slot = 0; slot < NUMPICKUPS; slot++) {
if (aPickUps[slot].m_eType == PICKUP_ONCE || aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT || aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT_SLOW) {
if (aPickUps[slot].m_pObject) {
if (CWeaponInfo::GetWeaponInfo(WeaponForModel(aPickUps[slot].m_pObject->GetModelIndex()))->m_nWeaponSlot == weaponSlot &&
aPickUps[slot].m_nQuantity == 0) {
CWorld::Remove(aPickUps[slot].m_pObject);
delete aPickUps[slot].m_pObject;
aPickUps[slot].m_bRemoved = true;
aPickUps[slot].m_pObject = nil;
aPickUps[slot].m_eType = PICKUP_NONE;
}
}
}
}
}
}
void
CPickups::DetonateMinesHitByGunShot(CVector *vec1, CVector *vec2)
{
for (int i = 0; i < NUMGENERALPICKUPS; i++) {
if (aPickUps[i].m_eType == PICKUP_NAUTICAL_MINE_ARMED)
aPickUps[i].ProcessGunShot(vec1, vec2);
}
}
void
CPickups::RemoveUnnecessaryPickups(const CVector& center, float radius)
{
for (int i = 0; i < NUMPICKUPS; i++) {
if (aPickUps[i].m_eType == PICKUP_ONCE_TIMEOUT || aPickUps[i].m_eType == PICKUP_MONEY) {
if (Distance(center, aPickUps[i].m_vecPos) < radius) {
aPickUps[i].GetRidOfObjects();
aPickUps[i].m_bRemoved = true;
aPickUps[i].m_eType = PICKUP_NONE;
}
}
}
}
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) {
if (aPickUps[i].m_pObject != nil)
aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((uintptr)aPickUps[i].m_pObject - 1);
if (aPickUps[i].m_pExtraObject != nil)
aPickUps[i].m_pExtraObject = CPools::GetObjectPool()->GetSlot((uintptr)aPickUps[i].m_pExtraObject - 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);
*size += 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) {
if (buf_pickup->m_pObject != nil)
buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(buf_pickup->m_pObject) + 1);
if (buf_pickup->m_pExtraObject != nil)
buf_pickup->m_pExtraObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(buf_pickup->m_pExtraObject) + 1);
}
}
WriteSaveBuf(buf, CollectedPickUpIndex);
WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
WriteSaveBuf(buf, aPickUpsCollected[i]);
VALIDATESAVEBUF(*size)
}
void
CPacManPickup::Update()
{
}
int32 CollectGameState;
int16 ThingsToCollect;
CPacManPickup CPacManPickups::aPMPickUps[NUMPACMANPICKUPS];
CVector CPacManPickups::LastPickUpCoors;
int32 CPacManPickups::PillsEatenInRace;
bool CPacManPickups::bPMActive;
void
CPacManPickups::Init()
{
}
void
CPacManPickups::Update()
{
}
void
CPacManPickups::GeneratePMPickUps(CVector pos, float scrambleMult, int16 count, uint8 type)
{
}
// diablo porn mission pickups
static const CVector aRacePoints1[] = {
CVector(913.62219f, -155.13692f, 4.9699469f),
CVector(913.92401f, -124.12943f, 4.9692569f),
CVector(913.27899f, -93.524231f, 7.4325991f),
CVector(912.60852f, -63.15905f, 7.4533591f),
CVector(934.22144f, -42.049122f, 7.4511471f),
CVector(0.0f, 0.0f, 0.0f),
};
void
CPacManPickups::GeneratePMPickUpsForRace(int32 race)
{
}
void
CPacManPickups::GenerateOnePMPickUp(CVector pos)
{
}
void
CPacManPickups::Render()
{
}
void
CPacManPickups::ClearPMPickUps()
{
}
void
CPacManPickups::StartPacManRace(int32 race)
{
}
void
CPacManPickups::StartPacManRecord()
{
}
uint32
CPacManPickups::QueryPowerPillsEatenInRace()
{
return 0;
}
void
CPacManPickups::ResetPowerPillsEatenInRace()
{
}
void
CPacManPickups::CleanUpPacManStuff()
{
}
void
CPacManPickups::StartPacManScramble(CVector pos, float scrambleMult, int16 count)
{
}
uint32
CPacManPickups::QueryPowerPillsCarriedByPlayer()
{
return 0;
}
void
CPacManPickups::ResetPowerPillsCarriedByPlayer()
{
}
void
CPed::CreateDeadPedMoney(void)
{
if (!CGame::nastyGame)
return;
int mi = GetModelIndex();
if ((mi >= MI_COP && mi <= MI_FIREMAN) || (CharCreatedBy == MISSION_CHAR && !bMoneyHasBeenGivenByScript) || bInVehicle)
return;
int money = m_nPedMoney;
if (money < 10)
return;
CVector pickupPos = GetPosition();
CPickups::CreateSomeMoney(pickupPos, money);
m_nPedMoney = 0;
}
void
CPed::CreateDeadPedWeaponPickups(void)
{
CVector pickupPos;
if (bInVehicle)
return;
for(int i = 0; i < TOTAL_WEAPON_SLOTS; i++) {
eWeaponType weapon = GetWeapon(i).m_eWeaponType;
int weaponAmmo = GetWeapon(i).m_nAmmoTotal;
if (weapon == WEAPONTYPE_UNARMED || weapon == WEAPONTYPE_DETONATOR || (weaponAmmo == 0 && !GetWeapon(i).IsTypeMelee()))
continue;
int quantity = Min(weaponAmmo, AmmoForWeapon_OnStreet[weapon] / 2);
CreateDeadPedPickupCoors(&pickupPos.x, &pickupPos.y, &pickupPos.z);
pickupPos.z += 0.3f;
if (!CPickups::TryToMerge_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, quantity, false)) {
CPickups::GenerateNewOne_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, Min(weaponAmmo, quantity));
}
}
ClearWeapons();
}
void
CPed::CreateDeadPedPickupCoors(float *x, float *y, float *z)
{
bool found = false;
CVector pickupPos;
#define NUMBER_OF_ATTEMPTS 32
for (int i = 0; i < NUMBER_OF_ATTEMPTS; i++) {
pickupPos = GetPosition();
pickupPos.x = 1.5f * Sin((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().x;
pickupPos.y = 1.5f * Cos((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().y;
pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f;
if (!found)
continue;
CVector pedPos = GetPosition();
pedPos.z += 0.3f;
CVector pedToPickup = pickupPos - pedPos;
float distance = pedToPickup.Magnitude();
// outer edge of pickup
distance = (distance + 0.4f) / distance;
CVector pickupPos2 = pedPos;
pickupPos2 += distance * pedToPickup;
if ((pickupPos - FindPlayerCoors()).Magnitude2D() > 2.0f || i > NUMBER_OF_ATTEMPTS / 2) {
if (i > NUMBER_OF_ATTEMPTS / 2 || !CPickups::TestForPickupsInBubble(pickupPos, 1.3f)) {
if (CWorld::GetIsLineOfSightClear(pickupPos2, pedPos,
true, i < NUMBER_OF_ATTEMPTS / 2, false, i < NUMBER_OF_ATTEMPTS / 2, false, false, false)) {
if (i > NUMBER_OF_ATTEMPTS / 2 || !CWorld::TestSphereAgainstWorld(pickupPos, 1.2f, nil, false, true, false, false, false, false)) {
*x = pickupPos.x;
*y = pickupPos.y;
*z = pickupPos.z;
return;
}
}
}
}
}
*x = GetPosition().x;
*y = GetPosition().y;
*z = GetPosition().z + 0.4f;
#undef NUMBER_OF_ATTEMPTS
}
float CPickups::GetValue(int index)
{
int i = GetActualPickupIndex(index);
if (i == -1)
return 0.0f;
return aPickUps[i].m_fRevenue;
}
void CPickups::SetValue(int index, float value)
{
int i = GetActualPickupIndex(index);
if (i == -1)
return;
aPickUps[i].m_fRevenue = value;
}