partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull) { if (shockwave) { GameMain.ParticleManager.CreateParticle("shockwave", worldPosition, Vector2.Zero, 0.0f, hull); } hull = hull ?? Hull.FindHull(worldPosition, useWorldCoordinates: true); bool underwater = hull == null || worldPosition.Y < hull.WorldSurface; if (underwater && underwaterBubble) { var underwaterExplosion = GameMain.ParticleManager.CreateParticle("underwaterexplosion", worldPosition, Vector2.Zero, 0.0f, hull); if (underwaterExplosion != null) { underwaterExplosion.Size *= MathHelper.Clamp(attack.Range / 150.0f, 0.5f, 10.0f); underwaterExplosion.StartDelay = 0.0f; } } for (int i = 0; i < attack.Range * 0.1f; i++) { if (!underwater) { float particleSpeed = Rand.Range(0.0f, 1.0f); particleSpeed = particleSpeed * particleSpeed * attack.Range; if (flames) { float particleScale = MathHelper.Clamp(attack.Range * 0.0025f, 0.5f, 2.0f); var flameParticle = GameMain.ParticleManager.CreateParticle("explosionfire", ClampParticlePos(worldPosition + Rand.Vector((float)System.Math.Sqrt(Rand.Range(0.0f, attack.Range))), hull), Rand.Vector(Rand.Range(0.0f, particleSpeed)), 0.0f, hull); if (flameParticle != null) { flameParticle.Size *= particleScale; } } if (smoke) { var smokeParticle = GameMain.ParticleManager.CreateParticle(Rand.Range(0.0f, 1.0f) < 0.5f ? "explosionsmoke" : "smoke", ClampParticlePos(worldPosition + Rand.Vector((float)System.Math.Sqrt(Rand.Range(0.0f, attack.Range))), hull), Rand.Vector(Rand.Range(0.0f, particleSpeed)), 0.0f, hull); } } else if (underwaterBubble) { Vector2 bubblePos = Rand.Vector(Rand.Range(0.0f, attack.Range * 0.5f)); GameMain.ParticleManager.CreateParticle("risingbubbles", worldPosition + bubblePos, Vector2.Zero, 0.0f, hull); if (i < attack.Range * 0.02f) { var underwaterExplosion = GameMain.ParticleManager.CreateParticle("underwaterexplosion", worldPosition + bubblePos, Vector2.Zero, 0.0f, hull); if (underwaterExplosion != null) { underwaterExplosion.Size *= MathHelper.Clamp(attack.Range / 300.0f, 0.5f, 2.0f) * Rand.Range(0.8f, 1.2f); } } } if (sparks) { GameMain.ParticleManager.CreateParticle("spark", worldPosition, Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f, hull); } } if (hull != null && !string.IsNullOrWhiteSpace(decal) && decalSize > 0.0f) { hull.AddDecal(decal, worldPosition, decalSize); } if (flash) { float displayRange = attack.Range; if (displayRange < 0.1f) { return; } var light = new LightSource(worldPosition, displayRange, Color.LightYellow, null); CoroutineManager.StartCoroutine(DimLight(light)); } }
private void GenerateLocations() { Voronoi voronoi = new Voronoi(0.5f); List <Vector2> sites = new List <Vector2>(); for (int i = 0; i < 100; i++) { sites.Add(new Vector2(Rand.Range(0.0f, size, Rand.RandSync.Server), Rand.Range(0.0f, size, Rand.RandSync.Server))); } List <GraphEdge> edges = voronoi.MakeVoronoiGraph(sites, size, size); sites.Clear(); foreach (GraphEdge edge in edges) { if (edge.point1 == edge.point2) { continue; } //remove points from the edge of the map if (edge.point1.X == 0 || edge.point1.X == size) { continue; } if (edge.point1.Y == 0 || edge.point1.Y == size) { continue; } if (edge.point2.X == 0 || edge.point2.X == size) { continue; } if (edge.point2.Y == 0 || edge.point2.Y == size) { continue; } Location[] newLocations = new Location[2]; newLocations[0] = locations.Find(l => l.MapPosition == edge.point1 || l.MapPosition == edge.point2); newLocations[1] = locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.point1 || l.MapPosition == edge.point2)); for (int i = 0; i < 2; i++) { if (newLocations[i] != null) { continue; } Vector2[] points = new Vector2[] { edge.point1, edge.point2 }; int positionIndex = Rand.Int(1, Rand.RandSync.Server); Vector2 position = points[positionIndex]; if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; } newLocations[i] = Location.CreateRandom(position); locations.Add(newLocations[i]); } //int seed = (newLocations[0].GetHashCode() | newLocations[1].GetHashCode()); connections.Add(new LocationConnection(newLocations[0], newLocations[1])); } //remove connections that are too short float minDistance = 50.0f; for (int i = connections.Count - 1; i >= 0; i--) { LocationConnection connection = connections[i]; if (Vector2.Distance(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minDistance) { continue; } locations.Remove(connection.Locations[0]); connections.Remove(connection); foreach (LocationConnection connection2 in connections) { if (connection2.Locations[0] == connection.Locations[0]) { connection2.Locations[0] = connection.Locations[1]; } if (connection2.Locations[1] == connection.Locations[0]) { connection2.Locations[1] = connection.Locations[1]; } } } foreach (LocationConnection connection in connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); } for (int i = connections.Count - 1; i >= 0; i--) { i = Math.Min(i, connections.Count - 1); LocationConnection connection = connections[i]; for (int n = Math.Min(i - 1, connections.Count - 1); n >= 0; n--) { if (connection.Locations.Contains(connections[n].Locations[0]) && connection.Locations.Contains(connections[n].Locations[1])) { connections.RemoveAt(n); } } } foreach (LocationConnection connection in connections) { Vector2 start = connection.Locations[0].MapPosition; Vector2 end = connection.Locations[1].MapPosition; int generations = (int)(Math.Sqrt(Vector2.Distance(start, end) / 10.0f)); connection.CrackSegments = MathUtils.GenerateJaggedLine(start, end, generations, 5.0f); } AssignBiomes(); }
private void HandleLevelCollision(Contact contact, Vector2 collisionNormal) { float wallImpact = Vector2.Dot(Velocity, -collisionNormal); ApplyImpact(wallImpact, -collisionNormal, contact); foreach (Submarine dockedSub in submarine.DockedTo) { dockedSub.SubBody.ApplyImpact(wallImpact, -collisionNormal, contact); } #if CLIENT Vector2 n; FixedArray2 <Vector2> particlePos; contact.GetWorldManifold(out n, out particlePos); int particleAmount = (int)Math.Min(wallImpact * 10.0f, 50); for (int i = 0; i < particleAmount; i++) { GameMain.ParticleManager.CreateParticle("iceshards", ConvertUnits.ToDisplayUnits(particlePos[0]) + Rand.Vector(Rand.Range(1.0f, 50.0f)), Rand.Vector(Rand.Range(50.0f, 500.0f)) + Velocity); } #endif }
partial void ApplyProjSpecific(float deltaTime, Entity entity, IEnumerable <ISerializableEntity> targets, Hull hull, Vector2 worldPosition, bool playSound) { if (entity == null) { return; } if (sounds.Count > 0 && playSound) { if (soundChannel == null || !soundChannel.IsPlaying) { if (soundSelectionMode == SoundSelectionMode.All) { foreach (RoundSound sound in sounds) { if (sound?.Sound == null) { string errorMsg = $"Error in StatusEffect.ApplyProjSpecific1 (sound \"{sound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace(); GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } soundChannel = SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, hullGuess: hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } else { int selectedSoundIndex; if (soundSelectionMode == SoundSelectionMode.ItemSpecific && entity is Item item) { selectedSoundIndex = item.ID % sounds.Count; } else if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && entity is Character user) { selectedSoundIndex = user.ID % sounds.Count; } else { selectedSoundIndex = Rand.Int(sounds.Count); } var selectedSound = sounds[selectedSoundIndex]; if (selectedSound?.Sound == null) { string errorMsg = $"Error in StatusEffect.ApplyProjSpecific2 (sound \"{selectedSound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace(); GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } if (selectedSound.Sound.Disposed) { Submarine.ReloadRoundSound(selectedSound); } soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, worldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } else { soundChannel.Position = new Vector3(worldPosition, 0.0f); } if (soundChannel != null && soundChannel.Looping) { ActiveLoopingSounds.Add(this); soundEmitter = entity; loopStartTime = Timing.TotalTime; } } foreach (ParticleEmitter emitter in particleEmitters) { float angle = 0.0f; float particleRotation = 0.0f; if (emitter.Prefab.CopyEntityAngle) { Limb targetLimb = null; if (entity is Item item && item.body != null) { angle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi); particleRotation = -item.body.Rotation; if (item.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; } } else if (entity is Character c && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType l) { targetLimb = c.AnimController.GetLimb(l); }
partial void UpdateProjSpecific(float growModifier) { if (hull.FireSources.Any(fs => fs != this && fs.size.X > size.X)) { if (basicSoundIndex > 0) { Sounds.SoundManager.Stop(basicSoundIndex); basicSoundIndex = -1; } if (largeSoundIndex > 0) { Sounds.SoundManager.Stop(largeSoundIndex); largeSoundIndex = -1; } } else { if (fireSoundBasic != null) { basicSoundIndex = fireSoundBasic.Loop(basicSoundIndex, Math.Min(size.X / 100.0f, 1.0f), WorldPosition + size / 2.0f, 1000.0f); } if (fireSoundLarge != null) { largeSoundIndex = fireSoundLarge.Loop(largeSoundIndex, MathHelper.Clamp((size.X - 200.0f) / 100.0f, 0.0f, 1.0f), WorldPosition + size / 2.0f, 1000.0f); } } float count = Rand.Range(0.0f, size.X / 50.0f); for (int i = 0; i < count; i++) { Vector2 particlePos = new Vector2( WorldPosition.X + Rand.Range(0.0f, size.X), Rand.Range(WorldPosition.Y - size.Y, WorldPosition.Y + 20.0f)); Vector2 particleVel = new Vector2( (particlePos.X - (WorldPosition.X + size.X / 2.0f)), (float)Math.Sqrt(size.X) * Rand.Range(0.0f, 15.0f) * growModifier); var particle = GameMain.ParticleManager.CreateParticle("flame", particlePos, particleVel, 0.0f, hull); if (particle == null) { continue; } //make some of the particles create another firesource when they enter another hull if (Rand.Int(20) == 1) { particle.OnChangeHull = OnChangeHull; } particle.Size *= MathHelper.Clamp(size.X / 60.0f * Math.Max(hull.Oxygen / hull.FullVolume, 0.4f), 0.5f, 1.0f); if (Rand.Int(5) == 1) { var smokeParticle = GameMain.ParticleManager.CreateParticle("smoke", particlePos, new Vector2(particleVel.X, particleVel.Y * 0.1f), 0.0f, hull); if (smokeParticle != null) { smokeParticle.Size *= MathHelper.Clamp(size.X / 100.0f * Math.Max(hull.Oxygen / hull.FullVolume, 0.4f), 0.5f, 1.0f); } } } lightSource.Range = Math.Max(size.X, size.Y) * 10.0f / 2.0f; lightSource.Color = new Color(1.0f, 0.45f, 0.3f) * Rand.Range(0.8f, 1.0f); lightSource.Position = position + Vector2.UnitY * 30.0f; if (size.X > 256.0f) { if (burnDecals.Count == 0) { var newDecal = hull.AddDecal("burnt", WorldPosition + size / 2); if (newDecal != null) { burnDecals.Add(newDecal); } } else if (WorldPosition.X < burnDecals[0].WorldPosition.X - 256.0f) { var newDecal = hull.AddDecal("burnt", WorldPosition); if (newDecal != null) { burnDecals.Insert(0, newDecal); } } else if (WorldPosition.X + size.X > burnDecals[burnDecals.Count - 1].WorldPosition.X + 256.0f) { var newDecal = hull.AddDecal("burnt", WorldPosition + Vector2.UnitX * size.X); if (newDecal != null) { burnDecals.Add(newDecal); } } } foreach (Decal d in burnDecals) { //prevent the decals from fading out as long as the firesource is alive d.FadeTimer = Math.Min(d.FadeTimer, d.FadeInTime); } }
private void UpdateEating(float deltaTime) { if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed) { state = AIState.None; return; } Limb mouthLimb = Array.Find(Character.AnimController.Limbs, l => l != null && l.MouthPos.HasValue); if (mouthLimb == null) { mouthLimb = Character.AnimController.GetLimb(LimbType.Head); } if (mouthLimb == null) { DebugConsole.ThrowError("Character \"" + Character.SpeciesName + "\" failed to eat a target (a head or a limb with a mouthpos required)"); state = AIState.None; return; } Character targetCharacter = selectedAiTarget.Entity as Character; float eatSpeed = Character.Mass / targetCharacter.Mass * 0.1f; eatTimer += deltaTime * eatSpeed; Vector2 mouthPos = mouthLimb.SimPosition; if (mouthLimb.MouthPos.HasValue) { float cos = (float)Math.Cos(mouthLimb.Rotation); float sin = (float)Math.Sin(mouthLimb.Rotation); mouthPos += new Vector2( mouthLimb.MouthPos.Value.X * cos - mouthLimb.MouthPos.Value.Y * sin, mouthLimb.MouthPos.Value.X * sin + mouthLimb.MouthPos.Value.Y * cos); } Vector2 attackSimPosition = Character.Submarine == null?ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition; Vector2 limbDiff = attackSimPosition - mouthPos; float limbDist = limbDiff.Length(); if (limbDist < 1.0f) { //pull the target character to the position of the mouth //(+ make the force fluctuate to waggle the character a bit) targetCharacter.AnimController.MainLimb.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f)); targetCharacter.AnimController.MainLimb.body.SmoothRotate(mouthLimb.Rotation); targetCharacter.AnimController.Collider.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f)); //pull the character's mouth to the target character (again with a fluctuating force) float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f)); steeringManager.SteeringManual(deltaTime, limbDiff * pullStrength); mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength); if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f) { //apply damage to the target character to get some blood particles flying targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), 10.0f, false); //keep severing joints until there is only one limb left LimbJoint[] nonSeveredJoints = Array.FindAll(targetCharacter.AnimController.LimbJoints, l => !l.IsSevered && l.CanBeSevered); if (nonSeveredJoints.Length == 0) { //only one limb left, the character is now full eaten Entity.Spawner.AddToRemoveQueue(targetCharacter); selectedAiTarget = null; state = AIState.None; } else //sever a random joint { targetCharacter.AnimController.SeverLimbJoint(nonSeveredJoints[Rand.Int(nonSeveredJoints.Length)]); } } } else if (limbDist < 2.0f) { steeringManager.SteeringManual(deltaTime, limbDiff); Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos); } else { steeringManager.SteeringSeek(attackSimPosition - (mouthPos - SimPosition), 3); } }
public float GetRandomFrequencyMultiplier() { return(Rand.Range(FrequencyMultiplierRange.X, FrequencyMultiplierRange.Y)); }
public void Update(float deltaTime) { position += new Vector2(velocity.X, velocity.Y) * deltaTime; depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth); checkWallsTimer -= deltaTime; if (checkWallsTimer <= 0.0f && Level.Loaded != null) { checkWallsTimer = CheckWallsInterval; obstacleDiff = Vector2.Zero; if (position.Y > Level.Loaded.Size.Y) { obstacleDiff = Vector2.UnitY; } else if (position.Y < 0.0f) { obstacleDiff = -Vector2.UnitY; } else if (position.X < 0.0f) { obstacleDiff = Vector2.UnitX; } else if (position.X > Level.Loaded.Size.X) { obstacleDiff = -Vector2.UnitX; } else { var cells = Level.Loaded.GetCells(position, 1); if (cells.Count > 0) { foreach (Voronoi2.VoronoiCell cell in cells) { obstacleDiff += cell.Center - position; } obstacleDiff /= cells.Count; obstacleDiff = Vector2.Normalize(obstacleDiff) * prefab.Speed; } } } if (Swarm != null) { Vector2 midPoint = Swarm.MidPoint(); float midPointDist = Vector2.Distance(SimPosition, midPoint); if (midPointDist > Swarm.MaxDistance) { steeringManager.SteeringSeek(midPoint, (midPointDist / Swarm.MaxDistance) * prefab.Speed); } } if (prefab.WanderAmount > 0.0f) { steeringManager.SteeringWander(prefab.Speed); } //Level.Loaded.Size if (obstacleDiff != Vector2.Zero) { steeringManager.SteeringSeek(SimPosition - obstacleDiff, prefab.Speed * 2.0f); } steeringManager.Update(prefab.Speed); if (prefab.WanderZAmount > 0.0f) { ang += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount); velocity.Z = (float)Math.Sin(ang) * prefab.Speed; } velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime); }
public AICharacter(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false) : base(file, position, characterInfo, isNetworkPlayer) { soundTimer = Rand.Range(0.0f, soundInterval); }
public static void CreateItems(List <PurchasedItem> itemsToSpawn) { if (itemsToSpawn.Count == 0) { return; } WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } #if CLIENT new GUIMessageBox("", TextManager.Get("CargoSpawnNotification").Replace("[roomname]", cargoRoom.RoomName)); #endif Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>(); ItemPrefab containerPrefab = null; foreach (PurchasedItem pi in itemsToSpawn) { Vector2 position = new Vector2( Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20), cargoRoom.Rect.Y - cargoRoom.Rect.Height + pi.ItemPrefab.Size.Y / 2); ItemContainer itemContainer = null; if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier)) { itemContainer = availableContainers.Keys.ToList().Find(ac => ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier || ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())); if (itemContainer == null) { containerPrefab = MapEntityPrefab.List.Find(ep => ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier || (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))) as ItemPrefab; if (containerPrefab == null) { DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!"); continue; } Item containerItem = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItem.GetComponent <ItemContainer>(); if (itemContainer == null) { DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!"); continue; } availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } } for (int i = 0; i < pi.Quantity; i++) { if (itemContainer == null) { //no container, place at the waypoint #if SERVER if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine); } else { #endif new Item(pi.ItemPrefab, position, wp.Submarine); #if SERVER } #endif continue; } //if the intial container has been removed due to it running out of space, add a new container //of the same type and begin filling it if (!availableContainers.ContainsKey(itemContainer)) { Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItemOverFlow.GetComponent <ItemContainer>(); availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } //place in the container #if SERVER if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory); } else { #endif var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemContainer.Inventory.TryPutItem(item, null); #if SERVER } #endif //reduce the number of available slots in the container //if there is a container if (availableContainers.ContainsKey(itemContainer)) { availableContainers[itemContainer]--; } if (availableContainers.ContainsKey(itemContainer) && availableContainers[itemContainer] <= 0) { availableContainers.Remove(itemContainer); } } } itemsToSpawn.Clear(); }
private void HandleLevelCollision(Impact impact) { float wallImpact = Vector2.Dot(impact.Velocity, -impact.Normal); ApplyImpact(wallImpact, -impact.Normal, impact.ImpactPos); foreach (Submarine dockedSub in submarine.DockedTo) { dockedSub.SubBody.ApplyImpact(wallImpact, -impact.Normal, impact.ImpactPos); } #if CLIENT int particleAmount = (int)Math.Min(wallImpact * 10.0f, 50); for (int i = 0; i < particleAmount; i++) { GameMain.ParticleManager.CreateParticle("iceshards", ConvertUnits.ToDisplayUnits(impact.ImpactPos) + Rand.Vector(Rand.Range(1.0f, 50.0f)), Rand.Vector(Rand.Range(50.0f, 500.0f)) + impact.Velocity); } #endif }
partial void UpdateProjSpecific(float deltaTime, Camera cam) { serverUpdateDelay -= deltaTime; if (serverUpdateDelay <= 0.0f) { ApplyRemoteState(); } if (networkUpdatePending) { networkUpdateTimer += deltaTime; if (networkUpdateTimer > 0.2f) { GameMain.NetworkMember?.CreateEntityEvent(this); networkUpdatePending = false; networkUpdateTimer = 0.0f; } } if (EditWater) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (Submarine.RectContains(WorldRect, position)) { if (PlayerInput.PrimaryMouseButtonHeld()) { WaterVolume += 1500.0f; networkUpdatePending = true; serverUpdateDelay = 0.5f; } else if (PlayerInput.SecondaryMouseButtonHeld()) { WaterVolume -= 1500.0f; networkUpdatePending = true; serverUpdateDelay = 0.5f; } } } else if (EditFire) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (Submarine.RectContains(WorldRect, position)) { if (PlayerInput.PrimaryMouseButtonClicked()) { new FireSource(position, this, isNetworkMessage: true); networkUpdatePending = true; serverUpdateDelay = 0.5f; } } } foreach (Decal decal in decals) { decal.Update(deltaTime); } decals.RemoveAll(d => d.FadeTimer >= d.LifeTime); if (waterVolume < 1.0f) { return; } for (int i = 1; i < waveY.Length - 1; i++) { float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i])); if (maxDelta > Rand.Range(1.0f, 10.0f)) { var particlePos = new Vector2(rect.X + WaveWidth * i, surface + waveY[i]); if (Submarine != null) { particlePos += Submarine.Position; } GameMain.ParticleManager.CreateParticle("mist", particlePos, new Vector2(0.0f, -50.0f), 0.0f, this); } } }
public static void DamageCharacters(Vector2 worldPosition, Attack attack, float force, Entity damageSource) { if (attack.Range <= 0.0f) { return; } //long range for the broad distance check, because large characters may still be in range even if their collider isn't float broadRange = Math.Max(attack.Range * 10.0f, 10000.0f); foreach (Character c in Character.CharacterList) { if (!c.Enabled || Math.Abs(c.WorldPosition.X - worldPosition.X) > broadRange || Math.Abs(c.WorldPosition.Y - worldPosition.Y) > broadRange) { continue; } Vector2 explosionPos = worldPosition; if (c.Submarine != null) { explosionPos -= c.Submarine.Position; } Hull hull = Hull.FindHull(ConvertUnits.ToDisplayUnits(explosionPos), null, false); bool underWater = hull == null || explosionPos.Y < hull.Surface; explosionPos = ConvertUnits.ToSimUnits(explosionPos); Dictionary <Limb, float> distFactors = new Dictionary <Limb, float>(); foreach (Limb limb in c.AnimController.Limbs) { float dist = Vector2.Distance(limb.WorldPosition, worldPosition); //calculate distance from the "outer surface" of the physics body //doesn't take the rotation of the limb into account, but should be accurate enough for this purpose float limbRadius = Math.Max(Math.Max(limb.body.width * 0.5f, limb.body.height * 0.5f), limb.body.radius); dist = Math.Max(0.0f, dist - FarseerPhysics.ConvertUnits.ToDisplayUnits(limbRadius)); if (dist > attack.Range) { continue; } float distFactor = 1.0f - dist / attack.Range; //solid obstacles between the explosion and the limb reduce the effect of the explosion by 90% if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null) { distFactor *= 0.1f; } distFactors.Add(limb, distFactor); List <Affliction> modifiedAfflictions = new List <Affliction>(); foreach (Affliction affliction in attack.Afflictions) { modifiedAfflictions.Add(affliction.CreateMultiplied(distFactor / c.AnimController.Limbs.Length)); } c.LastDamageSource = damageSource; Character attacker = null; if (damageSource is Item item) { attacker = item.GetComponent <Projectile>()?.User; if (attacker == null) { attacker = item.GetComponent <MeleeWeapon>()?.User; } } c.AddDamage(limb.WorldPosition, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker); if (attack.StatusEffects != null && attack.StatusEffects.Any()) { attack.SetUser(attacker); var statusEffectTargets = new List <ISerializableEntity>() { c, limb }; foreach (StatusEffect statusEffect in attack.StatusEffects) { statusEffect.Apply(ActionType.OnUse, 1.0f, damageSource, statusEffectTargets); statusEffect.Apply(ActionType.Always, 1.0f, damageSource, statusEffectTargets); statusEffect.Apply(underWater ? ActionType.InWater : ActionType.NotInWater, 1.0f, damageSource, statusEffectTargets); } } if (limb.WorldPosition != worldPosition && force > 0.0f) { Vector2 limbDiff = Vector2.Normalize(limb.WorldPosition - worldPosition); if (!MathUtils.IsValid(limbDiff)) { limbDiff = Rand.Vector(1.0f); } Vector2 impulse = limbDiff * distFactor * force; Vector2 impulsePoint = limb.SimPosition - limbDiff * limbRadius; limb.body.ApplyLinearImpulse(impulse, impulsePoint, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } } //sever joints if (c.IsDead && attack.SeverLimbsProbability > 0.0f) { foreach (Limb limb in c.AnimController.Limbs) { if (!distFactors.ContainsKey(limb)) { continue; } foreach (LimbJoint joint in c.AnimController.LimbJoints) { if (joint.IsSevered || (joint.LimbA != limb && joint.LimbB != limb)) { continue; } if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability * distFactors[limb]) { c.AnimController.SeverLimbJoint(joint); } } } } } }
private static void UpdateRandomAmbience(float deltaTime) { if (ambientSoundTimer > 0.0f) { ambientSoundTimer -= deltaTime; } else { PlaySound( "ambient", new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y) + Rand.Vector(100.0f), Rand.Range(0.5f, 1.0f), 1000.0f); ambientSoundTimer = Rand.Range(ambientSoundInterval.X, ambientSoundInterval.Y); } }
public override void Update(float deltaTime, Camera cam) { flowForce = Vector2.Zero; if (open == 0.0f) { lerpedFlowForce = Vector2.Zero; return; } UpdateOxygen(); if (linkedTo.Count == 1) { //gap leading from a room to outside UpdateRoomToOut(deltaTime); } else { //gap leading from a room to another UpdateRoomToRoom(deltaTime); } lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, deltaTime); if (LerpedFlowForce.LengthSquared() > 20000.0f && flowTargetHull != null && flowTargetHull.Volume < flowTargetHull.FullVolume) { //UpdateFlowForce(); Vector2 pos = Position; if (isHorizontal) { pos.X += Math.Sign(flowForce.X); pos.Y = MathHelper.Clamp((higherSurface + lowerSurface) / 2.0f, rect.Y - rect.Height, rect.Y) + 10; Vector2 velocity = new Vector2( MathHelper.Clamp(flowForce.X, -5000.0f, 5000.0f) * Rand.Range(0.5f, 0.7f), flowForce.Y * Rand.Range(0.5f, 0.7f)); #if CLIENT var particle = GameMain.ParticleManager.CreateParticle( "watersplash", (Submarine == null ? pos : pos + Submarine.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f), velocity, 0, flowTargetHull); if (particle != null) { particle.Size = particle.Size * Math.Min(Math.Abs(flowForce.X / 1000.0f), 5.0f); } #endif if (Math.Abs(flowForce.X) > 300.0f) { pos.X += Math.Sign(flowForce.X) * 10.0f; pos.Y = Rand.Range(lowerSurface, rect.Y - rect.Height); #if CLIENT GameMain.ParticleManager.CreateParticle( "bubbles", Submarine == null ? pos : pos + Submarine.Position, flowForce / 10.0f, 0, flowTargetHull); #endif } } else { if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) { return; } pos.Y += Math.Sign(flowForce.Y) * rect.Height / 2.0f; for (int i = 0; i < rect.Width; i += (int)Rand.Range(80, 100)) { pos.X = Rand.Range(rect.X, rect.X + rect.Width); Vector2 velocity = new Vector2( lerpedFlowForce.X * Rand.Range(0.5f, 0.7f), Math.Max(lerpedFlowForce.Y, -100.0f) * Rand.Range(0.5f, 0.7f)); #if CLIENT var splash = GameMain.ParticleManager.CreateParticle( "watersplash", Submarine == null ? pos : pos + Submarine.Position, -velocity, 0, FlowTargetHull); if (splash != null) { splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f); } GameMain.ParticleManager.CreateParticle( "bubbles", Submarine == null ? pos : pos + Submarine.Position, flowForce / 2.0f, 0, FlowTargetHull); #endif } } } if (flowTargetHull != null && lerpedFlowForce != Vector2.Zero) { foreach (Character character in Character.CharacterList) { if (character.AnimController.CurrentHull != flowTargetHull) { continue; } foreach (Limb limb in character.AnimController.Limbs) { if (!limb.inWater) { continue; } float dist = Vector2.Distance(limb.WorldPosition, WorldPosition); if (dist > lerpedFlowForce.Length()) { continue; } limb.body.ApplyForce(lerpedFlowForce / dist / 10.0f); } } } }
public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch, double deltaTime) { foreach (Submarine sub in Submarine.Loaded) { sub.UpdateTransform(); } GameMain.ParticleManager.UpdateTransforms(); GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision && (Character.Controlled.ViewTarget == Character.Controlled || Character.Controlled.ViewTarget == null); GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled?.CursorWorldPosition ?? Vector2.Zero); //------------------------------------------------------------------------ graphics.SetRenderTarget(renderTarget); graphics.Clear(Color.Transparent); //Draw background structures and wall background sprites //(= the background texture that's revealed when a wall is destroyed) into the background render target //These will be visible through the LOS effect. spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null)); Submarine.DrawPaintedColors(spriteBatch, false); spriteBatch.End(); graphics.SetRenderTarget(null); GameMain.LightManager.RenderLightMap(graphics, spriteBatch, cam, renderTarget); //------------------------------------------------------------------------ graphics.SetRenderTarget(renderTargetBackground); if (Level.Loaded == null) { graphics.Clear(new Color(11, 18, 26, 255)); } else { //graphics.Clear(new Color(255, 255, 255, 255)); Level.Loaded.DrawBack(graphics, spriteBatch, cam); } //draw alpha blended particles that are in water and behind subs #if LINUX || OSX spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); #else spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); #endif GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.AlphaBlend); spriteBatch.End(); //draw additive particles that are in water and behind subs spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.Additive); spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None); spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White); spriteBatch.End(); //---------------------------------------------------------------------------- //Start drawing to the normal render target (stuff that can't be seen through the LOS effect) graphics.SetRenderTarget(renderTarget); graphics.BlendState = BlendState.NonPremultiplied; graphics.SamplerStates[0] = SamplerState.LinearWrap; Quad.UseBasicEffect(renderTargetBackground); Quad.Render(); //Draw the rest of the structures, characters and front structures spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); Submarine.DrawBack(spriteBatch, false, e => !(e is Structure) || e.SpriteDepth < 0.9f); foreach (Character c in Character.CharacterList) { if (!c.IsVisible || c.AnimController.Limbs.Any(l => l.DeformSprite != null)) { continue; } c.Draw(spriteBatch, Cam); } spriteBatch.End(); //draw characters with deformable limbs last, because they can't be batched into SpriteBatch //pretty hacky way of preventing draw order issues between normal and deformable sprites spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); //backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth) for (int i = Character.CharacterList.Count - 1; i >= 0; i--) { Character c = Character.CharacterList[i]; if (!c.IsVisible || c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; } c.Draw(spriteBatch, Cam); } spriteBatch.End(); Level.Loaded?.DrawFront(spriteBatch, cam); //draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater graphics.SetRenderTarget(renderTargetWater); graphics.BlendState = BlendState.Opaque; graphics.SamplerStates[0] = SamplerState.LinearWrap; Quad.UseBasicEffect(renderTarget); Quad.Render(); //draw alpha blended particles that are inside a sub spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.AlphaBlend); spriteBatch.End(); graphics.SetRenderTarget(renderTarget); //draw alpha blended particles that are not in water spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.AlphaBlend); spriteBatch.End(); //draw additive particles that are not in water spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive); spriteBatch.End(); graphics.DepthStencilState = DepthStencilState.DepthRead; graphics.SetRenderTarget(renderTargetFinal); WaterRenderer.Instance.ResetBuffers(); Hull.UpdateVertices(cam, WaterRenderer.Instance); WaterRenderer.Instance.RenderWater(spriteBatch, renderTargetWater, cam); WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform); graphics.DepthStencilState = DepthStencilState.None; spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, null, null, damageEffect, cam.Transform); Submarine.DrawDamageable(spriteBatch, damageEffect, false); spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); Submarine.DrawFront(spriteBatch, false, null); spriteBatch.End(); //draw additive particles that are inside a sub spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive); foreach (var discharger in Items.Components.ElectricalDischarger.List) { discharger.DrawElectricity(spriteBatch); } spriteBatch.End(); if (GameMain.LightManager.LightingEnabled) { graphics.DepthStencilState = DepthStencilState.None; graphics.SamplerStates[0] = SamplerState.LinearWrap; graphics.BlendState = Lights.CustomBlendStates.Multiplicative; Quad.UseBasicEffect(GameMain.LightManager.LightMap); Quad.Render(); } spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform); foreach (Character c in Character.CharacterList) { c.DrawFront(spriteBatch, cam); } Level.Loaded?.DrawDebugOverlay(spriteBatch, cam); if (GameMain.DebugDraw) { MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch)); Character.CharacterList.ForEach(c => c.AiTarget?.Draw(spriteBatch)); if (GameMain.GameSession?.EventManager != null) { GameMain.GameSession.EventManager.DebugDraw(spriteBatch); } } spriteBatch.End(); if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Lights.LightManager.ViewTarget != null) { GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"]; GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground); GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture); GameMain.LightManager.LosEffect.Parameters["xLosAlpha"].SetValue(GameMain.LightManager.LosAlpha); Color losColor; if (GameMain.LightManager.LosMode == LosMode.Transparent) { //convert the los color to HLS and make sure the luminance of the color is always the same //as the luminance of the ambient light color float r = Character.Controlled?.CharacterHealth == null ? 0.0f : Math.Min(Character.Controlled.CharacterHealth.DamageOverlayTimer * 0.5f, 0.5f); Vector3 ambientLightHls = GameMain.LightManager.AmbientLight.RgbToHLS(); Vector3 losColorHls = Color.Lerp(GameMain.LightManager.AmbientLight, Color.Red, r).RgbToHLS(); losColorHls.Y = ambientLightHls.Y; losColor = ToolBox.HLSToRGB(losColorHls); } else { losColor = Color.Black; } GameMain.LightManager.LosEffect.Parameters["xColor"].SetValue(losColor.ToVector4()); graphics.BlendState = BlendState.NonPremultiplied; graphics.SamplerStates[0] = SamplerState.PointClamp; GameMain.LightManager.LosEffect.CurrentTechnique.Passes[0].Apply(); Quad.Render(); } if (Character.Controlled is { } character) { float grainStrength = character.GrainStrength; Rectangle screenRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight); spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: GrainEffect); GUI.DrawRectangle(spriteBatch, screenRect, Color.White, isFilled: true); GrainEffect.Parameters["seed"].SetValue(Rand.Range(0f, 1f, Rand.RandSync.Unsynced)); GrainEffect.Parameters["intensity"].SetValue(grainStrength); GrainEffect.Parameters["grainColor"].SetValue(character.GrainColor.ToVector4()); spriteBatch.End(); } graphics.SetRenderTarget(null); float BlurStrength = 0.0f; float DistortStrength = 0.0f; Vector3 chromaticAberrationStrength = GameMain.Config.ChromaticAberrationEnabled ? new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero; if (Character.Controlled != null) { BlurStrength = Character.Controlled.BlurStrength * 0.005f; DistortStrength = Character.Controlled.DistortStrength; if (GameMain.Config.EnableRadialDistortion) { chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength; } chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength; } else { BlurStrength = 0.0f; DistortStrength = 0.0f; } string postProcessTechnique = ""; if (BlurStrength > 0.0f) { postProcessTechnique += "Blur"; PostProcessEffect.Parameters["blurDistance"].SetValue(BlurStrength); } if (chromaticAberrationStrength != Vector3.Zero) { postProcessTechnique += "ChromaticAberration"; PostProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(chromaticAberrationStrength); } if (DistortStrength > 0.0f) { postProcessTechnique += "Distort"; PostProcessEffect.Parameters["distortScale"].SetValue(Vector2.One * DistortStrength); PostProcessEffect.Parameters["distortUvOffset"].SetValue(WaterRenderer.Instance.WavePos * 0.001f); } graphics.BlendState = BlendState.Opaque; graphics.SamplerStates[0] = SamplerState.LinearClamp; graphics.DepthStencilState = DepthStencilState.None; if (string.IsNullOrEmpty(postProcessTechnique)) { Quad.UseBasicEffect(renderTargetFinal); } else { PostProcessEffect.Parameters["MatrixTransform"].SetValue(Matrix.Identity); PostProcessEffect.Parameters["xTexture"].SetValue(renderTargetFinal); PostProcessEffect.CurrentTechnique = PostProcessEffect.Techniques[postProcessTechnique]; PostProcessEffect.CurrentTechnique.Passes[0].Apply(); } Quad.Render(); if (fadeToBlackState > 0.0f) { spriteBatch.Begin(SpriteSortMode.Deferred); GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Lerp(Color.TransparentBlack, Color.Black, fadeToBlackState), isFilled: true); spriteBatch.End(); } }
public void UpdateSubList(IEnumerable <SubmarineInfo> submarines) { List <SubmarineInfo> subsToShow; if (!isMultiplayer && subFilter != CategoryFilter.All) { subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && s.IsVanillaSubmarine() == (subFilter == CategoryFilter.Vanilla)).ToList(); } else { string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder); subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList(); } subsToShow.Sort((s1, s2) => { int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0; int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0; return(p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name)); }); subList.ClearChildren(); foreach (SubmarineInfo sub in subsToShow) { var textBlock = new GUITextBlock( new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) }, ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement") { ToolTip = sub.Description, UserData = sub }; if (!sub.RequiredContentPackagesInstalled) { textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f); textBlock.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + textBlock.RawToolTip; } var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight), TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont) { TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f, ToolTip = textBlock.ToolTip }; #if !DEBUG if (!GameMain.DebugDraw) { if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible) { textBlock.CanBeFocused = false; textBlock.TextColor *= 0.5f; } } #endif } if (SubmarineInfo.SavedSubmarines.Any()) { var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList(); if (validSubs.Count > 0) { subList.Select(validSubs[Rand.Int(validSubs.Count)]); } } }
protected override bool?DetermineSuccess() { var potentialTargets = ParentEvent.GetTargets(TargetTag).Where(e => e is Character).Select(e => e as Character); if (ProbabilityBased) { return(potentialTargets.Any(chr => chr.GetSkillLevel(RequiredSkill?.ToLowerInvariant()) / RequiredLevel > Rand.Range(0.0f, 1.0f, Rand.RandSync.Unsynced))); } else { return(potentialTargets.Any(chr => chr.GetSkillLevel(RequiredSkill?.ToLowerInvariant()) >= RequiredLevel)); } }
private void Emit(Vector2 position) { float angle = MathHelper.ToRadians(Rand.Range(emitter.AngleRange.X, emitter.AngleRange.Y)); Vector2 velocity = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Rand.Range(emitter.VelocityRange.X, emitter.VelocityRange.Y); var particle = GameMain.ParticleManager.CreateParticle(selectedPrefab, position, velocity, 0.0f); if (particle != null) { particle.Size *= Rand.Range(emitter.ScaleRange.X, emitter.ScaleRange.Y); } }
public static WayPoint[] SelectCrewSpawnPoints(List <CharacterInfo> crew, Submarine submarine) { List <WayPoint> subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine); List <WayPoint> unassignedWayPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human); WayPoint[] assignedWayPoints = new WayPoint[crew.Count]; for (int i = 0; i < crew.Count; i++) { //try to give the crew member a spawnpoint that hasn't been assigned to anyone and matches their job for (int n = 0; n < unassignedWayPoints.Count; n++) { if (crew[i].Job.Prefab != unassignedWayPoints[n].assignedJob) { continue; } assignedWayPoints[i] = unassignedWayPoints[n]; unassignedWayPoints.RemoveAt(n); break; } } //go through the crewmembers that don't have a spawnpoint yet (if any) for (int i = 0; i < crew.Count; i++) { if (assignedWayPoints[i] != null) { continue; } //try to assign a spawnpoint that matches the job, even if the spawnpoint is already assigned to someone else foreach (WayPoint wp in subWayPoints) { if (wp.spawnType != SpawnType.Human || wp.assignedJob != crew[i].Job.Prefab) { continue; } assignedWayPoints[i] = wp; break; } if (assignedWayPoints[i] != null) { continue; } //try to assign a spawnpoint that isn't meant for any specific job var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); if (nonJobSpecificPoints.Any()) { assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)]; } if (assignedWayPoints[i] != null) { continue; } //everything else failed -> just give a random spawnpoint inside the sub assignedWayPoints[i] = GetRandom(SpawnType.Human, null, submarine, useSyncedRand: true); } for (int i = 0; i < assignedWayPoints.Length; i++) { if (assignedWayPoints[i] == null) { DebugConsole.ThrowError("Couldn't find a waypoint for " + crew[i].Name + "!"); assignedWayPoints[i] = WayPointList[0]; } } return(assignedWayPoints); }
public static T SelectWeightedRandom <T>(IList <T> objects, IList <float> weights, Rand.RandSync randSync) { return(SelectWeightedRandom(objects, weights, Rand.GetRNG(randSync))); }
private Item GetWeapon(IEnumerable <ItemComponent> weaponList, out ItemComponent weaponComponent) { weaponComponent = null; float bestPriority = 0; float lethalDmg = -1; bool enemyIsClose = EnemyIsClose(); foreach (var weapon in weaponList) { float priority = weapon.CombatPriority; if (!IsLoaded(weapon)) { if (weapon is RangedWeapon && enemyIsClose) { // Close to the enemy. Ignore weapons that don't have any ammunition (-> Don't seek ammo). continue; } else { // Halve the priority for weapons that don't have proper ammunition loaded. priority /= 2; } } if (Enemy.IsKnockedDown) { // Enemy is stunned, reduce the priority of stunner weapons. Attack attack = GetAttackDefinition(weapon); if (attack != null) { lethalDmg = attack.GetTotalDamage(); float max = lethalDmg + 1; if (weapon.Item.HasTag("stunner")) { priority = max; } else { float stunDmg = ApproximateStunDamage(weapon, attack); float diff = stunDmg - lethalDmg; priority = Math.Clamp(priority - Math.Max(diff * 2, 0), min: 1, max); } } } else if (Mode == CombatMode.Arrest) { // Enemy is not stunned, increase the priority of stunner weapons and decrease the priority of lethal weapons. if (weapon.Item.HasTag("stunner")) { priority *= 2; } else { Attack attack = GetAttackDefinition(weapon); if (attack != null) { lethalDmg = attack.GetTotalDamage(); float stunDmg = ApproximateStunDamage(weapon, attack); float diff = stunDmg - lethalDmg; if (diff < 0) { priority /= 2; } } } } else if (weapon is MeleeWeapon && weapon.Item.HasTag("stunner") && !CanMeleeStunnerStun(weapon)) { Attack attack = GetAttackDefinition(weapon); priority = attack?.GetTotalDamage() ?? priority / 2; } if (priority > bestPriority) { weaponComponent = weapon; bestPriority = priority; } } if (weaponComponent == null) { return(null); } if (bestPriority < 1) { return(null); } if (Mode == CombatMode.Arrest) { if (weaponComponent.Item.HasTag("stunner")) { isLethalWeapon = false; } else { if (lethalDmg < 0) { lethalDmg = GetLethalDamage(weaponComponent); } isLethalWeapon = lethalDmg > 1; } if (allowHoldFire && !hasAimed && holdFireTimer <= 0) { holdFireTimer = arrestHoldFireTime * Rand.Range(0.75f, 1.25f); } } return(weaponComponent.Item);
public AIController(Character c) { Character = c; hullVisibilityTimer = Rand.Range(0f, hullVisibilityTimer); Enabled = true; }
public override void OnAttacked(Character attacker, AttackResult attackResult) { float damage = attackResult.Damage; if (damage <= 0) { return; } if (ObjectiveManager.CurrentObjective is AIObjectiveFightIntruders) { return; } if (attacker == null || attacker.IsDead || attacker.Removed) { // Ignore damage from falling etc that we shouldn't react to. if (Character.LastDamageSource == null) { return; } AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced)); } else if (IsFriendly(attacker)) { if (attacker.AnimController.Anim == Barotrauma.AnimController.Animation.CPR && attacker.SelectedCharacter == Character) { // Don't attack characters that damage you while doing cpr, because let's assume that they are helping you. // Should not cancel any existing ai objectives (so that if the character attacked you and then helped, we still would want to retaliate). return; } if (!attacker.IsRemotePlayer && Character.Controlled != attacker && attacker.AIController != null && attacker.AIController.Enabled) { // Don't retaliate on damage done by friendly ai, because we know that it's accidental AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced)); } else { // If not on the same team, always stay defensive if (attacker.TeamID != Character.TeamID) { AddCombatObjective(AIObjectiveCombat.CombatMode.Defensive, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced)); } else { float currentVitality = Character.CharacterHealth.Vitality; float dmgPercentage = damage / currentVitality * 100; if (dmgPercentage < currentVitality / 10) { // Don't retaliate on minor (accidental) dmg done by characters that are in the same team AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced)); } else { AddCombatObjective(AIObjectiveCombat.CombatMode.Defensive, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced)); } } } } else { AddCombatObjective(AIObjectiveCombat.CombatMode.Defensive); } void AddCombatObjective(AIObjectiveCombat.CombatMode mode, float delay = 0) { bool holdPosition = Character.Info?.Job?.Prefab.Identifier == "watchman"; if (ObjectiveManager.CurrentObjective is AIObjectiveCombat combatObjective) { if (combatObjective.Enemy != attacker || (combatObjective.Enemy == null && attacker == null)) { // Replace the old objective with the new. ObjectiveManager.Objectives.Remove(combatObjective); objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode, objectiveManager) { HoldPosition = holdPosition }); } } else { if (delay > 0) { objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode, objectiveManager) { HoldPosition = holdPosition }, delay); } else { objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode, objectiveManager) { HoldPosition = holdPosition }); } } } }
protected override void Act(float deltaTime) { if (character.LockHands || targetCharacter == null || targetCharacter.CurrentHull == null || targetCharacter.Removed || targetCharacter.IsDead) { Abandon = true; return; } var otherRescuer = targetCharacter.SelectedBy; if (otherRescuer != null && otherRescuer != character) { // Someone else is rescuing/holding the target. Abandon = otherRescuer.IsPlayer || character.GetSkillLevel("medical") < otherRescuer.GetSkillLevel("medical"); return; } if (targetCharacter != character) { if (targetCharacter.IsIncapacitated) { // Check if the character needs more oxygen if (!ignoreOxygen && character.SelectedCharacter == targetCharacter || character.CanInteractWith(targetCharacter)) { // Replace empty oxygen tank // First remove empty tanks if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out IEnumerable <Item> suits, requireEquipped: true)) { Item suit = suits.FirstOrDefault(); if (suit != null) { AIObjectiveFindDivingGear.EjectEmptyTanks(character, suit, out _); } } else if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.LIGHT_DIVING_GEAR, out IEnumerable <Item> masks, requireEquipped: true)) { Item mask = masks.FirstOrDefault(); if (mask != null) { AIObjectiveFindDivingGear.EjectEmptyTanks(character, mask, out _); } } bool ShouldRemoveDivingSuit() => targetCharacter.OxygenAvailable < CharacterHealth.InsufficientOxygenThreshold && targetCharacter.CurrentHull?.LethalPressure <= 0; if (ShouldRemoveDivingSuit()) { suits.ForEach(suit => suit.Drop(character)); } else if (suits.Any() && suits.None(s => s.OwnInventory?.AllItems != null && s.OwnInventory.AllItems.Any(it => it.HasTag(AIObjectiveFindDivingGear.OXYGEN_SOURCE) && it.ConditionPercentage > 0))) { // The target has a suit equipped with an empty oxygen tank. // Can't remove the suit, because the target needs it. // If we happen to have an extra oxygen tank in the inventory, let's swap it. Item spareOxygenTank = FindOxygenTank(targetCharacter) ?? FindOxygenTank(character); if (spareOxygenTank != null) { Item suit = suits.FirstOrDefault(); if (suit != null) { // Insert the new oxygen tank TryAddSubObjective(ref replaceOxygenObjective, () => new AIObjectiveContainItem(character, spareOxygenTank, suit.GetComponent <ItemContainer>(), objectiveManager), onCompleted: () => RemoveSubObjective(ref replaceOxygenObjective), onAbandon: () => { RemoveSubObjective(ref replaceOxygenObjective); ignoreOxygen = true; if (ShouldRemoveDivingSuit()) { suits.ForEach(suit => suit.Drop(character)); } }); return; } } Item FindOxygenTank(Character c) => c.Inventory.FindItem(i => i.HasTag(AIObjectiveFindDivingGear.OXYGEN_SOURCE) && i.ConditionPercentage > 1 && i.FindParentInventory(inv => inv.Owner is Item otherItem && otherItem.HasTag("diving")) == null, recursive: true); } } if (HumanAIController.GetHullSafety(targetCharacter.CurrentHull, targetCharacter) < HumanAIController.HULL_SAFETY_THRESHOLD) { // Incapacitated target is not in a safe place -> Move to a safe place first if (character.SelectedCharacter != targetCharacter) { if (targetCharacter.CurrentHull != null && HumanAIController.VisibleHulls.Contains(targetCharacter.CurrentHull) && targetCharacter.CurrentHull.DisplayName != null) { character.Speak(TextManager.GetWithVariables("DialogFoundUnconsciousTarget", new string[2] { "[targetname]", "[roomname]" }, new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }), null, 1.0f, "foundunconscioustarget" + targetCharacter.Name, 60.0f); } // Go to the target and select it if (!character.CanInteractWith(targetCharacter)) { RemoveSubObjective(ref replaceOxygenObjective); RemoveSubObjective(ref goToObjective); TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(targetCharacter, character, objectiveManager) { CloseEnough = CloseEnoughToTreat, DialogueIdentifier = "dialogcannotreachpatient", TargetName = targetCharacter.DisplayName }, onCompleted: () => RemoveSubObjective(ref goToObjective), onAbandon: () => { RemoveSubObjective(ref goToObjective); Abandon = true; }); } else { character.SelectCharacter(targetCharacter); } } else { // Drag the character into safety if (safeHull == null) { if (findHullTimer > 0) { findHullTimer -= deltaTime; } else { safeHull = objectiveManager.GetObjective <AIObjectiveFindSafety>().FindBestHull(HumanAIController.VisibleHulls); findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f); } } if (safeHull != null && character.CurrentHull != safeHull) { RemoveSubObjective(ref replaceOxygenObjective); RemoveSubObjective(ref goToObjective); TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(safeHull, character, objectiveManager), onCompleted: () => RemoveSubObjective(ref goToObjective), onAbandon: () => { RemoveSubObjective(ref goToObjective); safeHull = character.CurrentHull; }); } } } } } if (subObjectives.Any()) { return; } if (targetCharacter != character && !character.CanInteractWith(targetCharacter)) { RemoveSubObjective(ref replaceOxygenObjective); RemoveSubObjective(ref goToObjective); // Go to the target and select it TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(targetCharacter, character, objectiveManager) { CloseEnough = CloseEnoughToTreat, DialogueIdentifier = "dialogcannotreachpatient", TargetName = targetCharacter.DisplayName }, onCompleted: () => RemoveSubObjective(ref goToObjective), onAbandon: () => { RemoveSubObjective(ref goToObjective); Abandon = true; }); } else { // We can start applying treatment if (character != targetCharacter && character.SelectedCharacter != targetCharacter) { if (targetCharacter.CurrentHull.DisplayName != null) { character.Speak(TextManager.GetWithVariables("DialogFoundWoundedTarget", new string[2] { "[targetname]", "[roomname]" }, new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }), null, 1.0f, "foundwoundedtarget" + targetCharacter.Name, 60.0f); } character.SelectCharacter(targetCharacter); } GiveTreatment(deltaTime); } }
public override void Update(float deltaTime) { if (DisableCrewAI || Character.IsUnconscious || Character.Removed) { return; } float maxDistanceToSub = 3000; if (Character.Submarine != null || SelectedAiTarget?.Entity?.Submarine != null && Vector2.DistanceSquared(Character.WorldPosition, SelectedAiTarget.Entity.Submarine.WorldPosition) < maxDistanceToSub * maxDistanceToSub) { if (steeringManager != insideSteering) { insideSteering.Reset(); } steeringManager = insideSteering; } else { if (steeringManager != outsideSteering) { outsideSteering.Reset(); } steeringManager = outsideSteering; } AnimController.Crouching = shouldCrouch; CheckCrouching(deltaTime); Character.ClearInputs(); if (hullVisibilityTimer > 0) { hullVisibilityTimer--; } else { hullVisibilityTimer = hullVisibilityInterval; VisibleHulls = Character.GetVisibleHulls(); } objectiveManager.UpdateObjectives(deltaTime); if (sortTimer > 0.0f) { sortTimer -= deltaTime; } else { objectiveManager.SortObjectives(); sortTimer = sortObjectiveInterval; } if (reactTimer > 0.0f) { reactTimer -= deltaTime; } else { if (Character.CurrentHull != null) { VisibleHulls.ForEach(h => PropagateHullSafety(Character, h)); } if (Character.SpeechImpediment < 100.0f) { ReportProblems(); UpdateSpeaking(); } reactTimer = reactionTime * Rand.Range(0.75f, 1.25f); } if (objectiveManager.CurrentObjective == null) { return; } objectiveManager.DoCurrentObjective(deltaTime); bool run = objectiveManager.CurrentObjective.ForceRun || objectiveManager.GetCurrentPriority() > AIObjectiveManager.RunPriority; if (ObjectiveManager.CurrentObjective is AIObjectiveGoTo goTo && goTo.Target != null) { if (Character.CurrentHull == null) { run = Vector2.DistanceSquared(Character.WorldPosition, goTo.Target.WorldPosition) > 300 * 300; } else { float yDiff = goTo.Target.WorldPosition.Y - Character.WorldPosition.Y; if (Math.Abs(yDiff) > 100) { run = true; } else { float xDiff = goTo.Target.WorldPosition.X - Character.WorldPosition.X; run = Math.Abs(xDiff) > 300; } } } if (run) { run = !AnimController.Crouching && !AnimController.IsMovingBackwards; } float currentSpeed = Character.AnimController.GetCurrentSpeed(run); steeringManager.Update(currentSpeed); bool ignorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f && (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X)); if (steeringManager == insideSteering) { var currPath = PathSteering.CurrentPath; if (currPath != null && currPath.CurrentNode != null) { if (currPath.CurrentNode.SimPosition.Y < Character.AnimController.GetColliderBottom().Y) { // Don't allow to jump from too high. The formula might require tweaking. float allowedJumpHeight = Character.AnimController.ImpactTolerance / 2; float height = Math.Abs(currPath.CurrentNode.SimPosition.Y - Character.SimPosition.Y); ignorePlatforms = height < allowedJumpHeight; } } if (Character.IsClimbing && PathSteering.IsNextLadderSameAsCurrent) { Character.AnimController.TargetMovement = new Vector2(0.0f, Math.Sign(Character.AnimController.TargetMovement.Y)); } } Character.AnimController.IgnorePlatforms = ignorePlatforms; Vector2 targetMovement = AnimController.TargetMovement; if (!Character.AnimController.InWater) { targetMovement = new Vector2(Character.AnimController.TargetMovement.X, MathHelper.Clamp(Character.AnimController.TargetMovement.Y, -1.0f, 1.0f)); } float maxSpeed = Character.ApplyTemporarySpeedLimits(currentSpeed); targetMovement.X = MathHelper.Clamp(targetMovement.X, -maxSpeed, maxSpeed); targetMovement.Y = MathHelper.Clamp(targetMovement.Y, -maxSpeed, maxSpeed); //apply speed multiplier if // a. it's boosting the movement speed and the character is trying to move fast (= running) // b. it's a debuff that decreases movement speed float speedMultiplier = Character.SpeedMultiplier; if (run || speedMultiplier <= 0.0f) { targetMovement *= speedMultiplier; } Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update Character.AnimController.TargetMovement = targetMovement; if (!Character.LockHands) { DropUnnecessaryItems(); } if (Character.IsKeyDown(InputType.Aim)) { var cursorDiffX = Character.CursorPosition.X - Character.Position.X; if (cursorDiffX > 10.0f) { Character.AnimController.TargetDir = Direction.Right; } else if (cursorDiffX < -10.0f) { Character.AnimController.TargetDir = Direction.Left; } if (Character.SelectedConstruction != null) { Character.SelectedConstruction.SecondaryUse(deltaTime, Character); } } else if (Math.Abs(Character.AnimController.TargetMovement.X) > 0.1f && !Character.AnimController.InWater) { Character.AnimController.TargetDir = Character.AnimController.TargetMovement.X > 0.0f ? Direction.Right : Direction.Left; } }
public void AddDamage(int sectionIndex, float damage, Character attacker = null) { if (!Prefab.Body || Prefab.Platform || Indestructible) { return; } if (sectionIndex < 0 || sectionIndex > Sections.Length - 1) { return; } var section = Sections[sectionIndex]; #if CLIENT float particleAmount = Math.Min(Health - section.damage, damage) * Rand.Range(0.01f, 1.0f); particleAmount = Math.Min(particleAmount + Rand.Range(-5, 1), 5); for (int i = 0; i < particleAmount; i++) { Vector2 particlePos = new Vector2( Rand.Range(section.rect.X, section.rect.Right), Rand.Range(section.rect.Y - section.rect.Height, section.rect.Y)); if (Submarine != null) { particlePos += Submarine.DrawPosition; } var particle = GameMain.ParticleManager.CreateParticle("shrapnel", particlePos, Rand.Vector(Rand.Range(1.0f, 50.0f))); if (particle == null) { break; } } #endif #if CLIENT if (GameMain.Client == null) { #endif SetDamage(sectionIndex, section.damage + damage, attacker); #if CLIENT } #endif }
partial void UpdateProjSpecific(float deltaTime, Camera cam) { if (EditWater) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (Submarine.RectContains(WorldRect, position)) { if (PlayerInput.LeftButtonHeld()) { WaterVolume += 1500.0f; } else if (PlayerInput.RightButtonHeld()) { WaterVolume -= 1500.0f; } } } else if (EditFire) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (Submarine.RectContains(WorldRect, position)) { if (PlayerInput.LeftButtonClicked()) { new FireSource(position, this); } } } foreach (Decal decal in decals) { decal.Update(deltaTime); } decals.RemoveAll(d => d.FadeTimer >= d.LifeTime); float strongestFlow = 0.0f; foreach (Gap gap in ConnectedGaps) { if (gap.IsRoomToRoom) { //only the first linked hull plays the flow sound if (gap.linkedTo[1] == this) { continue; } } float gapFlow = gap.LerpedFlowForce.Length(); if (gapFlow > strongestFlow) { strongestFlow = gapFlow; } } if (strongestFlow > 1.0f) { soundVolume = soundVolume + ((strongestFlow < 100.0f) ? -deltaTime * 0.5f : deltaTime * 0.5f); soundVolume = MathHelper.Clamp(soundVolume, 0.0f, 1.0f); int index = (int)Math.Floor(strongestFlow / 100.0f); index = Math.Min(index, 2); var flowSound = SoundPlayer.flowSounds[index]; if (flowSound != currentFlowSound && soundIndex > -1) { Sounds.SoundManager.Stop(soundIndex); currentFlowSound = null; soundIndex = -1; } currentFlowSound = flowSound; soundIndex = currentFlowSound.Loop(soundIndex, soundVolume, WorldPosition, Math.Min(strongestFlow * 5.0f, 2000.0f)); } else { if (soundIndex > -1) { Sounds.SoundManager.Stop(soundIndex); currentFlowSound = null; soundIndex = -1; } } for (int i = 0; i < waveY.Length; i++) { float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i])); if (maxDelta > Rand.Range(1.0f, 10.0f)) { var particlePos = new Vector2(rect.X + WaveWidth * i, surface + waveY[i]); if (Submarine != null) { particlePos += Submarine.Position; } GameMain.ParticleManager.CreateParticle("mist", particlePos, new Vector2(0.0f, -50.0f), 0.0f, this); } } }
protected override AIObjective ObjectiveConstructor(Character target) { var combatObjective = new AIObjectiveCombat(character, target, AIObjectiveCombat.CombatMode.Offensive, objectiveManager, PriorityModifier); if (character.TeamID == CharacterTeamType.FriendlyNPC && target.TeamID == CharacterTeamType.Team1 && GameMain.GameSession?.GameMode is CampaignMode campaign) { var reputation = campaign.Map?.CurrentLocation?.Reputation; if (reputation != null && reputation.NormalizedValue < Reputation.HostileThreshold) { combatObjective.holdFireCondition = () => { //hold fire while the enemy is in the airlock (except if they've attacked us) if (HumanAIController.GetDamageDoneByAttacker(target) > 0.0f) { return(false); } return(target.CurrentHull == null || target.CurrentHull.OutpostModuleTags.Any(t => t.Equals("airlock", System.StringComparison.OrdinalIgnoreCase))); }; character.Speak(TextManager.Get("dialogenteroutpostwarning"), null, Rand.Range(0.5f, 1.0f), "leaveoutpostwarning", 30.0f); } } return(combatObjective); }
private void DrawDecorativeHUD(SpriteBatch spriteBatch, Rectangle rect) { spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, GameMain.ScissorTestEnable); if (generationParams.ShowOverlay) { Vector2 mapCenter = rect.Center.ToVector2() + (new Vector2(size, size) / 2 + drawOffset + drawOffsetNoise) * zoom; Vector2 centerDiff = CurrentLocation.MapPosition - new Vector2(size) / 2; int currentZone = (int)Math.Floor((centerDiff.Length() / (size * 0.5f) * generationParams.DifficultyZones)); for (int i = 0; i < generationParams.DifficultyZones; i++) { float radius = size / 2 * ((i + 1.0f) / generationParams.DifficultyZones); float textureSize = (radius / (generationParams.MapCircle.size.X / 2) * zoom); generationParams.MapCircle.Draw(spriteBatch, mapCenter, i == currentZone || i == currentZone - 1 ? Color.White * 0.5f : Color.White * 0.2f, i * 0.4f + (float)Timing.TotalTime * 0.01f, textureSize); } } float animPulsate = (float)Math.Sin(Timing.TotalTime * 2.0f) * 0.1f; Vector2 frameSize = generationParams.DecorativeGraphSprite.FrameSize.ToVector2(); generationParams.DecorativeGraphSprite.Draw(spriteBatch, (int)((cameraNoiseStrength + animPulsate) * hudOpenState * generationParams.DecorativeGraphSprite.FrameCount), new Vector2(rect.Right, rect.Bottom), Color.White, frameSize, 0, Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 10), frameSize)); frameSize = generationParams.DecorativeMapSprite.FrameSize.ToVector2(); generationParams.DecorativeMapSprite.Draw(spriteBatch, (int)((cameraNoiseStrength + animPulsate) * hudOpenState * generationParams.DecorativeMapSprite.FrameCount), new Vector2(rect.X, rect.Y), Color.White, new Vector2(0, frameSize.Y * 0.2f), 0, Vector2.Divide(new Vector2(rect.Width / 3, rect.Height / 5), frameSize), spriteEffect: SpriteEffects.FlipVertically); GUI.DrawString(spriteBatch, new Vector2(rect.X + rect.Width / 15, rect.Y + rect.Height / 11), "JOVIAN FLUX " + ((cameraNoiseStrength + Rand.Range(-0.02f, 0.02f)) * 500), Color.White * hudOpenState, font: GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(rect.X + rect.Width * 0.27f, rect.Y + rect.Height * 0.93f), "LAT " + (-drawOffset.Y / 100.0f) + " LON " + (-drawOffset.X / 100.0f), Color.White * hudOpenState, font: GUI.SmallFont); System.Text.StringBuilder sb = new System.Text.StringBuilder("GEST F "); for (int i = 0; i < 20; i++) { sb.Append(Rand.Range(0.0f, 1.0f) < cameraNoiseStrength ? ToolBox.RandomSeed(1) : "0"); } GUI.DrawString(spriteBatch, new Vector2(rect.X + rect.Width * 0.8f, rect.Y + rect.Height * 0.96f), sb.ToString(), Color.White * hudOpenState, font: GUI.SmallFont); frameSize = generationParams.DecorativeLineTop.FrameSize.ToVector2(); generationParams.DecorativeLineTop.Draw(spriteBatch, (int)(hudOpenState * generationParams.DecorativeLineTop.FrameCount), new Vector2(rect.Right, rect.Y), Color.White, new Vector2(frameSize.X, frameSize.Y * 0.2f), 0, Vector2.Divide(new Vector2(rect.Width * 0.72f, rect.Height / 9), frameSize)); frameSize = generationParams.DecorativeLineBottom.FrameSize.ToVector2(); generationParams.DecorativeLineBottom.Draw(spriteBatch, (int)(hudOpenState * generationParams.DecorativeLineBottom.FrameCount), new Vector2(rect.X, rect.Bottom), Color.White, new Vector2(0, frameSize.Y * 0.6f), 0, Vector2.Divide(new Vector2(rect.Width * 0.72f, rect.Height / 9), frameSize)); frameSize = generationParams.DecorativeLineCorner.FrameSize.ToVector2(); generationParams.DecorativeLineCorner.Draw(spriteBatch, (int)((hudOpenState + animPulsate) * generationParams.DecorativeLineCorner.FrameCount), new Vector2(rect.Right - rect.Width / 8, rect.Bottom), Color.White, frameSize * 0.8f, 0, Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 4), frameSize), spriteEffect: SpriteEffects.FlipVertically); generationParams.DecorativeLineCorner.Draw(spriteBatch, (int)((hudOpenState + animPulsate) * generationParams.DecorativeLineCorner.FrameCount), new Vector2(rect.X + rect.Width / 8, rect.Y), Color.White, frameSize * 0.1f, 0, Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 4), frameSize), spriteEffect: SpriteEffects.FlipHorizontally); //reticles generationParams.ReticleLarge.Draw(spriteBatch, (int)(subReticleAnimState * generationParams.ReticleLarge.FrameCount), rect.Center.ToVector2() + (subReticlePosition + drawOffset - drawOffsetNoise * 2) * zoom, Color.White, generationParams.ReticleLarge.Origin, 0, Vector2.One * (float)Math.Sqrt(zoom) * 0.4f); generationParams.ReticleMedium.Draw(spriteBatch, (int)(subReticleAnimState * generationParams.ReticleMedium.FrameCount), rect.Center.ToVector2() + (subReticlePosition + drawOffset - drawOffsetNoise) * zoom, Color.White, generationParams.ReticleMedium.Origin, 0, new Vector2(1.0f, 0.7f) * (float)Math.Sqrt(zoom) * 0.4f); if (selectedLocation != null) { generationParams.ReticleSmall.Draw(spriteBatch, (int)(targetReticleAnimState * generationParams.ReticleSmall.FrameCount), rect.Center.ToVector2() + (selectedLocation.MapPosition + drawOffset + drawOffsetNoise * 2) * zoom, Color.White, generationParams.ReticleSmall.Origin, 0, new Vector2(1.0f, 0.7f) * (float)Math.Sqrt(zoom) * 0.4f); } spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable); }