diff --git a/src/Ext/ObjectType/Body.h b/src/Ext/ObjectType/Body.h index c283c42f5..6ab4ab113 100644 --- a/src/Ext/ObjectType/Body.h +++ b/src/Ext/ObjectType/Body.h @@ -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); } diff --git a/src/Ext/OverlayType/Body.h b/src/Ext/OverlayType/Body.h index 97996ae18..185b79fd0 100644 --- a/src/Ext/OverlayType/Body.h +++ b/src/Ext/OverlayType/Body.h @@ -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(this)->ObjectTypeExtData::SaveToStream(Stm); - const_cast(this)->Serialize(Stm); + this->ObjectTypeExtData::SaveToStream(Stm); + this->Serialize(Stm); } virtual AbstractType WhatIam() const { return base_type::AbsID; } diff --git a/src/Ext/Particle/Body.cpp b/src/Ext/Particle/Body.cpp index bf6768bc9..5d903a039 100644 --- a/src/Ext/Particle/Body.cpp +++ b/src/Ext/Particle/Body.cpp @@ -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; } @@ -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) { @@ -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(this->GasVelocity.Y + drift, -5, 5); } else { - this->GasVelocity.X = std::clamp(this->GasVelocity.X + drift, -5, 5); + this->GasVelocity.X = std::clamp(this->GasVelocity.X + drift, -5, 5); } } @@ -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() @@ -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 @@ -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; } diff --git a/src/Ext/Particle/Hooks.cpp b/src/Ext/Particle/Hooks.cpp index f66338c61..60b444c7e 100644 --- a/src/Ext/Particle/Hooks.cpp +++ b/src/Ext/Particle/Hooks.cpp @@ -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; diff --git a/src/Ext/ParticleSystem/Body.cpp b/src/Ext/ParticleSystem/Body.cpp index 9f73cf08b..102ab18d8 100644 --- a/src/Ext/ParticleSystem/Body.cpp +++ b/src/Ext/ParticleSystem/Body.cpp @@ -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) @@ -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) @@ -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; diff --git a/src/Ext/Side/Body.cpp b/src/Ext/Side/Body.cpp index aee8d0332..3c54eef35 100644 --- a/src/Ext/Side/Body.cpp +++ b/src/Ext/Side/Body.cpp @@ -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 { diff --git a/src/Ext/Sidebar/Body.cpp b/src/Ext/Sidebar/Body.cpp index 197d724f4..524a332b1 100644 --- a/src/Ext/Sidebar/Body.cpp +++ b/src/Ext/Sidebar/Body.cpp @@ -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) { @@ -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(); diff --git a/src/Ext/SmudgeType/Body.cpp b/src/Ext/SmudgeType/Body.cpp index 1f7e85e51..357e82569 100644 --- a/src/Ext/SmudgeType/Body.cpp +++ b/src/Ext/SmudgeType/Body.cpp @@ -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; } diff --git a/src/Ext/SpawnManager/Body.cpp b/src/Ext/SpawnManager/Body.cpp index 06250b9e8..fdd33f581 100644 --- a/src/Ext/SpawnManager/Body.cpp +++ b/src/Ext/SpawnManager/Body.cpp @@ -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; } } } diff --git a/src/Ext/Super/Body.cpp b/src/Ext/Super/Body.cpp index 3c1bf474e..d3b990199 100644 --- a/src/Ext/Super/Body.cpp +++ b/src/Ext/Super/Body.cpp @@ -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; @@ -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 @@ -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 diff --git a/src/Ext/Surface/Body.cpp b/src/Ext/Surface/Body.cpp index 6aba41cad..89d69b200 100644 --- a/src/Ext/Surface/Body.cpp +++ b/src/Ext/Surface/Body.cpp @@ -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++) { @@ -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++) { diff --git a/src/Ext/Team/Hook.NewTeamSelector.cpp b/src/Ext/Team/Hook.NewTeamSelector.cpp index 5cae627c3..d779ab4f3 100644 --- a/src/Ext/Team/Hook.NewTeamSelector.cpp +++ b/src/Ext/Team/Hook.NewTeamSelector.cpp @@ -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(pItem)) { if (auto pListBld = cast_to(list)) diff --git a/src/Ext/Team/Hooks.ConvertedTeam.cpp b/src/Ext/Team/Hooks.ConvertedTeam.cpp index bb44c54cd..ca14fd41f 100644 --- a/src/Ext/Team/Hooks.ConvertedTeam.cpp +++ b/src/Ext/Team/Hooks.ConvertedTeam.cpp @@ -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 @@ -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 @@ -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); @@ -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 diff --git a/src/Ext/Techno/Hooks.GreatestThreat.cpp b/src/Ext/Techno/Hooks.GreatestThreat.cpp index 85308b83e..936787987 100644 --- a/src/Ext/Techno/Hooks.GreatestThreat.cpp +++ b/src/Ext/Techno/Hooks.GreatestThreat.cpp @@ -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); @@ -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; diff --git a/src/Ext/Temporal/Body.cpp b/src/Ext/Temporal/Body.cpp index b41246f92..f85e72795 100644 --- a/src/Ext/Temporal/Body.cpp +++ b/src/Ext/Temporal/Body.cpp @@ -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(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 @@ -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); } diff --git a/src/Ext/Temporal/Hooks.cpp b/src/Ext/Temporal/Hooks.cpp index 1f33b0316..fdaadac71 100644 --- a/src/Ext/Temporal/Hooks.cpp +++ b/src/Ext/Temporal/Hooks.cpp @@ -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); + } } } } diff --git a/src/Ext/Terrain/Body.cpp b/src/Ext/Terrain/Body.cpp index fea15842f..5002f5583 100644 --- a/src/Ext/Terrain/Body.cpp +++ b/src/Ext/Terrain/Body.cpp @@ -67,7 +67,7 @@ void TerrainExtData::InitializeAnim() if (pAnimType) { - auto const Coords = this->AttachedAnim->GetCoords(); + auto const Coords = This()->GetCoords(); AttachedAnim.reset(GameCreate(pAnimType, Coords)); } diff --git a/src/Ext/TerrainType/Hooks.cpp b/src/Ext/TerrainType/Hooks.cpp index 504ecdde8..834c359be 100644 --- a/src/Ext/TerrainType/Hooks.cpp +++ b/src/Ext/TerrainType/Hooks.cpp @@ -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) { diff --git a/src/Ext/Tiberium/Body.cpp b/src/Ext/Tiberium/Body.cpp index 2fde18966..413d2de2f 100644 --- a/src/Ext/Tiberium/Body.cpp +++ b/src/Ext/Tiberium/Body.cpp @@ -25,7 +25,11 @@ void TiberiumExtData::Spread_AI() if (!SpreadQueue.empty() && This()->SpreadPercentage > 0.00001) { int count = std::clamp((int)(SpreadQueue.size() * This()->SpreadPercentage), 5, 300); - count = ScenarioClass::Instance->Random.RandomRanged(1, count); + if (count > 0) { + count = ScenarioClass::Instance->Random.RandomRanged(1, count); + } else { + count = 1; + } for (int index = 0; index < count && !SpreadQueue.empty();) { @@ -118,7 +122,11 @@ void TiberiumExtData::Growth_AI() if (!GrowthQueue.empty() && This()->GrowthPercentage > 0.00001) { int count = std::clamp((int)(GrowthQueue.size() * This()->GrowthPercentage), 5, 300); - count = ScenarioClass::Instance->Random.RandomRanged(1, count); + if (count > 0) { + count = ScenarioClass::Instance->Random.RandomRanged(1, count); + } else { + count = 1; + } for (int index = 0; index < count && !GrowthQueue.empty(); index++) { diff --git a/src/Ext/Trigger/Hooks.cpp b/src/Ext/Trigger/Hooks.cpp index fa6a277fd..19d47180f 100644 --- a/src/Ext/Trigger/Hooks.cpp +++ b/src/Ext/Trigger/Hooks.cpp @@ -12,8 +12,8 @@ ASMJIT_PATCH(0x727064, TriggerTypeClass_HasLocalSetOrClearedEvent, 0x5) return nIndex >= (int)PhobosTriggerEvent::LocalVariableGreaterThan && nIndex <= (int)PhobosTriggerEvent::LocalVariableAndIsTrue || - nIndex >= (int)PhobosTriggerEvent::LocalVariableGreaterThanLocalVariable && nIndex >= (int)PhobosTriggerEvent::LocalVariableAndIsTrueLocalVariable || - nIndex >= (int)PhobosTriggerEvent::LocalVariableGreaterThanGlobalVariable && nIndex >= (int)PhobosTriggerEvent::LocalVariableAndIsTrueGlobalVariable || + nIndex >= (int)PhobosTriggerEvent::LocalVariableGreaterThanLocalVariable && nIndex <= (int)PhobosTriggerEvent::LocalVariableAndIsTrueLocalVariable || + nIndex >= (int)PhobosTriggerEvent::LocalVariableGreaterThanGlobalVariable && nIndex <= (int)PhobosTriggerEvent::LocalVariableAndIsTrueGlobalVariable || nIndex == static_cast(TriggerEvent::LocalSet) ? 0x72706E : 0x727069; @@ -25,8 +25,8 @@ ASMJIT_PATCH(0x727024, TriggerTypeClass_HasGlobalSetOrClearedEvent, 0x5) return nIndex >= (int)PhobosTriggerEvent::GlobalVariableGreaterThan && nIndex <= (int)PhobosTriggerEvent::GlobalVariableAndIsTrue || - nIndex >= (int)PhobosTriggerEvent::GlobalVariableGreaterThanLocalVariable && nIndex >= (int)PhobosTriggerEvent::GlobalVariableAndIsTrueLocalVariable || - nIndex >= (int)PhobosTriggerEvent::GlobalVariableGreaterThanGlobalVariable && nIndex >= (int)PhobosTriggerEvent::GlobalVariableAndIsTrueGlobalVariable || + nIndex >= (int)PhobosTriggerEvent::GlobalVariableGreaterThanLocalVariable && nIndex <= (int)PhobosTriggerEvent::GlobalVariableAndIsTrueLocalVariable || + nIndex >= (int)PhobosTriggerEvent::GlobalVariableGreaterThanGlobalVariable && nIndex <= (int)PhobosTriggerEvent::GlobalVariableAndIsTrueGlobalVariable || nIndex == static_cast(TriggerEvent::GlobalSet) ? 0x72702E : 0x727029; @@ -226,7 +226,6 @@ ASMJIT_PATCH(0x7264C0, TriggerClass_RegisterEvent_ForceSequentialEvents, 0x7) if (it != triggerOwners.end()) { if (auto const pHouse = HouseClass::FindByPlayerAt(it->second)) { pEventOwner = pHouse; - break; } } diff --git a/src/Ext/Wave/Body.cpp b/src/Ext/Wave/Body.cpp index 30d156d47..d61019f20 100644 --- a/src/Ext/Wave/Body.cpp +++ b/src/Ext/Wave/Body.cpp @@ -46,13 +46,13 @@ void FakeWaveClass::_DamageCell(CoordStruct* pLoc){ } } - if(pCell->OverlayTypeIndex != -1){ + if(pCell->OverlayTypeIndex != -1 && pCell->OverlayTypeIndex < OverlayTypeClass::Array->Count){ auto pOverlay = OverlayTypeClass::Array->Items[pCell->OverlayTypeIndex]; - if(pOverlay->ChainReaction){ + if(pOverlay && pOverlay->ChainReaction){ FakeCellClass::_ChainReaction(&pCell->MapCoords); } - if(pOverlay->Wall && pWH->Wall) { + if(pOverlay && pOverlay->Wall && pWH->Wall) { pCell->ReduceWall(pWpn->Damage); } } diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index 41abaacf1..1c475b3e2 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -307,7 +307,10 @@ bool WeaponTypeExtData::LoadFromINI(CCINIClass* pINI, bool parseFailAddr) bool WeaponTypeExtData::IsVeterancyInThreshold(TechnoClass* pTarget) const { - return !EnumFunctions::CanTargetVeterancy(this->CanTargetVeterancy, pTarget); + if (this->CanTargetVeterancy == AffectedVeterancy::All) + return true; + + return EnumFunctions::CanTargetVeterancy(this->CanTargetVeterancy, pTarget); } int WeaponTypeExtData::GetRangeWithModifiers(WeaponTypeClass* pThis, TechnoClass* pFirer, std::optional fallback) @@ -380,14 +383,15 @@ int WeaponTypeExtData::GetTechnoKeepRange(WeaponTypeClass* pThis, TechnoClass* p if (pFirer->RearmTimer.GetTimeLeft() < pExt->KeepRange_EarlyStopFrame) return 0; + // Only check spawn manager for units that have spawns + const auto spawnsNumber = GET_TECHNOTYPE(pFirer)->SpawnsNumber; + if (spawnsNumber > 0) { const auto spawnManager = pFirer->SpawnManager; if (!spawnManager || spawnManager->Status != SpawnManagerStatus::CoolDown) return 0; - const auto spawnsNumber = GET_TECHNOTYPE(pFirer)->SpawnsNumber; - for (int i = 0; i < spawnsNumber; i++) { const auto status = spawnManager->SpawnedNodes[i]->Status; diff --git a/src/ExtraHeaders/MemoryPool.cpp b/src/ExtraHeaders/MemoryPool.cpp index 8ec26cb7e..ab3807c4e 100644 --- a/src/ExtraHeaders/MemoryPool.cpp +++ b/src/ExtraHeaders/MemoryPool.cpp @@ -116,6 +116,7 @@ static PoolSizeRec sizes[] = { "RadarJammerClass" , 100 , 50 }, { "PoweredUnitClass" , 100 , 50 }, { "PrismForwarding" , 9000 , 1024 }, + { nullptr , 0 , 0 } }; static void userMemoryAdjustPoolSize(const char* poolName, Int& initialAllocationCount, Int& overflowAllocationCount) diff --git a/src/ExtraHeaders/Placeholders/DiscreteSelectionClass_s.h b/src/ExtraHeaders/Placeholders/DiscreteSelectionClass_s.h index 60a89cddd..98c4cc7e9 100644 --- a/src/ExtraHeaders/Placeholders/DiscreteSelectionClass_s.h +++ b/src/ExtraHeaders/Placeholders/DiscreteSelectionClass_s.h @@ -87,7 +87,7 @@ class DiscreteSelectionClass_s protected: bool ValidIndex(int nIdx) const { - return nIdx > 0 && nIdx < (int)Items.size(); + return nIdx >= 0 && nIdx < (int)Items.size(); } private: diff --git a/src/ExtraHeaders/Placeholders/StackAllocator.h b/src/ExtraHeaders/Placeholders/StackAllocator.h index d5e586378..aac01db57 100644 --- a/src/ExtraHeaders/Placeholders/StackAllocator.h +++ b/src/ExtraHeaders/Placeholders/StackAllocator.h @@ -86,7 +86,7 @@ class StackAllocator : public std::allocator // Actually do the allocation. Use the stack buffer if nobody has used it yet // and the size requested fits. Otherwise, fall through to the standard // allocator. - pointer allocate(size_type n, void* hint = 0) + pointer allocate(size_type n) { if (source_ != NULL && !source_->used_stack_buffer_ && n <= stack_capacity) @@ -96,7 +96,7 @@ class StackAllocator : public std::allocator } else { - return std::allocator::allocate(n, hint); + return std::allocator::allocate(n); } } // Free: when trying to free the stack buffer, just mark it as free. For diff --git a/src/ExtraHeaders/Placeholders/TRange.h b/src/ExtraHeaders/Placeholders/TRange.h index afd9684e5..f1f2e5790 100644 --- a/src/ExtraHeaders/Placeholders/TRange.h +++ b/src/ExtraHeaders/Placeholders/TRange.h @@ -95,7 +95,7 @@ class TRange return TRange(s, e); } //! Add new value to range. - TRange& operator += (T v) const + TRange& operator += (T v) { if (v < start) { diff --git a/src/Misc/Ares/Hooks/Hooks.Bugfixes.Safeguard.cpp b/src/Misc/Ares/Hooks/Hooks.Bugfixes.Safeguard.cpp index 34b5d1c81..a80dc85f2 100644 --- a/src/Misc/Ares/Hooks/Hooks.Bugfixes.Safeguard.cpp +++ b/src/Misc/Ares/Hooks/Hooks.Bugfixes.Safeguard.cpp @@ -18,10 +18,10 @@ ASMJIT_PATCH(0x547043, IsometricTileTypeClass_ReadFromFile, 0x6) if (FileSize == 0) { - auto what = (pTileType->ID + strlen(pTileType->ID) + 1 - pTileType->ID); + const size_t nameLength = strlen(pTileType->ID); auto pFileName = pFile->FileName; - if (what > 9) { + if (nameLength > 9) { Debug::FatalErrorAndExit("Maximum allowed length for tile names, excluding the extension, is 9 characters.\n" "The tileset using filename '%s - %s' exceeds this limit - the game cannot proceed.", pTileType->ID , pFileName); } diff --git a/src/Misc/DynamicPatcher/AttachedAffects/AttachEffectType.cpp b/src/Misc/DynamicPatcher/AttachedAffects/AttachEffectType.cpp index 2fab91011..f4114dfa8 100644 --- a/src/Misc/DynamicPatcher/AttachedAffects/AttachEffectType.cpp +++ b/src/Misc/DynamicPatcher/AttachedAffects/AttachEffectType.cpp @@ -127,16 +127,16 @@ void AttachEffectType::LoadFromINI(CCINIClass* pINI) StandTypeData.IsOnWorld.Read(exINI, pSection, "Stand.IsOnWorld"); StandTypeData.DrawLayer.Read(exINI, pSection, "Stand.DrawLayer"); StandTypeData.ZOffset.Read(exINI, pSection, "Stand.ZOffset"); - StandTypeData.Powered.Read(exINI, pSection, "Stand.SameHouse"); - StandTypeData.SameHouse.Read(exINI, pSection, "Stand.SameTarget"); - StandTypeData. SameTarget.Read(exINI, pSection, "Stand.SameLoseTarget"); - StandTypeData. SameLoseTarget.Read(exINI, pSection, "Stand.ForceAttackMaster"); - StandTypeData. ForceAttackMaster.Read(exINI, pSection, "Stand.MobileFire"); - StandTypeData. MobileFire.Read(exINI, pSection, "Stand.Powered"); - StandTypeData. Explodes.Read(exINI, pSection, "Stand.Explodes"); - StandTypeData. ExplodesWithMaster.Read(exINI, pSection, "Stand.ExplodesWithMaster"); - StandTypeData. RemoveAtSinking.Read(exINI, pSection, "Stand.RemoveAtSinking"); - StandTypeData. PromoteFormMaster.Read(exINI, pSection, "Stand.PromoteFormMaster"); + StandTypeData.Powered.Read(exINI, pSection, "Stand.Powered"); + StandTypeData.SameHouse.Read(exINI, pSection, "Stand.SameHouse"); + StandTypeData.SameTarget.Read(exINI, pSection, "Stand.SameTarget"); + StandTypeData.SameLoseTarget.Read(exINI, pSection, "Stand.SameLoseTarget"); + StandTypeData.ForceAttackMaster.Read(exINI, pSection, "Stand.ForceAttackMaster"); + StandTypeData.MobileFire.Read(exINI, pSection, "Stand.MobileFire"); + StandTypeData.Explodes.Read(exINI, pSection, "Stand.Explodes"); + StandTypeData.ExplodesWithMaster.Read(exINI, pSection, "Stand.ExplodesWithMaster"); + StandTypeData.RemoveAtSinking.Read(exINI, pSection, "Stand.RemoveAtSinking"); + StandTypeData.PromoteFormMaster.Read(exINI, pSection, "Stand.PromoteFormMaster"); double experienceToMaster = 0.0; StandTypeData.ExperienceToMaster.Read(exINI, pSection, "Stand.ExperienceToMaster"); if (StandTypeData.ExperienceToMaster > 1.0) diff --git a/src/Misc/DynamicPatcher/Helpers/CircleDifferentiator.cpp b/src/Misc/DynamicPatcher/Helpers/CircleDifferentiator.cpp index ca44de057..24c54dc5f 100644 --- a/src/Misc/DynamicPatcher/Helpers/CircleDifferentiator.cpp +++ b/src/Misc/DynamicPatcher/Helpers/CircleDifferentiator.cpp @@ -3,10 +3,10 @@ std::vector CircleDifferentiator::DivideArcByTolerance(const CoordStruct& center, int radius, int tolerance, const Vector3D& upVector) { - tolerance = MinImpl(tolerance, (int)(Math::SQRT_TWO) * radius)); + tolerance = MinImpl(tolerance, (int)(Math::SQRT_TWO * radius)); // start from nearest count n that satisfy: d = sqrt(2) * r * sin(a) <= tolerance, a = 2 * pi / n - double maxRad = Math::asin(tolerance / (Math::SQRT_TWO) * radius)); + double maxRad = Math::asin(tolerance / (Math::SQRT_TWO * radius)); int n = (int)(Math::TWO_BY_PI / maxRad); // find n that satisfy d <= length, d = sqrt(2) * r * sin(a), a = 2 * pi / n diff --git a/src/Misc/DynamicPatcher/Main.h b/src/Misc/DynamicPatcher/Main.h index 034cb543a..9fe22402c 100644 --- a/src/Misc/DynamicPatcher/Main.h +++ b/src/Misc/DynamicPatcher/Main.h @@ -19,10 +19,11 @@ class Registration public: static bool Register(std::wstring dllPath) { - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; + STARTUPINFOW startupInfo = { sizeof(STARTUPINFOW) }; PROCESS_INFORMATION processInfo; - if (CreateProcess((LPCSTR)Registration::RegAsm, (LPSTR)(L" " + GetSafePath(dllPath)).data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) + std::wstring cmdLine = L" " + GetSafePath(dllPath); + if (CreateProcessW(Registration::RegAsm, cmdLine.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) { WaitForSingleObject(processInfo.hProcess, INFINITE); DWORD exitCode; @@ -36,24 +37,17 @@ class Registration } else { - Debug::fata - ShowErrorAndExit(L"Register Dynamic Patcher failed."); + Debug::FatalError("Register Dynamic Patcher failed. Exit code: %d", exitCode); } } else { - std::wstring error (L"GetExitCodeProcess() failed: %ld"); - error += std::to_wstring(GetLastError()); - - ShowErrorAndExit(error); + Debug::FatalError("GetExitCodeProcess() failed: %ld", GetLastError()); } } else { - std::wstring error = L"CreateProcess() failed: %ld"; - error += std::to_wstring(GetLastError()); - - ShowErrorAndExit(error); + Debug::FatalError("CreateProcess() failed: %ld", GetLastError()); } return false; @@ -61,10 +55,11 @@ class Registration static bool Unregister(std::wstring dllPath) { - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; + STARTUPINFOW startupInfo = { sizeof(STARTUPINFOW) }; PROCESS_INFORMATION processInfo; - if (CreateProcess(RegAsm, (L" /u " + GetSafePath(dllPath)).data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) + std::wstring cmdLine = L" /u " + GetSafePath(dllPath); + if (CreateProcessW(RegAsm, cmdLine.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) { WaitForSingleObject(processInfo.hProcess, INFINITE); DWORD exitCode; diff --git a/src/Misc/Hooks.BugFixes.cpp b/src/Misc/Hooks.BugFixes.cpp index 31ae33913..124967643 100644 --- a/src/Misc/Hooks.BugFixes.cpp +++ b/src/Misc/Hooks.BugFixes.cpp @@ -2098,6 +2098,9 @@ DEFINE_JUMP(LJMP, 0x65B3F7, 0x65B416);//RadSite, no effect #pragma region TeamCloseRangeFix + // Dead code: _CoordinateMove is LJMP-replaced at 0x6EBAD0 by FakeTeamClass::_CoordinateMove + // The jumpjet 2D distance fix is integrated via FakeObjectClass::_GetDistanceOfObj usage +#if 0 static int __fastcall Check2DDistanceInsteadOf3D(ObjectClass* pSource, void* _, AbstractClass* pTarget) { return (pSource->IsInAir() && pSource->WhatAmI() != AbstractType::Aircraft) // Jumpjets or sth in the air @@ -2105,6 +2108,7 @@ DEFINE_JUMP(LJMP, 0x65B3F7, 0x65B416);//RadSite, no effect : pSource->DistanceFromSquared(pTarget); // 3D distance (vanilla) } DEFINE_FUNCTION_JUMP(CALL, 0x6EBCC9, Check2DDistanceInsteadOf3D); +#endif #pragma endregion diff --git a/src/Misc/Hooks.CRT.cpp b/src/Misc/Hooks.CRT.cpp index 3d0771973..5ce29d070 100644 --- a/src/Misc/Hooks.CRT.cpp +++ b/src/Misc/Hooks.CRT.cpp @@ -8447,9 +8447,9 @@ void CRTHooks::ApplyftolHooks() { Patch::Apply_CALL(0x5081BF, ftol_safe); Patch::Apply_CALL(0x5081FE, ftol_safe); Patch::Apply_CALL(0x50823C, ftol_safe); - Patch::Apply_CALL(0x50BC66, ftol_safe); - Patch::Apply_CALL(0x50BC75, ftol_safe); - Patch::Apply_CALL(0x50BC80, ftol_safe); + Patch::Apply_CALL(0x50BC66, ftol_safe); // inside init_laser_color (0x50BA00) - dead code due to LJMP + Patch::Apply_CALL(0x50BC75, ftol_safe); // inside init_laser_color (0x50BA00) - dead code due to LJMP + Patch::Apply_CALL(0x50BC80, ftol_safe); // inside init_laser_color (0x50BA00) - dead code due to LJMP Patch::Apply_CALL(0x50DD2B, ftol_safe); Patch::Apply_CALL(0x50DD95, ftol_safe); Patch::Apply_CALL(0x50DE06, ftol_safe); @@ -11287,8 +11287,8 @@ void CRTHooks::ApplyMathHooks() Patch::Apply_CALL(0x5063F1, PhobosMath::sqrtd); Patch::Apply_CALL(0x506E3A, PhobosMath::sqrtd); Patch::Apply_CALL(0x50B94D, PhobosMath::sqrtd); - Patch::Apply_CALL(0x50BA64, PhobosMath::sqrtd); - Patch::Apply_CALL(0x50BBA8, PhobosMath::sqrtd); + Patch::Apply_CALL(0x50BA64, PhobosMath::sqrtd); // inside init_laser_color (0x50BA00) - dead code due to LJMP + Patch::Apply_CALL(0x50BBA8, PhobosMath::sqrtd); // inside init_laser_color (0x50BA00) - dead code due to LJMP Patch::Apply_CALL(0x50DD23, PhobosMath::sqrtd); Patch::Apply_CALL(0x50DD8D, PhobosMath::sqrtd); Patch::Apply_CALL(0x50DDFE, PhobosMath::sqrtd); diff --git a/src/Misc/Hooks.Otamaa.cpp b/src/Misc/Hooks.Otamaa.cpp index bf1b46379..70298d701 100644 --- a/src/Misc/Hooks.Otamaa.cpp +++ b/src/Misc/Hooks.Otamaa.cpp @@ -4634,6 +4634,9 @@ ASMJIT_PATCH(0x467C2E, BulletClass_AI_FuseCheck, 0x7) return 0x467C3A; } +// Dead code: _Coordinate_Do is LJMP-replaced at 0x6ED7E0 by FakeTeamClass::_Coordinate_Do +// The Harvest fix is integrated into the backported _Coordinate_Do function +#if 0 ASMJIT_PATCH(0x6EDA50, Team_DoMission_Harvest, 0x5) { GET(Mission, setTo, EBX); @@ -4647,6 +4650,7 @@ ASMJIT_PATCH(0x6EDA50, Team_DoMission_Harvest, 0x5) return 0x0; } +#endif #ifndef ASTAR_HOOKS @@ -5078,7 +5082,7 @@ static void PriorityQueue_Clear_Safe(PriorityQueueClass_AStarHierarchical* queue return; int clearCount = std::min(queue->Count + 1, queue->Capacity); - for (int i = 0; i <= clearCount; ++i) + for (int i = 0; i < clearCount; ++i) { queue->Heap[i] = nullptr; } @@ -7012,13 +7016,15 @@ ASMJIT_PATCH(0x5F6560, AbstractClass_Distance2DSquared_2, 5) #else DEFINE_FUNCTION_JUMP(LJMP, 0x5F6500, FakeObjectClass::_GetDistanceOfObj); -DEFINE_FUNCTION_JUMP(CALL, 0x6EB2DC, FakeObjectClass::_GetDistanceOfObj); +// Dead: 0x6EB2DC is inside _Calc_Center (LJMP'd at 0x6EAEE0), logic integrated into backport +//DEFINE_FUNCTION_JUMP(CALL, 0x6EB2DC, FakeObjectClass::_GetDistanceOfObj); DEFINE_FUNCTION_JUMP(CALL, 0x4DEFF4, FakeObjectClass::_GetDistanceOfObj); DEFINE_FUNCTION_JUMP(LJMP, 0x5F6560, FakeObjectClass::_GetDistanceOfCoord); -DEFINE_FUNCTION_JUMP(CALL, 0x6EABCB, FakeObjectClass::_GetDistanceOfCoord); -DEFINE_FUNCTION_JUMP(CALL, 0x6EAC96, FakeObjectClass::_GetDistanceOfCoord); -DEFINE_FUNCTION_JUMP(CALL, 0x6EAD4B, FakeObjectClass::_GetDistanceOfCoord); +// Dead: 0x6EABCB, 0x6EAC96, 0x6EAD4B are inside _Recruit (LJMP'd at 0x6EAA90), logic integrated into backport +//DEFINE_FUNCTION_JUMP(CALL, 0x6EABCB, FakeObjectClass::_GetDistanceOfCoord); +//DEFINE_FUNCTION_JUMP(CALL, 0x6EAC96, FakeObjectClass::_GetDistanceOfCoord); +//DEFINE_FUNCTION_JUMP(CALL, 0x6EAD4B, FakeObjectClass::_GetDistanceOfCoord); DEFINE_FUNCTION_JUMP(CALL, 0x741801, FakeObjectClass::_GetDistanceOfCoord); #endif diff --git a/src/Misc/MapRevealer.cpp b/src/Misc/MapRevealer.cpp index a8065f986..a63abb0ce 100644 --- a/src/Misc/MapRevealer.cpp +++ b/src/Misc/MapRevealer.cpp @@ -183,7 +183,7 @@ void MapRevealer::Process1(CellClass* const pCell, bool fog, bool add) const } } else { if (this->IsCellAllowed(pCell->MapCoords)) { - MouseClass::Instance->RevealFogShroud(pCell->MapCoords, HouseClass::CurrentPlayer, add); + MouseClass::Instance->RevealFogShroud(pCell->MapCoords, HouseClass::CurrentPlayer(), add); } } } diff --git a/src/Misc/PNGFile.cpp b/src/Misc/PNGFile.cpp index 131588f4b..b5b984b66 100644 --- a/src/Misc/PNGFile.cpp +++ b/src/Misc/PNGFile.cpp @@ -210,6 +210,7 @@ BSurface* PNGFile::Read(FileClass* name, unsigned char* palette, void* buff, lon return nullptr; } + unsigned char* png_image_ptr = png_image; // Save original pointer for freeing later for (int y = 0; y < pic->Height; ++y) { @@ -217,9 +218,9 @@ BSurface* PNGFile::Read(FileClass* name, unsigned char* palette, void* buff, lon for (int x = 0; x < pic->Width; ++x) { - int r = *png_image++; // & 0xFF; - int g = *png_image++; // & 0xFF; - int b = *png_image++; // & 0xFF; + int r = *png_image_ptr++; // & 0xFF; + int g = *png_image_ptr++; // & 0xFF; + int b = *png_image_ptr++; // & 0xFF; *buffptr++ = (unsigned short)DSurface::RGBA_To_Pixel(r, g, b); } @@ -228,6 +229,7 @@ BSurface* PNGFile::Read(FileClass* name, unsigned char* palette, void* buff, lon } ::free(png_buffer); + ::free(png_image); // Free the original png_image pointer lodepng_state_cleanup(&state); if (file_opened) { diff --git a/src/Misc/Spawner/NetHack.cpp b/src/Misc/Spawner/NetHack.cpp index 815b8667d..80bdba4f6 100644 --- a/src/Misc/Spawner/NetHack.cpp +++ b/src/Misc/Spawner/NetHack.cpp @@ -100,7 +100,8 @@ int WINAPI Tunnel::SendTo( int addrlen ) { - char TempBuf[1024 + 4]; + constexpr size_t MAX_PACKET_SIZE = 1024; + char TempBuf[MAX_PACKET_SIZE + 4]; uint16_t* BufFrom = reinterpret_cast(TempBuf); uint16_t* BufTo = reinterpret_cast(TempBuf + 2); @@ -108,6 +109,10 @@ int WINAPI Tunnel::SendTo( if (!Tunnel::Port) return sendto(sockfd, buf, len, flags, (struct sockaddr*)dest_addr, addrlen); + // validate packet size to prevent buffer overflow + if (len > MAX_PACKET_SIZE) + return -1; + // copy packet to our buffer memcpy(TempBuf + 4, buf, len); @@ -130,7 +135,8 @@ int WINAPI Tunnel::RecvFrom( int* addrlen ) { - char TempBuf[1024 + 4]; + constexpr size_t MAX_PACKET_SIZE = 1024; + char TempBuf[MAX_PACKET_SIZE + 4]; uint16_t* BufFrom = reinterpret_cast(TempBuf); uint16_t* BufTo = reinterpret_cast(TempBuf + 2); @@ -145,10 +151,15 @@ int WINAPI Tunnel::RecvFrom( if (ret < 5 || *BufTo != Tunnel::Id) return -1; - memcpy(buf, TempBuf + 4, ret - 4); + // validate that we don't write past the destination buffer + size_t dataLen = static_cast(ret - 4); + if (dataLen > len) + dataLen = len; + + memcpy(buf, TempBuf + 4, dataLen); src_addr->sin_port = *BufFrom; src_addr->sin_addr.s_addr = 0; - return ret - 4; + return static_cast(dataLen); } diff --git a/src/Misc/SyncLogging.h b/src/Misc/SyncLogging.h index d684b12c8..c4ff048f9 100644 --- a/src/Misc/SyncLogging.h +++ b/src/Misc/SyncLogging.h @@ -28,7 +28,7 @@ class SyncLogEventBuffer std::array Data {}; int LastWritePosition { 0 }; int LastReadPosition { -1 }; - bool HasBeenFilled { true }; + bool HasBeenFilled { false }; public: @@ -51,7 +51,7 @@ class SyncLogEventBuffer COMPILETIMEEVAL T* Get() { if (!LastWritePosition && LastReadPosition == -1 && !HasBeenFilled) - return nullptr; // this will never executed , because the HasBeenFilled will always default to true ,... + return nullptr; if (LastReadPosition == -1 && HasBeenFilled) LastReadPosition = LastWritePosition;