// Update position, check collisions, etc. // Return false if projectile dies/timeouts in this tick. public bool Update() { // Projectile was killed , but still not last time drawn, so we don't need to do update (we are waiting for last draw) if (m_state == MyProjectileStateEnum.KILLED) { return(true); } // Projectile was killed and last time drawn, so we can finally remove it from buffer if (m_state == MyProjectileStateEnum.KILLED_AND_DRAWN) { StopEffect(); return(false); } Vector3D position = m_position; m_position += m_velocity * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS * MyFakes.SIMULATION_SPEED; // Distance timeout Vector3 positionDelta = m_position - m_origin; if (Vector3.Dot(positionDelta, positionDelta) >= m_maxTrajectory * m_maxTrajectory) { StopEffect(); m_state = MyProjectileStateEnum.KILLED; return(true); } m_checkIntersectionIndex = ++m_checkIntersectionIndex % CHECK_INTERSECTION_INTERVAL; if (m_checkIntersectionIndex != 0 && m_positionChecked) //check only each n-th intersection { return(true); } // Calculate hit point, create decal and throw debris particles Vector3D lineEndPosition = position + CHECK_INTERSECTION_INTERVAL * (m_velocity * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS * MyFakes.SIMULATION_SPEED); LineD line = new LineD(m_positionChecked ? position : m_origin, lineEndPosition); m_positionChecked = true; IMyEntity entity; MyHitInfo hitInfo; object customdata; GetHitEntityAndPosition(line, out entity, out hitInfo, out customdata); if (entity == null || entity.Physics == null) { return(true); } if (IsIgnoredEntity(entity)) { return(true); // prevent player shooting himself } ProfilerShort.Begin("Projectile.Update"); bool headShot = false; MyCharacter hitCharacter = entity as MyCharacter; if (hitCharacter != null) { IStoppableAttackingTool stoppableTool = hitCharacter.CurrentWeapon as IStoppableAttackingTool; if (stoppableTool != null) { stoppableTool.StopShooting(OwnerEntity); } headShot = (customdata as MyCharacterHitInfo).HitHead && m_projectileAmmoDefinition.HeadShot; // allow head shots only for ammo supporting it in definition } m_position = hitInfo.Position; bool isProjectileGroupKilled = false; if (!isProjectileGroupKilled) { MySurfaceImpactEnum surfaceImpact; MyStringHash materialType; GetSurfaceAndMaterial(entity, ref line, ref hitInfo.Position, out surfaceImpact, out materialType); PlayHitSound(materialType, entity, hitInfo.Position, m_projectileAmmoDefinition.PhysicalMaterial); hitInfo.Velocity = m_velocity; float damage = entity is IMyCharacter ? (headShot ? m_projectileAmmoDefinition.ProjectileHeadShotDamage : m_projectileAmmoDefinition.ProjectileHealthDamage) : m_projectileAmmoDefinition.ProjectileMassDamage; DoDamage(damage, hitInfo, customdata, entity); MyDecals.HandleAddDecal(entity, hitInfo, materialType, m_projectileAmmoDefinition.PhysicalMaterial, (customdata as MyCharacterHitInfo), damage); //particle effect defined in materialProperties.sbc Vector3D particleHitPosition = hitInfo.Position + (Vector3D)line.Direction * -0.2; bool createdEffect = MyMaterialPropertiesHelper.Static.TryCreateCollisionEffect(MyMaterialPropertiesHelper.CollisionType.Hit, particleHitPosition, hitInfo.Normal, m_projectileAmmoDefinition.PhysicalMaterial, materialType); if (!createdEffect && surfaceImpact != MySurfaceImpactEnum.CHARACTER) { MyParticleEffects.CreateBasicHitParticles(m_projectileAmmoDefinition.ProjectileOnHitEffectName, ref hitInfo.Position, ref hitInfo.Normal, ref line.Direction, entity, m_weapon, 1, OwnerEntity); } CreateDecal(materialType); if (m_weapon == null || (entity.GetTopMostParent() != m_weapon.GetTopMostParent())) { ApplyProjectileForce(entity, hitInfo.Position, m_directionNormalized, false, m_projectileAmmoDefinition.ProjectileHitImpulse * m_impulseMultiplier); } StopEffect(); m_state = MyProjectileStateEnum.KILLED; } ProfilerShort.End(); return(true); }
// Update position, check collisions, etc. // Return false if projectile dies/timeouts in this tick. public bool Update() { // Projectile was killed , but still not last time drawn, so we don't need to do update (we are waiting for last draw) if (m_state == MyProjectileStateEnum.KILLED) { return(true); } // Projectile was killed and last time drawn, so we can finally remove it from buffer if (m_state == MyProjectileStateEnum.KILLED_AND_DRAWN) { StopEffect(); return(false); } Vector3D position = m_position; m_position += m_velocity * MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS; // Distance timeout Vector3 positionDelta = m_position - m_origin; if (Vector3.Dot(positionDelta, positionDelta) >= m_maxTrajectory * m_maxTrajectory) { StopEffect(); m_state = MyProjectileStateEnum.KILLED; return(true); } m_checkIntersectionIndex = ++m_checkIntersectionIndex % CHECK_INTERSECTION_INTERVAL; if (m_checkIntersectionIndex != 0 && m_positionChecked) //check only each n-th intersection { return(true); } // Calculate hit point, create decal and throw debris particles Vector3D lineEndPosition = position + CHECK_INTERSECTION_INTERVAL * (m_velocity * MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); LineD line = new LineD(m_positionChecked ? position : m_origin, lineEndPosition); m_positionChecked = true; IMyEntity entity; Vector3D hitPosition; Vector3 hitNormal; bool headShot; GetHitEntityAndPosition(line, out entity, out hitPosition, out hitNormal, out headShot); if (entity == null || entity == m_ignoreEntity || entity.Physics == null) { return(true); } ProfilerShort.Begin("Projectile.Update"); { MyCharacter hitCharacter = entity as MyCharacter; if (hitCharacter != null) { IStoppableAttackingTool stoppableTool = hitCharacter.CurrentWeapon as IStoppableAttackingTool; if (stoppableTool != null) { stoppableTool.StopShooting(OwnerEntity); } } } m_position = hitPosition; bool isProjectileGroupKilled = false; if (!isProjectileGroupKilled) { MySurfaceImpactEnum surfaceImpact; MyStringHash materialType; GetSurfaceAndMaterial(entity, ref hitPosition, out surfaceImpact, out materialType); PlayHitSound(materialType, entity, hitPosition); DoDamage(headShot ? m_projectileAmmoDefinition.ProjectileHeadShotDamage : m_projectileAmmoDefinition.ProjectileMassDamage, hitPosition, entity); // Create smoke and debris particle at the place of voxel/model hit if (surfaceImpact != MySurfaceImpactEnum.CHARACTER) { m_projectileAmmoDefinition.ProjectileOnHitParticles(ref hitPosition, ref hitNormal, ref line.Direction, entity, m_weapon, 1, OwnerEntity); } m_projectileAmmoDefinition.ProjectileOnHitMaterialParticles(ref hitPosition, ref hitNormal, ref line.Direction, entity, surfaceImpact, m_weapon, 1); CreateDecal(materialType); if (m_weapon == null || (entity.GetTopMostParent() != m_weapon.GetTopMostParent())) { ApplyProjectileForce(entity, hitPosition, m_directionNormalized, false, m_projectileAmmoDefinition.ProjectileHitImpulse * m_impulseMultiplier); } StopEffect(); m_state = MyProjectileStateEnum.KILLED; } ProfilerShort.End(); return(true); }