private Vector3D PlaceDecal() { Vector3D explosionPoint = m_collisionPoint.Value; MyHitInfo hitInfo = new MyHitInfo() { Position = explosionPoint, Normal = m_collisionNormal }; MyDecals.HandleAddDecal(m_collidedEntity, hitInfo, this.m_missileAmmoDefinition.PhysicalMaterial); return(explosionPoint); }
// 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); }
private void DoDamage(float damage, MyHitInfo hitInfo, object customdata, IMyEntity damagedEntity) { //damage tracking MyEntity ent = (MyEntity)MySession.Static.ControlledEntity; if (this.OwnerEntityAbsolute != null && this.OwnerEntityAbsolute.Equals(MySession.Static.ControlledEntity) && (damagedEntity is IMyDestroyableObject || damagedEntity is MyCubeGrid)) { MySession.Static.TotalDamageDealt += (uint)damage; } MyDecals.HandleAddDecal(damagedEntity, hitInfo, m_projectileAmmoDefinition.PhysicalMaterial, customdata, damage); if (!Sync.IsServer) { return; } if (m_projectileAmmoDefinition.PhysicalMaterial == m_hashBolt) { IMyDestroyableObject destroyable = damagedEntity as IMyDestroyableObject; if (destroyable != null && damagedEntity is MyCharacter) { destroyable.DoDamage(damage, MyDamageType.Bolt, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); } } else { var grid = damagedEntity as MyCubeGrid; IMyDestroyableObject destroyable; if (grid != null) { if (grid.Physics != null && grid.Physics.Enabled && (grid.BlocksDestructionEnabled || MyFakes.ENABLE_VR_FORCE_BLOCK_DESTRUCTIBLE)) { bool causeDeformation = false; var block = grid.GetTargetedBlock(hitInfo.Position); if (block != null && (grid.BlocksDestructionEnabled || block.ForceBlockDestructible)) { block.DoDamage(damage, MyDamageType.Bullet, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); if (block.FatBlock == null) { causeDeformation = true; } } if (grid.BlocksDestructionEnabled && causeDeformation) { ApllyDeformationCubeGrid(hitInfo.Position, grid); } } } //By Gregory: When MyEntitySubpart (e.g. extended parts of pistons and doors) damage the whole parent component //Temporary fix! Maybe other solution? MyEntitySubpart cannot implement IMyDestroyableObject cause is on dependent namespace else if (damagedEntity is MyEntitySubpart) { if (damagedEntity.Parent != null && damagedEntity.Parent.Parent is MyCubeGrid) { hitInfo.Position = damagedEntity.Parent.WorldAABB.Center; DoDamage(damage, hitInfo, customdata, damagedEntity.Parent.Parent); } } else if ((destroyable = damagedEntity as IMyDestroyableObject) != null) { destroyable.DoDamage(damage, MyDamageType.Bullet, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); } } //Handle damage ?? some WIP code by Ondrej //MyEntity damagedObject = entity; //damagedObject.DoDamage(m_ammoProperties.HealthDamage, m_ammoProperties.ShipDamage, m_ammoProperties.EMPDamage, m_ammoProperties.DamageType, m_ammoProperties.AmmoType, m_ignorePhysObject); //if (MyMultiplayerGameplay.IsRunning) // MyMultiplayerGameplay.Static.ProjectileHit(damagedObject, intersectionValue.IntersectionPointInWorldSpace, this.m_directionNormalized, MyAmmoConstants.FindAmmo(m_ammoProperties), this.OwnerEntity); }
/// <summary> /// Updates resource. /// </summary> public override void UpdateBeforeSimulation() { try { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("MyMissile.UpdateBeforeSimulation"); if (m_isExploded) { if (Sandbox.Game.Multiplayer.Sync.IsServer) { // Create explosion float radius = m_missileAmmoDefinition.MissileExplosionRadius; BoundingSphereD explosionSphere = new BoundingSphereD(m_collisionPoint.HasValue ? m_collisionPoint.Value : PositionComp.GetPosition(), radius); MyEntity ownerEntity = null; var ownerId = Sync.Players.TryGetIdentity(m_owner); if (ownerId != null) { ownerEntity = ownerId.Character; } //MyEntities.TryGetEntityById(m_owner, out ownerEntity); // Call main explosion starter MyExplosionInfo info = new MyExplosionInfo() { PlayerDamage = 0, //Damage = m_ammoProperties.Damage, Damage = MyFakes.ENABLE_VOLUMETRIC_EXPLOSION ? m_missileAmmoDefinition.MissileExplosionDamage : 200, ExplosionType = m_explosionType, ExplosionSphere = explosionSphere, LifespanMiliseconds = MyExplosionsConstants.EXPLOSION_LIFESPAN, CascadeLevel = CascadedExplosionLevel, HitEntity = m_collidedEntity, ParticleScale = 0.2f, OwnerEntity = ownerEntity, Direction = WorldMatrix.Forward, VoxelExplosionCenter = explosionSphere.Center + radius * WorldMatrix.Forward * 0.25f, ExplosionFlags = MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.CREATE_DEBRIS | MyExplosionFlags.CREATE_DECALS | MyExplosionFlags.CREATE_SHRAPNELS | MyExplosionFlags.APPLY_DEFORMATION, VoxelCutoutScale = 0.3f, PlaySound = true, ApplyForceAndDamage = true }; if (!MarkedToDestroy) { info.ExplosionFlags |= MyExplosionFlags.CREATE_PARTICLE_EFFECT; } MyExplosions.AddExplosion(ref info); if (m_collidedEntity != null && !(m_collidedEntity is MyAmmoBase)) { if (!m_collidedEntity.Physics.IsStatic) { m_collidedEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, 100 * Physics.LinearVelocity, m_collisionPoint, null); } } } //by Gregory: added null check. Decal won't be added if m_collidedEntity not found if (m_collisionPoint.HasValue && m_collidedEntity != null) { MyHitInfo hitInfo = new MyHitInfo(); hitInfo.Position = m_collisionPoint.Value; hitInfo.Normal = new Vector3D(1, 0, 0); // FIXME MyDecals.HandleAddDecal(m_collidedEntity, hitInfo, MyDamageType.Rocket); } Close(); return; } base.UpdateBeforeSimulation(); if (m_missileAmmoDefinition.MissileSkipAcceleration) { Physics.LinearVelocity = WorldMatrix.Forward * m_missileAmmoDefinition.DesiredSpeed * 0.7f; } else { Physics.LinearVelocity += PositionComp.WorldMatrix.Forward * m_missileAmmoDefinition.MissileAcceleration * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS; } if (m_smokeEffect == null) { // if (MyCamera.GetDistanceWithFOV(GetPosition()) < 150) { if (MyParticlesManager.TryCreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_Missile, out m_smokeEffect)) { m_smokeEffect.UserScale = 0.3f; var matrix = PositionComp.WorldMatrix; matrix.Translation -= matrix.Forward * m_smokeEffectOffsetMultiplier; m_smokeEffect.WorldMatrix = matrix; //m_smokeEffect.WorldMatrix = PositionComp.WorldMatrix; m_smokeEffect.AutoDelete = false; m_smokeEffect.CalculateDeltaMatrix = true; } } } Physics.AngularVelocity = Vector3.Zero; if ((Vector3.Distance(PositionComp.GetPosition(), m_origin) >= m_maxTrajectory)) { Explode(); return; } } finally { VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } }
public override void UpdateAfterSimulation() { base.UpdateAfterSimulation(); bool isShooting = IsShooting; if (!m_isHit && IsShooting && (MySandboxGame.Static.UpdateTime - m_lastShot > MyTimeSpan.FromSeconds(m_shotToolAction.Value.HitStart))) { IMyHandToolComponent toolComponent; if (m_toolComponents.TryGetValue(m_shotHitCondition.Component, out toolComponent)) { MyCharacterDetectorComponent detectorComponent = m_owner.Components.Get <MyCharacterDetectorComponent>(); if (detectorComponent != null) { if (m_shotToolAction.Value.CustomShapeRadius > 0 && detectorComponent is MyCharacterShapecastDetectorComponent) { var shapeCastComponent = detectorComponent as MyCharacterShapecastDetectorComponent; shapeCastComponent.ShapeRadius = m_shotToolAction.Value.CustomShapeRadius; shapeCastComponent.DoDetectionModel(); shapeCastComponent.ShapeRadius = MyCharacterShapecastDetectorComponent.DEFAULT_SHAPE_RADIUS; } if (detectorComponent.DetectedEntity != null) { MyHitInfo hitInfo = new MyHitInfo(); hitInfo.Position = detectorComponent.HitPosition; hitInfo.Normal = detectorComponent.HitNormal; bool isBlock = false; float efficiencyMultiplier = 1.0f; bool canHit = CanHit(toolComponent, detectorComponent, ref isBlock, out efficiencyMultiplier); MyDecals.HandleAddDecal(detectorComponent.DetectedEntity, hitInfo, MyDamageType.Weapon); bool isHit = false; if (canHit) { if (!string.IsNullOrEmpty(m_shotToolAction.Value.StatsEfficiency) && Owner.StatComp != null) { efficiencyMultiplier *= Owner.StatComp.GetEfficiencyModifier(m_shotToolAction.Value.StatsEfficiency); } float efficiency = m_shotToolAction.Value.Efficiency * efficiencyMultiplier; var tool = detectorComponent.DetectedEntity as MyHandToolBase; if (isBlock && tool != null) { isHit = toolComponent.Hit(tool.Owner, hitInfo, detectorComponent.ShapeKey, efficiency); } else { isHit = toolComponent.Hit((MyEntity)detectorComponent.DetectedEntity, hitInfo, detectorComponent.ShapeKey, efficiency); } if (isHit && Sync.IsServer && Owner.StatComp != null) { if (!string.IsNullOrEmpty(m_shotHitCondition.StatsActionIfHit)) { Owner.StatComp.DoAction(m_shotHitCondition.StatsActionIfHit); } if (!string.IsNullOrEmpty(m_shotHitCondition.StatsModifierIfHit)) { Owner.StatComp.ApplyModifier(m_shotHitCondition.StatsModifierIfHit); } } } if (canHit || isBlock) // real hit is not controlled now - there isn't any server-client synchronization of hit currently and hit is performed only at server { if (!string.IsNullOrEmpty(m_shotToolAction.Value.HitSound)) { PlaySound(m_shotToolAction.Value.HitSound); } else { MyStringId collisionType = MyMaterialPropertiesHelper.CollisionType.Hit; bool showParticles = false; // If it didn't play the Sound with "Hit", it will try with "Start" if (MyAudioComponent.PlayContactSound(EntityId, m_hitCue, detectorComponent.HitPosition, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial)) { showParticles = true; } else if (MyAudioComponent.PlayContactSound(EntityId, m_startCue, detectorComponent.HitPosition, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial)) { showParticles = true; collisionType = MyMaterialPropertiesHelper.CollisionType.Start; } if (showParticles) { MyMaterialPropertiesHelper.Static.TryCreateCollisionEffect( collisionType, detectorComponent.HitPosition, detectorComponent.HitNormal, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial); } } this.RaiseEntityEvent(MyStringHash.GetOrCompute("Hit"), new MyEntityContainerEventExtensions.HitParams(MyStringHash.GetOrCompute(m_shotHitCondition.Component), detectorComponent.HitMaterial)); m_soundEmitter.StopSound(true); } } } } m_isHit = true; } if (!m_swingSoundPlayed && IsShooting && !m_isHit && (MySandboxGame.Static.UpdateTime - m_lastShot > MyTimeSpan.FromSeconds(m_shotToolAction.Value.SwingSoundStart))) { if (!string.IsNullOrEmpty(m_shotToolAction.Value.SwingSound)) { PlaySound(m_shotToolAction.Value.SwingSound); } m_swingSoundPlayed = true; } if (!isShooting && m_wasShooting) { m_owner.StopUpperCharacterAnimation(0.4f); m_shotToolAction = null; } m_wasShooting = isShooting; if (m_owner != null) { MatrixD blockingMatrix = MatrixD.CreateWorld(((MyEntity)m_owner.CurrentWeapon).PositionComp.GetPosition(), m_owner.WorldMatrix.Forward, m_owner.WorldMatrix.Up); ((MyBlockingBody)Physics).SetWorldMatrix(blockingMatrix); } foreach (var c in m_toolComponents.Values) { c.Update(); } }