Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Ext/ObjectType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ObjectTypeExtData : public AbstractTypeExtData
this->AbstractTypeExtData::Internal_LoadFromStream(Stm);
}

virtual void SaveToStream(PhobosStreamWriter& Stm)
virtual void SaveToStream(PhobosStreamWriter& Stm) override
{
this->AbstractTypeExtData::Internal_SaveToStream(Stm);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Ext/OverlayType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ class OverlayTypeExtData final : public ObjectTypeExtData
this->Serialize(Stm);
}

virtual void SaveToStream(PhobosStreamWriter& Stm)
virtual void SaveToStream(PhobosStreamWriter& Stm) override
{
const_cast<OverlayTypeExtData*>(this)->ObjectTypeExtData::SaveToStream(Stm);
const_cast<OverlayTypeExtData*>(this)->Serialize(Stm);
this->ObjectTypeExtData::SaveToStream(Stm);
this->Serialize(Stm);
}

virtual AbstractType WhatIam() const { return base_type::AbsID; }
Expand Down
21 changes: 9 additions & 12 deletions src/Ext/Particle/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ bool IsUnderwaterAtBridge(CoordStruct& pos, int newZ)
CellClass* cell = MapClass::Instance->GetCellAt(pos);

// Check if cell has bridge
if (!cell->ContainsBridgeHead()) {
if (!cell || !cell->ContainsBridgeHead()) {
return false;
}

Expand Down Expand Up @@ -190,9 +190,6 @@ void FakeParticleClass::ApplySmokeDrift(CoordStruct& pos)
pos.Z -= descentRate;
}

// Apply gas drift
pos += this->GasVelocity;

// Ensure smoke stays above ground
const int newTerrainHeight = MapClass::Instance->GetZPos(&pos);
if (pos.Z < newTerrainHeight + 5) {
Expand Down Expand Up @@ -433,11 +430,11 @@ void FakeParticleClass::ApplyRandomDrift()

if (driftInY)
{
this->GasVelocity.Y = std::clamp(this->GasVelocity.Y + drift, -5, 5);
this->GasVelocity.Y = std::clamp<int>(this->GasVelocity.Y + drift, -5, 5);
}
else
{
this->GasVelocity.X = std::clamp(this->GasVelocity.X + drift, -5, 5);
this->GasVelocity.X = std::clamp<int>(this->GasVelocity.X + drift, -5, 5);
}
}

Expand Down Expand Up @@ -611,12 +608,12 @@ void FakeParticleClass::UpdateGasMovement()

const auto pExt = this->_GetTypeExtData();

const auto maxDriftSpeedX = &pExt->Gas_DriftSpeedX.Get();
const auto minDriftSpeedY = &pExt->Gas_DriftSpeedY.Get();
const auto driftSpeedX = &pExt->Gas_DriftSpeedX.Get();
const auto driftSpeedY = &pExt->Gas_DriftSpeedY.Get();

// Update and clamp gas movement vector
this->GasVelocity.X = std::clamp(this->GasVelocity.X + deltaX, maxDriftSpeedX->Min, maxDriftSpeedX->Max);
this->GasVelocity.Y = std::clamp(this->GasVelocity.Y + deltaY, minDriftSpeedY->Min, minDriftSpeedY->Max);
this->GasVelocity.X = std::clamp(this->GasVelocity.X + deltaX, driftSpeedX->Min, driftSpeedX->Max);
this->GasVelocity.Y = std::clamp(this->GasVelocity.Y + deltaY, driftSpeedY->Min, driftSpeedY->Max);
}

void FakeParticleClass::UpdateGasHeight()
Expand Down Expand Up @@ -841,7 +838,7 @@ void FakeParticleClass::__Smoke_AI() {

// Apply ramp matrix rotation if needed
if (needsMatrixRotation) {
ReflectOffSurface(nextPos, this->SmokeVelocity, this->SmokeVelocity);
ReflectOffSurface(nextPos, this->Spark10C, this->Spark10C);
}

// Update gas height based on particle height
Expand Down Expand Up @@ -1025,7 +1022,7 @@ void FakeParticleClass::__Spark_AI() {

// Apply ramp matrix rotation if needed
if (needsMatrixRotation) {
ReflectOffSurface(nextPos, this->SmokeVelocity, this->SmokeVelocity);
ReflectOffSurface(nextPos, this->Spark10C, this->Spark10C);
this->TimeToDelete = true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Ext/Particle/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ static CoordStruct GetFLHAbsoluteCoords(CoordStruct nFLH, CoordStruct nCurLoc)
//
// if (value_Y >= minDriftSpeedY->Y) {
// if (value_Y > minDriftSpeedY->X) {
// pParticle->GasVelocity.X = minDriftSpeedY->X;
// pParticle->GasVelocity.Y = minDriftSpeedY->X;
// }
// } else {
// pParticle->GasVelocity.X = minDriftSpeedY->Y;
// pParticle->GasVelocity.Y = minDriftSpeedY->Y;
// }
//
// return 0x62BE60;
Expand Down
19 changes: 15 additions & 4 deletions src/Ext/ParticleSystem/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ParticleSystemExtData::ParticleSystemExtData(ParticleSystemClass* pObj) : Object
this->AbsType = ParticleSystemClass::AbsID;
auto pType = pObj->Type;
{
if (!ParticleSystemTypeExtContainer::Instance.Find(pType)->ApplyOptimization || (size_t)pType->HoldsWhat >= ParticleTypeClass::Array->size())
if (!ParticleSystemTypeExtContainer::Instance.Find(pType)->ApplyOptimization || pType->HoldsWhat < 0 || (size_t)pType->HoldsWhat >= ParticleTypeClass::Array->size())
return;
this->HeldType = ParticleTypeClass::Array->Items[pType->HoldsWhat];
if (!this->HeldType->UseLineTrail && !this->HeldType->AlphaImage)
Expand Down Expand Up @@ -149,10 +149,16 @@ void ParticleSystemExtData::UpdateState()

void ParticleSystemExtData::UpdateColor()
{
if (!this->HeldType || this->HeldType->ColorList.Count < 2)
if (!this->HeldType)
{
return; // Safety: Need valid particle type with at least 2 colors
return; // Safety: Need valid particle type
}

if (this->HeldType->ColorList.Count < 2)
{
return; // Need at least 2 colors
}

const int maxColorIndex = this->HeldType->ColorList.Count - 2;

for (auto& particle : this->OtherParticleData)
Expand Down Expand Up @@ -319,11 +325,16 @@ void ParticleSystemExtData::UpdateRailgun()
Difference_X = -differeceCoordsLXYLength;
}

if (differeceCoordsLXYLength == 0 || differeceCoordsLXYZLength == 0) {
pThis->TimeToDie = true;
return;
}

const auto ParticlePerCoords = differeceCoordsLXYZLength * pThis->Type->ParticlesPerCoord;
Matrix3D mtx = Matrix3D::GetIdentity();
const auto acos = Math::acos((double)Difference_X / (double)differeceCoordsLXYLength);
mtx.PreRotateZ(float(acos < 0 ? -acos : acos));
const auto theta = Math::asin((double)Difference_Z / (double)differeceCoordsLXYLength);
const auto theta = Math::asin((double)Difference_Z / (double)differeceCoordsLXYZLength);
mtx.PreRotateX(float(theta));

auto pHeldType = this->HeldType;
Expand Down
4 changes: 3 additions & 1 deletion src/Ext/Side/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ bool SideExtData::isNODSidebar()
return !SideExtContainer::Instance.Find(pSide)->Sidebar_GDIPositions.Get(PlayerSideIndex == 0);
}

return PlayerSideIndex == 0;
// Fallback: Allied (index 0) uses GDI positions, so NOT NOD sidebar
// NOD sidebar is for Soviet/Yuri (index != 0)
return PlayerSideIndex != 0;
}

int SideExtData::GetSurvivorDivisor() const {
Expand Down
5 changes: 2 additions & 3 deletions src/Ext/Sidebar/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void SidebarExtData::DrawProducingProgress()
{
const auto pPlayer = HouseClass::CurrentPlayer();

if (HouseExtData::IsObserverPlayer(pPlayer))
if (!pPlayer || HouseExtData::IsObserverPlayer(pPlayer)) // Added null check for pPlayer
return;

if (Phobos::UI::ShowProducingProgress) {
Expand Down Expand Up @@ -60,8 +60,7 @@ void SidebarExtData::DrawProducingProgress()
if(pFactory) {

int idxFrame = (int)(((double)pFactory->GetProgress() / 54) * (pSHP->Frames - 1)) ;
idxFrame = idxFrame > pSHP->Frames ? pSHP->Frames: idxFrame;

idxFrame = idxFrame >= pSHP->Frames ? pSHP->Frames - 1 : idxFrame;
Point2D vPos = { XBase + i * XOffset, YBase };
RectangleStruct sidebarRect = DSurface::Sidebar()->Get_Rect();

Expand Down
7 changes: 6 additions & 1 deletion src/Ext/SmudgeType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,12 @@ bool FakeSmudgeTypeClass::_CanPlaceHere(CellStruct* origin, bool underbuildings)
{
CellStruct trycell = *origin + CellStruct(w, h);
CellClass* cell = MapClass::Instance->TryGetCellAt(trycell);
if (!!MapClass::Instance->IsWithinUsableArea(trycell, true))
if (!MapClass::Instance->IsWithinUsableArea(trycell, true))
{
return false;
}

if (!cell) // Added null check for cell pointer
{
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Ext/SpawnManager/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ void FakeSpawnManagerClass::_DetachB(AbstractClass* pTarget, bool removed)
|| pSpawnee->Unit->IsKamikaze))
// || pSpawnee->IsSpawnMissile == 1
) {
this->SpawnedNodes.Items[max]->Unit = nullptr;
this->SpawnedNodes.Items[max]->NodeSpawnTimer.Start(this->RegenRate);
this->SpawnedNodes.Items[max]->Status = SpawnNodeStatus::Dead;
pSpawnee->Unit = nullptr;
pSpawnee->NodeSpawnTimer.Start(this->RegenRate);
pSpawnee->Status = SpawnNodeStatus::Dead;
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions src/Ext/Super/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void SuperExtData::UpdateSuperWeaponStatuses(HouseClass* pHouse)
{
const auto idxSW = pUpgradeExt->GetSuperWeaponIndex(i);

if (idxSW >= 0)
if (idxSW >= 0 && idxSW < pHouse->Supers.Count)
{
const auto pSuperExt = SuperExtContainer::Instance.Find(pHouse->Supers[idxSW]);
auto& status = pSuperExt->Statusses;
Expand Down Expand Up @@ -313,7 +313,11 @@ int FakeSuperClass::_GetAnimStage()
} else {
// Charging state
int divisor = (customRechargeTime == -1) ? pType->RechargeTime : customRechargeTime;
progress = (double)(rechargeTime - delayTime) / divisor;
if (divisor > 0) {
progress = (double)(rechargeTime - delayTime) / divisor;
} else {
progress = 0.0;
}
}
}
else
Expand All @@ -325,7 +329,11 @@ int FakeSuperClass::_GetAnimStage()

// Normal charging
int divisor = (customRechargeTime == -1) ? pType->RechargeTime : customRechargeTime;
progress = (double)(rechargeTime - delayTime) / divisor;
if (divisor > 0) {
progress = (double)(rechargeTime - delayTime) / divisor;
} else {
progress = 0.0;
}
}

// Convert to stage
Expand Down
12 changes: 6 additions & 6 deletions src/Ext/Surface/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ void SurfaceExt::BlurRect(const RectangleStruct& rect, float blurSize)
int li = ti;
int ri = ti + r;

int fv[3] = { in[ti * c + 0], in[ti * c + 1], in[ti * c + 2] };
int lv[3] = { in[(ti + w - 1) * c + 0], in[(ti + w - 1) * c + 1], in[(ti + w - 1) * c + 2] };
int val[3] = { (r + 1) * fv[0], (r + 1) * fv[1], (r + 1) * fv[2] };
long long fv[3] = { in[ti * c + 0], in[ti * c + 1], in[ti * c + 2] };
long long lv[3] = { in[(ti + w - 1) * c + 0], in[(ti + w - 1) * c + 1], in[(ti + w - 1) * c + 2] };
long long val[3] = { (r + 1) * fv[0], (r + 1) * fv[1], (r + 1) * fv[2] };

for (int j = 0; j < r; j++)
{
Expand Down Expand Up @@ -108,9 +108,9 @@ void SurfaceExt::BlurRect(const RectangleStruct& rect, float blurSize)
int li = ti;
int ri = ti + r * w;

int fv[3] = { in[ti * c + 0], in[ti * c + 1], in[ti * c + 2] };
int lv[3] = { in[(ti + w * (h - 1)) * c + 0], in[(ti + w * (h - 1)) * c + 1], in[(ti + w * (h - 1)) * c + 2] };
int val[3] = { (r + 1) * fv[0], (r + 1) * fv[1], (r + 1) * fv[2] };
long long fv[3] = { in[ti * c + 0], in[ti * c + 1], in[ti * c + 2] };
long long lv[3] = { in[(ti + w * (h - 1)) * c + 0], in[(ti + w * (h - 1)) * c + 1], in[(ti + w * (h - 1)) * c + 2] };
long long val[3] = { (r + 1) * fv[0], (r + 1) * fv[1], (r + 1) * fv[2] };

for (int j = 0; j < r; j++)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Team/Hook.NewTeamSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ COMPILETIMEEVAL void ModifyOperand(bool& result, int counter, AITriggerCondition
}
}

// NOTE: These ownership check functions (HouseOwns, EnemyOwns, NeutralOwns, etc.) are similar to
// the ones in Body.cpp but include additional deploy/undeploy conversion checks via OwnStuffs().
// Consider consolidating these into a shared utility in the future to reduce code duplication.

bool OwnStuffs(TechnoTypeClass* pItem, TechnoClass* list) {
if (auto pItemUnit = type_cast<UnitTypeClass*, false>(pItem)) {
if (auto pListBld = cast_to<BuildingClass*, false>(list))
Expand Down
12 changes: 12 additions & 0 deletions src/Ext/Team/Hooks.ConvertedTeam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ASMJIT_PATCH(0x509697, HouseClass_CanInstansiateTeam_CompareType_Convert, 0xA)
ContinueCheck : ContinueLoop;
}

// Dead code: _Remove is LJMP-replaced at 0x6EA870 by FakeTeamClass::_Remove
// The IsEligible check is integrated into the backported _Remove function
#if 0
ASMJIT_PATCH(0x6EA8FA, TeamClass_Remove_CompareType_Convert, 0x6)
{
enum
Expand All @@ -39,7 +42,11 @@ ASMJIT_PATCH(0x6EA8FA, TeamClass_Remove_CompareType_Convert, 0x6)
|| TeamExtData::IsEligible(pTeam, pTaskForceTeam)
? jz_ : advance;
}
#endif

// Dead code: _Can_Add is LJMP-replaced at 0x6EA610 by FakeTeamClass::_Can_Add
// The IsEligible check is integrated into the backported _Can_Add function
#if 0
ASMJIT_PATCH(0x6EAD86, TeamClass_CanAdd_CompareType_Convert_UnitType, 0x7) //6
{
enum
Expand All @@ -61,7 +68,11 @@ ASMJIT_PATCH(0x6EAD86, TeamClass_CanAdd_CompareType_Convert_UnitType, 0x7) //6
?
ContinueCheck : ContinueLoop;
}
#endif

// Dead code: _Can_Add is LJMP-replaced at 0x6EA610 by FakeTeamClass::_Can_Add
// The IsEligible check is integrated into the backported _Can_Add function
#if 0
ASMJIT_PATCH(0x6EA6D3, TeamClass_CanAdd_ReplaceLoop, 0x7)
{
GET(TechnoClass*, pGoingToBeRecuited, ESI);
Expand All @@ -80,3 +91,4 @@ ASMJIT_PATCH(0x6EA6D3, TeamClass_CanAdd_ReplaceLoop, 0x7)
//|| TeamExtData::GroupAllowed(pForce->Entries[idx].Type, TechnoExtContainer::Instance.Find(pGoingToBeRecuited)->Type)
? Conditionmet : ContinueLoop;
}
#endif
16 changes: 13 additions & 3 deletions src/Ext/Techno/Hooks.GreatestThreat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ AbstractClass* __fastcall FakeTechnoClass::__Greatest_Threat(TechnoClass* pThis,
}

// Scan aircraft in range
if (!RulesExtData::Instance()->AIAirTargetingFix && method & ThreatType::Air)
if (method & ThreatType::Air)
{

AircraftTrackerClass::Instance->FillCurrentVector(MapClass::Instance->GetCellAt(centerCell), cellRange);
Expand All @@ -321,8 +321,18 @@ AbstractClass* __fastcall FakeTechnoClass::__Greatest_Threat(TechnoClass* pThis,
if (!aircraft->IsOnMap)
continue;

if (aircraft->InWhichLayer() == Layer::Ground)
continue;
if (RulesExtData::Instance()->AIAirTargetingFix)
{
// With fix: skip only if underground
if (aircraft->InWhichLayer() == Layer::Underground)
continue;
}
else
{
// Original behavior: skip if not in air
if (aircraft->InWhichLayer() == Layer::Ground)
continue;
}

if (onlyEnemy && aircraft->Owner->ArrayIndex != pOwner->EnemyHouseIndex)
continue;
Expand Down
4 changes: 2 additions & 2 deletions src/Ext/Temporal/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void HandleBuildingDestruction(TemporalClass* pTemporal, BuildingClass* building
) {
for (auto i = 0; i < building->RadioLinks.Capacity; ++i) {
if (auto const pAir = cast_to<AircraftClass*>(building->RadioLinks[i])) {
if (pAir->IsAlive && !pAir->InLimbo && !pAir->TemporalTargetingMe) {
if (pAir->IsAlive && !pAir->InLimbo && !pAir->TemporalTargetingMe && pAir->Type) {
const auto pExt = TechnoTypeExtContainer::Instance.Find(pAir->Type);

if (pAir->IsInAir() || !AircraftTypeExtContainer::Instance.Find(pAir->Type)->ExtendedAircraftMissions_FastScramble
Expand Down Expand Up @@ -285,7 +285,7 @@ void FakeTemporalClass::_Detonate(TechnoClass* pTarget) {
}

} else if (pBuilding) {
if (!pBuilding->Type->Insignificant && !pBuilding->IsStrange()) {
if (pTargetOwner && !pBuilding->Type->Insignificant && !pBuilding->IsStrange()) {
((FakeHouseClass*)pTargetOwner)->_Attacked(pBuilding, pWeapon->Warhead);
}

Expand Down
8 changes: 5 additions & 3 deletions src/Ext/Temporal/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ ASMJIT_PATCH(0x71AC50, TemporalClass_LetItGo_ExpireEffect, 0x5)

if (peWHext->TemporalExpiredApplyDamage.Get() && pThis->WarpRemaining > 0 && pTarget->IsAlive && !pTarget->IsSinking && !pTarget->IsCrashing) {
auto const pTargetStreght = GET_TECHNOTYPE(pTarget)->Strength;
auto damage = int((pTargetStreght * ((((double)pThis->WarpRemaining) / 10.0 / pTargetStreght)
* (pWeapon->Damage * peWHext->TemporalDetachDamageFactor.Get()) / 100)));
if (pTargetStreght > 0) {
auto damage = int(((double)pThis->WarpRemaining / 10.0 / pTargetStreght)
* (pWeapon->Damage * peWHext->TemporalDetachDamageFactor.Get() / 100.0));

pTarget->ReceiveDamage(&damage, pTempOwner->DistanceFrom(pTarget), Warhead, pTempOwner, false, ScenarioClass::Instance->Random.RandomBool(), pTempOwner->Owner);
pTarget->ReceiveDamage(&damage, pTempOwner->DistanceFrom(pTarget), Warhead, pTempOwner, false, ScenarioClass::Instance->Random.RandomBool(), pTempOwner->Owner);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/Terrain/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void TerrainExtData::InitializeAnim()

if (pAnimType)
{
auto const Coords = this->AttachedAnim->GetCoords();
auto const Coords = This()->GetCoords();

AttachedAnim.reset(GameCreate<AnimClass>(pAnimType, Coords));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/TerrainType/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ASMJIT_PATCH(0x71C812, TerrainClass_AI_Crumbling, 0x6)
}

int animationLength = pTypeExt->AnimationLength.Get(pThis->Type->GetImage()->Frames / (2 * (pTypeExt->HasDamagedFrames + 1)));
int currentStage = pThis->Animation.Stage + (pThis->Type->IsAnimated ? animationLength * (pTypeExt->HasDamagedFrames + 1) : 0 + pTypeExt->HasDamagedFrames);
int currentStage = pThis->Animation.Stage + (pThis->Type->IsAnimated ? animationLength * (pTypeExt->HasDamagedFrames + 1) : (0 + pTypeExt->HasDamagedFrames));

if (currentStage + 1 == pThis->Type->GetImage()->Frames / 2)
{
Expand Down
Loading