27 [
Attribute(
"1.5",
desc:
"Max distance of hitzone, which should receive damage, from contact point.",
category:
"Collision Damage")]
28 protected float m_fMaxSharedDamageDistance;
48 [
Attribute(
"30",
"Speed in km/h over which will occupants be dealt damage in collision",
category:
"Collision Damage")]
51 [
Attribute(
"100",
"Speed in km/h over which will occupants die in collision",
category:
"Collision Damage")]
54 [
Attribute(
"0 0 0",
"Position for frontal impact calculation",
category:
"Collision Damage",
params:
"inf inf 0 purpose=coords space=entity coordsVar=m_vFrontalImpact")]
61 return m_fMaxSharedDamageDistance;
153 static ref map<SCR_EPhysicsResponseIndex, float> s_mResponseIndexMomentumMap =
new map<SCR_EPhysicsResponseIndex, float>();
155 [
Attribute(
"0",
desc:
"Print relative force in collisions of this vehicle? Can be used to determine ideal Collision Damage Force Threshold.",
category:
"Debug")]
158 [
Attribute(
"0",
"Frontal impact damage needed to destroy this vehicle\nTakes into account current damage multipliers\nUse context menu on Damage Manager component to compute this value.\n[hp]",
category:
"Collision Damage")]
159 protected float m_fVehicleDestroyDamage;
161 [
Attribute(
"15",
"Speed of collision that damages the vehicle\n[km/h]",
category:
"Collision Damage")]
162 protected float m_fVehicleDamageSpeedThreshold;
164 [
Attribute(
"120",
"Speed of collision that destroys the vehicle\n[km/h]",
category:
"Collision Damage")]
165 protected float m_fVehicleSpeedDestroy;
167 [
Attribute(
"0.7",
"Engine efficiency at which it is considered to be malfunctioning\n[x * 100%]",
category:
"Vehicle Damage")]
168 protected float m_fEngineMalfunctioningThreshold;
170 [
Attribute(defvalue:
"VehicleFireState",
desc:
"Vehicle parts fire state signal name",
category:
"Secondary damage")]
173 [
Attribute(defvalue:
"FuelTankFireState",
desc:
"Fuel tank fire signal name",
category:
"Secondary damage")]
176 [
Attribute(defvalue:
"SuppliesFireState",
desc:
"Supplies fire signal name",
category:
"Secondary damage")]
180 protected float m_fFuelTankFireDamageRate;
183 protected float m_fSuppliesFireDamageRate;
186 protected float m_fSecondaryFireDamageDelay;
230 [
RplProp(onRplName:
"OnVehicleFireStateChanged")]
233 [
RplProp(onRplName:
"OnFuelTankFireStateChanged")]
236 [
RplProp(onRplName:
"OnSuppliesFireStateChanged")]
249 protected static const float APPROXIMATE_CHARACTER_LETHAL_DAMAGE = 150;
251 #ifdef VEHICLE_DAMAGE_DEBUG
254 #ifdef VEHICLE_DEBUG_OTHER
273 return prefabData.GetTopMultiplier();
284 return prefabData.GetRightMultiplier();
295 return prefabData.GetLeftMultiplier();
306 return prefabData.GetRearMultiplier();
317 return prefabData.GetBottomMultiplier();
328 return prefabData.GetFrontMultiplier();
339 return prefabData.GetMaxSharedDamageDistance();
350 return prefabData.GetOccupantsDamageSpeedThreshold();
361 return prefabData.GetOccupantsSpeedDeath();
372 return prefabData.GetFrontalImpact();
410 super.OnPostInit(owner);
412 Vehicle vehicle = Vehicle.Cast(owner);
416 m_CompartmentManager = SCR_BaseCompartmentManagerComponent.Cast(vehicle.FindComponent(SCR_BaseCompartmentManagerComponent));
417 m_Controller = CompartmentControllerComponent.Cast(owner.FindComponent(CompartmentControllerComponent));
418 m_Simulation = VehicleBaseSimulation.Cast(owner.FindComponent(VehicleBaseSimulation));
419 m_FuelManager = FuelManagerComponent.Cast(owner.FindComponent(FuelManagerComponent));
420 m_SignalsManager = SignalsManagerComponent.Cast(owner.FindComponent(SignalsManagerComponent));
432 RplComponent rpl = vehicle.GetRplComponent();
433 if (rpl && rpl.IsProxy())
436 Physics physics = owner.GetPhysics();
441 SetEventMask(owner, EntityEvent.CONTACT);
470 float engineEfficiency;
471 bool engineFunctional;
474 float gearboxEfficiency;
475 bool gearboxFunctional;
486 engineEfficiency += engineHitZone.GetEfficiency();
488 if (engineHitZone.GetDamageState() !=
EDamageState.DESTROYED)
489 engineFunctional =
true;
498 gearboxEfficiency += gearboxHitZone.GetEfficiency();
500 if (gearboxHitZone.GetDamageState() !=
EDamageState.DESTROYED)
501 gearboxFunctional =
true;
513 if (gearboxCount > 0)
526 float movementDamage;
533 SetMovementDamage(movementDamage);
535 VehicleControllerComponent controller = VehicleControllerComponent.Cast(
m_Controller);
537 controller.SetCanMove(movementDamage < 1);
557 VehicleControllerComponent controller = VehicleControllerComponent.Cast(
m_Controller);
558 if (controller && controller.IsEngineOn())
559 controller.StopEngine(
false);
563 VehicleControllerComponent_SA controller = VehicleControllerComponent_SA.Cast(
m_Controller);
564 if (controller && controller.IsEngineOn())
565 controller.StopEngine(
false);
573 return m_fEngineMalfunctioningThreshold;
590 VehicleWheeledSimulation simulation = VehicleWheeledSimulation.Cast(
m_Simulation);
591 if (simulation && simulation.IsValid())
593 simulation.EngineSetPeakTorqueState(efficiency * simulation.EngineGetPeakTorque());
594 simulation.EngineSetPeakPowerState(efficiency * simulation.EngineGetPeakPower());
599 VehicleWheeledSimulation_SA simulation = VehicleWheeledSimulation_SA.Cast(
m_Simulation);
600 if (simulation && simulation.IsValid())
602 simulation.EngineSetPeakTorqueState(efficiency * simulation.EngineGetPeakTorque());
603 simulation.EngineSetPeakPowerState(efficiency * simulation.EngineGetPeakPower());
614 VehicleControllerComponent controller = VehicleControllerComponent.Cast(
m_Controller);
616 controller.SetCanMove(functional);
620 VehicleControllerComponent_SA controller = VehicleControllerComponent_SA.Cast(
m_Controller);
622 controller.SetCanMove(functional);
647 VehicleWheeledSimulation simulation = VehicleWheeledSimulation.Cast(
m_Simulation);
648 if (simulation && simulation.IsValid())
649 simulation.GearboxSetEfficiencyState(efficiency * simulation.GearboxGetEfficiency());
653 VehicleWheeledSimulation_SA simulation = VehicleWheeledSimulation_SA.Cast(
m_Simulation);
654 if (simulation && simulation.IsValid())
655 simulation.GearboxSetEfficiencyState(efficiency * simulation.GearboxGetEfficiency());
667 Physics physics =
GetOwner().GetPhysics();
671 array<HitZone> hitzones = {};
673 int count = GetAllHitZones(hitzones);
675 float maxDistanceSq = maxSharedDamageDistance * maxSharedDamageDistance;
677 array<string> hitzoneColliderNames = {};
678 vector closestPosition;
680 float distancePercent;
681 float currentDistance;
686 int hitzonesInRangeCount;
687 float hitzonesDistancePercentSum;
689 IEntity hitzoneParentEntity;
693 map<HitZone, float> hitzoneDistancePercentMap =
new map<HitZone, float>();
694 for (
int i = count - 1; i >= 0; i--)
696 hitzone = hitzones[i];
697 minDistance =
float.MAX;
698 colliderCount = hitzone.GetAllColliderNames(hitzoneColliderNames);
700 if (colliderCount == 0)
702 hitzoneContainer = hitzone.GetHitZoneContainer();
703 if (!hitzoneContainer || hitzoneContainer ==
this)
706 hitzoneParentEntity = hitzoneContainer.GetOwner();
707 hitzoneParentEntity.GetBounds(mins, maxs);
709 for (
int j = 0; j < 3; j++)
710 center[j] = mins[j] + Math.AbsFloat(((maxs[j] - mins[j]) * 0.5));
712 minDistance = vector.DistanceSq(
position, hitzoneParentEntity.CoordToParent(center));
716 for (
int y = colliderCount - 1; y >= 0; y--)
718 geomIndex = physics.GetGeom(hitzoneColliderNames[y]);
722 physics.GetGeomWorldTransform(geomIndex, mat);
723 currentDistance = vector.DistanceSq(
position, mat[3]);
725 if (currentDistance < minDistance)
727 minDistance = currentDistance;
728 closestPosition = mat[3];
733 if (minDistance > maxDistanceSq)
736 minDistance = Math.Sqrt(minDistance);
739 hitzonesInRangeCount++;
740 hitzonesDistancePercentSum += distancePercent;
741 hitzoneDistancePercentMap.Insert(hitzone, distancePercent);
744 float leftoverDamage = damage;
746 float currentDamagePercent;
748 float damageMultiplier;
753 empty[0] = vector.Zero;
754 empty[1] = vector.Zero;
755 empty[2] = vector.Zero;
757 for (
int i = hitzonesInRangeCount - 1; i >= 0; i--)
759 hitzone = hitzoneDistancePercentMap.GetKey(i);
760 distancePercent = hitzoneDistancePercentMap.Get(hitzone);
761 currentDamagePercent = distancePercent / hitzonesDistancePercentSum;
763 currentDamage = currentDamagePercent * damage;
769 hitzoneHealth = hitzone.GetHealth();
771 damageMultiplier = hitzone.GetDamageMultiplier(damageType) * hitzone.GetBaseDamageMultiplier();
772 if (damageMultiplier != 0)
773 currentDamage = Math.Clamp(currentDamage, 0, (hitzoneHealth + hitzone.GetDamageReduction()) / damageMultiplier);
780 damageManager.HandleDamage(damageContext);
782 leftoverDamage -= currentDamage;
785 leftoverDamage = Math.Clamp(leftoverDamage, 0,
float.MAX);
787 return leftoverDamage;
806 vector contact = owner.CoordToLocal(
position);
810 owner.GetBounds(mins, maxs);
813 vector bboxCenter = (maxs - mins) * 0.5 + mins;
816 contact = contact - bboxCenter;
820 vector normalXZA, normalXZB, normalYZA, normalYZB, normalXYA, normalXYB;
821 float distanceXZA, distanceXZB, distanceYZA, distanceYZB, distanceXYA, distanceXYB;
823 normalYZA = Vector(0, mins[2] - maxs[2], maxs[1] - mins[1]).Normalized();
824 distanceYZA = vector.Dot(normalYZA, Vector(0, mins[1], mins[2]));
826 normalYZB = Vector(0, mins[2] - maxs[2], mins[1] - maxs[1]).Normalized();
827 distanceYZB = vector.Dot(normalYZB, Vector(0, mins[1], mins[2]));
829 normalXZA = Vector(maxs[2] - mins[2], 0, mins[0] - maxs[0]).Normalized();
830 distanceXZA = vector.Dot(normalXZA, Vector(mins[0], 0, mins[2]));
832 normalXZB = Vector(mins[2] - maxs[2], 0, mins[0] - maxs[0]).Normalized();
833 distanceXZB = vector.Dot(normalXZB, Vector(mins[0], 0, mins[2]));
835 normalXYA = Vector(maxs[1] - mins[1], mins[0] - maxs[0], 0).Normalized();
836 distanceXYA = vector.Dot(normalXYA, Vector(mins[0], mins[1], 0));
838 normalXYB = Vector(mins[1] - maxs[1], mins[0] - maxs[0], 0).Normalized();
839 distanceXYB = vector.Dot(normalXYB, Vector(mins[0], mins[1], 0));
841 #ifdef VEHICLE_DAMAGE_DEBUG
846 m_aDebugShapes.Insert(Shape.Create(ShapeType.BBOX, ARGB(255, 0, 255, 255), ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, owner.CoordToParent(mins), owner.CoordToParent(maxs)));
847 m_aDebugShapes.Insert(Shape.CreateSphere(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME,
position, 0.2));
850 p[0] = owner.CoordToParent(bboxCenter);
851 p[1] = owner.CoordToParent(normalXZA);
852 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
854 p[1] = owner.CoordToParent(normalXZB);
855 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, p, 2));
857 p[1] = owner.CoordToParent(normalYZA);
858 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 0, 255), ShapeFlags.NOZBUFFER, p, 2));
860 p[1] = owner.CoordToParent(normalYZB);
861 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 255), ShapeFlags.NOZBUFFER, p, 2));
863 p[1] = owner.CoordToParent(normalXYA);
864 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 255, 255), ShapeFlags.NOZBUFFER, p, 2));
866 p[1] = owner.CoordToParent(normalXYB);
867 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
869 p[1] = owner.CoordToParent(contact);
870 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 155, 255), ShapeFlags.NOZBUFFER, p, 2));
872 #ifdef VEHICLE_DEBUG_OTHER
878 vector globalMins, globalMaxs;
879 globalMins = owner.CoordToParent(mins);
880 globalMaxs = owner.CoordToParent(maxs);
882 m_aDebugShapes.Insert(Shape.CreateSphere(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME,
position, 0.2));
907 p[1][1] = globalMaxs[1];
908 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
911 p[0][0] = globalMaxs[0];
913 p[1][1] = globalMaxs[1];
914 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
918 p[1][1] = globalMins[1];
919 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
922 p[0][0] = globalMins[0];
924 p[1][1] = globalMins[1];
925 m_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, p, 2));
928 Math3D.MatrixIdentity4(mat);
931 p[0][1] = maxs[1] * 0.5;
933 Shape shape = Shape.Create(ShapeType.PYRAMID, ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, p[1], p[0]);
935 mat[3] = owner.GetOrigin();
936 shape.SetMatrix(mat);
941 p[1][1] = p[1][1] * 0.5;
942 shape = Shape.Create(ShapeType.PYRAMID, ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, p[0], p[1]);
944 shape.SetMatrix(mat);
971 bool XZA, XZB, YZA, YZB, XYA, XYB;
972 XZA = (vector.Dot(contact, normalXZA) > 0) - distanceXZA;
973 XZB = (vector.Dot(contact, normalXZB) > 0) - distanceXZB;
974 YZA = (vector.Dot(contact, normalYZA) > 0) - distanceYZA;
975 YZB = (vector.Dot(contact, normalYZB) > 0) - distanceYZB;
976 XYA = (vector.Dot(contact, normalXYA) > 0) - distanceXYA;
977 XYB = (vector.Dot(contact, normalXYB) > 0) - distanceXYB;
994 if (XZA && !XZB && XYA && !XYB)
998 if (!XZA && XZB && !XYA && XYB)
1002 if (YZA && YZB && XYA && XYB)
1006 if (!YZA && !YZB && !XYA && !XYB)
1010 if (!XZA && !XZB && YZA && !YZB)
1014 if (XZA && XZB && !YZA && YZB)
1022 override array<ref WB_UIMenuItem> _WB_GetContextMenuItems(IEntity owner)
1024 array<ref WB_UIMenuItem> items = {
new WB_UIMenuItem(
"Compute collision damage", 0) };
1030 override void _WB_OnContextMenu(IEntity owner,
int id)
1040 WorldEditorAPI api = entity._WB_GetEditorAPI();
1044 array<HitZone> hitzones;
1046 hitzones.Insert(GetDefaultHitZone());
1048 float damage = GetMinDestroyDamage(
EDamageType.COLLISION, hitzones, count);
1053 Print(
"Cannot destroy selected vehicle on collision", LogLevel.WARNING);
1058 float targetFrontalDamage = Math.Ceil(damage / newFrontMultiplier);
1060 api.BeginEntityAction();
1062 IEntitySource ownerSource = api.EntityToSource(owner);
1063 IEntityComponentSource componentSource =
SCR_BaseContainerTools.FindComponentSource(ownerSource, Type().ToString());
1065 if (componentSource && componentSource.Set(
"m_fVehicleDestroyDamage", targetFrontalDamage.ToString()))
1066 Print(
"Entity instance's m_fVehicleDestroyDamage set to " + targetFrontalDamage.ToString(), LogLevel.WARNING);
1068 Print(
"Error setting m_fVehicleDestroyDamage set to " + targetFrontalDamage.ToString(), LogLevel.ERROR);
1070 api.EndEntityAction();
1078 override bool OnContact(IEntity owner, IEntity other, Contact contact)
1080 super.OnContact(owner, other, contact);
1085 ChimeraCharacter
char = ChimeraCharacter.Cast(other);
1090 charDamageMan.ContactDamage(other, owner, contact);
1102 bool CollisionDamage(notnull IEntity owner, notnull IEntity other, notnull Contact contact)
1113 Physics ownerPhysics = owner.GetPhysics();
1114 if (!ownerPhysics.IsDynamic())
1120 Physics otherPhysics = other.GetPhysics();
1123 float relativeForce = contact.Impulse / ownerPhysics.GetMass();
1127 int ownerResponseIndex = ownerPhysics.GetResponseIndex();
1128 int otherResponseIndex = otherPhysics.GetResponseIndex();
1129 if (otherPhysics && !otherPhysics.IsDynamic() && other.FindComponent(SCR_DestructionDamageManagerComponent) && otherResponseIndex - MIN_DESTRUCTION_RESPONSE_INDEX <= ownerResponseIndex - MIN_MOMENTUM_RESPONSE_INDEX)
1132 float ownerMass = owner.GetPhysics().GetMass();
1133 float otherMass = otherPhysics.GetMass();
1138 #ifdef DISABLE_VEHICLE_COLLISION_DAMAGE
1144 float momentumVehicleThreshold = ownerMass * m_fVehicleDamageSpeedThreshold * KM_PER_H_TO_M_PER_S;
1145 float momentumVehicleDestroy = ownerMass * m_fVehicleSpeedDestroy * KM_PER_H_TO_M_PER_S;
1146 float damageScaleToVehicle = m_fVehicleDestroyDamage / (momentumVehicleDestroy - momentumVehicleThreshold);
1153 Print(contact.Impulse, LogLevel.DEBUG);
1154 Print(contact.VelocityBefore1, LogLevel.DEBUG);
1158 float damageShare = 1;
1160 damageShare -= ownerMass / (ownerMass + otherMass);
1162 float DotMultiplier = vector.Dot(contact.VelocityAfter1.Normalized(), contact.VelocityBefore1.Normalized());
1163 float MomentumBefore = ownerMass * contact.VelocityBefore1.Length();
1164 float MomentumAfter = ownerMass * contact.VelocityAfter1.Length() * DotMultiplier;
1165 float momentumA = Math.AbsFloat(MomentumBefore - MomentumAfter);
1167 DotMultiplier = vector.Dot(contact.VelocityAfter2.Normalized(), contact.VelocityBefore2.Normalized());
1168 MomentumBefore = otherMass * contact.VelocityBefore2.Length();
1169 MomentumAfter = otherMass * contact.VelocityAfter2.Length() * DotMultiplier;
1170 float momentumB = Math.AbsFloat(MomentumBefore - MomentumAfter);
1172 float collisionDamage = damageScaleToVehicle * (momentumA + momentumB - momentumVehicleThreshold);
1173 IEntity instigatorEntity;
1181 float damageScaleToCharacter = APPROXIMATE_CHARACTER_LETHAL_DAMAGE / (momentumOccupantsDeath - momentumOccupantsThreshold);
1185 float momentumOverOccupantsThreshold = (momentumA + momentumB) * damageShare - momentumOccupantsThreshold;
1188 if (momentumOverOccupantsThreshold > 0)
1192 if (otherPhysics.IsDynamic() && contact.VelocityBefore1.LengthSq() > m_fVehicleDamageSpeedThreshold * m_fVehicleDamageSpeedThreshold)
1195 Vehicle otherVehicle = Vehicle.Cast(other);
1197 otherPilot = otherVehicle.GetPilot();
1206 vector directionToOther = (other.GetOrigin() - owner.GetOrigin()).Normalized();
1207 if (vector.Dot(contact.VelocityBefore1.Normalized(), directionToOther) < 0.5)
1208 instigatorEntity = otherPilot;
1213 if (!instigatorEntity && Vehicle.Cast(owner))
1214 instigatorEntity = Vehicle.Cast(owner).GetPilot();
1222 if (collisionDamage > 0)
1227 collisionDamage *= damageSideMultiplier * damageShare;
1230 empty[0] = vector.Zero;
1231 empty[1] = vector.Zero;
1232 empty[2] = vector.Zero;
1234 SCR_DamageContext damageContext =
new SCR_DamageContext(
EDamageType.COLLISION,
DamageSurroundingHitzones(contact.Position, collisionDamage,
EDamageType.COLLISION), empty,
GetOwner(), GetDefaultHitZone(),
Instigator.CreateInstigator(instigatorEntity),
null, -1, -1);
1236 HandleDamage(damageContext);
1249 if (!s_OnVehicleDestroyed)
1252 return s_OnVehicleDestroyed;
1259 super.OnDamageStateChanged(state);
1260 HitZone defaultHitZone = GetDefaultHitZone();
1261 if (!defaultHitZone)
1265 if (vehicleBuoyancy)
1266 vehicleBuoyancy.SetHealth(defaultHitZone.GetDamageStateThreshold(state));
1268 if (s_OnVehicleDestroyed && state ==
EDamageState.DESTROYED)
1269 s_OnVehicleDestroyed.Invoke(
GetInstigator().GetInstigatorPlayerID());
1277 BaseVehicleNodeComponent vehicleNode = BaseVehicleNodeComponent.Cast(
GetOwner().FindComponent(BaseVehicleNodeComponent));
1282 VehicleControllerComponent vehicleController = VehicleControllerComponent.Cast(vehicleNode.FindComponent(VehicleControllerComponent));
1283 if (vehicleController && vehicleController.GetEngineDrowned())
1288 VehicleControllerComponent_SA vehicleController = VehicleControllerComponent_SA.Cast(vehicleNode.FindComponent(VehicleControllerComponent_SA));
1289 if (vehicleController && vehicleController.GetEngineDrowned())
1294 return super.CanBeHealed();
1303 BaseVehicleNodeComponent vehicleNode = BaseVehicleNodeComponent.Cast(
GetOwner().FindComponent(BaseVehicleNodeComponent));
1308 VehicleControllerComponent vehicleController = VehicleControllerComponent.Cast(vehicleNode.FindComponent(VehicleControllerComponent));
1309 if (vehicleController && vehicleController.GetEngineDrowned())
1310 vehicleController.SetEngineDrowned(
false);
1314 VehicleControllerComponent_SA vehicleController = VehicleControllerComponent_SA.Cast(vehicleNode.FindComponent(VehicleControllerComponent_SA));
1315 if (vehicleController && vehicleController.GetEngineDrowned())
1316 vehicleController.SetEngineDrowned(
false);
1322 super.FullHeal(ignoreHealingDOT);
1330 Physics physics =
GetOwner().GetPhysics();
1334 float momentum = physics.GetMass() * physics.GetVelocity().Length();
1335 float currentIndexMinMomentum = s_mResponseIndexMomentumMap.Get(physics.GetResponseIndex());
1336 int currentIndex = physics.GetResponseIndex();
1341 currentIndexMinMomentum = s_mResponseIndexMomentumMap.Get(currentIndex);
1342 if (momentum < currentIndexMinMomentum)
1346 currentIndexMinMomentum = s_mResponseIndexMomentumMap.Get(currentIndex);
1354 currentIndexMinMomentum = s_mResponseIndexMomentumMap.Get(currentIndex);
1355 if (momentum > currentIndexMinMomentum)
1359 physics.SetResponseIndex(currentIndex);
1363 [
RplRpc(RplChannel.Reliable, RplRcver.Server)]
1387 Vehicle vehicle = Vehicle.Cast(owner);
1391 RplComponent rplComponent = vehicle.GetRplComponent();
1397 if (rplComponent.IsProxy() && !rplComponent.IsOwner())
1403 else if (rplComponent.IsOwner() || !rplComponent.IsProxy())
1410 if (rplComponent.IsProxy())
1416 else if (rplComponent.IsOwner())
1474 Replication.BumpMe();
1496 Replication.BumpMe();
1518 Replication.BumpMe();
1526 vector averagePosition = GetSecondaryExplosionPosition(SCR_FlammableHitZone, fireRate);
1532 EntitySpawnParams spawnParams();
1533 spawnParams.Transform[3] = averagePosition;
1534 ResourceName fireDamage = GetSecondaryExplosion(fireRate, SCR_ESecondaryExplosionType.FUEL, fire:
true);
1535 SecondaryExplosion(fireDamage,
GetInstigator(), spawnParams);
1567 vector averagePosition = GetSecondaryExplosionPosition(
SCR_FuelHitZone, burningFuel);
1568 if (
float.AlmostEqual(burningFuel, 0))
1579 EntitySpawnParams spawnParams();
1580 spawnParams.Transform[3] = averagePosition;
1581 ResourceName fireDamage = GetSecondaryExplosion(burningFuel / fireRate, SCR_ESecondaryExplosionType.FUEL, fire:
true);
1582 SecondaryExplosion(fireDamage,
GetInstigator(), spawnParams);
1586 fuelBurnRate = fireRate * m_fSecondaryFireDamageDelay * m_fFuelTankFireDamageRate;
1590 if (fuelBurnRate > 0)
1592 SCR_FuelNode fuelTank;
1594 array<BaseFuelNode> fuelTanks = {};
1598 fuelTank = SCR_FuelNode.Cast(fuelNode);
1603 fuelLoss = fuelBurnRate * (1 - fuelTank.GetHealth()) * fuelNode.GetFuel() / burningFuel;
1605 fuelTank.SetFuel(fuelTank.GetFuel() - fuelLoss);
1635 float totalResources = encapsulator.GetAggregatedResourceValue();
1636 if (totalResources <= 0)
1643 int containerCount = encapsulator.GetContainerCount();
1649 vector averagePosition =
GetOwner().CoordToLocal(encapsulator.GetOwnerOrigin());
1652 for (
int i; i < containerCount; i++)
1654 container = containerQueue.GetContainerAt(i);
1659 weight = container.GetResourceValue() / totalResources;
1664 averagePosition +=
position * weight;
1671 float suppliesDamage;
1676 EntitySpawnParams spawnParams();
1677 spawnParams.Transform[3] = averagePosition;
1678 ResourceName fireDamage = GetSecondaryExplosion(fireRate, SCR_ESecondaryExplosionType.RESOURCE, fire:
true);
1679 SecondaryExplosion(fireDamage,
GetInstigator(), spawnParams);
1683 suppliesDamage = Math.Ceil(fireRate * m_fSecondaryFireDamageDelay * m_fSuppliesFireDamageRate);
1686 if (containerCount > 1)
1687 suppliesDamage /= containerCount;
1689 for (
int i; i < containerCount; i++)
1691 container = containerQueue.GetContainerAt(i);
1693 container.DecreaseResourceValue(suppliesDamage);
1723 Vehicle ownerVehicle = Vehicle.Cast(ent);