partial void ApplyProjSpecific(float deltaTime, Entity entity, List <ISerializableEntity> targets, Hull hull, Vector2 worldPosition) { if (entity == null) { return; } if (sounds.Count > 0) { 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; GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } soundChannel = SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } else { int selectedSoundIndex = 0; 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; GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, worldPosition, selectedSound.Volume, selectedSound.Range, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } if (soundChannel != null && soundChannel.Looping) { ActiveLoopingSounds.Add(this); soundEmitter = entity; loopStartTime = Timing.TotalTime; } } foreach (ParticleEmitter emitter in particleEmitters) { float angle = 0.0f; if (emitter.Prefab.CopyEntityAngle) { if (entity is Item item && item.body != null) { angle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi); } } emitter.Emit(deltaTime, worldPosition, hull, angle); } }
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); }
private IEnumerable <object> Load(bool isSeparateThread) { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("LOADING COROUTINE", Color.Lime); } while (TitleScreen.WaitForLanguageSelection) { yield return(CoroutineStatus.Running); } SoundManager = new Sounds.SoundManager(); SoundManager.SetCategoryGainMultiplier("default", Config.SoundVolume, 0); SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0); SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0); SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0); SoundManager.SetCategoryGainMultiplier("voip", Math.Min(Config.VoiceChatVolume, 1.0f), 0); if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro")) { var pendingSplashScreens = TitleScreen.PendingSplashScreens; float baseVolume = MathHelper.Clamp(Config.SoundVolume * 2.0f, 0.0f, 1.0f); pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_UTG.webm", baseVolume * 0.5f)); pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_FF.webm", baseVolume)); pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_Daedalic.webm", baseVolume * 0.1f)); } //if not loading in a separate thread, wait for the splash screens to finish before continuing the loading //otherwise the videos will look extremely choppy if (!isSeparateThread) { while (TitleScreen.PlayingSplashScreen || TitleScreen.PendingSplashScreens.Count > 0) { yield return(CoroutineStatus.Running); } } GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice); DebugConsole.Init(); if (Config.AutoUpdateWorkshopItems) { bool waitingForWorkshopUpdates = true; bool result = false; TaskPool.Add(SteamManager.AutoUpdateWorkshopItemsAsync(), (task) => { result = task.Result; waitingForWorkshopUpdates = false; }); while (waitingForWorkshopUpdates) { yield return(CoroutineStatus.Running); } if (result) { CrossThread.RequestExecutionOnMainThread(() => { ContentPackage.LoadAll(); Config.ReloadContentPackages(); }); } } if (SelectedPackages.None()) { DebugConsole.Log("No content packages selected"); } else { DebugConsole.Log("Selected content packages: " + string.Join(", ", SelectedPackages.Select(cp => cp.Name))); } #if DEBUG GameSettings.ShowUserStatisticsPrompt = false; GameSettings.SendUserStatistics = false; #endif InitUserStats(); yield return(CoroutineStatus.Running); Debug.WriteLine("sounds"); int i = 0; foreach (object crObj in SoundPlayer.Init()) { CoroutineStatus status = (CoroutineStatus)crObj; if (status == CoroutineStatus.Success) { break; } i++; TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ? 1.0f : Math.Min(40.0f * i / Math.Max(SoundPlayer.SoundCount, 1), 40.0f); yield return(CoroutineStatus.Running); } TitleScreen.LoadState = 40.0f; yield return(CoroutineStatus.Running); LightManager = new Lights.LightManager(base.GraphicsDevice, Content); TitleScreen.LoadState = 41.0f; yield return(CoroutineStatus.Running); GUI.LoadContent(); TitleScreen.LoadState = 42.0f; yield return(CoroutineStatus.Running); CharacterPrefab.LoadAll(); MissionPrefab.Init(); TraitorMissionPrefab.Init(); MapEntityPrefab.Init(); Tutorials.Tutorial.Init(); MapGenerationParams.Init(); LevelGenerationParams.LoadPresets(); WreckAIConfig.LoadAll(); ScriptedEventSet.LoadPrefabs(); AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions)); SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings)); Order.Init(); EventManagerSettings.Init(); TitleScreen.LoadState = 50.0f; yield return(CoroutineStatus.Running); StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure)); TitleScreen.LoadState = 53.0f; yield return(CoroutineStatus.Running); ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item)); TitleScreen.LoadState = 55.0f; yield return(CoroutineStatus.Running); JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs)); CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses)); NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations)); ItemAssemblyPrefab.LoadAll(); TitleScreen.LoadState = 60.0f; yield return(CoroutineStatus.Running); GameModePreset.Init(); SubmarineInfo.RefreshSavedSubs(); TitleScreen.LoadState = 65.0f; yield return(CoroutineStatus.Running); GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content); TitleScreen.LoadState = 68.0f; yield return(CoroutineStatus.Running); MainMenuScreen = new MainMenuScreen(this); LobbyScreen = new LobbyScreen(); ServerListScreen = new ServerListScreen(); TitleScreen.LoadState = 70.0f; yield return(CoroutineStatus.Running); #if USE_STEAM SteamWorkshopScreen = new SteamWorkshopScreen(); if (SteamManager.IsInitialized) { Steamworks.SteamFriends.OnGameRichPresenceJoinRequested += OnInvitedToGame; Steamworks.SteamFriends.OnGameLobbyJoinRequested += OnLobbyJoinRequested; } #endif SubEditorScreen = new SubEditorScreen(); TitleScreen.LoadState = 75.0f; yield return(CoroutineStatus.Running); ParticleEditorScreen = new ParticleEditorScreen(); TitleScreen.LoadState = 80.0f; yield return(CoroutineStatus.Running); LevelEditorScreen = new LevelEditorScreen(); SpriteEditorScreen = new SpriteEditorScreen(); CharacterEditorScreen = new CharacterEditor.CharacterEditorScreen(); yield return(CoroutineStatus.Running); TitleScreen.LoadState = 85.0f; ParticleManager = new ParticleManager(GameScreen.Cam); ParticleManager.LoadPrefabs(); TitleScreen.LoadState = 88.0f; LevelObjectPrefab.LoadAll(); TitleScreen.LoadState = 90.0f; yield return(CoroutineStatus.Running); DecalManager = new DecalManager(); LocationType.Init(); MainMenuScreen.Select(); CheckContentPackage(); foreach (string steamError in SteamManager.InitializationErrors) { new GUIMessageBox(TextManager.Get("Error"), TextManager.Get(steamError)); } TitleScreen.LoadState = 100.0f; hasLoaded = true; if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("LOADING COROUTINE FINISHED", Color.Lime); } yield return(CoroutineStatus.Success); }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds; int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step); if (Timing.Accumulator > Timing.Step * 6.0) { //if the game's running too slowly then we have no choice //but to skip a bunch of steps //otherwise it snowballs and becomes unplayable Timing.Accumulator = Timing.Step; } CrossThread.ProcessTasks(); PlayerInput.UpdateVariable(); if (SoundManager != null) { if (WindowActive || !Config.MuteOnFocusLost) { SoundManager.ListenerGain = SoundManager.CompressionDynamicRangeGain; } else { SoundManager.ListenerGain = 0.0f; } } while (Timing.Accumulator >= Timing.Step) { Timing.TotalTime += Timing.Step; Stopwatch sw = new Stopwatch(); sw.Start(); fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly; TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16); fixedTime.ElapsedGameTime = addTime; fixedTime.TotalGameTime.Add(addTime); base.Update(fixedTime); PlayerInput.Update(Timing.Step); if (loadingScreenOpen) { //reset accumulator if loading // -> less choppy loading screens because the screen is rendered after each update // -> no pause caused by leftover time in the accumulator when starting a new shift GameMain.ResetFrameTime(); if (!TitleScreen.PlayingSplashScreen) { SoundPlayer.Update((float)Timing.Step); } if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.PrimaryMouseButtonClicked()) && WindowActive))) { loadingScreenOpen = false; } #if DEBUG if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && Config.AutomaticQuickStartEnabled && FirstLoad) { loadingScreenOpen = false; FirstLoad = false; MainMenuScreen.QuickStart(); } #endif if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine)) { throw new LoadingException(loadingCoroutine.Exception); } } else if (hasLoaded) { if (ConnectLobby != 0) { if (Client != null) { Client.Disconnect(); Client = null; GameMain.MainMenuScreen.Select(); } Steam.SteamManager.JoinLobby(ConnectLobby, true); ConnectLobby = 0; ConnectEndpoint = null; ConnectName = null; } else if (!string.IsNullOrWhiteSpace(ConnectEndpoint)) { if (Client != null) { Client.Disconnect(); Client = null; GameMain.MainMenuScreen.Select(); } UInt64 serverSteamId = SteamManager.SteamIDStringToUInt64(ConnectEndpoint); Client = new GameClient(Config.PlayerName, serverSteamId != 0 ? null : ConnectEndpoint, serverSteamId, string.IsNullOrWhiteSpace(ConnectName) ? ConnectEndpoint : ConnectName); ConnectLobby = 0; ConnectEndpoint = null; ConnectName = null; } SoundPlayer.Update((float)Timing.Step); if (PlayerInput.KeyHit(Keys.Escape) && WindowActive) { // Check if a text input is selected. if (GUI.KeyboardDispatcher.Subscriber != null) { if (GUI.KeyboardDispatcher.Subscriber is GUITextBox textBox) { textBox.Deselect(); } GUI.KeyboardDispatcher.Subscriber = null; } //if a verification prompt (are you sure you want to x) is open, close it else if (GUIMessageBox.VisibleBox as GUIMessageBox != null && GUIMessageBox.VisibleBox.UserData as string == "verificationprompt") { ((GUIMessageBox)GUIMessageBox.VisibleBox).Close(); } else if (Tutorial.Initialized && Tutorial.ContentRunning) { (GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI(); } else if (GameSession.IsTabMenuOpen) { gameSession.ToggleTabMenu(); } else if (GUI.PauseMenuOpen) { GUI.TogglePauseMenu(); } //open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC else if ((Character.Controlled == null || !itemHudActive()) //TODO: do we need to check Inventory.SelectedSlot? && Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null && !CrewManager.IsCommandInterfaceOpen && !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null)) { // Otherwise toggle pausing, unless another window/interface is open. GUI.TogglePauseMenu(); } bool itemHudActive() { if (Character.Controlled?.SelectedConstruction == null) { return(false); } return (Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) || ((Character.Controlled.ViewTarget as Item)?.Prefab?.FocusOnSelected ?? false)); } } #if DEBUG if (GameMain.NetworkMember == null) { if (PlayerInput.KeyHit(Keys.P) && !(GUI.KeyboardDispatcher.Subscriber is GUITextBox)) { DebugConsole.Paused = !DebugConsole.Paused; } } #endif GUI.ClearUpdateList(); Paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning || DebugConsole.Paused) && (NetworkMember == null || !NetworkMember.GameStarted); #if !DEBUG if (NetworkMember == null && !WindowActive && !Paused && true && Screen.Selected != MainMenuScreen && Config.PauseOnFocusLost) { GUI.TogglePauseMenu(); Paused = true; } #endif Screen.Selected.AddToGUIUpdateList(); if (Client != null) { Client.AddToGUIUpdateList(); } FileSelection.AddToGUIUpdateList(); DebugConsole.AddToGUIUpdateList(); DebugConsole.Update((float)Timing.Step); Paused = Paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted)); if (!Paused) { Screen.Selected.Update(Timing.Step); } else if (Tutorial.Initialized && Tutorial.ContentRunning) { (GameSession.GameMode as TutorialMode).Update((float)Timing.Step); } else if (DebugConsole.Paused) { if (Screen.Selected.Cam == null) { DebugConsole.Paused = false; } else { Screen.Selected.Cam.MoveCamera((float)Timing.Step); } } if (NetworkMember != null) { NetworkMember.Update((float)Timing.Step); } GUI.Update((float)Timing.Step); } CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step); SteamManager.Update((float)Timing.Step); TaskPool.Update(); SoundManager?.Update(); Timing.Accumulator -= Timing.Step; sw.Stop(); PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks); PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency); PerformanceCounter.UpdateIterationsGraph.Update(updateIterations); } if (!Paused) { Timing.Alpha = Timing.Accumulator / Timing.Step; } }
private void ApplyImpact(float impact, Vector2 direction, Vector2 impactPos, bool applyDamage = true) { if (impact < MinCollisionImpact) { return; } Vector2 impulse = direction * impact * 0.5f; impulse = impulse.ClampLength(MaxCollisionImpact); if (!MathUtils.IsValid(impulse)) { string errorMsg = "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse + ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + "."; if (GameMain.NetworkMember != null) { errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server."; } if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); } GameAnalyticsManager.AddErrorEventOnce( "SubmarineBody.ApplyImpact:InvalidImpulse", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } #if CLIENT if (Character.Controlled != null && Character.Controlled.Submarine == submarine) { GameMain.GameScreen.Cam.Shake = impact * 2.0f; if (submarine.Info.Type == SubmarineInfo.SubmarineType.Player && !submarine.DockedTo.Any(s => s.Info.Type != SubmarineInfo.SubmarineType.Player)) { float angularVelocity = (impactPos.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y - (impactPos.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X; GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f); } } #endif foreach (Character c in Character.CharacterList) { if (c.Submarine != submarine) { continue; } foreach (Limb limb in c.AnimController.Limbs) { limb.body.ApplyLinearImpulse(limb.Mass * impulse, 10.0f); } c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 10.0f); bool holdingOntoSomething = false; if (c.SelectedConstruction != null) { var controller = c.SelectedConstruction.GetComponent <Items.Components.Controller>(); holdingOntoSomething = controller != null && controller.LimbPositions.Any(); } //stun for up to 1 second if the impact equal or higher to the maximum impact if (impact >= MaxCollisionImpact && !holdingOntoSomething) { c.SetStun(Math.Min(impulse.Length() * 0.2f, 1.0f)); } } foreach (Item item in Item.ItemList) { if (item.Submarine != submarine || item.CurrentHull == null || item.body == null || !item.body.Enabled) { continue; } item.body.ApplyLinearImpulse(item.body.Mass * impulse, 10.0f); } var damagedStructures = Explosion.RangedStructureDamage( ConvertUnits.ToDisplayUnits(impactPos), impact * 50.0f, applyDamage ? impact * ImpactDamageMultiplier : 0.0f); #if CLIENT //play a damage sound for the structure that took the most damage float maxDamage = 0.0f; Structure maxDamageStructure = null; foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures) { if (maxDamageStructure == null || structureDamage.Value > maxDamage) { maxDamage = structureDamage.Value; maxDamageStructure = structureDamage.Key; } } if (maxDamageStructure != null) { SoundPlayer.PlayDamageSound( "StructureBlunt", impact * 10.0f, ConvertUnits.ToDisplayUnits(impactPos), MathHelper.Lerp(2000.0f, 10000.0f, (impact - MinCollisionImpact) / 2.0f), maxDamageStructure.Tags); } #endif }
protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets) { Hull hull = null; if (entity is Character) { hull = ((Character)entity).AnimController.CurrentHull; } else if (entity is Item) { hull = ((Item)entity).CurrentHull; } #if CLIENT if (entity != null && sounds.Count > 0) { if (soundChannel == null || !soundChannel.IsPlaying) { if (soundSelectionMode == SoundSelectionMode.All) { foreach (RoundSound sound in sounds) { soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } else { int selectedSoundIndex = 0; 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]; soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } } #endif foreach (ISerializableEntity serializableEntity in targets) { Item item = serializableEntity as Item; if (item == null) { continue; } Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character; if (targetCharacter == null) { foreach (var target in targets) { if (target is Limb limb && limb.character != null && !limb.character.Removed) { targetCharacter = ((Limb)target).character; } } } for (int i = 0; i < useItemCount; i++) { if (item.Removed) { continue; } item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb); } } if (removeItem) { foreach (Item item in targets.Where(t => t is Item).Cast <Item>()) { Entity.Spawner?.AddToRemoveQueue(item); } } if (duration > 0.0f) { DurationListElement element = new DurationListElement { Parent = this, Timer = duration, Entity = entity, Targets = targets }; DurationList.Add(element); } else { foreach (ISerializableEntity target in targets) { if (target is Entity targetEntity) { if (targetEntity.Removed) { continue; } } for (int i = 0; i < propertyNames.Length; i++) { if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property)) { continue; } ApplyToProperty(target, property, propertyEffects[i], deltaTime); } } } if (explosion != null && entity != null) { explosion.Explode(entity.WorldPosition, entity); } foreach (ISerializableEntity target in targets) { foreach (Affliction affliction in Afflictions) { Affliction multipliedAffliction = affliction; if (!disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); } if (target is Character character) { character.LastDamageSource = entity; foreach (Limb limb in character.AnimController.Limbs) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); //only apply non-limb-specific afflictions to the first limb if (!affliction.Prefab.LimbSpecific) { break; } } } else if (target is Limb limb) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); } } foreach (Pair <string, float> reduceAffliction in ReduceAffliction) { float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; if (target is Character character) { character.CharacterHealth.ReduceAffliction(null, reduceAffliction.First, reduceAmount); } else if (target is Limb limb) { limb.character.CharacterHealth.ReduceAffliction(limb, reduceAffliction.First, reduceAmount); } } } if (FireSize > 0.0f && entity != null) { var fire = new FireSource(entity.WorldPosition, hull); fire.Size = new Vector2(FireSize, fire.Size.Y); } bool isNotClient = true; #if CLIENT isNotClient = GameMain.Client == null; #endif if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items { foreach (ItemSpawnInfo itemSpawnInfo in spawnItems) { switch (itemSpawnInfo.SpawnPosition) { case ItemSpawnInfo.SpawnPositionType.This: Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, entity.WorldPosition); break; case ItemSpawnInfo.SpawnPositionType.ThisInventory: { if (entity is Character character) { if (character.Inventory != null && character.Inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory); } } else if (entity is Item item) { var inventory = item?.GetComponent <ItemContainer>()?.Inventory; if (inventory != null && inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory); } } } break; case ItemSpawnInfo.SpawnPositionType.ContainedInventory: { Inventory thisInventory = null; if (entity is Character character) { thisInventory = character.Inventory; } else if (entity is Item item) { thisInventory = item?.GetComponent <ItemContainer>()?.Inventory; } if (thisInventory != null) { foreach (Item item in thisInventory.Items) { if (item == null) { continue; } Inventory containedInventory = item.GetComponent <ItemContainer>()?.Inventory; if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) { continue; } Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory); break; } } } break; } } } #if CLIENT if (entity != null) { foreach (ParticleEmitter emitter in particleEmitters) { float angle = 0.0f; if (emitter.Prefab.CopyEntityAngle) { if (entity is Item it) { angle = it.body == null ? 0.0f : it.body.Rotation; } } emitter.Emit(deltaTime, entity.WorldPosition, hull, angle); } } #endif }
/// <summary> /// Update the selection logic in submarine editor /// </summary> public static void UpdateSelecting(Camera cam) { if (resizing) { if (selectedList.Count == 0) { resizing = false; } return; } foreach (MapEntity e in mapEntityList) { e.isHighlighted = false; } if (DisableSelect) { DisableSelect = false; return; } if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow) { if (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))) { UpdateHighlightedListBox(null, false); return; } } if (MapEntityPrefab.Selected != null) { selectionPos = Vector2.Zero; selectedList.Clear(); return; } if (GUI.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyHit(Keys.Delete)) { if (selectedList.Any()) { SubEditorScreen.StoreCommand(new AddOrDeleteCommand(selectedList, true)); } selectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } }); selectedList.Clear(); } if (PlayerInput.IsCtrlDown()) { #if DEBUG if (PlayerInput.KeyHit(Keys.D)) { bool terminate = false; foreach (MapEntity entity in selectedList) { if (entity is Item item && item.GetComponent <Planter>() is { } planter) { planter.Update(1.0f, cam); for (var i = 0; i < planter.GrowableSeeds.Length; i++) { Growable seed = planter.GrowableSeeds[i]; PlantSlot slot = planter.PlantSlots.ContainsKey(i) ? planter.PlantSlots[i] : Planter.NullSlot; if (seed == null) { continue; } seed.CreateDebugHUD(planter, slot); terminate = true; break; } } if (terminate) { break; } } } #endif if (PlayerInput.KeyHit(Keys.C)) { Copy(selectedList); } else if (PlayerInput.KeyHit(Keys.X)) { Cut(selectedList); } else if (PlayerInput.KeyHit(Keys.V)) { Paste(cam.ScreenToWorld(PlayerInput.MousePosition)); } else if (PlayerInput.KeyHit(Keys.G)) { if (selectedList.Any()) { if (SelectionGroups.ContainsKey(selectedList.Last())) { // Ungroup all selected selectedList.ForEach(e => SelectionGroups.Remove(e)); } else { foreach (var entity in selectedList) { // Remove the old group, if any SelectionGroups.Remove(entity); // Create a group that can be accessed with any member SelectionGroups.Add(entity, selectedList); } } } } } } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); MapEntity highLightedEntity = null; if (startMovingPos == Vector2.Zero) { List <MapEntity> highlightedEntities = new List <MapEntity>(); if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn)) { highLightedEntity = GUI.MouseOn.UserData as MapEntity; } else { foreach (MapEntity e in mapEntityList) { if (!e.SelectableInEditor) { continue; } if (e.IsMouseOn(position)) { int i = 0; while (i < highlightedEntities.Count && e.Sprite != null && (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth)) { i++; } highlightedEntities.Insert(i, e); if (i == 0) { highLightedEntity = e; } } } UpdateHighlighting(highlightedEntities); } if (highLightedEntity != null) { highLightedEntity.isHighlighted = true; } } if (GUI.KeyboardDispatcher.Subscriber == null) { Vector2 nudge = GetNudgeAmount(); if (nudge != Vector2.Zero) { foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudge); } } } else { keyDelay = 0; } bool isShiftDown = PlayerInput.IsShiftDown(); //started moving selected entities if (startMovingPos != Vector2.Zero) { Item targetContainer = GetPotentialContainer(position, selectedList); if (targetContainer != null) { targetContainer.IsHighlighted = true; } if (PlayerInput.PrimaryMouseButtonReleased()) { //mouse released -> move the entities to the new position of the mouse Vector2 moveAmount = position - startMovingPos; if (!isShiftDown) { moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X; moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y; } if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown) { if (!isShiftDown) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); } //clone if (PlayerInput.IsCtrlDown()) { var clones = Clone(selectedList).Where(c => c != null).ToList(); selectedList = clones; selectedList.ForEach(c => c.Move(moveAmount)); SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false)); } else // move { var oldRects = selectedList.Select(e => e.Rect).ToList(); List <MapEntity> deposited = new List <MapEntity>(); foreach (MapEntity e in selectedList) { e.Move(moveAmount); if (isShiftDown && e is Item item && targetContainer != null) { if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled)) { SoundPlayer.PlayUISound(GUISoundType.DropItem); deposited.Add(item); } else { SoundPlayer.PlayUISound(GUISoundType.PickItemFail); } } } SubEditorScreen.StoreCommand(new TransformCommand(new List <MapEntity>(selectedList), selectedList.Select(entity => entity.Rect).ToList(), oldRects, false)); if (deposited.Any() && deposited.Any(entity => entity is Item)) { var depositedItems = deposited.Where(entity => entity is Item).Cast <Item>().ToList(); SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false)); } deposited.ForEach(entity => { selectedList.Remove(entity); }); } } startMovingPos = Vector2.Zero; } } //started dragging a "selection rectangle" else if (selectionPos != Vector2.Zero) { selectionSize.X = position.X - selectionPos.X; selectionSize.Y = selectionPos.Y - position.Y; List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize); if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y) { newSelection = FindSelectedEntities(selectionPos, selectionSize); } else { if (highLightedEntity != null) { if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group)) { newSelection.AddRange(group); } else { newSelection.Add(highLightedEntity); } } } if (PlayerInput.PrimaryMouseButtonReleased()) { if (PlayerInput.IsCtrlDown()) { foreach (MapEntity e in newSelection) { if (selectedList.Contains(e)) { RemoveSelection(e); } else { AddSelection(e); } } } else { selectedList = new List <MapEntity>(newSelection); //selectedList.Clear(); //newSelection.ForEach(e => AddSelection(e)); foreach (var entity in newSelection) { HandleDoorGapLinks(entity, onGapFound: (door, gap) => { door.RefreshLinkedGap(); if (!selectedList.Contains(gap)) { selectedList.Add(gap); } }, onDoorFound: (door, gap) => { if (!selectedList.Contains(door.Item)) { selectedList.Add(door.Item); } }); } } //select wire if both items it's connected to are selected var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList(); foreach (Item item in selectedItems) { if (item.Connections == null) { continue; } foreach (Connection c in item.Connections) { foreach (Wire w in c.Wires) { if (w == null || selectedList.Contains(w.Item)) { continue; } if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item)) { selectedList.Add(w.Item); } } } } selectionPos = Vector2.Zero; selectionSize = Vector2.Zero; } } //default, not doing anything specific yet else { if (PlayerInput.PrimaryMouseButtonHeld() && PlayerInput.KeyUp(Keys.Space) && PlayerInput.KeyUp(Keys.LeftAlt) && PlayerInput.KeyUp(Keys.RightAlt) && (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))) { //if clicking a selected entity, start moving it foreach (MapEntity e in selectedList) { if (e.IsMouseOn(position)) { startMovingPos = position; } } selectionPos = position; //stop camera movement to prevent accidental dragging or rect selection Screen.Selected.Cam.StopMovement(); } } }
static partial void PlayTinnitusProjSpecific(float volume) => SoundPlayer.PlaySound("tinnitus", volume: volume);
public void StartShift(Level level, bool reloadSub = true, bool loadSecondSub = false) { #if CLIENT GameMain.LightManager.LosEnabled = GameMain.NetworkMember == null || GameMain.NetworkMember.CharacterInfo != null; #endif this.level = level; if (submarine == null) { DebugConsole.ThrowError("Couldn't start game session, submarine not selected"); return; } if (reloadSub || Submarine.MainSub != submarine) { submarine.Load(true); } Submarine.MainSub = submarine; if (loadSecondSub) { if (Submarine.MainSubs[1] == null) { Submarine.MainSubs[1] = new Submarine(Submarine.MainSub.FilePath, Submarine.MainSub.MD5Hash.Hash, true); Submarine.MainSubs[1].Load(false); } else if (reloadSub) { Submarine.MainSubs[1].Load(false); } } if (level != null) { level.Generate(); submarine.SetPosition(submarine.FindSpawnPos(level.StartPosition - new Vector2(0.0f, 2000.0f))); #if CLIENT GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(80); #endif } if (gameMode.Mission != null) { currentMission = gameMode.Mission; } if (gameMode != null) { gameMode.Start(); } if (gameMode.Mission != null) { Mission.Start(Level.Loaded); } TaskManager.StartShift(level); if (gameMode != null) { gameMode.MsgBox(); } Entity.Spawner = new EntitySpawner(); #if CLIENT shiftSummary = new ShiftSummary(this); GameMain.GameScreen.ColorFade(Color.Black, Color.TransparentBlack, 5.0f); SoundPlayer.SwitchMusic(); #endif }
partial void AddDamageProjSpecific(IEnumerable <Affliction> afflictions, bool playSound, IEnumerable <DamageModifier> appliedDamageModifiers) { float bleedingDamage = character.CharacterHealth.DoesBleed ? afflictions.Where(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth)) : 0; float damage = afflictions.Where(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth)); float damageMultiplier = 1; foreach (DamageModifier damageModifier in appliedDamageModifiers) { foreach (var afflictionPrefab in AfflictionPrefab.List) { if (damageModifier.MatchesAffliction(afflictionPrefab.Identifier, afflictionPrefab.AfflictionType)) { if (afflictionPrefab.Effects.Any(e => e.MaxVitalityDecrease > 0)) { damageMultiplier *= damageModifier.DamageMultiplier; } } } } if (playSound) { string damageSoundType = (bleedingDamage > damage) ? "LimbSlash" : "LimbBlunt"; foreach (DamageModifier damageModifier in appliedDamageModifiers) { if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound)) { damageSoundType = damageModifier.DamageSound; break; } } SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition); } // spawn damage particles float damageParticleAmount = Math.Min(damage / 10, 1.0f) * damageMultiplier; if (damageParticleAmount > 0.001f) { foreach (ParticleEmitter emitter in character.DamageEmitters) { if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; } if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; } emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount); } } if (bleedingDamage > 0) { float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * damageMultiplier; float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f); foreach (ParticleEmitter emitter in character.BloodEmitters) { if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; } if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; } emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount); } if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName)) { character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f)); } } }
public void StartRound(Level level, bool reloadSub = true, bool loadSecondSub = false, bool mirrorLevel = false) { #if CLIENT GameMain.LightManager.LosEnabled = GameMain.NetworkMember == null || GameMain.NetworkMember.CharacterInfo != null; #endif this.level = level; if (submarine == null) { DebugConsole.ThrowError("Couldn't start game session, submarine not selected"); return; } if (reloadSub || Submarine.MainSub != submarine) { submarine.Load(true); } Submarine.MainSub = submarine; if (loadSecondSub) { if (Submarine.MainSubs[1] == null) { Submarine.MainSubs[1] = new Submarine(Submarine.MainSub.FilePath, Submarine.MainSub.MD5Hash.Hash, true); Submarine.MainSubs[1].Load(false); } else if (reloadSub) { Submarine.MainSubs[1].Load(false); } } if (level != null) { level.Generate(mirrorLevel); submarine.SetPosition(submarine.FindSpawnPos(level.StartPosition - new Vector2(0.0f, 2000.0f))); } Entity.Spawner = new EntitySpawner(); if (GameMode.Mission != null) { currentMission = GameMode.Mission; } if (GameMode != null) { GameMode.Start(); } if (GameMode.Mission != null) { Mission.Start(Level.Loaded); } EventManager.StartRound(level); if (GameMode != null) { GameMode.MsgBox(); if (GameMode is MultiPlayerCampaign mpCampaign && GameMain.Server != null) { mpCampaign.CargoManager.CreateItems(); } } GameAnalyticsManager.AddDesignEvent("Submarine:" + submarine.Name); GameAnalyticsManager.AddDesignEvent("Level", ToolBox.StringToInt(level.Seed)); GameAnalyticsManager.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start, GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); #if CLIENT roundSummary = new RoundSummary(this); GameMain.GameScreen.ColorFade(Color.Black, Color.TransparentBlack, 5.0f); SoundPlayer.SwitchMusic(); #endif }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { Timing.TotalTime = gameTime.TotalGameTime.TotalSeconds; Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds; PlayerInput.UpdateVariable(); bool paused = true; if (GameMain.NilMod.UseExperimentalFPSLagPrevention && !loadingScreenOpen) { if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 2) { Timing.Step = 1.0 / 8.0; FarseerPhysics.Settings.VelocityIterations = 10; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 25; FarseerPhysics.Settings.TOIVelocityIterations = 10; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 4) { Timing.Step = 1.0 / 10.0; FarseerPhysics.Settings.VelocityIterations = 10; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 25; FarseerPhysics.Settings.TOIVelocityIterations = 10; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 6) { Timing.Step = 1.0 / 12.0; FarseerPhysics.Settings.VelocityIterations = 10; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 25; FarseerPhysics.Settings.TOIVelocityIterations = 10; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 8) { Timing.Step = 1.0 / 15.0; FarseerPhysics.Settings.VelocityIterations = 9; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 22; FarseerPhysics.Settings.TOIVelocityIterations = 9; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 10) { Timing.Step = 1.0 / 20.0; FarseerPhysics.Settings.VelocityIterations = 9; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 22; FarseerPhysics.Settings.TOIVelocityIterations = 9; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 12) { Timing.Step = 1.0 / 25.0; FarseerPhysics.Settings.VelocityIterations = 9; FarseerPhysics.Settings.PositionIterations = 4; FarseerPhysics.Settings.TOIPositionIterations = 22; FarseerPhysics.Settings.TOIVelocityIterations = 9; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 14) { Timing.Step = 1.0 / 30.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 16) { Timing.Step = 1.0 / 35.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 18) { Timing.Step = 1.0 / 40.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 20) { Timing.Step = 1.0 / 45.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 22) { Timing.Step = 1.0 / 50.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 25) { Timing.Step = 1.0 / 55.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } else { Timing.Step = 1.0 / 60.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } } else { Timing.Step = 1.0 / 60.0; FarseerPhysics.Settings.VelocityIterations = 8; FarseerPhysics.Settings.PositionIterations = 3; FarseerPhysics.Settings.TOIPositionIterations = 20; FarseerPhysics.Settings.TOIVelocityIterations = 8; } while (Timing.Accumulator >= Timing.Step) { NilModProfiler.SWMainUpdateLoop.Start(); fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly; TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16); if (GameMain.NilMod.UseExperimentalFPSLagPrevention) { if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 2) { addTime = new TimeSpan(0, 0, 0, 0, 125); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 4) { addTime = new TimeSpan(0, 0, 0, 0, 100); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 6) { addTime = new TimeSpan(0, 0, 0, 0, 83); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 8) { addTime = new TimeSpan(0, 0, 0, 0, 66); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 10) { addTime = new TimeSpan(0, 0, 0, 0, 50); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 12) { addTime = new TimeSpan(0, 0, 0, 0, 40); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 14) { addTime = new TimeSpan(0, 0, 0, 0, 33); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 16) { addTime = new TimeSpan(0, 0, 0, 0, 28); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 18) { addTime = new TimeSpan(0, 0, 0, 0, 25); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 20) { addTime = new TimeSpan(0, 0, 0, 0, 22); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 22) { addTime = new TimeSpan(0, 0, 0, 0, 20); } else if ((int)GameMain.FrameCounter.CurrentFramesPerSecond <= 25) { addTime = new TimeSpan(0, 0, 0, 0, 18); } else { addTime = new TimeSpan(0, 0, 0, 0, 16); } } fixedTime.ElapsedGameTime = addTime; fixedTime.TotalGameTime.Add(addTime); base.Update(fixedTime); NilModProfiler.SWPlayerInput.Start(); if (WindowActive) { PlayerInput.Update(Timing.Step); } NilModProfiler.RecordPlayerInput(); if (loadingScreenOpen) { //reset accumulator if loading // -> less choppy loading screens because the screen is rendered after each update // -> no pause caused by leftover time in the accumulator when starting a new shift if (TitleScreen.LoadState >= 100f) { Timing.Accumulator = 0.0f; this.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 12); } else { Timing.Accumulator = Timing.Step * 1.99; this.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 1); } if (TitleScreen.LoadState >= 100.0f && (!waitForKeyHit || PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.LeftButtonClicked())) { loadingScreenOpen = false; } if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine)) { throw new Exception("Loading was interrupted due to an error"); } } else if (hasLoaded) { NilMod.Update((float)Timing.Step); NilModProfiler.SWSoundPlayer.Start(); SoundPlayer.Update((float)Timing.Step); NilModProfiler.RecordSoundPlayer(); if (PlayerInput.KeyHit(Keys.Escape)) { GUI.TogglePauseMenu(); } GUIComponent.ClearUpdateList(); paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen) && (NetworkMember == null || !NetworkMember.GameStarted); if (!paused) { Screen.Selected.AddToGUIUpdateList(); } if (NetworkMember != null) { NetworkMember.AddToGUIUpdateList(); } GUI.AddToGUIUpdateList(); DebugConsole.AddToGUIUpdateList(); GUIComponent.UpdateMouseOn(); NilModProfiler.SWDebugConsole.Start(); DebugConsole.Update(this, (float)Timing.Step); paused = paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted)); NilModProfiler.RecordDebugConsole(); if (!paused) { NilModProfiler.SWGameScreen.Start(); Screen.Selected.Update(Timing.Step); NilModProfiler.RecordGameScreen(); } if (NetworkMember != null) { NilModProfiler.SWNetworkMember.Start(); NetworkMember.Update((float)Timing.Step); NilModProfiler.RecordNetworkMember(); } NilModProfiler.SWGUIUpdate.Start(); GUI.Update((float)Timing.Step); NilModProfiler.RecordGUIUpdate(); } NilModProfiler.SWCoroutineManager.Start(); CoroutineManager.Update((float)Timing.Step, paused ? 0.0f : (float)Timing.Step); NilModProfiler.RecordCoroutineManager(); Timing.Accumulator -= Timing.Step; if (NilModProfiler.SWMainUpdateLoop.ElapsedTicks > 0) { NilModProfiler.RecordMainLoopUpdate(); } } GameMain.NilModProfiler.Update((float)Timing.Step); if (!paused) { Timing.Alpha = Timing.Accumulator / Timing.Step; } }
private IEnumerable <object> Load() { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("LOADING COROUTINE", Color.Lime); } GUI.GraphicsDevice = base.GraphicsDevice; GUI.Init(Content); InitUserStats(); GUIComponent.Init(Window); DebugConsole.Init(Window); DebugConsole.Log(SelectedPackage == null ? "No content package selected" : "Content package \"" + SelectedPackage.Name + "\" selected"); yield return(CoroutineStatus.Running); LightManager = new Lights.LightManager(base.GraphicsDevice, Content); Hull.renderer = new WaterRenderer(base.GraphicsDevice, Content); TitleScreen.LoadState = 1.0f; yield return(CoroutineStatus.Running); Sound.Init(); GUI.LoadContent(); TitleScreen.LoadState = 2.0f; yield return(CoroutineStatus.Running); MissionPrefab.Init(); MapEntityPrefab.Init(); LevelGenerationParams.LoadPresets(); TitleScreen.LoadState = 10.0f; yield return(CoroutineStatus.Running); JobPrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Jobs)); // Add any missing jobs from the prefab into Config.JobNamePreferences. foreach (JobPrefab job in JobPrefab.List) { if (!Config.JobNamePreferences.Contains(job.Name)) { Config.JobNamePreferences.Add(job.Name); } } StructurePrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Structure)); TitleScreen.LoadState = 20.0f; yield return(CoroutineStatus.Running); ItemPrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Item)); TitleScreen.LoadState = 30.0f; yield return(CoroutineStatus.Running); Debug.WriteLine("sounds"); CoroutineManager.StartCoroutine(SoundPlayer.Init()); int i = 0; while (!SoundPlayer.Initialized) { i++; TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ? 30.0f : Math.Min(30.0f + 40.0f * i / Math.Max(SoundPlayer.SoundCount, 1), 70.0f); yield return(CoroutineStatus.Running); } TitleScreen.LoadState = 70.0f; yield return(CoroutineStatus.Running); GameModePreset.Init(); Submarine.RefreshSavedSubs(); TitleScreen.LoadState = 80.0f; yield return(CoroutineStatus.Running); GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content); TitleScreen.LoadState = 90.0f; yield return(CoroutineStatus.Running); MainMenuScreen = new MainMenuScreen(this); LobbyScreen = new LobbyScreen(); ServerListScreen = new ServerListScreen(); SubEditorScreen = new SubEditorScreen(Content); CharacterEditorScreen = new CharacterEditorScreen(); ParticleEditorScreen = new ParticleEditorScreen(); GameSession.inGameInfo = new InGameInfo(); yield return(CoroutineStatus.Running); ParticleManager = new ParticleManager(GameScreen.Cam); ParticleManager.LoadPrefabs(); DecalManager = new DecalManager(); yield return(CoroutineStatus.Running); LocationType.Init(); MainMenuScreen.Select(); NilMod.GameInitialize(true); TitleScreen.LoadState = 100.0f; hasLoaded = true; if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("LOADING COROUTINE FINISHED", Color.Lime); } //Nilmod Server Start code HandleParameters(); if (NilMod.StartToServer) { Autostart(); } GameMain.NilMod.SuccesfulStart = true; yield return(CoroutineStatus.Success); }
protected override void Update(float deltaTime) { if (!Visible) { return; } base.Update(deltaTime); if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && CanBeFocused && Enabled && GUI.IsMouseOn(this)) { State = Selected ? ComponentState.HoverSelected : ComponentState.Hover; if (PlayerInput.PrimaryMouseButtonDown()) { OnButtonDown?.Invoke(); } if (PlayerInput.PrimaryMouseButtonHeld()) { if (OnPressed != null) { if (OnPressed()) { State = ComponentState.Pressed; } } else { State = ComponentState.Pressed; } } else if (PlayerInput.PrimaryMouseButtonClicked()) { SoundPlayer.PlayUISound(ClickSound); if (OnClicked != null) { if (OnClicked(this, UserData)) { State = ComponentState.Selected; } } else { Selected = !Selected; } } } else { if (!ExternalHighlight) { State = Selected ? ComponentState.Selected : ComponentState.None; } else { State = ComponentState.Hover; } } foreach (GUIComponent child in Children) { child.State = State; } if (Pulse) { pulseTimer += deltaTime; if (pulseTimer > 1.0f) { if (!flashed) { flashed = true; Frame.Flash(Color.White * 0.2f, 0.8f, true); } pulseExpand += deltaTime; if (pulseExpand > 1.0f) { pulseTimer = 0.0f; pulseExpand = 0.0f; flashed = false; } } } }
protected bool TrySwapping(int index, Item item, Character user, bool createNetworkEvent, bool swapWholeStack) { if (item?.ParentInventory == null || !slots[index].Any()) { return(false); } if (slots[index].Items.Any(it => !it.IsInteractable(user))) { return(false); } if (!AllowSwappingContainedItems) { return(false); } //swap to InvSlotType.Any if possible Inventory otherInventory = item.ParentInventory; bool otherIsEquipped = false; int otherIndex = -1; for (int i = 0; i < otherInventory.slots.Length; i++) { if (!otherInventory.slots[i].Contains(item)) { continue; } if (otherInventory is CharacterInventory characterInventory) { if (characterInventory.SlotTypes[i] == InvSlotType.Any) { otherIndex = i; break; } else { otherIsEquipped = true; } } } if (otherIndex == -1) { otherIndex = otherInventory.FindIndex(item); if (otherIndex == -1) { DebugConsole.ThrowError("Something went wrong when trying to swap items between inventory slots: couldn't find the source item from it's inventory.\n" + Environment.StackTrace.CleanupStackTrace()); return(false); } } List <Item> existingItems = new List <Item>(); if (swapWholeStack) { existingItems.AddRange(slots[index].Items); for (int j = 0; j < capacity; j++) { if (existingItems.Any(existingItem => slots[j].Contains(existingItem))) { slots[j].RemoveAllItems(); } } } else { existingItems.Add(slots[index].FirstOrDefault()); for (int j = 0; j < capacity; j++) { if (existingItems.Any(existingItem => slots[j].Contains(existingItem))) { slots[j].RemoveItem(existingItems.First()); } } } List <Item> stackedItems = new List <Item>(); if (swapWholeStack) { for (int j = 0; j < otherInventory.capacity; j++) { if (otherInventory.slots[j].Contains(item)) { stackedItems.AddRange(otherInventory.slots[j].Items); otherInventory.slots[j].RemoveAllItems(); } } } else { stackedItems.Add(item); otherInventory.slots[otherIndex].RemoveItem(item); } bool swapSuccessful = false; if (otherIsEquipped) { swapSuccessful = stackedItems.Distinct().All(stackedItem => TryPutItem(stackedItem, index, false, false, user, createNetworkEvent)) && (existingItems.All(existingItem => otherInventory.TryPutItem(existingItem, otherIndex, false, false, user, createNetworkEvent)) || existingItems.Count == 1 && otherInventory.TryPutItem(existingItems.First(), user, CharacterInventory.anySlot, createNetworkEvent)); } else { swapSuccessful = (existingItems.All(existingItem => otherInventory.TryPutItem(existingItem, otherIndex, false, false, user, createNetworkEvent)) || existingItems.Count == 1 && otherInventory.TryPutItem(existingItems.First(), user, CharacterInventory.anySlot, createNetworkEvent)) && stackedItems.Distinct().All(stackedItem => TryPutItem(stackedItem, index, false, false, user, createNetworkEvent)); if (!swapSuccessful && existingItems.Count == 1 && existingItems[0].AllowDroppingOnSwapWith(item)) { if (!(existingItems[0].Container?.ParentInventory is CharacterInventory characterInv) || !characterInv.TryPutItem(existingItems[0], user, new List <InvSlotType>() { InvSlotType.Any })) { existingItems[0].Drop(user, createNetworkEvent); } swapSuccessful = stackedItems.Distinct().Any(stackedItem => TryPutItem(stackedItem, index, false, false, user, createNetworkEvent)); #if CLIENT if (swapSuccessful) { SoundPlayer.PlayUISound(GUISoundType.DropItem); if (otherInventory.visualSlots != null && otherIndex > -1) { otherInventory.visualSlots[otherIndex].ShowBorderHighlight(Color.Transparent, 0.1f, 0.1f); } } #endif } } //if the item in the slot can be moved to the slot of the moved item if (swapSuccessful) { System.Diagnostics.Debug.Assert(slots[index].Contains(item), "Something when wrong when swapping items, item is not present in the inventory."); System.Diagnostics.Debug.Assert(!existingItems.Any(it => !it.Prefab.AllowDroppingOnSwap && !otherInventory.Contains(it)), "Something when wrong when swapping items, item is not present in the other inventory."); #if CLIENT if (visualSlots != null) { for (int j = 0; j < capacity; j++) { if (slots[j].Contains(item)) { visualSlots[j].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.9f); } } for (int j = 0; j < otherInventory.capacity; j++) { if (otherInventory.slots[j].Contains(existingItems.FirstOrDefault())) { otherInventory.visualSlots[j].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.9f); } } } #endif return(true); } else //swapping the items failed -> move them back to where they were { if (swapWholeStack) { foreach (Item stackedItem in stackedItems) { for (int j = 0; j < capacity; j++) { if (slots[j].Contains(stackedItem)) { slots[j].RemoveItem(stackedItem); } ; } } foreach (Item existingItem in existingItems) { for (int j = 0; j < otherInventory.capacity; j++) { if (otherInventory.slots[j].Contains(existingItem)) { otherInventory.slots[j].RemoveItem(existingItem); } } } } else { for (int j = 0; j < capacity; j++) { if (slots[j].Contains(item)) { slots[j].RemoveWhere(it => existingItems.Contains(it) || stackedItems.Contains(it)); } } for (int j = 0; j < otherInventory.capacity; j++) { if (otherInventory.slots[j].Contains(existingItems.FirstOrDefault())) { otherInventory.slots[j].RemoveWhere(it => existingItems.Contains(it) || stackedItems.Contains(it)); } } } if (otherIsEquipped) { existingItems.ForEach(existingItem => TryPutItem(existingItem, index, false, false, user, createNetworkEvent)); stackedItems.ForEach(stackedItem => otherInventory.TryPutItem(stackedItem, otherIndex, false, false, user, createNetworkEvent)); } else { stackedItems.ForEach(stackedItem => otherInventory.TryPutItem(stackedItem, otherIndex, false, false, user, createNetworkEvent)); existingItems.ForEach(existingItem => TryPutItem(existingItem, index, false, false, user, createNetworkEvent)); } #if CLIENT if (visualSlots != null) { for (int j = 0; j < capacity; j++) { if (slots[j].Contains(existingItems.FirstOrDefault())) { visualSlots[j].ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.9f); } } } #endif return(false); } }
private void ApplyImpact(float impact, Vector2 direction, Contact contact) { if (impact < 3.0f) { return; } Vector2 tempNormal; FixedArray2 <Vector2> worldPoints; contact.GetWorldManifold(out tempNormal, out worldPoints); Vector2 lastContactPoint = worldPoints[0]; if (Character.Controlled != null && Character.Controlled.Submarine == submarine) { GameMain.GameScreen.Cam.Shake = impact * 2.0f; } Vector2 impulse = direction * impact * 0.5f; impulse = impulse.ClampLength(5.0f); foreach (Character c in Character.CharacterList) { if (c.Submarine != submarine) { continue; } if (impact > 2.0f) { c.SetStun((impact - 2.0f) * 0.1f); } foreach (Limb limb in c.AnimController.Limbs) { limb.body.ApplyLinearImpulse(limb.Mass * impulse, 20.0f); } c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 20.0f); } foreach (Item item in Item.ItemList) { if (item.Submarine != submarine || item.CurrentHull == null || item.body == null || !item.body.Enabled) { continue; } item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f); } var damagedStructures = Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * ImpactDamageMultiplier); #if CLIENT //play a damage sound for the structure that took the most damage float maxDamage = 0.0f; Structure maxDamageStructure = null; foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures) { if (maxDamageStructure == null || structureDamage.Value > maxDamage) { maxDamage = structureDamage.Value; maxDamageStructure = structureDamage.Key; } } if (maxDamageStructure != null) { SoundPlayer.PlayDamageSound( "StructureBlunt", impact * 10.0f, ConvertUnits.ToDisplayUnits(lastContactPoint), MathHelper.Clamp(maxDamage * 4.0f, 1000.0f, 4000.0f), maxDamageStructure.Tags); } #endif }
private void ApplyImpact(float impact, Vector2 direction, Contact contact, bool applyDamage = true) { float minImpact = 3.0f; if (impact < minImpact) { return; } contact.GetWorldManifold(out Vector2 tempNormal, out FixedArray2 <Vector2> worldPoints); Vector2 lastContactPoint = worldPoints[0]; Vector2 impulse = direction * impact * 0.5f; impulse = impulse.ClampLength(5.0f); if (!MathUtils.IsValid(impulse)) { string errorMsg = "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse + ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + "."; if (GameMain.NetworkMember != null) { errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server."; } if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); } GameAnalyticsManager.AddErrorEventOnce( "SubmarineBody.ApplyImpact:InvalidImpulse", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } #if CLIENT if (Character.Controlled != null && Character.Controlled.Submarine == submarine) { GameMain.GameScreen.Cam.Shake = impact * 2.0f; float angularVelocity = (lastContactPoint.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y - (lastContactPoint.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X; GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f); } #endif foreach (Character c in Character.CharacterList) { if (c.Submarine != submarine) { continue; } if (impact > 2.0f) { c.SetStun((impact - 2.0f) * 0.1f); } foreach (Limb limb in c.AnimController.Limbs) { limb.body.ApplyLinearImpulse(limb.Mass * impulse, 20.0f); } c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 20.0f); } foreach (Item item in Item.ItemList) { if (item.Submarine != submarine || item.CurrentHull == null || item.body == null || !item.body.Enabled) { continue; } item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f); } var damagedStructures = Explosion.RangedStructureDamage( ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, applyDamage ? impact * ImpactDamageMultiplier : 0.0f); #if CLIENT //play a damage sound for the structure that took the most damage float maxDamage = 0.0f; Structure maxDamageStructure = null; foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures) { if (maxDamageStructure == null || structureDamage.Value > maxDamage) { maxDamage = structureDamage.Value; maxDamageStructure = structureDamage.Key; } } if (maxDamageStructure != null) { SoundPlayer.PlayDamageSound( "StructureBlunt", impact * 10.0f, ConvertUnits.ToDisplayUnits(lastContactPoint), MathHelper.Lerp(2000.0f, 10000.0f, (impact - minImpact) / 2.0f), maxDamageStructure.Tags); } #endif }