summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/control/Pickups.cpp828
-rw-r--r--src/control/Pickups.h25
-rw-r--r--src/control/Replay.cpp12
-rw-r--r--src/control/Script.cpp22
-rw-r--r--src/core/Timer.cpp3
-rw-r--r--src/core/main.cpp2
-rw-r--r--src/modelinfo/WeaponModelInfo.cpp4
-rw-r--r--src/modelinfo/WeaponModelInfo.h3
-rw-r--r--src/peds/Ped.cpp7
-rw-r--r--src/render/Glass.cpp478
-rw-r--r--src/render/Glass.h12
-rw-r--r--src/render/SpecialFX.cpp524
-rw-r--r--src/render/SpecialFX.h48
13 files changed, 1266 insertions, 702 deletions
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index 490be370..ddf7cefb 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -49,30 +49,70 @@ uint32 CPickups::StaticCamStartTime;
tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
-// TODO(Miami)
-uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
+// --MIAMI: Done
+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 };
+
+// --MIAMI: Done
+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 };
// --MIAMI: Done
-uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS] = {
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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 }
};
-uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
-
-// TODO(Miami): Those are all placeholders!!
-uint8 aWeaponReds[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 128, 0, 255, 0 };
-uint8 aWeaponGreens[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-0, 255, 0, 255, 0 };
-uint8 aWeaponBlues[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-0, 128, 255, 0, 0 };
+
void
ModifyStringLabelForControlSetting(char *str)
@@ -117,16 +157,37 @@ CPickup::Remove()
m_eType = PICKUP_NONE;
}
+// --MIAMI: Done
CObject *
-CPickup::GiveUsAPickUpObject(int32 handle)
+CPickup::GiveUsAPickUpObject(CObject **ppObject, CObject **ppExtraObject, int32 handle, int32 extraHandle)
{
- CObject *object;
+ 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);
- object = new (handle) CObject(m_eModelIndex, false);
- } else
+ 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;
@@ -139,15 +200,38 @@ CPickup::GiveUsAPickUpObject(int32 handle)
object->bExplosionProof = true;
object->bUsesCollision = false;
object->bIsPickup = true;
+ object->obj_flag_02 = m_effects;
object->bHasPreRenderEffects = true;
- object->m_nBonusValue = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
+ 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->obj_flag_02 = 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:
@@ -193,28 +277,20 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
float waterLevel;
if (m_pObject) {
- m_pObject->SetPosition(m_vecPos);
- // TODO(Miami): Extra object
+ m_pObject->GetMatrix().GetPosition() = m_vecPos;
+ if (m_pExtraObject)
+ m_pExtraObject->GetMatrix().GetPosition() = m_vecPos;
}
if (m_eType == PICKUP_ASSET_REVENUE) {
- uint32 oldTimer = m_nTimer;
+ uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nTimer;
m_nTimer = CTimer::GetTimeInMilliseconds();
- float calculatedRevenue;
- if ((FindPlayerCoors() - m_vecPos).Magnitude() > 10.0) {
- uint32 timePassed = CTimer::GetTimeInMilliseconds() - oldTimer;
- calculatedRevenue = m_nRevenue + (timePassed * m_nMoneySpeed) * sq(1.f / 1200.f);
- } else {
- calculatedRevenue = m_nRevenue;
- }
- m_nRevenue = Min(calculatedRevenue, m_nQuantity);
- // TODO(Miami): For pickup glow effect?
- /*
- if (calculatedRevenue < 10.0) {
- m_pObject->m_nCostValue = 0;
- } else {
- m_pObject->m_nCostValue = calculatedRevenue;
- }
- */
+
+ 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) {
@@ -222,7 +298,7 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
// 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);
+ m_pObject = GiveUsAPickUpObject(&m_pObject, &m_pExtraObject, -1, -1);
if (m_pObject) {
CWorld::Add(m_pObject);
m_bRemoved = false;
@@ -232,6 +308,14 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
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()) {
@@ -261,6 +345,10 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
}
}
+ // MIAMI code here
+
+ // ...
+
// if we didn't then we've got nothing to do
if (isPickupTouched && CanBePickedUp(player, playerId)) {
CPad::GetPad(0)->StartShake(120, 100);
@@ -345,8 +433,8 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
return true;
case PICKUP_ASSET_REVENUE:
- CWorld::Players[CWorld::PlayerInFocus].m_nMoney += m_nRevenue;
- m_nRevenue = 0;
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += m_fRevenue;
+ m_fRevenue = 0.0f;
DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
return false;
// TODO(Miami): Control flow
@@ -462,6 +550,23 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
return false;
}
+// --MIAMI: Done
+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;
+ }
+}
+
+// --MIAMI: Done
void
CPickups::Init(void)
{
@@ -470,6 +575,7 @@ CPickups::Init(void)
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++)
@@ -502,6 +608,7 @@ CPickups::TryToMerge_WeaponType(CVector pos, eWeaponType weapon, uint8 type, uin
return false;
}
+// --MIAMI: Done
bool
CPickups::IsPickUpPickedUp(int32 pickupId)
{
@@ -514,11 +621,12 @@ CPickups::IsPickUpPickedUp(int32 pickupId)
return false;
}
+// --MIAMI: Done
void
CPickups::PassTime(uint32 time)
{
for (int i = 0; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE) {
+ 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
@@ -527,6 +635,7 @@ CPickups::PassTime(uint32 time)
}
}
+// --MIAMI: Done
int32
CPickups::GetActualPickupIndex(int32 index)
{
@@ -537,6 +646,7 @@ CPickups::GetActualPickupIndex(int32 index)
return (uint16)index;
}
+// --MIAMI: Done
bool
CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
{
@@ -566,8 +676,7 @@ CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
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;
+ int32 level = Max(FindPlayerPed()->m_pWanted->m_nWantedLevel - 1, 0);
player->SetWantedLevel(level);
DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
return true;
@@ -578,6 +687,7 @@ CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
return false;
}
+// --MIAMI: Todo
void
CPickups::RemoveAllFloatingPickups()
{
@@ -592,10 +702,11 @@ CPickups::RemoveAllFloatingPickups()
}
}
+// --MIAMI: Done
void
CPickups::RemovePickUp(int32 pickupIndex)
{
- int32 index = CPickups::GetActualPickupIndex(pickupIndex);
+ int32 index = GetActualPickupIndex(pickupIndex);
if (index == -1) return;
if (aPickUps[index].m_pObject) {
@@ -603,10 +714,16 @@ CPickups::RemovePickUp(int32 pickupIndex)
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;
}
+// --MIAMI: Done
int32
CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity, uint32 rate, bool highPriority, char* pText)
{
@@ -620,7 +737,8 @@ CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quan
break;
}
}
- } else {
+ }
+ if (!bFreeFound) {
for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
if (aPickUps[slot].m_eType == PICKUP_NONE) {
bFreeFound = true;
@@ -640,6 +758,7 @@ CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quan
}
if (slot >= NUMGENERALPICKUPS) return -1;
+ aPickUps[slot].GetRidOfObjects();
}
}
@@ -649,8 +768,10 @@ CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quan
aPickUps[slot].m_bRemoved = false;
aPickUps[slot].m_nQuantity = quantity;
aPickUps[slot].m_nMoneySpeed = rate;
- aPickUps[slot].m_nRevenue = 0;
+ aPickUps[slot].m_fRevenue = 0.0f;
aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds();
+ aPickUps[slot].m_effects = highPriority;
+ aPickUps[slot].m_effects2 = false;
if (type == PICKUP_ONCE_TIMEOUT)
aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
else if (type == PICKUP_ONCE_TIMEOUT_SLOW)
@@ -671,18 +792,22 @@ CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quan
aPickUps[slot].m_sTextKey[0] = '\0';
aPickUps[slot].m_vecPos = pos;
- aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
+ 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);
}
+// --MIAMI: Done
int32
CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
{
return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
}
+// --MIAMI: Done
int32
CPickups::GetNewUniquePickupIndex(int32 slot)
{
@@ -711,6 +836,7 @@ CPickups::WeaponForModel(int32 model)
return (eWeaponType)((CWeaponModelInfo*)CModelInfo::GetModelInfo(model))->GetWeaponInfo();
}
+// --MIAMI: Done
void
CPickups::AddToCollectedPickupsArray(int32 index)
{
@@ -753,15 +879,13 @@ CPickups::Update()
}
}
#endif
- if (CPad::GetPad(0)->CollectPickupJustDown()) {
+ if (CPad::GetPad(0)->CollectPickupJustDown())
CollectPickupBuffer = 6;
- } else {
+ else
CollectPickupBuffer = Max(0, CollectPickupBuffer - 1);
- }
- if (PlayerOnWeaponPickup) {
+ if (PlayerOnWeaponPickup)
PlayerOnWeaponPickup = Max(0, PlayerOnWeaponPickup - 1);
- }
#define PICKUPS_FRAME_SPAN (6)
#ifdef FIX_BUGS
@@ -781,9 +905,24 @@ CPickups::Update()
}
}
+// --MIAMI: Done
+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];
+}
+
+// --MIAMI: Done
void
CPickups::DoPickUpEffects(CEntity *entity)
{
+ CPickup *pickup = FindPickUpForThisObject(entity);
+
if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
entity->bDoNotRender = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
@@ -801,7 +940,7 @@ CPickups::DoPickUpEffects(CEntity *entity)
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR) {
- colorId = WEAPONTYPE_TOTALWEAPONS + 1;
+ colorId = WEAPONTYPE_ARMOUR;
} else if (entity->GetModelIndex() == MI_PICKUP_BRIBE) {
doInnerGlow = true;
doOuterGlow = false;
@@ -810,33 +949,92 @@ CPickups::DoPickUpEffects(CEntity *entity)
doInnerGlow = true;
doOuterGlow = false;
} else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS) {
- colorId = WEAPONTYPE_TOTALWEAPONS;
+ 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 = entity->GetPosition();
+ const CVector& pos = pickup->m_vecPos;
if (doOuterGlow) {
- 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, 0,
- aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier, 4.0f,
- 1.0f, 40.0f, false, 0.0f);
+ 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;
- 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);
+ if (((CObject*)entity)->obj_flag_02) {
+ 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) {
+ if (object->bPickupObjWithMessage || object->bOutOfStock || object->m_nBonusValue || object->m_nCostValue) {
+
float dist = Distance2D(pos, TheCamera.GetPosition());
- const float MAXDIST = 12.0f;
+ const float MAXDIST = 14.0f;
if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
RwV3d vecOut;
@@ -847,33 +1045,80 @@ CPickups::DoPickUpEffects(CEntity *entity)
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.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();
+ 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 / Max(colLength.x, Max(colLength.y, colLength.z))) - 1.0f) * 0.6f + 1.0f;
+ float scale = (Max(1.f, 1.2f / maxDimension) - 1.0f) * 0.6f + 1.0f;
if (model == MI_MINIGUN || model == MI_MINIGUN2)
scale = 1.2f;
entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), 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.731), DEGTORAD(-1.064));
+ matrix1.Translate(CVector(0.829, -0.001, 0.226));
+ 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);
+ }
+ }
+
if (doInnerGlow)
- CCoronas::RegisterCorona((uintptr)entity + 1, 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.f, false);
+ 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);
}
}
+// --MIAMI: Done
void
CPickups::DoMineEffects(CEntity *entity)
{
@@ -893,6 +1138,7 @@ CPickups::DoMineEffects(CEntity *entity)
entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
}
+// --MIAMI: Done
void
CPickups::DoMoneyEffects(CEntity *entity)
{
@@ -912,6 +1158,7 @@ CPickups::DoMoneyEffects(CEntity *entity)
entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
}
+// --MIAMI: Done
void
CPickups::DoCollectableEffects(CEntity *entity)
{
@@ -931,18 +1178,22 @@ CPickups::DoCollectableEffects(CEntity *entity)
entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
}
+// --MIAMI: Done
void
CPickups::RenderPickUpText()
{
wchar *strToPrint;
for (int32 i = 0; i < NumMessages; i++) {
- if (aMessages[i].m_quantity <= 39) {
+
+ 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_TOTALWEAPONS) { // unreachable code?
- // what is this??
- sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
+ if (aMessages[i].m_weaponType == WEAPONTYPE_HEALTH || aMessages[i].m_weaponType == WEAPONTYPE_ARMOUR) {
strToPrint = nil;
} else {
if (aMessages[i].m_bOutOfStock)
@@ -955,121 +1206,43 @@ CPickups::RenderPickUpText()
}
break;
case 1:
- strToPrint = TheText.Get("SECURI");
+ strToPrint = TheText.Get("OUTFT1");
break;
case 2:
- strToPrint = TheText.Get("MOONBM");
+ strToPrint = TheText.Get("OUTFT2");
break;
case 3:
- strToPrint = TheText.Get("COACH");
+ strToPrint = TheText.Get("OUTFT3");
break;
case 4:
- strToPrint = TheText.Get("FLATBED");
+ strToPrint = TheText.Get("OUTFT4");
break;
case 5:
- strToPrint = TheText.Get("LINERUN");
+ strToPrint = TheText.Get("OUTFT5");
break;
case 6:
- strToPrint = TheText.Get("TRASHM");
+ strToPrint = TheText.Get("OUTFT6");
break;
case 7:
- strToPrint = TheText.Get("PATRIOT");
+ strToPrint = TheText.Get("OUTFT7");
break;
case 8:
- strToPrint = TheText.Get("WHOOPEE");
+ strToPrint = TheText.Get("OUTFT8");
break;
case 9:
- strToPrint = TheText.Get("BLISTA");
+ strToPrint = TheText.Get("OUTFT9");
break;
case 10:
- strToPrint = TheText.Get("MULE");
+ strToPrint = TheText.Get("OUTFT10");
break;
case 11:
- strToPrint = TheText.Get("YANKEE");
+ strToPrint = TheText.Get("OUTFT11");
break;
case 12:
- strToPrint = TheText.Get("BOBCAT");
+ strToPrint = TheText.Get("OUTFT12");
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");
+ strToPrint = TheText.Get("OUTFT13");
break;
default:
break;
@@ -1080,12 +1253,16 @@ CPickups::RenderPickUpText()
CFont::SetPropOn();
CFont::SetBackgroundOff();
- const float MAX_SCALE = 1.0f;
+#ifdef FIX_BUGS
+ const float MAX_SCALE = SCREEN_WIDTH / DEFAULT_SCREEN_WIDTH;
+#else
+ const float MAX_SCALE = RsGlobal.width / DEFAULT_SCREEN_WIDTH;
+#endif
- float fScaleY = aMessages[i].m_dist.y / 100.0f;
+ float fScaleY = aMessages[i].m_dist.y / 30.0f;
if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
- float fScaleX = aMessages[i].m_dist.x / 100.0f;
+ float fScaleX = aMessages[i].m_dist.x / 30.0f;
if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
CFont::SetScale(fScaleX, fScaleY);
@@ -1101,6 +1278,7 @@ CPickups::RenderPickUpText()
NumMessages = 0;
}
+// --MIAMI: Done
void
CPickups::CreateSomeMoney(CVector pos, int money)
{
@@ -1120,6 +1298,30 @@ CPickups::CreateSomeMoney(CVector pos, int money)
}
}
+// --MIAMI: Done
+void
+CPickups::RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType weaponType)
+{
+ uint32 weaponSlot = CWeaponInfo::GetWeaponInfo(weaponType)->m_nWeaponSlot;
+ if (weaponSlot >= WEAPONSLOT_SHOTGUN && weaponSlot <= WEAPONSLOT_RIFLE) {
+ 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;
+ }
+ }
+ }
+ }
+ }
+}
+
+// --MIAMI: Done
void
CPickups::Load(uint8 *buf, uint32 size)
{
@@ -1128,8 +1330,13 @@ 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((uintptr)aPickUps[i].m_pObject - 1);
+ 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);
@@ -1142,17 +1349,23 @@ INITSAVEBUF
VALIDATESAVEBUF(size)
}
+// --MIAMI: Done
void
CPickups::Save(uint8 *buf, uint32 *size)
{
- *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
+ *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 && buf_pickup->m_pObject != nil)
- buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
+ if (buf_pickup->m_eType != PICKUP_NONE) {
+ if (buf_pickup->m_pObject != nil)
+ buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
+ if (buf_pickup->m_pExtraObject != nil)
+ buf_pickup->m_pExtraObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pExtraObject) + 1);
+ }
}
WriteSaveBuf(buf, CollectedPickUpIndex);
@@ -1167,40 +1380,6 @@ VALIDATESAVEBUF(*size)
void
CPacManPickup::Update()
{
- if (FindPlayerVehicle() == nil) return;
-
- CVehicle *veh = FindPlayerVehicle();
-
- if (DistanceSqr2D(FindPlayerVehicle()->GetPosition(), m_vecPosn.x, m_vecPosn.y) < 100.0f && veh->IsSphereTouchingVehicle(m_vecPosn.x, m_vecPosn.y, m_vecPosn.z, 1.5f)) {
- switch (m_eType)
- {
- case PACMAN_SCRAMBLE:
- {
- veh->m_nPacManPickupsCarried++;
- veh->m_vecMoveSpeed *= 0.65f;
- float massMult = (veh->m_fMass + 250.0f) / veh->m_fMass;
- veh->m_fMass *= massMult;
- veh->m_fTurnMass *= massMult;
- veh->m_fForceMultiplier *= massMult;
- FindPlayerPed()->m_pWanted->m_nChaos += 10;
- FindPlayerPed()->m_pWanted->UpdateWantedLevel();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PACKAGE, 0);
- break;
- }
- case PACMAN_RACE:
- CPacManPickups::PillsEatenInRace++;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PILL, 0);
- break;
- default:
- break;
- }
- m_eType = PACMAN_NONE;
- if (m_pObject != nil) {
- CWorld::Remove(m_pObject);
- delete m_pObject;
- m_pObject = nil;
- }
- }
}
int32 CollectGameState;
@@ -1214,52 +1393,11 @@ bool CPacManPickups::bPMActive;
void
CPacManPickups::Init()
{
- for (int i = 0; i < NUMPACMANPICKUPS; i++)
- aPMPickUps[i].m_eType = PACMAN_NONE;
- bPMActive = false;
}
void
CPacManPickups::Update()
{
- if (FindPlayerVehicle()) {
- float dist = Distance(FindPlayerCoors(), CVector(1072.0f, -948.0f, 14.5f));
- switch (CollectGameState) {
- case 1:
- if (dist < 10.0f) {
- ThingsToCollect -= FindPlayerVehicle()->m_nPacManPickupsCarried;
- FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
- FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
- FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
- FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
- }
- if (ThingsToCollect <= 0) {
- CollectGameState = 2;
- ClearPMPickUps();
- }
- break;
- case 2:
- if (dist > 11.0f)
- CollectGameState = 0;
- break;
- case 20:
- if (Distance(FindPlayerCoors(), LastPickUpCoors) > 30.0f) {
- LastPickUpCoors = FindPlayerCoors();
- printf("%f, %f, %f,\n", LastPickUpCoors.x, LastPickUpCoors.y, LastPickUpCoors.z);
- }
- break;
- default:
- break;
- }
- }
- if (bPMActive) {
-#define PACMANPICKUPS_FRAME_SPAN (4)
- for (uint32 i = (CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i < ((CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) + 1) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i++) {
- if (aPMPickUps[i].m_eType != PACMAN_NONE)
- aPMPickUps[i].Update();
- }
-#undef PACMANPICKUPS_FRAME_SPAN
- }
}
void
@@ -1274,107 +1412,6 @@ static const CVector aRacePoints1[] = {
CVector(913.27899f, -93.524231f, 7.4325991f),
CVector(912.60852f, -63.15905f, 7.4533591f),
CVector(934.22144f, -42.049122f, 7.4511471f),
- CVector(958.88092f, -23.863735f, 7.4652338f),
- CVector(978.50812f, -0.78458798f, 5.13515f),
- CVector(1009.4175f, -2.1041219f, 2.4461579f),
- CVector(1040.6313f, -2.0793829f, 2.293175f),
- CVector(1070.7863f, -2.084095f, 2.2789791f),
- CVector(1100.5773f, -8.468729f, 5.3248072f),
- CVector(1119.9341f, -31.738031f, 7.1913071f),
- CVector(1122.1664f, -62.762737f, 7.4703908f),
- CVector(1122.814f, -93.650566f, 8.5577497f),
- CVector(1125.8253f, -124.26616f, 9.9803305f),
- CVector(1153.8727f, -135.47169f, 14.150617f),
- CVector(1184.0831f, -135.82845f, 14.973998f),
- CVector(1192.0432f, -164.57816f, 19.18627f),
- CVector(1192.7761f, -194.28871f, 24.799675f),
- CVector(1215.1527f, -215.0714f, 25.74975f),
- CVector(1245.79f, -215.39304f, 28.70726f),
- CVector(1276.2477f, -216.39485f, 33.71236f),
- CVector(1306.5535f, -216.71007f, 39.711472f),
- CVector(1335.0244f, -224.59329f, 46.474979f),
- CVector(1355.4879f, -246.27664f, 49.934841f),
- CVector(1362.6003f, -276.47064f, 49.96265f),
- CVector(1363.027f, -307.30847f, 49.969173f),
- CVector(1365.343f, -338.08609f, 49.967789f),
- CVector(1367.5957f, -368.01105f, 50.092304f),
- CVector(1368.2749f, -398.38049f, 50.061268f),
- CVector(1366.9034f, -429.98483f, 50.057545f),
- CVector(1356.8534f, -459.09259f, 50.035545f),
- CVector(1335.5819f, -481.13544f, 47.217903f),
- CVector(1306.7552f, -491.07443f, 40.202629f),
- CVector(1275.5978f, -491.33194f, 33.969223f),
- CVector(1244.702f, -491.46451f, 29.111021f),
- CVector(1213.2222f, -491.8754f, 25.771168f),
- CVector(1182.7729f, -492.19995f, 24.749964f),
- CVector(1152.6874f, -491.42221f, 21.70038f),
- CVector(1121.5352f, -491.94604f, 20.075182f),
- CVector(1090.7056f, -492.63751f, 17.585758f),
- CVector(1059.6008f, -491.65762f, 14.848632f),
- CVector(1029.113f, -489.66031f, 14.918498f),
- CVector(998.20679f, -486.78107f, 14.945688f),
- CVector(968.00555f, -484.91266f, 15.001229f),
- CVector(937.74939f, -492.09015f, 14.958629f),
- CVector(927.17352f, -520.97736f, 14.972308f),
- CVector(929.29749f, -552.08643f, 14.978855f),
- CVector(950.69525f, -574.47778f, 14.972788f),
- CVector(974.02826f, -593.56024f, 14.966445f),
- CVector(989.04779f, -620.12854f, 14.951016f),
- CVector(1014.1639f, -637.3905f, 14.966736f),
- CVector(1017.5961f, -667.3736f, 14.956415f),
- CVector(1041.9735f, -685.94391f, 15.003841f),
- CVector(1043.3064f, -716.11298f, 14.974236f),
- CVector(1043.5337f, -746.63855f, 14.96919f),
- CVector(1044.142f, -776.93823f, 14.965424f),
- CVector(1044.2657f, -807.29395f, 14.97171f),
- CVector(1017.0797f, -820.1076f, 14.975431f),
- CVector(986.23865f, -820.37103f, 14.972883f),
- CVector(956.10065f, -820.23291f, 14.981133f),
- CVector(925.86914f, -820.19049f, 14.976553f),
- CVector(897.69702f, -831.08734f, 14.962709f),
- CVector(868.06586f, -835.99237f, 14.970685f),
- CVector(836.93054f, -836.84387f, 14.965049f),
- CVector(811.63586f, -853.7915f, 15.067576f),
- CVector(811.46344f, -884.27368f, 12.247812f),
- CVector(811.60651f, -914.70959f, 9.2393751f),
- CVector(811.10425f, -945.16272f, 5.817255f),
- CVector(816.54584f, -975.64587f, 4.998558f),
- CVector(828.2951f, -1003.3685f, 5.0471172f),
- CVector(852.28839f, -1021.5963f, 4.9371028f),
- CVector(882.50067f, -1025.4459f, 5.14077f),
- CVector(912.84821f, -1026.7874f, 8.3415451f),
- CVector(943.68274f, -1026.6914f, 11.341879f),
- CVector(974.4129f, -1027.3682f, 14.410345f),
- CVector(1004.1079f, -1036.0778f, 14.92961f),
- CVector(1030.1144f, -1051.1224f, 14.850387f),
- CVector(1058.7585f, -1060.342f, 14.821624f),
- CVector(1087.7797f, -1068.3263f, 14.800561f),
- CVector(1099.8807f, -1095.656f, 11.877907f),
- CVector(1130.0005f, -1101.994f, 11.853914f),
- CVector(1160.3809f, -1101.6355f, 11.854824f),
- CVector(1191.8524f, -1102.1577f, 11.853843f),
- CVector(1223.3307f, -1102.7448f, 11.852233f),
- CVector(1253.564f, -1098.1045f, 11.853944f),
- CVector(1262.0203f, -1069.1785f, 14.8147f),
- CVector(1290.9998f, -1059.1882f, 14.816016f),
- CVector(1316.246f, -1041.0635f, 14.81109f),
- CVector(1331.7539f, -1013.835f, 14.81207f),
- CVector(1334.0579f, -983.55402f, 14.827253f),
- CVector(1323.2429f, -954.23083f, 14.954678f),
- CVector(1302.7495f, -932.21216f, 14.962917f),
- CVector(1317.418f, -905.89325f, 14.967506f),
- CVector(1337.9503f, -883.5025f, 14.969675f),
- CVector(1352.6929f, -855.96954f, 14.967854f),
- CVector(1357.2388f, -826.26971f, 14.97295f),
- CVector(1384.8668f, -812.47693f, 12.907736f),
- CVector(1410.8983f, -795.39056f, 12.052228f),
- CVector(1433.901f, -775.55811f, 11.96265f),
- CVector(1443.8615f, -746.92511f, 11.976114f),
- CVector(1457.7015f, -720.00903f, 11.971177f),
- CVector(1481.5685f, -701.30237f, 11.977908f),
- CVector(1511.4004f, -696.83295f, 11.972709f),
- CVector(1542.1796f, -695.61676f, 11.970441f),
- CVector(1570.3301f, -684.6239f, 11.969202f),
CVector(0.0f, 0.0f, 0.0f),
};
@@ -1386,119 +1423,56 @@ CPacManPickups::GeneratePMPickUpsForRace(int32 race)
void
CPacManPickups::GenerateOnePMPickUp(CVector pos)
{
- bPMActive = true;
- aPMPickUps[0].m_eType = PACMAN_RACE;
- aPMPickUps[0].m_vecPosn = pos;
}
void
CPacManPickups::Render()
{
- if (!bPMActive) return;
-
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[6]));
-
- RwV3d pos;
- float w, h;
-
- for (int i = 0; i < NUMPACMANPICKUPS; i++) {
- switch (aPMPickUps[i].m_eType)
- {
- case PACMAN_SCRAMBLE:
- case PACMAN_RACE:
- if (CSprite::CalcScreenCoors(aPMPickUps[i].m_vecPosn, &pos, &w, &h, true) && pos.z < 100.0f) {
- if (aPMPickUps[i].m_pObject != nil) {
- aPMPickUps[i].m_pObject->GetMatrix().SetRotateZOnly((CTimer::GetTimeInMilliseconds() % 1024) * TWOPI / 1024.0f);
- aPMPickUps[i].m_pObject->GetMatrix().UpdateRW();
- aPMPickUps[i].m_pObject->UpdateRwFrame();
- }
- float fsin = Sin((CTimer::GetTimeInMilliseconds() % 1024) * 6.28f / 1024.0f); // yes, it is 6.28f when it was TWOPI just now...
- CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z, 0.8f * w * fsin, 0.8f * h, 100, 50, 5, 255, 1.0f / pos.z, 255);
- }
- break;
- default:
- break;
- }
- }
-
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE);
}
void
CPacManPickups::ClearPMPickUps()
{
- bPMActive = false;
-
- for (int i = 0; i < NUMPACMANPICKUPS; i++) {
- if (aPMPickUps[i].m_pObject != nil) {
- CWorld::Remove(aPMPickUps[i].m_pObject);
- delete aPMPickUps[i].m_pObject;
- aPMPickUps[i].m_pObject = nil;
- }
- aPMPickUps[i].m_eType = PACMAN_NONE;
- }
}
void
CPacManPickups::StartPacManRace(int32 race)
{
- GeneratePMPickUpsForRace(race);
- PillsEatenInRace = 0;
}
void
CPacManPickups::StartPacManRecord()
{
- CollectGameState = 20;
- LastPickUpCoors = FindPlayerCoors();
}
uint32
CPacManPickups::QueryPowerPillsEatenInRace()
{
- return PillsEatenInRace;
+ return 0;
}
void
CPacManPickups::ResetPowerPillsEatenInRace()
{
- PillsEatenInRace = 0;
}
void
CPacManPickups::CleanUpPacManStuff()
{
- ClearPMPickUps();
}
void
CPacManPickups::StartPacManScramble(CVector pos, float scrambleMult, int16 count)
{
- GeneratePMPickUps(pos, scrambleMult, count, PACMAN_SCRAMBLE);
}
uint32
CPacManPickups::QueryPowerPillsCarriedByPlayer()
{
- if (FindPlayerVehicle())
- return FindPlayerVehicle()->m_nPacManPickupsCarried;
return 0;
}
void
CPacManPickups::ResetPowerPillsCarriedByPlayer()
{
- if (FindPlayerVehicle() != nil) {
- FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
- FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
- FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
- FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
- }
}
diff --git a/src/control/Pickups.h b/src/control/Pickups.h
index d7d22174..6c3045f7 100644
--- a/src/control/Pickups.h
+++ b/src/control/Pickups.h
@@ -34,21 +34,23 @@ class CPickup
{
public:
CVector m_vecPos;
- uint32 m_nRevenue;
+ float m_fRevenue;
CObject *m_pObject;
CObject *m_pExtraObject;
- uint16 m_nQuantity;
+ uint32 m_nQuantity;
uint32 m_nTimer;
- int16 m_nMoneySpeed;
+ uint16 m_nMoneySpeed;
int16 m_eModelIndex;
uint16 m_nIndex;
char m_sTextKey[8];
ePickupType m_eType;
bool m_bRemoved;
- uint8 m_effects;
+ uint8 m_effects:1;
+ uint8 m_effects2:1;
- CObject *GiveUsAPickUpObject(int32 handle);
+ CObject *GiveUsAPickUpObject(CObject **object, CObject **extraObject, int32 handle, int32 extraHandle);
bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
+ void GetRidOfObjects();
private:
bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
inline bool CanBePickedUp(CPlayerPed *player, int playerId);
@@ -64,8 +66,9 @@ struct tPickupMessage
eWeaponType m_weaponType;
CVector2D m_dist;
CRGBA m_color;
- uint8 m_bOutOfStock : 1;
+ uint8 m_bOutOfStock;
uint8 m_quantity;
+ uint16 money;
};
class CPickups
@@ -111,13 +114,13 @@ public:
static CVector StaticCamCoors;
static uint32 StaticCamStartTime;
-//TODO(MIAMI)
- static void RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType) {}
+ static void RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType);
+ static CPickup *FindPickUpForThisObject(CEntity*);
};
-extern uint16 AmmoForWeapon[20];
-extern uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS];
-extern uint16 CostOfWeapon[20];
+extern uint16 AmmoForWeapon[WEAPONTYPE_TOTALWEAPONS + 1];
+extern uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS + 1];
+extern uint16 CostOfWeapon[WEAPONTYPE_TOTALWEAPONS + 3];
enum ePacmanPickupType
{
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 310d9686..4fdd3439 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -387,10 +387,8 @@ void CReplay::RecordThisFrame(void)
tBulletTracePacket* bt = (tBulletTracePacket*)&Record.m_pBase[Record.m_nOffset];
bt->type = REPLAYPACKET_BULLET_TRACES;
bt->index = i;
- bt->frames = CBulletTraces::aTraces[i].m_framesInUse;
- bt->lifetime = CBulletTraces::aTraces[i].m_lifeTime;
- bt->inf = CBulletTraces::aTraces[i].m_vecCurrentPos;
- bt->sup = CBulletTraces::aTraces[i].m_vecTargetPos;
+ bt->inf = CBulletTraces::aTraces[i].m_vecStartPos;
+ bt->sup = CBulletTraces::aTraces[i].m_vecEndPos;
Record.m_nOffset += sizeof(*bt);
}
tMiscPacket* misc = (tMiscPacket*)&Record.m_pBase[Record.m_nOffset];
@@ -1117,10 +1115,8 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
{
tBulletTracePacket* pb = (tBulletTracePacket*)&ptr[offset];
CBulletTraces::aTraces[pb->index].m_bInUse = true;
- CBulletTraces::aTraces[pb->index].m_framesInUse = pb->frames;
- CBulletTraces::aTraces[pb->index].m_lifeTime = pb->lifetime;
- CBulletTraces::aTraces[pb->index].m_vecCurrentPos = pb->inf;
- CBulletTraces::aTraces[pb->index].m_vecTargetPos = pb->sup;
+ CBulletTraces::aTraces[pb->index].m_vecStartPos = pb->inf;
+ CBulletTraces::aTraces[pb->index].m_vecEndPos = pb->sup;
buffer->m_nOffset += sizeof(tBulletTracePacket);
break;
}
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index a2ab5f0b..0df6d5a2 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -31,6 +31,7 @@
#include "GameLogic.h"
#include "Garages.h"
#include "General.h"
+#include "Glass.h"
#ifdef MISSION_REPLAY
#include "GenericGameStorage.h"
#endif
@@ -1804,9 +1805,8 @@ void CMissionCleanup::Process()
if (!CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
TheCamera.Restore();
TheCamera.SetWideScreenOff();
- // TODO(MIAMI)
- //CSpecialFX::bLiftCam = false;
- //CSpecialFX::bVideoCam = false;
+ CSpecialFX::bLiftCam = false;
+ CSpecialFX::bVideoCam = false;
CTimeCycle::StopExtraColour(0);
for (int i = 0; i < MISSION_AUDIO_SLOTS; i++)
DMAudio.ClearMissionAudio(i);
@@ -12404,7 +12404,7 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
case COMMAND_SWITCH_SECURITY_CAMERA:
{
CollectParameters(&m_nIp, 1);
- debug("SWITCH_SECURITY_CAMERA is not implemented\n"); // TODO(MIAMI)
+ CSpecialFX::bVideoCam = ScriptParams[0] != 0;
return 0;
}
//case COMMAND_IS_CHAR_IN_FLYING_VEHICLE:
@@ -12844,7 +12844,7 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
case COMMAND_SWITCH_LIFT_CAMERA:
{
CollectParameters(&m_nIp, 1);
- debug("SWITCH_LIFT_CAMERA is not implemented\n"); // TODO(MIAMI)
+ CSpecialFX::bLiftCam = ScriptParams[0] != 0;
return 0;
}
case COMMAND_CLOSE_ALL_CAR_DOORS:
@@ -13013,12 +13013,12 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command)
case COMMAND_HAS_GLASS_BEEN_SHATTERED_NEARBY:
{
CollectParameters(&m_nIp, 3);
- static bool bShowed = false;
- if (!bShowed) {
- debug("HAS_GLASS_BEEN_SHATTERED_NEARBY not implemented, default to TRUE\n"); // TODO(MIAMI)
- bShowed = true;
- }
- UpdateCompareFlag(true);
+
+ bool shattered = false;
+ if ( CGlass::HasGlassBeenShatteredAtCoors(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]) )
+ shattered = true;
+
+ UpdateCompareFlag(shattered);
return 0;
}
case COMMAND_ATTACH_CUTSCENE_OBJECT_TO_BONE:
diff --git a/src/core/Timer.cpp b/src/core/Timer.cpp
index f60adf07..5adc36b5 100644
--- a/src/core/Timer.cpp
+++ b/src/core/Timer.cpp
@@ -5,6 +5,7 @@
#include "DMAudio.h"
#include "Record.h"
#include "Timer.h"
+#include "SpecialFX.h"
uint32 CTimer::m_snTimeInMilliseconds;
PauseModeTime CTimer::m_snTimeInMillisecondsPauseMode = 1;
@@ -141,7 +142,7 @@ void CTimer::Update(void)
}
}
- if ( ms_fTimeStep < 0.01f && !GetIsPaused() )
+ if ( ms_fTimeStep < 0.01f && !GetIsPaused() && !CSpecialFX::bSnapShotActive)
ms_fTimeStep = 0.01f;
ms_fTimeStepNonClipped = ms_fTimeStep;
diff --git a/src/core/main.cpp b/src/core/main.cpp
index b39a9c8b..fa5a5000 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -969,7 +969,7 @@ Render2dStuff(void)
else
CHud::Draw();
// TODO(Miami)
- // CSpecialFX::Render2DFXs();
+ CSpecialFX::Render2DFXs();
CUserDisplay::OnscnTimer.ProcessForDisplay();
CMessages::Display();
CDarkel::DrawMessages();
diff --git a/src/modelinfo/WeaponModelInfo.cpp b/src/modelinfo/WeaponModelInfo.cpp
index 2a79fada..bd8f5cb8 100644
--- a/src/modelinfo/WeaponModelInfo.cpp
+++ b/src/modelinfo/WeaponModelInfo.cpp
@@ -40,10 +40,10 @@ CWeaponModelInfo::SetWeaponInfo(int32 weaponId)
m_atomics[2] = (RpAtomic*)weaponId;
}
-int32
+eWeaponType
CWeaponModelInfo::GetWeaponInfo(void)
{
- return (int32)(uintptr)m_atomics[2];
+ return (eWeaponType)(uintptr)m_atomics[2];
}
void
diff --git a/src/modelinfo/WeaponModelInfo.h b/src/modelinfo/WeaponModelInfo.h
index 5c690c29..548bf8a6 100644
--- a/src/modelinfo/WeaponModelInfo.h
+++ b/src/modelinfo/WeaponModelInfo.h
@@ -1,6 +1,7 @@
#pragma once
#include "SimpleModelInfo.h"
+#include "WeaponType.h"
class CWeaponModelInfo : public CSimpleModelInfo
{
@@ -18,5 +19,5 @@ public:
void Init(void);
void SetWeaponInfo(int32 weaponId);
- int32 GetWeaponInfo(void);
+ eWeaponType GetWeaponInfo(void);
};
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index f9f658b4..82298e74 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -14,6 +14,7 @@
#include "AnimBlendClumpData.h"
#include "AnimBlendAssociation.h"
#include "Fire.h"
+#include "Glass.h"
#include "DMAudio.h"
#include "General.h"
#include "SurfaceTable.h"
@@ -5865,7 +5866,7 @@ CPed::FightStrike(CVector &touchedNodePos, bool fightWithWeapon)
if (m_fightState == FIGHTSTATE_JUST_ATTACKED)
return false;
- // TODO(Miami): BreakGlassPhysically
+ CGlass::BreakGlassPhysically(touchedNodePos, radius);
for (int i = 0; i < m_numNearPeds; i++) {
int8 pedFound = 0;
@@ -15403,7 +15404,7 @@ CPed::ProcessObjective(void)
CVector distance = m_nextRoutePointPos - GetPosition();
distance.z = 0.0f;
if (m_objective == OBJECTIVE_GOTO_SHELTER_ON_FOOT) {
- if (m_nMoveState == PEDMOVE_RUN && distance.Magnitude() < SQR(2.0f)) {
+ if (m_nMoveState == PEDMOVE_RUN && distance.MagnitudeSqr() < SQR(2.0f)) {
SetMoveState(PEDMOVE_WALK);
bIsRunning = false;
}
@@ -15413,7 +15414,7 @@ CPed::ProcessObjective(void)
}
}
else if (m_objective == OBJECTIVE_GOTO_ICE_CREAM_VAN_ON_FOOT) {
- if (m_nMoveState == PEDMOVE_RUN && distance.Magnitude() < SQR(4.0f)) {
+ if (m_nMoveState == PEDMOVE_RUN && distance.MagnitudeSqr() < SQR(4.0f)) {
SetMoveState(PEDMOVE_WALK);
bIsRunning = false;
}
diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp
index aabb6e52..0e26ee0b 100644
--- a/src/render/Glass.cpp
+++ b/src/render/Glass.cpp
@@ -3,6 +3,8 @@
#include "Glass.h"
#include "Timer.h"
#include "Object.h"
+#include "Vehicle.h"
+#include "Pools.h"
#include "General.h"
#include "AudioScriptObject.h"
#include "World.h"
@@ -14,6 +16,7 @@
#include "ModelIndices.h"
#include "main.h"
#include "soundlist.h"
+#include "SurfaceTable.h"
uint32 CGlass::NumGlassEntities;
@@ -57,17 +60,17 @@ const CVector2D CoorsWithTriangle[NUM_GLASSTRIANGLES][3] =
#define TEMPBUFFERVERTHILIGHTOFFSET 0
#define TEMPBUFFERINDEXHILIGHTOFFSET 0
-#define TEMPBUFFERVERTHILIGHTSIZE 128
+#define TEMPBUFFERVERTHILIGHTSIZE 256
#define TEMPBUFFERINDEXHILIGHTSIZE 512
#define TEMPBUFFERVERTSHATTEREDOFFSET TEMPBUFFERVERTHILIGHTSIZE
#define TEMPBUFFERINDEXSHATTEREDOFFSET TEMPBUFFERINDEXHILIGHTSIZE
-#define TEMPBUFFERVERTSHATTEREDSIZE 192
+#define TEMPBUFFERVERTSHATTEREDSIZE 384
#define TEMPBUFFERINDEXSHATTEREDSIZE 768
#define TEMPBUFFERVERTREFLECTIONOFFSET TEMPBUFFERVERTSHATTEREDSIZE
#define TEMPBUFFERINDEXREFLECTIONOFFSET TEMPBUFFERINDEXSHATTEREDSIZE
-#define TEMPBUFFERVERTREFLECTIONSIZE 256
+#define TEMPBUFFERVERTREFLECTIONSIZE 512
#define TEMPBUFFERINDEXREFLECTIONSIZE 1024
int32 TempBufferIndicesStoredHiLight = 0;
@@ -83,10 +86,16 @@ CFallingGlassPane::Update(void)
if ( CTimer::GetTimeInMilliseconds() >= m_nTimer )
{
// Apply MoveSpeed
- GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
+ if ( m_bCarGlass )
+ GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep() * 0.35f;
+ else
+ GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
// Apply Gravity
- m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep();
+ if ( m_bCarGlass )
+ m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
+ else
+ m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep();
// Apply TurnSpeed
GetRight() += CrossProduct(m_vecTurn, GetRight());
@@ -106,24 +115,27 @@ CFallingGlassPane::Update(void)
RwRGBA color = { 255, 255, 255, 255 };
- static int32 nFrameGen = 0;
-
- for ( int32 i = 0; i < 4; i++ )
+ if ( !m_bCarGlass )
{
- dir.x = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
- dir.y = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
- dir.z = CGeneral::GetRandomNumberInRange(0.05f, 0.20f);
-
- CParticle::AddParticle(PARTICLE_CAR_DEBRIS,
- pos,
- dir,
- nil,
- CGeneral::GetRandomNumberInRange(0.02f, 0.2f),
- color,
- CGeneral::GetRandomNumberInRange(-40, 40),
- 0,
- ++nFrameGen & 3,
- 500);
+ static int32 nFrameGen = 0;
+
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ dir.x = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
+ dir.z = CGeneral::GetRandomNumberInRange(0.05f, 0.20f);
+
+ CParticle::AddParticle(PARTICLE_CAR_DEBRIS,
+ pos,
+ dir,
+ nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.2f),
+ color,
+ CGeneral::GetRandomNumberInRange(-40, 40),
+ 0,
+ ++nFrameGen & 3,
+ 500);
+ }
}
}
}
@@ -146,7 +158,10 @@ CFallingGlassPane::Render(void)
CGlass::RenderHiLightPolys();
// HiLight Polys
-
+
+ if ( m_bCarGlass && color < 64 )
+ color = 64;
+
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], color, color, color, color);
@@ -186,9 +201,9 @@ CFallingGlassPane::Render(void)
if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-7 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-4 )
CGlass::RenderShatteredPolys();
- uint8 shatteredColor = 255;
+ uint8 shatteredColor = 140;
if ( distToCamera > 30.0f )
- shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
+ shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 140);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
@@ -292,8 +307,8 @@ CGlass::FindFreePane(void)
}
void
-CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point,
- float moveSpeed, bool cracked, bool explosion)
+CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector center,
+ float moveSpeed, bool cracked, bool explosion, int32 stepmul, bool carGlass)
{
float upLen = up.Magnitude();
float rightLen = right.Magnitude();
@@ -304,10 +319,10 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
float rightSteps = rightLen + 0.75f;
if ( rightSteps < 1.0f ) rightSteps = 1.0f;
- uint32 ysteps = (uint32)upSteps;
+ uint32 ysteps = stepmul * (uint32)upSteps;
if ( ysteps > 3 ) ysteps = 3;
- uint32 xsteps = (uint32)rightSteps;
+ uint32 xsteps = stepmul * (uint32)rightSteps;
if ( xsteps > 3 ) xsteps = 3;
if ( explosion )
@@ -338,11 +353,8 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
pane->m_nTriIndex = i;
pane->GetRight() = (right * rightScl) / rightLen;
-#ifdef FIX_BUGS
pane->GetUp() = (up * upScl) / upLen;
-#else
- pane->GetUp() = (up * upScl) / rightLen; // copypaste bug
-#endif
+
CVector fwd = CrossProduct(pane->GetRight(), pane->GetUp());
fwd.Normalise();
@@ -358,7 +370,7 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
if ( moveSpeed != 0.0f )
{
- CVector dist = pane->GetPosition() - point;
+ CVector dist = pane->GetPosition() - center;
dist.Normalise();
pane->m_vecMoveSpeed += moveSpeed * dist;
@@ -371,10 +383,11 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
switch ( type )
{
case 0:
+ case 2:
pane->m_nTimer = CTimer::GetTimeInMilliseconds();
break;
case 1:
- float dist = (pane->GetPosition() - point).Magnitude();
+ float dist = (pane->GetPosition() - center).Magnitude();
pane->m_nTimer = uint32(dist*100 + CTimer::GetTimeInMilliseconds());
break;
}
@@ -382,6 +395,7 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
pane->m_fGroundZ = groundZ;
pane->m_bShattered = cracked;
pane->m_fStep = upLen / float(ysteps);
+ pane->m_bCarGlass = carGlass;
pane->m_bActive = true;
}
}
@@ -613,42 +627,48 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
CColModel *col = object->GetColModel();
ASSERT(col!=nil);
- CVector a = object->GetMatrix() * col->vertices[0].Get();
- CVector b = object->GetMatrix() * col->vertices[1].Get();
- CVector c = object->GetMatrix() * col->vertices[2].Get();
- CVector d = object->GetMatrix() * col->vertices[3].Get();
-
- float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
- float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
- float miny = Min(Min(a.y, b.y), Min(c.y, d.y));
- float maxy = Max(Max(a.y, b.y), Max(c.y, d.y));
- float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
- float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
-
-
- if ( amount > 300.0f )
- {
- PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, object->GetPosition());
-
- GeneratePanesForWindow(0,
- CVector(minx, miny, minz),
- CVector(0.0f, 0.0f, maxz-minz),
- CVector(maxx-minx, maxy-miny, 0.0f),
- speed, point, 0.1f, !!object->bGlassCracked, explosion);
- }
- else
+ if ( col->numTriangles == 2 )
{
- PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
-
- GeneratePanesForWindow(1,
- CVector(minx, miny, minz),
- CVector(0.0f, 0.0f, maxz-minz),
- CVector(maxx-minx, maxy-miny, 0.0f),
- speed, point, 0.1f, !!object->bGlassCracked, explosion);
+ CVector a = col->vertices[0].Get();
+ CVector b = col->vertices[1].Get();
+ CVector c = col->vertices[2].Get();
+ CVector d = col->vertices[3].Get();
+
+ float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
+ float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
+ float miny = Min(Min(a.y, b.y), Min(c.y, d.y));
+ float maxy = Max(Max(a.y, b.y), Max(c.y, d.y));
+ float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
+ float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
+
+ CVector pa = object->GetMatrix() * CVector(minx, miny, minz);
+ CVector pb = object->GetMatrix() * CVector(maxx, maxy, minz);
+
+ if ( amount > 300.0f )
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, object->GetPosition());
+
+ GeneratePanesForWindow(0,
+ pa,
+ CVector(0.0f, 0.0f, maxz-minz),
+ pb - pa,
+ speed, point, 0.1f, !!object->bGlassCracked, explosion, 1, false);
+ }
+ else
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
+
+ GeneratePanesForWindow(1,
+ pa,
+ CVector(0.0f, 0.0f, maxz-minz),
+ pb - pa,
+ speed, point, 0.1f, !!object->bGlassCracked, explosion, 1, false);
+ }
}
-
+
object->bGlassBroken = true;
- object->GetMatrix().GetPosition().z = -100.0f;
+ object->bIsVisible = false;
+ object->bUsesCollision = true;
}
void
@@ -658,7 +678,7 @@ CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
CObject *object = (CObject *)entity;
- if ( amount > 50.0f && !object->bGlassCracked )
+ if ( entity->bUsesCollision && amount > 50.0f && !object->bGlassCracked )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
object->bGlassCracked = true;
@@ -674,15 +694,18 @@ CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
if ( IsGlass(object->GetModelIndex()) )
{
- if ( !object->bGlassCracked )
- {
- PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
- object->bGlassCracked = true;
- }
- else
+ if ( object->bUsesCollision )
{
- if ( (CGeneral::GetRandomNumber() & 3) == 2 )
- WindowRespondsToCollision(object, 0.0f, CVector(0.0f, 0.0f, 0.0f), point, false);
+ if ( !object->bGlassCracked )
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
+ object->bGlassCracked = true;
+ }
+ else
+ {
+ if ( (CGeneral::GetRandomNumber() & 3) == 2 )
+ WindowRespondsToCollision(object, 0.0f, CVector(0.0f, 0.0f, 0.0f), point, false);
+ }
}
}
}
@@ -693,19 +716,304 @@ CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
+
+ if ( object->bUsesCollision )
+ {
+ CVector distToGlass = object->GetPosition() - point;
+
+ float fDistToGlass = distToGlass.Magnitude();
+
+ if ( fDistToGlass < 10.0f )
+ {
+ distToGlass *= (0.3f / fDistToGlass); // normalise
+ WindowRespondsToCollision(object, 10000.0f, distToGlass, object->GetPosition(), true);
+ }
+ else
+ {
+ if ( fDistToGlass < 30.0f )
+ object->bGlassCracked = true;
+ }
+ }
+}
- CVector distToGlass = object->GetPosition() - point;
- float fDistToGlass = distToGlass.Magnitude();
+void
+CGlass::CarWindscreenShatters(CVehicle *vehicle, bool unk)
+{
+ ASSERT(vehicle!=nil);
+
+ CColModel *col = vehicle->GetColModel();
+ ASSERT(col!=nil);
+
+ if ( col->numTriangles < 2 )
+ return;
+
+ CColTriangle *tria = nil;
+ int32 triIndex = -1;
+ CColTriangle *trib = nil;
+
+ for ( int32 i = 0; i < col->numTriangles; i++ )
+ {
+ CColTriangle *tri = &col->triangles[i];
+ if ( tri->surface == SURFACE_GLASS )
+ {
+ if ( tria )
+ {
+ trib = tri;
+ break;
+ }
+
+ triIndex = i;
+ tria = tri;
+ }
+ }
+
+ if ( trib == nil )
+ return;
+
+ CCollision::CalculateTrianglePlanes(col);
+
+ CColTrianglePlane *triPlanes = col->trianglePlanes;
+
+ if ( triPlanes == nil )
+ return;
+
+ CVector planeNormal;
+ triPlanes[triIndex].GetNormal(planeNormal);
+ planeNormal = Multiply3x3(vehicle->GetMatrix(), planeNormal);
+
+ CVector vec1 = CrossProduct(vehicle->GetRight(), planeNormal);
+ vec1.Normalise();
+
+ CVector vec2 = CrossProduct(planeNormal, vehicle->GetUp());
+ vec2.Normalise();
+
+ CVector v[6];
+ float proj1[6];
+ float proj2[6];
+
+ v[0] = col->vertices[tria->a].Get();
+ v[1] = col->vertices[tria->b].Get();
+ v[2] = col->vertices[tria->c].Get();
+
+ v[3] = col->vertices[trib->a].Get();
+ v[4] = col->vertices[trib->b].Get();
+ v[5] = col->vertices[trib->c].Get();
+
+ v[0] = vehicle->GetMatrix() * v[0];
+ v[1] = vehicle->GetMatrix() * v[1];
+ v[2] = vehicle->GetMatrix() * v[2];
+ v[3] = vehicle->GetMatrix() * v[3];
+ v[4] = vehicle->GetMatrix() * v[4];
+ v[5] = vehicle->GetMatrix() * v[5];
+
+ proj1[0] = DotProduct(v[0], vec1);
+ proj2[0] = DotProduct(v[0], vec2);
+ proj1[1] = DotProduct(v[1], vec1);
+ proj2[1] = DotProduct(v[1], vec2);
+ proj1[2] = DotProduct(v[2], vec1);
+ proj2[2] = DotProduct(v[2], vec2);
+
+ proj1[3] = DotProduct(v[3], vec1);
+ proj2[3] = DotProduct(v[3], vec2);
+ proj1[4] = DotProduct(v[4], vec1);
+ proj2[4] = DotProduct(v[4], vec2);
+ proj1[5] = DotProduct(v[5], vec1);
+ proj2[5] = DotProduct(v[5], vec2);
+
+ int32 originIndex = 0;
+ float max1 = proj1[0];
+ float max2 = proj2[0];
+ float origin = proj1[0] + proj2[0];
+
+ for ( int32 i = 1; i < 6; i++ )
+ {
+ float o = proj1[i] + proj2[i];
+ if ( o < origin )
+ {
+ origin = o;
+ originIndex = i;
+ }
+
+ if ( proj1[i] > max1 )
+ max1 = proj1[i];
+ if ( proj2[i] > max2 )
+ max2 = proj2[i];
+ }
+
+ float bound1 = max1 - proj1[originIndex];
+ float bound2 = max2 - proj2[originIndex];
+
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, vehicle->GetPosition());
+
+ CVector center = v[originIndex] + ((0.5f*bound1) * vec1) + ((0.5f*bound2) * vec2);
+ CVector speed = vehicle->m_vecMoveSpeed;
+ CVector right = bound2 * vec2;
+ CVector up = bound1 * vec1;
+ CVector pos = v[originIndex];
+
+ GeneratePanesForWindow(2, pos, up, right, speed, center, 0.1f, false, false, 2, true);
+}
- if ( fDistToGlass < 10.0f )
+bool
+CGlass::HasGlassBeenShatteredAtCoors(float x, float y, float z)
+{
+ CEntity *entity = nil;
+ float dist = 20.0f;
+
+ int32 nStartX = Max(CWorld::GetSectorIndexX(x - 30.0f), 0);
+ int32 nStartY = Max(CWorld::GetSectorIndexY(y - 30.0f), 0);
+ int32 nEndX = Min(CWorld::GetSectorIndexX(x + 30.0f), NUMSECTORS_X-1);
+ int32 nEndY = Min(CWorld::GetSectorIndexY(y + 30.0f), NUMSECTORS_Y-1);
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for ( int32 y = nStartY; y <= nEndY; y++ )
{
- distToGlass *= (0.3f / fDistToGlass); // normalise
- WindowRespondsToCollision(object, 10000.0f, distToGlass, object->GetPosition(), true);
+ for ( int32 x = nStartX; x <= nEndX; x++ )
+ {
+ CSector *sector = CWorld::GetSector(x, y);
+
+ ASSERT(sector != nil);
+
+ FindWindowSectorList(sector->m_lists[ENTITYLIST_OBJECTS], &dist, &entity, x, y, z);
+ FindWindowSectorList(sector->m_lists[ENTITYLIST_DUMMIES], &dist, &entity, x, y, z);
+ }
}
- else
+
+ if ( entity )
{
- if ( fDistToGlass < 30.0f )
- object->bGlassCracked = true;
+ if ( entity->GetType() == ENTITY_TYPE_DUMMY )
+ return false;
+
+ return !!((CObject*)entity)->bGlassBroken;
}
+
+ return false;
}
+
+void
+CGlass::FindWindowSectorList(CPtrList &list, float *dist, CEntity **entity, float x, float y, float z)
+{
+ ASSERT(dist!=nil);
+ ASSERT(entity!=nil);
+
+ CPtrNode *node = list.first;
+
+ while ( node != nil )
+ {
+ CEntity *ent = (CEntity *)node->item;
+ uint16 scanCode = ent->m_scanCode;
+ node = node->next;
+
+ ASSERT(ent!=nil);
+
+ if ( IsGlass(ent->GetModelIndex()) )
+ {
+ if ( scanCode != CWorld::GetCurrentScanCode() )
+ {
+ ent->m_scanCode = CWorld::GetCurrentScanCode();
+
+ float dst = (CVector(x,y,z) - ent->GetPosition()).Magnitude();
+
+ if ( dst < *dist )
+ {
+ *dist = dst;
+ *entity = ent;
+ }
+ }
+ }
+ }
+}
+
+void
+CGlass::BreakGlassPhysically(CVector pos, float radius)
+{
+ static uint32 breakTime = 0;
+
+ if ( CTimer::GetTimeInMilliseconds() < breakTime + 1000 && CTimer::GetTimeInMilliseconds() >= breakTime )
+ return;
+
+ CColSphere sphere;
+ sphere.piece = 0;
+ sphere.radius = radius;
+ sphere.surface = 0;
+
+ for ( int32 i = CPools::GetObjectPool()->GetSize() - 1; i >= 0; i-- )
+ {
+ CObject *object = CPools::GetObjectPool()->GetSlot(i);
+ if (object)
+ {
+ if ( IsGlass(object->GetModelIndex()) )
+ {
+ if ( object->bUsesCollision )
+ {
+ CColModel *col = object->GetColModel();
+ ASSERT(col!=nil);
+
+ if ( col->numTriangles < 2 )
+ continue;
+
+ bool hit = false;
+
+ CVector dist = pos - object->GetPosition();
+
+ sphere.center.x = DotProduct(dist, object->GetRight());
+ sphere.center.y = DotProduct(dist, object->GetForward());
+ sphere.center.z = DotProduct(dist, object->GetUp());
+
+ CCollision::CalculateTrianglePlanes(col);
+
+ for ( int32 j = 0; j < col->numTriangles; j++ )
+ {
+ if ( CCollision::TestSphereTriangle(sphere,
+ col->vertices, col->triangles[i], col->trianglePlanes[i]) )
+ {
+ hit = true;
+ }
+ }
+
+ if ( hit )
+ {
+ breakTime = CTimer::GetTimeInMilliseconds();
+
+ if ( object->bGlassCracked )
+ {
+ CVector a = col->vertices[0].Get();
+ CVector b = col->vertices[1].Get();
+ CVector c = col->vertices[2].Get();
+ CVector d = col->vertices[3].Get();
+
+ float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
+ float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
+ float miny = Min(Min(a.y, b.y), Min(c.y, d.y));
+ float maxy = Max(Max(a.y, b.y), Max(c.y, d.y));
+ float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
+ float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
+
+ CVector pa = object->GetMatrix() * CVector(minx, miny, minz);
+ CVector pb = object->GetMatrix() * CVector(maxx, maxy, minz);
+
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
+
+ GeneratePanesForWindow(1,
+ pa,
+ CVector(0.0f, 0.0f, maxz-minz),
+ pb - pa,
+ CVector(0.0f, 0.0f, 0.0f), pos, 0.1f, !!object->bGlassCracked, false, 1, false);
+
+ object->bGlassBroken = true;
+ object->bIsVisible = false;
+ object->bUsesCollision = false;
+ }
+ else
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
+ object->bGlassCracked = true;
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/render/Glass.h b/src/render/Glass.h
index 937ab6a9..f1c85779 100644
--- a/src/render/Glass.h
+++ b/src/render/Glass.h
@@ -2,6 +2,7 @@
class CEntity;
class CVehicle;
+class CPtrList;
class CFallingGlassPane : public CMatrix
{
@@ -14,6 +15,7 @@ public:
uint8 m_nTriIndex;
bool m_bActive;
bool m_bShattered;
+ bool m_bCarGlass;
CFallingGlassPane() { }
~CFallingGlassPane() { }
@@ -39,7 +41,7 @@ public:
static void Update(void);
static void Render(void);
static CFallingGlassPane *FindFreePane(void);
- static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, float moveSpeed, bool cracked, bool explosion);
+ static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector center, float moveSpeed, bool cracked, bool explosion, int32 stepmul, bool carGlass);
static void AskForObjectToBeRenderedInGlass(CEntity *entity);
static void RenderEntityInGlass(CEntity *entity);
static int32 CalcAlphaWithNormal(CVector *normal);
@@ -50,8 +52,8 @@ public:
static void WindowRespondsToSoftCollision(CEntity *entity, float amount);
static void WasGlassHitByBullet(CEntity *entity, CVector point);
static void WindowRespondsToExplosion(CEntity *entity, CVector point);
-
-//TODO(MIAMI)
- static void CarWindscreenShatters(CVehicle *vehicle, bool unk) {}
- static void BreakGlassPhysically(CVector, float) {}
+ static void CarWindscreenShatters(CVehicle *vehicle, bool unk);
+ static bool HasGlassBeenShatteredAtCoors(float x, float y, float z);
+ static void FindWindowSectorList(CPtrList &list, float *dist, CEntity **entity, float x, float y, float z);
+ static void BreakGlassPhysically(CVector pos, float radius);
}; \ No newline at end of file
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 08dfda35..7864b0f0 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -24,21 +24,44 @@
#include "ColStore.h"
#include "Coronas.h"
#include "Script.h"
+#include "DMAudio.h"
RwIm3DVertex StreakVertices[4];
RwImVertexIndex StreakIndexList[12];
-RwIm3DVertex TraceVertices[6];
-RwImVertexIndex TraceIndexList[12];
+RwIm3DVertex TraceVertices[10];
+static RwImVertexIndex TraceIndexList[48] = {0, 5, 7, 0, 7, 2, 0, 7, 5, 0, 2, 7, 0, 4, 9, 0,
+ 9, 5, 0, 9, 4, 0, 5, 9, 0, 1, 6, 0, 6, 5, 0, 6,
+ 1, 0, 5, 6, 0, 3, 8, 0, 8, 5, 0, 8, 3, 0, 5, 8 };
+bool CSpecialFX::bVideoCam;
+bool CSpecialFX::bLiftCam;
bool CSpecialFX::bSnapShotActive;
int32 CSpecialFX::SnapShotFrames;
+static RwTexture* gpSmokeTrailTexture;
+
void
CSpecialFX::Init(void)
{
CBulletTraces::Init();
+ RwIm3DVertexSetU(&TraceVertices[0], 0.0);
+ RwIm3DVertexSetV(&TraceVertices[0], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[1], 1.0);
+ RwIm3DVertexSetV(&TraceVertices[1], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[2], 1.0);
+ RwIm3DVertexSetV(&TraceVertices[2], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[3], 1.0);
+ RwIm3DVertexSetV(&TraceVertices[3], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[4], 1.0);
+ RwIm3DVertexSetV(&TraceVertices[4], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[5], 0.0);
+ RwIm3DVertexSetU(&TraceVertices[6], 1.0);
+ RwIm3DVertexSetU(&TraceVertices[7], 1.0);
+ RwIm3DVertexSetU(&TraceVertices[8], 1.0);
+ RwIm3DVertexSetU(&TraceVertices[9], 1.0);
+
RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
@@ -47,7 +70,6 @@ CSpecialFX::Init(void)
RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
-
StreakIndexList[0] = 0;
StreakIndexList[1] = 1;
StreakIndexList[2] = 2;
@@ -61,43 +83,51 @@ CSpecialFX::Init(void)
StreakIndexList[10] = 2;
StreakIndexList[11] = 3;
- RwIm3DVertexSetRGBA(&TraceVertices[0], 20, 20, 20, 255);
- RwIm3DVertexSetRGBA(&TraceVertices[1], 20, 20, 20, 255);
- RwIm3DVertexSetRGBA(&TraceVertices[2], 70, 70, 70, 255);
- RwIm3DVertexSetRGBA(&TraceVertices[3], 70, 70, 70, 255);
- RwIm3DVertexSetRGBA(&TraceVertices[4], 10, 10, 10, 255);
- RwIm3DVertexSetRGBA(&TraceVertices[5], 10, 10, 10, 255);
- RwIm3DVertexSetU(&TraceVertices[0], 0.0);
- RwIm3DVertexSetV(&TraceVertices[0], 0.0);
- RwIm3DVertexSetU(&TraceVertices[1], 1.0);
- RwIm3DVertexSetV(&TraceVertices[1], 0.0);
- RwIm3DVertexSetU(&TraceVertices[2], 0.0);
- RwIm3DVertexSetV(&TraceVertices[2], 0.5);
- RwIm3DVertexSetU(&TraceVertices[3], 1.0);
- RwIm3DVertexSetV(&TraceVertices[3], 0.5);
- RwIm3DVertexSetU(&TraceVertices[4], 0.0);
- RwIm3DVertexSetV(&TraceVertices[4], 1.0);
- RwIm3DVertexSetU(&TraceVertices[5], 1.0);
- RwIm3DVertexSetV(&TraceVertices[5], 1.0);
-
- TraceIndexList[0] = 0;
- TraceIndexList[1] = 2;
- TraceIndexList[2] = 1;
- TraceIndexList[3] = 1;
- TraceIndexList[4] = 2;
- TraceIndexList[5] = 3;
- TraceIndexList[6] = 2;
- TraceIndexList[7] = 4;
- TraceIndexList[8] = 3;
- TraceIndexList[9] = 3;
- TraceIndexList[10] = 4;
- TraceIndexList[11] = 5;
-
CMotionBlurStreaks::Init();
CBrightLights::Init();
CShinyTexts::Init();
CMoneyMessages::Init();
C3dMarkers::Init();
+ CSpecialFX::bSnapShotActive = false;
+ CSpecialFX::bVideoCam = false;
+ CSpecialFX::SnapShotFrames = 0;
+ CSpecialFX::bLiftCam = false;
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
+ if(gpSmokeTrailTexture == nil)
+ gpSmokeTrailTexture = RwTextureRead("smoketrail", 0);
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CSpecialFX::AddWeaponStreak(int type)
+{
+ static CMatrix matrix;
+ CVector start;
+ CVector end;
+
+ if (FindPlayerPed() != nil && FindPlayerPed()->m_pWeaponModel != nil) {
+ switch (type) {
+ case WEAPONTYPE_BASEBALLBAT:
+ matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
+ start = matrix * CVector(0.02f, 0.05f, 0.07f);
+ end = matrix * CVector(0.246f, 0.0325f, 0.796f);
+ break;
+ case WEAPONTYPE_GOLFCLUB:
+ matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
+ start = matrix * CVector(0.02f, 0.05f, 0.07f);
+ end = matrix * CVector(-0.054f, 0.0325f, 0.796f);
+ break;
+ case WEAPONTYPE_KATANA:
+ matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
+ start = matrix * CVector(0.02f, 0.05f, 0.07f);
+ end = matrix * CVector(0.096f, -0.0175f, 1.096f);
+ break;
+ default:
+ return;
+ }
+ CMotionBlurStreaks::RegisterStreak((uintptr)FindPlayerPed()->m_pWeaponModel, 100, 100, 100, start, end);
+ }
}
RwObject*
@@ -119,23 +149,16 @@ CSpecialFX::Update(void)
{
CMotionBlurStreaks::Update();
CBulletTraces::Update();
-
- if(FindPlayerPed() &&
- FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
- FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING){
-#ifdef PED_SKIN
- if(IsClumpSkinned(FindPlayerPed()->GetClump())){
- LookForBatCB((RwObject*)FindPlayerPed()->m_pWeaponModel, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
- }else
-#endif
- RwFrameForAllObjects(FindPlayerPed()->m_pFrames[PED_HANDR]->frame, LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
- }
}
void
CSpecialFX::Shutdown(void)
{
C3dMarkers::Shutdown();
+ if (gpSmokeTrailTexture) {
+ RwTextureDestroy(gpSmokeTrailTexture);
+ gpSmokeTrailTexture = nil;
+ }
}
void
@@ -149,6 +172,80 @@ CSpecialFX::Render(void)
C3dMarkers::Render();
}
+void
+CSpecialFX::Render2DFXs(void)
+{
+ if (CSpecialFX::bVideoCam) {
+ CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
+ CFont::SetJustifyOff();
+ CFont::SetBackgroundOff();
+ CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f));
+ CFont::SetCentreOff();
+ CFont::SetPropOn();
+ CFont::SetColor(CRGBA(0, 255, 0, 200));
+ FONT_LOCALE(FONT_STANDARD);
+ sprintf(gString, "%d", CTimer::GetFrameCounter() & 0x3F); // mb % 63
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(SCREEN_WIDTH * 8 / 10, SCREEN_HEIGHT * 8 / 10, gUString);
+ for (int32 i = 0; i < SCREEN_HEIGHT; i += 4) {
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
+ CSprite2d::Draw2DPolygon(0.0f, i, SCREEN_WIDTH, i, 0.0f, i+1, SCREEN_WIDTH, i+1, CRGBA(0, 100, 0, 100));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ CSprite2d::Draw2DPolygon(0.0f, i+2, SCREEN_WIDTH, i+2, 0.0f, i+3, SCREEN_WIDTH, i+3, CRGBA(0, 0, 0, 150));
+ }
+ int32 tmp = (CTimer::GetTimeInMilliseconds() & 0x7ff) * (SCREEN_HEIGHT + 70.0f) / 2048 - 70.0f; //mb % 2048
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ CSprite2d::Draw2DPolygon(0.0, tmp, SCREEN_WIDTH, tmp, 0.0, tmp + 70.0f, SCREEN_WIDTH, tmp + 70.0f , CRGBA(0, 100, 0, 60));
+ }
+ if (CSpecialFX::bLiftCam) {
+ CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
+ CFont::SetJustifyOff();
+ CFont::SetBackgroundOff();
+ CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f));
+ CFont::SetCentreOff();
+ CFont::SetPropOn();
+ CFont::SetColor(CRGBA(100, 100, 100, 200));
+ FONT_LOCALE(FONT_STANDARD);
+ CFont::PrintString(SCREEN_WIDTH * 8 / 10, SCREEN_HEIGHT * 8 / 10, gUString);
+ for (int32 i = 0; i < SCREEN_HEIGHT; i += 4) {
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ CSprite2d::Draw2DPolygon(0.0f, i, SCREEN_WIDTH, i, 0.0f, i + 1, SCREEN_WIDTH, i + 1, CRGBA(100, 100, 100, 100));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ CSprite2d::Draw2DPolygon(0.0f, i + 2, SCREEN_WIDTH, i + 2, 0.0f, i + 3, SCREEN_WIDTH, i + 3, CRGBA(0, 0, 0, 150));
+ }
+ int32 tmp = (CTimer::GetTimeInMilliseconds() & 0x7ff) * (SCREEN_HEIGHT + 70.0f) / 2048 - 70.0f; //mb % 2048
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ CSprite2d::Draw2DPolygon(0.0, tmp, SCREEN_WIDTH, tmp, 0.0, tmp + 70.0f, SCREEN_WIDTH, tmp + 70.0f, CRGBA(100, 100, 100, 60));
+ for (int32 i = 0; i < 200; i++) {
+ int32 posX = CGeneral::GetRandomNumber() % (int32)SCREEN_WIDTH;
+ int32 posY = CGeneral::GetRandomNumber() % (int32)SCREEN_HEIGHT;
+ CSprite2d::DrawRect(CRect(posX, posY + 2, posX+20, posY), CRGBA(255, 255, 255, 64));
+ }
+ }
+ if (CSpecialFX::bSnapShotActive) {
+ if (++CSpecialFX::SnapShotFrames > 20) {
+ CSpecialFX::bSnapShotActive = false;
+ CTimer::SetTimeScale(1.0f);
+ } else {
+ CTimer::SetTimeScale(0.0f); //in andro it's 0.00001
+ if (CSpecialFX::SnapShotFrames < 10) {
+ int32 tmp = (255 - 255 * CSpecialFX::SnapShotFrames / 10) * 0.65f;
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ CSprite2d::Draw2DPolygon(0.0f, 0.0f, SCREEN_WIDTH, 0.0f, 0.0f, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT, CRGBA(tmp, tmp, tmp, tmp));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ }
+ }
+ }
+}
+
CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
void
@@ -217,6 +314,7 @@ void
CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2)
{
int i;
+
for(i = 0; i < NUMMBLURSTREAKS; i++){
if(aStreaks[i].m_id == id){
// Found a streak from last frame, update
@@ -229,10 +327,12 @@ CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVecto
return;
}
}
+
// Find free slot
- for(i = 0; aStreaks[i].m_id != 0; i++)
+ for(i = 0; aStreaks[i].m_id != 0 ; i++)
if(i == NUMMBLURSTREAKS-1)
return;
+
// Create a new streak
aStreaks[i].m_id = id;
aStreaks[i].m_red = r;
@@ -281,20 +381,103 @@ void CBulletTraces::Init(void)
aTraces[i].m_bInUse = false;
}
-void CBulletTraces::AddTrace(CVector* vecStart, CVector* vecTarget)
+void CBulletTraces::AddTrace(CVector* start, CVector* end, float thickness, uint32 lifeTime, uint8 visibility)
{
- int index;
- for (index = 0; index < NUMBULLETTRACES; index++) {
- if (!aTraces[index].m_bInUse)
- break;
+ int32 enabledCount;
+ uint32 modifiedLifeTime;
+ int32 nextSlot;
+
+ enabledCount = 0;
+ for (int i = 0; i < NUMBULLETTRACES; i++)
+ if (aTraces[i].m_bInUse)
+ enabledCount++;
+ if (enabledCount >= 10)
+ modifiedLifeTime = lifeTime / 4;
+ else if (enabledCount >= 5)
+ modifiedLifeTime = lifeTime / 2;
+ else
+ modifiedLifeTime = lifeTime;
+
+ nextSlot = 0;
+ for (int i = 0; nextSlot < NUMBULLETTRACES && aTraces[i].m_bInUse; i++)
+ nextSlot++;
+ if (nextSlot < 16) {
+ aTraces[nextSlot].m_vecStartPos = *start;
+ aTraces[nextSlot].m_vecEndPos = *end;
+ aTraces[nextSlot].m_bInUse = true;
+ aTraces[nextSlot].m_nCreationTime = CTimer::GetTimeInMilliseconds();
+ aTraces[nextSlot].m_fVisibility = visibility;
+ aTraces[nextSlot].m_fThickness = thickness;
+ aTraces[nextSlot].m_nLifeTime = modifiedLifeTime;
+ }
+
+ float startProjFwd = DotProduct(TheCamera.GetForward(), *start - TheCamera.GetPosition());
+ float endProjFwd = DotProduct(TheCamera.GetForward(), *end - TheCamera.GetPosition());
+ if (startProjFwd * endProjFwd < 0.0f) { //if one of point behind us and second before us
+ float fStartDistFwd = Abs(startProjFwd) / (Abs(startProjFwd) + Abs(endProjFwd));
+
+ float startProjUp = DotProduct(TheCamera.GetUp(), *start - TheCamera.GetPosition());
+ float endProjUp = DotProduct(TheCamera.GetUp(), *end - TheCamera.GetPosition());
+ float distUp = (endProjUp - startProjUp) * fStartDistFwd + startProjUp;
+
+ float startProjRight = DotProduct(TheCamera.GetRight(), *start - TheCamera.GetPosition());
+ float endProjRight = DotProduct(TheCamera.GetRight(), *end - TheCamera.GetPosition());
+ float distRight = (endProjRight - startProjRight) * fStartDistFwd + startProjRight;
+
+ float dist = Sqrt(SQR(distUp) + SQR(distRight));
+ if (dist < 2.0f) {
+ if(distRight < 0.0f)
+ DMAudio.PlayFrontEndSound(SOUND_BULLETTRACE_2, 127 * (1.0f - dist * 0.5f));
+ else
+ DMAudio.PlayFrontEndSound(SOUND_BULLETTRACE_1, 127 * (1.0f - dist * 0.5f));
+ }
+ }
+}
+
+void CBulletTraces::AddTrace(CVector* start, CVector* end, int32 weaponType, class CEntity* shooter)
+{
+ CPhysical* player;
+ float speed;
+ int16 camMode;
+
+ if (shooter == (CEntity*)FindPlayerPed() || (FindPlayerVehicle() != nil && FindPlayerVehicle() == (CVehicle*)shooter)) {
+ camMode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if (camMode == CCam::MODE_M16_1STPERSON
+ || camMode == CCam::MODE_CAMERA
+ || camMode == CCam::MODE_SNIPER
+ || camMode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || camMode == CCam::MODE_ROCKETLAUNCHER
+ || camMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT
+ || camMode == CCam::MODE_SNIPER_RUNABOUT
+ || camMode == CCam::MODE_HELICANNON_1STPERSON) {
+
+ player = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+ speed = player->m_vecMoveSpeed.Magnitude();
+ if (speed < 0.05f)
+ return;
+ }
+ }
+
+ switch (weaponType) {
+ case WEAPONTYPE_PYTHON:
+ case WEAPONTYPE_SHOTGUN:
+ case WEAPONTYPE_SPAS12_SHOTGUN:
+ case WEAPONTYPE_STUBBY_SHOTGUN:
+ CBulletTraces::AddTrace(start, end, 0.7f, 1000, 200);
+ break;
+ case WEAPONTYPE_M4:
+ case WEAPONTYPE_RUGER:
+ case WEAPONTYPE_SNIPERRIFLE:
+ case WEAPONTYPE_LASERSCOPE:
+ case WEAPONTYPE_M60:
+ case WEAPONTYPE_MINIGUN:
+ case WEAPONTYPE_HELICANNON:
+ CBulletTraces::AddTrace(start, end, 1.0f, 2000, 220);
+ break;
+ default:
+ CBulletTraces::AddTrace(start, end, 0.4f, 750, 150);
+ break;
}
- if (index == NUMBULLETTRACES)
- return;
- aTraces[index].m_vecCurrentPos = *vecStart;
- aTraces[index].m_vecTargetPos = *vecTarget;
- aTraces[index].m_bInUse = true;
- aTraces[index].m_framesInUse = 0;
- aTraces[index].m_lifeTime = 25 + CGeneral::GetRandomNumber() % 32;
}
void CBulletTraces::Render(void)
@@ -303,31 +486,131 @@ void CBulletTraces::Render(void)
if (!aTraces[i].m_bInUse)
continue;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSmokeTrailTexture));
+
+ float timeAlive = CTimer::GetTimeInMilliseconds() - aTraces[i].m_nCreationTime;
+
+ float traceThickness = aTraces[i].m_fThickness * timeAlive / aTraces[i].m_nLifeTime;
+ CVector horizontalOffset = aTraces[i].m_vecEndPos - aTraces[i].m_vecStartPos;
+ horizontalOffset.Normalise();
+ horizontalOffset *= traceThickness;
+
+ //then closer trace to die then it more transparent
+ uint8 nAlphaValue = aTraces[i].m_fVisibility * (aTraces[i].m_nLifeTime - timeAlive) / aTraces[i].m_nLifeTime;
+
+ CVector start = aTraces[i].m_vecStartPos;
+ CVector end = aTraces[i].m_vecEndPos;
+ float startProj = DotProduct(start - TheCamera.GetPosition(), TheCamera.GetForward()) - 0.7f;
+ float endProj = DotProduct(end - TheCamera.GetPosition(), TheCamera.GetForward()) - 0.7f;
+ if (startProj < 0.0f && endProj < 0.0f) //we dont need render trace behind us
+ continue;
+
+ if (startProj < 0.0f) { //if strat behind us move it closer
+ float absStartProj = Abs(startProj);
+ float absEndProj = Abs(endProj);
+ start = (absEndProj * start + absStartProj * end) / (absStartProj + absEndProj);
+ } else if (endProj < 0.0f) {
+ float absStartProj = Abs(startProj);
+ float absEndProj = Abs(endProj);
+ end = (absEndProj * start + absStartProj * end) / (absStartProj + absEndProj);
+ }
+
+ //we divide trace at three parts
+ CVector start2 = (7.0f * start + end) / 8;
+ CVector end2 = (7.0f * end + start) / 8;
+
+ RwIm3DVertexSetV(&TraceVertices[5], 10.0f);
+ RwIm3DVertexSetV(&TraceVertices[6], 10.0f);
+ RwIm3DVertexSetV(&TraceVertices[7], 10.0f);
+ RwIm3DVertexSetV(&TraceVertices[8], 10.0f);
+ RwIm3DVertexSetV(&TraceVertices[9], 10.0f);
+
+ RwIm3DVertexSetRGBA(&TraceVertices[0], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[1], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[2], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[3], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[4], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[5], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[6], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[7], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[8], 255, 255, 255, nAlphaValue);
+ RwIm3DVertexSetRGBA(&TraceVertices[9], 255, 255, 255, nAlphaValue);
+ //two points in center
+ RwIm3DVertexSetPos(&TraceVertices[0], start2.x, start2.y, start2.z);
+ RwIm3DVertexSetPos(&TraceVertices[5], end2.x, end2.y, end2.z);
+ //vertical planes
+ RwIm3DVertexSetPos(&TraceVertices[1], start2.x, start2.y, start2.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[3], start2.x, start2.y, start2.z - traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[6], end2.x, end2.y, end2.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[8], end2.x, end2.y, end2.z - traceThickness);
+ //horizontal planes
+ RwIm3DVertexSetPos(&TraceVertices[2], start2.x + horizontalOffset.y, start2.y - horizontalOffset.x, start2.z);
+ RwIm3DVertexSetPos(&TraceVertices[7], end2.x + horizontalOffset.y, end2.y - horizontalOffset.x, end2.z);
+#ifdef FIX_BUGS //this point calculated wrong for some reason
+ RwIm3DVertexSetPos(&TraceVertices[4], start2.x - horizontalOffset.y, start2.y + horizontalOffset.x, start2.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y + horizontalOffset.x, end2.z);
+#else
+ RwIm3DVertexSetPos(&TraceVertices[4], start2.x - horizontalOffset.y, start2.y - horizontalOffset.y, start2.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y - horizontalOffset.y, end2.z);
+#endif
+
+ if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, 1)) {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
+ RwIm3DEnd();
+ }
+
+ RwIm3DVertexSetV(&TraceVertices[5], 2.0f);
+ RwIm3DVertexSetV(&TraceVertices[6], 2.0f);
+ RwIm3DVertexSetV(&TraceVertices[7], 2.0f);
+ RwIm3DVertexSetV(&TraceVertices[8], 2.0f);
+ RwIm3DVertexSetV(&TraceVertices[9], 2.0f);
+ RwIm3DVertexSetRGBA(&TraceVertices[0], 255, 255, 255, 0);
+ RwIm3DVertexSetRGBA(&TraceVertices[1], 255, 255, 255, 0);
+ RwIm3DVertexSetRGBA(&TraceVertices[2], 255, 255, 255, 0);
+ RwIm3DVertexSetRGBA(&TraceVertices[3], 255, 255, 255, 0);
+ RwIm3DVertexSetRGBA(&TraceVertices[4], 255, 255, 255, 0);
+
+ RwIm3DVertexSetPos(&TraceVertices[0], start.x, start.y, start.z);
+ RwIm3DVertexSetPos(&TraceVertices[1], start.x, start.y, start.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[3], start.x, start.y, start.z - traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[2], start.x + horizontalOffset.y, start.y - horizontalOffset.x, start.z);
+
+ RwIm3DVertexSetPos(&TraceVertices[5], start2.x, start2.y, start2.z);
+ RwIm3DVertexSetPos(&TraceVertices[6], start2.x, start2.y, start2.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[8], start2.x, start2.y, start2.z - traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[7], start2.x + horizontalOffset.y, start2.y - horizontalOffset.x, start2.z);
#ifdef FIX_BUGS
- // Raster has no transparent pixels so it relies on the raster format having alpha
- // to turn on blending. librw image conversion might get rid of it right now so let's
- // just force it on.
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwIm3DVertexSetPos(&TraceVertices[4], start.x - horizontalOffset.y, start.y + horizontalOffset.x, start.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], start2.x - horizontalOffset.y, start2.y + horizontalOffset.x, start2.z);
+#else
+ RwIm3DVertexSetPos(&TraceVertices[4], start.x - horizontalOffset.y, start.y - horizontalOffset.y, start.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], start2.x - horizontalOffset.y, start2.y - horizontalOffset.y, start2.z);
#endif
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpShadowExplosionTex));
- CVector inf = aTraces[i].m_vecCurrentPos;
- CVector sup = aTraces[i].m_vecTargetPos;
- CVector center = (inf + sup) / 2;
- CVector width = CrossProduct(TheCamera.GetForward(), (sup - inf));
- width.Normalise();
- width /= 20;
- uint8 intensity = aTraces[i].m_lifeTime;
- for (int i = 0; i < ARRAY_SIZE(TraceVertices); i++)
- RwIm3DVertexSetRGBA(&TraceVertices[i], intensity, intensity, intensity, 0xFF);
- RwIm3DVertexSetPos(&TraceVertices[0], inf.x + width.x, inf.y + width.y, inf.z + width.z);
- RwIm3DVertexSetPos(&TraceVertices[1], inf.x - width.x, inf.y - width.y, inf.z - width.z);
- RwIm3DVertexSetPos(&TraceVertices[2], center.x + width.x, center.y + width.y, center.z + width.z);
- RwIm3DVertexSetPos(&TraceVertices[3], center.x - width.x, center.y - width.y, center.z - width.z);
- RwIm3DVertexSetPos(&TraceVertices[4], sup.x + width.x, sup.y + width.y, sup.z + width.z);
- RwIm3DVertexSetPos(&TraceVertices[5], sup.x - width.x, sup.y - width.y, sup.z - width.z);
- LittleTest();
+
+ if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, rwIM3D_VERTEXUV)) {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
+ RwIm3DEnd();
+ }
+
+ RwIm3DVertexSetPos(&TraceVertices[1], end.x, end.y, end.z);
+ RwIm3DVertexSetPos(&TraceVertices[2], end.x, end.y, end.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[4], end.x, end.y, end.z - traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[3], end.x + horizontalOffset.y, end.y - horizontalOffset.x, end.z);
+
+ RwIm3DVertexSetPos(&TraceVertices[5], end2.x, end2.y, end2.z);
+ RwIm3DVertexSetPos(&TraceVertices[6], end2.x, end2.y, end2.z + traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[8], end2.x, end2.y, end2.z - traceThickness);
+ RwIm3DVertexSetPos(&TraceVertices[7], end2.x + horizontalOffset.y, end2.y - horizontalOffset.x, end2.z);
+#ifdef FIX_BUGS
+ RwIm3DVertexSetPos(&TraceVertices[5], end.x - horizontalOffset.y, end.y + horizontalOffset.x, end.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y + horizontalOffset.x, end2.z);
+#else
+ RwIm3DVertexSetPos(&TraceVertices[5], end.x - horizontalOffset.y, end.y - horizontalOffset.y, end.z);
+ RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y - horizontalOffset.y, end2.z);
+#endif
+
if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, rwIM3D_VERTEXUV)) {
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
RwIm3DEnd();
@@ -348,23 +631,8 @@ void CBulletTraces::Update(void)
void CBulletTrace::Update(void)
{
- if (m_framesInUse == 0) {
- m_framesInUse++;
- return;
- }
- if (m_framesInUse > 60) {
+ if (CTimer::GetTimeInMilliseconds() - m_nCreationTime >= m_nLifeTime)
m_bInUse = false;
- return;
- }
- CVector diff = m_vecCurrentPos - m_vecTargetPos;
- float remaining = diff.Magnitude();
- if (remaining > 0.8f)
- m_vecCurrentPos = m_vecTargetPos + (remaining - 0.8f) / remaining * diff;
- else
- m_bInUse = false;
- if (--m_lifeTime == 0)
- m_bInUse = false;
- m_framesInUse++;
}
RpAtomic *
@@ -578,7 +846,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
} else {
pMarker->m_fStdSize = size;
}
- } else if (type == MARKERTYPE_CYLINDER) {
+ } else {
if (dist < size + 12.0f) {
if (dist > size + 1.0f)
pMarker->m_Color.alpha = (1.0f - (size + 12.0f - dist) * 0.7f / 11.0f) * (float)a;
@@ -591,15 +859,9 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
float someSin = Sin(TWOPI * (float)((pMarker->m_nPulsePeriod - 1) & (CTimer::GetTimeInMilliseconds() - pMarker->m_nStartTime)) / (float)pMarker->m_nPulsePeriod);
pMarker->m_fSize = pMarker->m_fStdSize - pulseFraction * pMarker->m_fStdSize * someSin;
- if (type == MARKERTYPE_ARROW) {
+ if (type == MARKERTYPE_ARROW)
pos.z += 0.25f * pMarker->m_fStdSize * someSin;
- } else if (type == MARKERTYPE_0) {
- if (someSin > 0.0f)
- pMarker->m_Color.alpha = (float)a * 0.7f * someSin + a;
- else
- pMarker->m_Color.alpha = (float)a * 0.4f * someSin + a;
- }
- if (pMarker->m_nRotateRate) {
+ if (pMarker->m_nRotateRate != 0) {
RwV3d pos = pMarker->m_Matrix.m_matrix.pos;
pMarker->m_Matrix.RotateZ(DEGTORAD(pMarker->m_nRotateRate * CTimer::GetTimeStep()));
pMarker->m_Matrix.GetPosition() = pos;
@@ -623,7 +885,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
pMarker->DeleteMarkerObject();
pMarker->AddMarker(identifier, type, size, r, g, b, a, pulsePeriod, pulseFraction, rotateRate);
- if (type == MARKERTYPE_CYLINDER || type == MARKERTYPE_0 || type == MARKERTYPE_2) {
+ if (type == MARKERTYPE_CYLINDER) {
if ((playerPos - pos).MagnitudeSqr() < sq(100.f) && CColStore::HasCollisionLoaded(CVector2D(pos))) {
float z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 1.0f, nil);
if (z != 0.0f)
@@ -634,10 +896,6 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
}
}
pMarker->m_Matrix.SetTranslate(pos.x, pos.y, pos.z);
- if (type == MARKERTYPE_2) {
- pMarker->m_Matrix.RotateX(PI);
- pMarker->m_Matrix.GetPosition() = pos;
- }
pMarker->m_Matrix.UpdateRW();
if (type == MARKERTYPE_ARROW) {
if (dist < 25.0f) {
@@ -648,7 +906,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
} else {
pMarker->m_fStdSize = size;
}
- } else if (type == MARKERTYPE_CYLINDER) {
+ } else {
if (dist < size + 12.0f) {
if (dist > size + 1.0f)
pMarker->m_Color.alpha = (1.0f - (size + 12.0f - dist) * 0.7f / 11.0f) * (float)a;
@@ -752,6 +1010,9 @@ CBrightLights::Render(void)
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+
for(i = 0; i < NumBrightLights; i++){
if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
RenderOutGeometryBuffer();
@@ -788,6 +1049,10 @@ CBrightLights::Render(void)
g = aBrightLights[i].m_green;
b = aBrightLights[i].m_blue;
break;
+#ifdef FIX_BUGS //just to make sure that color never will be undefined
+ default:
+ return;
+#endif
}
if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
@@ -854,18 +1119,18 @@ CBrightLights::Render(void)
case BRIGHTLIGHT_FRONT_BIG:
case BRIGHTLIGHT_REAR_BIG:
for (j = 0; j < 8; j++) {
- pos = BigCarHeadLightsSide[j] * aBrightLights[i].m_side +
- BigCarHeadLightsUp[j] * aBrightLights[i].m_up +
- BigCarHeadLightsFront[j] * aBrightLights[i].m_front +
- aBrightLights[i].m_pos;
- RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + j], r, g, b, a);
- RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + j], pos.x, pos.y, pos.z);
- }
- for (j = 0; j < 12 * 3; j++)
- TempBufferRenderIndexList[TempBufferIndicesStored + j] = CubeIndices[j] + TempBufferVerticesStored;
- TempBufferVerticesStored += 8;
- TempBufferIndicesStored += 12 * 3;
- break;
+ pos = BigCarHeadLightsSide[j] * aBrightLights[i].m_side +
+ BigCarHeadLightsUp[j] * aBrightLights[i].m_up +
+ BigCarHeadLightsFront[j] * aBrightLights[i].m_front +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + j], pos.x, pos.y, pos.z);
+ }
+ for (j = 0; j < 12 * 3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored + j] = CubeIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 8;
+ TempBufferIndicesStored += 12 * 3;
+ break;
case BRIGHTLIGHT_FRONT_TALL:
case BRIGHTLIGHT_REAR_TALL:
@@ -1072,8 +1337,9 @@ CMoneyMessage::Render()
{
const float MAX_SCALE = 4.0f;
uint32 nLifeTime = CTimer::GetTimeInMilliseconds() - m_nTimeRegistered;
- if (nLifeTime >= MONEY_MESSAGE_LIFETIME_MS) m_nTimeRegistered = 0;
- else {
+ if (nLifeTime >= MONEY_MESSAGE_LIFETIME_MS) {
+ m_nTimeRegistered = 0;
+ } else {
float fLifeTime = (float)nLifeTime / MONEY_MESSAGE_LIFETIME_MS;
RwV3d vecOut;
float fDistX, fDistY;
@@ -1082,17 +1348,15 @@ CMoneyMessage::Render()
fDistY *= (0.7 * fLifeTime + 2.0) * m_fSize;
CFont::SetPropOn();
CFont::SetBackgroundOff();
-
float fScaleY = Min(fDistY / 100.0f, MAX_SCALE);
float fScaleX = Min(fDistX / 100.0f, MAX_SCALE);
-
CFont::SetScale(fScaleX, fScaleY); // maybe use SCREEN_SCALE_X and SCREEN_SCALE_Y here?
CFont::SetCentreOn();
CFont::SetCentreSize(SCREEN_WIDTH);
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(m_Colour.r, m_Colour.g, m_Colour.b, (255.0f - 255.0f * fLifeTime) * m_fOpacity));
CFont::SetBackGroundOnlyTextOff();
- CFont::SetFontStyle(FONT_STANDARD);
+ FONT_LOCALE(FONT_STANDARD);
CFont::PrintString(vecOut.x, vecOut.y, m_aText);
}
}
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 8bd0d5e1..f163d8ca 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -1,8 +1,12 @@
#pragma once
+//file done
+
class CSpecialFX
{
public:
+ static bool bVideoCam;
+ static bool bLiftCam;
static bool bSnapShotActive;
static int32 SnapShotFrames;
@@ -10,8 +14,11 @@ public:
static void Update(void);
static void Init(void);
static void Shutdown(void);
+ static void AddWeaponStreak(int type);
+ static void Render2DFXs();
};
+
class CRegisteredMotionBlurStreak
{
public:
@@ -27,6 +34,7 @@ public:
void Render(void);
};
+
class CMotionBlurStreaks
{
static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
@@ -37,33 +45,31 @@ public:
static void Render(void);
};
+
struct CBulletTrace
{
- CVector m_vecCurrentPos;
- CVector m_vecTargetPos;
+ CVector m_vecStartPos;
+ CVector m_vecEndPos;
bool m_bInUse;
- uint8 m_framesInUse;
- uint8 m_lifeTime;
+ uint32 m_nCreationTime;
+ uint32 m_nLifeTime;
+ float m_fThickness;
+ uint8 m_fVisibility;
void Update(void);
};
+
class CBulletTraces
{
public:
static CBulletTrace aTraces[NUMBULLETTRACES];
static void Init(void);
- static void AddTrace(CVector*, CVector*);
static void Render(void);
static void Update(void);
-
-//TODO(MIAMI)
- static void AddTrace(CVector *, CVector *, float, unsigned int, unsigned char) {}
- static void AddTrace(CVector *a, CVector *b, int32 weapontype, class CEntity *shooter)
- {
- AddTrace(a, b); //TODO: temp
- }
+ static void AddTrace(CVector* start, CVector* end, float thickness, uint32 lifeTime, uint8 visibility);
+ static void AddTrace(CVector* start, CVector* end, int32 weaponType, class CEntity* shooter);
};
enum
@@ -104,6 +110,7 @@ public:
void Render();
};
+
class C3dMarkers
{
public:
@@ -144,6 +151,7 @@ enum
BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
};
+
class CBrightLight
{
public:
@@ -158,6 +166,7 @@ public:
uint8 m_blue;
};
+
class CBrightLights
{
static int NumBrightLights;
@@ -177,6 +186,7 @@ enum
SHINYTEXT_FLAT
};
+
class CShinyText
{
public:
@@ -189,7 +199,8 @@ public:
uint8 m_blue;
};
-class CShinyTexts
+
+class CShinyTexts
{
static int NumShinyTexts;
static CShinyText aShinyTexts[NUMSHINYTEXTS];
@@ -197,11 +208,12 @@ public:
static void Init(void);
static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
- uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
+ uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist); //not used
static void Render(void);
static void RenderOutGeometryBuffer(void);
};
+
class CMoneyMessage
{
friend class CMoneyMessages;
@@ -216,6 +228,7 @@ public:
void Render();
};
+
class CMoneyMessages
{
static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
@@ -225,11 +238,12 @@ public:
static void RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
};
+
class CSpecialParticleStuff
{
static uint32 BoatFromStart;
public:
- static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
- static void StartBoatFoamAnimation();
- static void UpdateBoatFoamAnimation(CMatrix*);
+ static void CreateFoamAroundObject(CMatrix*, float, float, float, int32); //not used
+ static void StartBoatFoamAnimation(); //not used
+ static void UpdateBoatFoamAnimation(CMatrix*); //not used
};