public override XElement Save(XElement parentElement) { if (Submarine == null) { string errorMsg = "Error - tried to save a hull that's not a part of any submarine.\n" + Environment.StackTrace; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("Hull.Save:WorldHull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return(null); } XElement element = new XElement("Hull"); element.Add ( new XAttribute("ID", ID), new XAttribute("rect", (int)(rect.X - Submarine.HiddenSubPosition.X) + "," + (int)(rect.Y - Submarine.HiddenSubPosition.Y) + "," + rect.Width + "," + rect.Height), new XAttribute("water", waterVolume) ); if (linkedTo != null && linkedTo.Count > 0) { var saveableLinked = linkedTo.Where(l => l.ShouldBeSaved && !l.Removed).ToList(); element.Add(new XAttribute("linked", string.Join(",", saveableLinked.Select(l => l.ID.ToString())))); } if (OriginalAmbientLight != null) { element.Add(new XAttribute("originalambientlight", XMLExtensions.ColorToString(OriginalAmbientLight.Value))); } SerializableProperty.SerializeProperties(this, element); parentElement.Add(element); return(element); }
public void CreateServerEvent <T>(T ic) where T : ItemComponent, IServerSerializable { if (GameMain.Server == null) { return; } if (!ItemList.Contains(this)) { string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet."; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } int index = components.IndexOf(ic); if (index == -1) { return; } GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.ComponentState, index }); }
private bool IsValidValue(Vector2 value, string valueName, float?minValue = null, float?maxValue = null) { if (!MathUtils.IsValid(value) || (minValue.HasValue && (value.X < minValue.Value || value.Y < minValue.Value)) || (maxValue.HasValue && (value.X > maxValue.Value || value.Y > maxValue))) { string userData = UserData == null ? "null" : UserData.ToString(); string errorMsg = "Attempted to apply invalid " + valueName + " to a physics body (userdata: " + userData + "), value: " + value + "\n" + Environment.StackTrace; if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); } GameAnalyticsManager.AddErrorEventOnce( "PhysicsBody.SetPosition:InvalidPosition" + userData, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return(false); } return(true); }
public void SelectMission(int missionIndex) { if (SelectedConnection == null) { return; } if (CurrentLocation == null) { string errorMsg = "Failed to select a mission (current location not set)."; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("Map.SelectMission:CurrentLocationNotSet", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } CurrentLocation.SelectedMissionIndex = missionIndex; //the destination must be the same as the destination of the mission if (CurrentLocation.SelectedMission != null && CurrentLocation.SelectedMission.Locations[1] != SelectedLocation) { SelectLocation(CurrentLocation.SelectedMission.Locations[1]); } OnMissionSelected?.Invoke(SelectedConnection, CurrentLocation.SelectedMission); }
public bool IsValidValue(float value, string valueName, float minValue = float.MinValue, float maxValue = float.MaxValue) { if (!MathUtils.IsValid(value) || value < minValue || value > maxValue) { string userData = UserData == null ? "null" : UserData.ToString(); string errorMsg = "Attempted to apply invalid " + valueName + " to a physics body (userdata: " + userData + "), value: " + value; if (GameMain.NetworkMember != null) { errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server."; } errorMsg += "\n" + Environment.StackTrace; if (GameSettings.VerboseLogging) DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce( "PhysicsBody.SetPosition:InvalidPosition" + userData, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return false; } return true; }
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { switch (type) { case ServerNetObject.ENTITY_POSITION: bool facingRight = AnimController.Dir > 0.0f; lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now; AnimController.Frozen = false; Enabled = true; UInt16 networkUpdateID = 0; if (msg.ReadBoolean()) { networkUpdateID = msg.ReadUInt16(); } else { bool aimInput = msg.ReadBoolean(); keys[(int)InputType.Aim].Held = aimInput; keys[(int)InputType.Aim].SetState(false, aimInput); bool shootInput = msg.ReadBoolean(); keys[(int)InputType.Shoot].Held = shootInput; keys[(int)InputType.Shoot].SetState(false, shootInput); bool useInput = msg.ReadBoolean(); keys[(int)InputType.Use].Held = useInput; keys[(int)InputType.Use].SetState(false, useInput); if (AnimController is HumanoidAnimController) { bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); } bool attackInput = msg.ReadBoolean(); keys[(int)InputType.Attack].Held = attackInput; keys[(int)InputType.Attack].SetState(false, attackInput); double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI; cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f; TransformCursorPos(); bool ragdollInput = msg.ReadBoolean(); keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); facingRight = msg.ReadBoolean(); } bool entitySelected = msg.ReadBoolean(); Character selectedCharacter = null; Item selectedItem = null; AnimController.Animation animation = AnimController.Animation.None; if (entitySelected) { ushort characterID = msg.ReadUInt16(); ushort itemID = msg.ReadUInt16(); selectedCharacter = FindEntityByID(characterID) as Character; selectedItem = FindEntityByID(itemID) as Item; if (characterID != NullEntityID) { bool doingCpr = msg.ReadBoolean(); if (doingCpr && SelectedCharacter != null) { animation = AnimController.Animation.CPR; } } } Vector2 pos = new Vector2( msg.ReadSingle(), msg.ReadSingle()); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float?rotation = null; float?angularVelocity = null; if (!fixedRotation) { rotation = msg.ReadSingle(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); if (readStatus) { ReadStatus(msg); (AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg); } msg.ReadPadBits(); int index = 0; if (GameMain.Client.Character == this && CanMove) { var posInfo = new CharacterStateInfo( pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) { index++; } memState.Insert(index, posInfo); } else { var posInfo = new CharacterStateInfo( pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) { index++; } memState.Insert(index, posInfo); } break; case ServerNetObject.ENTITY_EVENT: int eventType = msg.ReadRangedInteger(0, 5); switch (eventType) { case 0: //NetEntityEvent.Type.InventoryState if (Inventory == null) { string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); //read anyway to prevent messing up reading the rest of the message UInt16 lastEventID = msg.ReadUInt16(); byte itemCount = msg.ReadByte(); for (int i = 0; i < itemCount; i++) { msg.ReadUInt16(); } } else { Inventory.ClientRead(type, msg, sendingTime); } break; case 1: //NetEntityEvent.Type.Control byte ownerID = msg.ReadByte(); ResetNetState(); if (ownerID == GameMain.Client.ID) { if (controlled != null) { LastNetworkUpdateID = controlled.LastNetworkUpdateID; } if (!IsDead) { Controlled = this; } IsRemotePlayer = false; GameMain.Client.HasSpawned = true; GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; } else { if (controlled == this) { Controlled = null; IsRemotePlayer = ownerID > 0; } } break; case 2: //NetEntityEvent.Type.Status ReadStatus(msg); break; case 3: //NetEntityEvent.Type.UpdateSkills int skillCount = msg.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = msg.ReadString(); float skillLevel = msg.ReadSingle(); info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f); } break; case 4: //NetEntityEvent.Type.ExecuteAttack int attackLimbIndex = msg.ReadByte(); UInt16 targetEntityID = msg.ReadUInt16(); int targetLimbIndex = msg.ReadByte(); //255 = entity already removed, no need to do anything if (attackLimbIndex == 255 || Removed) { break; } if (attackLimbIndex >= AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"); break; } Limb attackLimb = AnimController.Limbs[attackLimbIndex]; Limb targetLimb = null; if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity)) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target entity not found (ID {targetEntityID})"); break; } if (targetEntity is Character targetCharacter) { if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"); break; } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; } if (attackLimb?.attack != null) { attackLimb.ExecuteAttack(targetEntity, targetLimb, out _); } break; case 5: //NetEntityEvent.Type.AssignCampaignInteraction byte campaignInteractionType = msg.ReadByte(); (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType); break; } msg.ReadPadBits(); break; } }
public void SaveNewPlayerConfig() { XDocument doc = new XDocument(); UnsavedSettings = false; if (doc.Root == null) { doc.Add(new XElement("config")); } doc.Root.Add( new XAttribute("language", TextManager.Language), new XAttribute("masterserverurl", MasterServerUrl), new XAttribute("autocheckupdates", AutoCheckUpdates), new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), new XAttribute("verboselogging", VerboseLogging), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), new XAttribute("enablesplashscreen", EnableSplashScreen), new XAttribute("usesteammatchmaking", useSteamMatchmaking), new XAttribute("quickstartsub", QuickStartSubmarineName), new XAttribute("requiresteamauthentication", requireSteamAuthentication), new XAttribute("autoupdateworkshopitems", AutoUpdateWorkshopItems), new XAttribute("pauseonfocuslost", PauseOnFocusLost), new XAttribute("aimassistamount", aimAssistAmount), new XAttribute("enablemouselook", EnableMouseLook), new XAttribute("chatopen", ChatOpen), new XAttribute("crewmenuopen", CrewMenuOpen), new XAttribute("campaigndisclaimershown", CampaignDisclaimerShown), new XAttribute("editordisclaimershown", EditorDisclaimerShown)); if (!string.IsNullOrEmpty(overrideSaveFolder)) { doc.Root.Add(new XAttribute("overridesavefolder", overrideSaveFolder)); } if (!string.IsNullOrEmpty(overrideMultiplayerSaveFolder)) { doc.Root.Add(new XAttribute("overridemultiplayersavefolder", overrideMultiplayerSaveFolder)); } if (!ShowUserStatisticsPrompt) { doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics)); } XElement gMode = doc.Root.Element("graphicsmode"); if (gMode == null) { gMode = new XElement("graphicsmode"); doc.Root.Add(gMode); } if (GraphicsWidth == 0 || GraphicsHeight == 0) { gMode.ReplaceAttributes(new XAttribute("displaymode", windowMode)); } else { gMode.ReplaceAttributes( new XAttribute("width", GraphicsWidth), new XAttribute("height", GraphicsHeight), new XAttribute("vsync", VSyncEnabled), new XAttribute("displaymode", windowMode)); } XElement audio = doc.Root.Element("audio"); if (audio == null) { audio = new XElement("audio"); doc.Root.Add(audio); } audio.ReplaceAttributes( new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), new XAttribute("voicechatvolume", voiceChatVolume), new XAttribute("microphonevolume", microphoneVolume), new XAttribute("muteonfocuslost", MuteOnFocusLost), new XAttribute("usedirectionalvoicechat", UseDirectionalVoiceChat), new XAttribute("voicesetting", VoiceSetting), new XAttribute("voicecapturedevice", VoiceCaptureDevice ?? ""), new XAttribute("noisegatethreshold", NoiseGateThreshold)); XElement gSettings = doc.Root.Element("graphicssettings"); if (gSettings == null) { gSettings = new XElement("graphicssettings"); doc.Root.Add(gSettings); } gSettings.ReplaceAttributes( new XAttribute("particlelimit", ParticleLimit), new XAttribute("lightmapscale", LightMapScale), new XAttribute("specularity", SpecularityEnabled), new XAttribute("chromaticaberration", ChromaticAberrationEnabled), new XAttribute("losmode", LosMode), new XAttribute("hudscale", HUDScale), new XAttribute("inventoryscale", InventoryScale)); foreach (ContentPackage contentPackage in SelectedContentPackages) { doc.Root.Add(new XElement("contentpackage", new XAttribute("path", contentPackage.Path))); } var keyMappingElement = new XElement("keymapping"); doc.Root.Add(keyMappingElement); for (int i = 0; i < keyMapping.Length; i++) { if (keyMapping[i].MouseButton == null) { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].Key)); } else { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].MouseButton)); } } var gameplay = new XElement("gameplay"); var jobPreferences = new XElement("jobpreferences"); foreach (string jobName in JobPreferences) { jobPreferences.Add(new XElement("job", new XAttribute("identifier", jobName))); } gameplay.Add(jobPreferences); doc.Root.Add(gameplay); var playerElement = new XElement("player", new XAttribute("name", defaultPlayerName ?? ""), new XAttribute("headindex", CharacterHeadIndex), new XAttribute("gender", CharacterGender), new XAttribute("race", CharacterRace), new XAttribute("hairindex", CharacterHairIndex), new XAttribute("beardindex", CharacterBeardIndex), new XAttribute("moustacheindex", CharacterMoustacheIndex), new XAttribute("faceattachmentindex", CharacterFaceAttachmentIndex)); doc.Root.Add(playerElement); #if CLIENT if (Tutorial.Tutorials != null) { foreach (Tutorial tutorial in Tutorial.Tutorials) { if (tutorial.Completed && !CompletedTutorialNames.Contains(tutorial.Identifier)) { CompletedTutorialNames.Add(tutorial.Identifier); } } } #endif var tutorialElement = new XElement("tutorials"); foreach (string tutorialName in CompletedTutorialNames) { tutorialElement.Add(new XElement("Tutorial", new XAttribute("name", tutorialName))); } doc.Root.Add(tutorialElement); XmlWriterSettings settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NewLineOnAttributes = true }; try { using (var writer = XmlWriter.Create(playerSavePath, settings)) { doc.WriteTo(writer); writer.Flush(); } } catch (Exception e) { DebugConsole.ThrowError("Saving game settings failed.", e); GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace); } }
private void SaveNewDefaultConfig() { XDocument doc = new XDocument(); if (doc.Root == null) { doc.Add(new XElement("config")); } doc.Root.Add( new XAttribute("language", TextManager.Language), new XAttribute("masterserverurl", MasterServerUrl), new XAttribute("autocheckupdates", AutoCheckUpdates), new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), new XAttribute("microphonevolume", microphoneVolume), new XAttribute("voicechatvolume", voiceChatVolume), new XAttribute("verboselogging", VerboseLogging), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), new XAttribute("enablesplashscreen", EnableSplashScreen), new XAttribute("usesteammatchmaking", useSteamMatchmaking), new XAttribute("quickstartsub", QuickStartSubmarineName), new XAttribute("requiresteamauthentication", requireSteamAuthentication), new XAttribute("aimassistamount", aimAssistAmount)); if (!ShowUserStatisticsPrompt) { doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics)); } if (WasGameUpdated) { doc.Root.Add(new XAttribute("wasgameupdated", true)); } XElement gMode = doc.Root.Element("graphicsmode"); if (gMode == null) { gMode = new XElement("graphicsmode"); doc.Root.Add(gMode); } if (GraphicsWidth == 0 || GraphicsHeight == 0) { gMode.ReplaceAttributes(new XAttribute("displaymode", windowMode)); } else { gMode.ReplaceAttributes( new XAttribute("width", GraphicsWidth), new XAttribute("height", GraphicsHeight), new XAttribute("vsync", VSyncEnabled), new XAttribute("displaymode", windowMode)); } XElement gSettings = doc.Root.Element("graphicssettings"); if (gSettings == null) { gSettings = new XElement("graphicssettings"); doc.Root.Add(gSettings); } gSettings.ReplaceAttributes( new XAttribute("particlelimit", ParticleLimit), new XAttribute("lightmapscale", LightMapScale), new XAttribute("specularity", SpecularityEnabled), new XAttribute("chromaticaberration", ChromaticAberrationEnabled), new XAttribute("losmode", LosMode), new XAttribute("hudscale", HUDScale), new XAttribute("inventoryscale", InventoryScale)); foreach (ContentPackage contentPackage in SelectedContentPackages) { if (contentPackage.Path.Contains(vanillaContentPackagePath)) { doc.Root.Add(new XElement("contentpackage", new XAttribute("path", contentPackage.Path))); break; } } var keyMappingElement = new XElement("keymapping"); doc.Root.Add(keyMappingElement); for (int i = 0; i < keyMapping.Length; i++) { if (keyMapping[i].MouseButton == null) { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].Key)); } else { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].MouseButton)); } } var gameplay = new XElement("gameplay"); var jobPreferences = new XElement("jobpreferences"); foreach (string jobName in JobPreferences) { jobPreferences.Add(new XElement("job", new XAttribute("identifier", jobName))); } gameplay.Add(jobPreferences); doc.Root.Add(gameplay); var playerElement = new XElement("player", new XAttribute("name", defaultPlayerName ?? ""), new XAttribute("headindex", CharacterHeadIndex), new XAttribute("gender", CharacterGender), new XAttribute("race", CharacterRace), new XAttribute("hairindex", CharacterHairIndex), new XAttribute("beardindex", CharacterBeardIndex), new XAttribute("moustacheindex", CharacterMoustacheIndex), new XAttribute("faceattachmentindex", CharacterFaceAttachmentIndex)); doc.Root.Add(playerElement); XmlWriterSettings settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NewLineOnAttributes = true }; try { using (var writer = XmlWriter.Create(savePath, settings)) { doc.WriteTo(writer); writer.Flush(); } } catch (Exception e) { DebugConsole.ThrowError("Saving game settings failed.", e); GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace); } }
public override void Update(float deltaTime, Camera cam) { flowForce = Vector2.Zero; outsideColliderRaycastTimer -= deltaTime; if (open == 0.0f || linkedTo.Count == 0) { lerpedFlowForce = Vector2.Zero; return; } Hull hull1 = (Hull)linkedTo[0]; Hull hull2 = linkedTo.Count < 2 ? null : (Hull)linkedTo[1]; if (hull1 == hull2) { return; } UpdateOxygen(hull1, hull2); if (linkedTo.Count == 1) { //gap leading from a room to outside UpdateRoomToOut(deltaTime, hull1); } else if (linkedTo.Count == 2) { //gap leading from a room to another UpdateRoomToRoom(deltaTime, hull1, hull2); } flowForce.X = MathHelper.Clamp(flowForce.X, -MaxFlowForce, MaxFlowForce); flowForce.Y = MathHelper.Clamp(flowForce.Y, -MaxFlowForce, MaxFlowForce); lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, deltaTime * 5.0f); EmitParticles(deltaTime); if (flowTargetHull != null && lerpedFlowForce.LengthSquared() > 0.0001f) { foreach (Character character in Character.CharacterList) { if (character.CurrentHull == null) { continue; } if (character.CurrentHull != linkedTo[0] as Hull && (linkedTo.Count < 2 || character.CurrentHull != linkedTo[1] as Hull)) { continue; } foreach (Limb limb in character.AnimController.Limbs) { if (!limb.inWater) { continue; } float dist = Vector2.Distance(limb.WorldPosition, WorldPosition); if (dist > lerpedFlowForce.Length()) { continue; } Vector2 force = lerpedFlowForce / (float)Math.Max(Math.Sqrt(dist), 20.0f) * 0.025f; //vertical gaps only apply forces if the character is roughly above/below the gap if (!IsHorizontal) { float xDist = Math.Abs(limb.WorldPosition.X - WorldPosition.X); if (xDist > rect.Width || rect.Width == 0) { break; } force *= 1.0f - xDist / rect.Width; } if (!MathUtils.IsValid(force)) { string errorMsg = "Attempted to apply invalid flow force to the character \"" + character.Name + "\", gap pos: " + WorldPosition + ", limb pos: " + limb.WorldPosition + ", flowforce: " + flowForce + ", lerpedFlowForce:" + lerpedFlowForce + ", dist: " + dist; DebugConsole.Log(errorMsg); GameAnalyticsManager.AddErrorEventOnce("Gap.Update:InvalidFlowForce:" + character.Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); continue; } character.AnimController.Collider.ApplyForce(force * limb.body.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } } } }
void UpdateDying(float deltaTime) { if (deathAnimDuration <= 0.0f) { return; } float noise = (PerlinNoise.GetPerlin(WalkPos * 0.002f, WalkPos * 0.003f) - 0.5f) * 5.0f; float animStrength = (1.0f - deathAnimTimer / deathAnimDuration); Limb head = GetLimb(LimbType.Head); if (head != null && head.IsSevered) { return; } Limb tail = GetLimb(LimbType.Tail); if (head != null && !head.IsSevered) { head.body.ApplyTorque((float)(Math.Sqrt(head.Mass) * Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } if (tail != null && !tail.IsSevered) { tail.body.ApplyTorque((float)(Math.Sqrt(tail.Mass) * -Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } WalkPos += deltaTime * 10.0f * animStrength; Vector2 centerOfMass = GetCenterOfMass(); foreach (Limb limb in Limbs) { if (limb.IsSevered) { continue; } #if CLIENT if (limb.LightSource != null) { limb.LightSource.Color = Color.Lerp(limb.InitialLightSourceColor, Color.TransparentBlack, deathAnimTimer / deathAnimDuration); if (limb.InitialLightSpriteAlpha.HasValue) { limb.LightSource.OverrideLightSpriteAlpha = MathHelper.Lerp(limb.InitialLightSpriteAlpha.Value, 0.0f, deathAnimTimer / deathAnimDuration); } } #endif if (limb.type == LimbType.Head || limb.type == LimbType.Tail || limb.IsSevered || !limb.body.Enabled) { continue; } if (limb.Mass <= 0.0f) { string errorMsg = "Creature death animation error: invalid limb mass on character \"" + character.SpeciesName + "\" (type: " + limb.type + ", mass: " + limb.Mass + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidMass" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } Vector2 diff = (centerOfMass - limb.SimPosition); if (!MathUtils.IsValid(diff)) { string errorMsg = "Creature death animation error: invalid diff (center of mass: " + centerOfMass + ", limb position: " + limb.SimPosition + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidDiff" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength, maxVelocity: 10.0f); } }
public GUIFrame CreateSummaryFrame(string endMessage) { bool singleplayer = GameMain.NetworkMember == null; bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsUnconscious); bool progress = Submarine.MainSub.AtEndPosition; if (!singleplayer) { SoundPlayer.OverrideMusicType = gameOver ? "crewdead" : "endround"; SoundPlayer.OverrideMusicDuration = 18.0f; } GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker"); int width = 760, height = 500; GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.5f), frame.RectTransform, Anchor.Center, minSize: new Point(width, height))); var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center)) { Stretch = true, RelativeSpacing = 0.03f }; GUIListBox infoTextBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), paddedFrame.RectTransform)) { Spacing = (int)(5 * GUI.Scale) }; //spacing new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), infoTextBox.Content.RectTransform), style: null); string summaryText = TextManager.GetWithVariables(gameOver ? "RoundSummaryGameOver" : (progress ? "RoundSummaryProgress" : "RoundSummaryReturn"), new string[2] { "[sub]", "[location]" }, new string[2] { Submarine.MainSub.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name }); var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform), summaryText, wrap: true); GUIComponent endText = null; if (!string.IsNullOrWhiteSpace(endMessage)) { endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform), TextManager.GetServerMessage(endMessage), wrap: true); } //don't show the mission info if the mission was not completed and there's no localized "mission failed" text available if (GameMain.GameSession.Mission != null) { string message = GameMain.GameSession.Mission.Completed ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage; if (!string.IsNullOrEmpty(message)) { //spacing var spacingTransform = new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform); new GUIFrame(spacingTransform, style: null); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("Mission"), GameMain.GameSession.Mission.Name), font: GUI.LargeFont); var missionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform), message, wrap: true); if (GameMain.GameSession.Mission.Completed && singleplayer) { var missionReward = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform), TextManager.GetWithVariable("MissionReward", "[reward]", GameMain.GameSession.Mission.Reward.ToString())); } } } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), TextManager.Get("RoundSummaryCrewStatus"), font: GUI.LargeFont); GUIListBox characterListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), paddedFrame.RectTransform, minSize: new Point(0, 75)), isHorizontal: true); foreach (CharacterInfo characterInfo in gameSession.CrewManager.GetCharacterInfos()) { if (GameMain.GameSession.Mission is CombatMission && characterInfo.TeamID != GameMain.GameSession.WinningTeam) { continue; } var characterFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), characterListBox.Content.RectTransform, minSize: new Point(170, 0))) { CanBeFocused = false, Stretch = true }; characterInfo.CreateCharacterFrame(characterFrame, characterInfo.Job != null ? (characterInfo.Name + '\n' + "(" + characterInfo.Job.Name + ")") : characterInfo.Name, null); string statusText = TextManager.Get("StatusOK"); Color statusColor = Color.DarkGreen; Character character = characterInfo.Character; if (character == null || character.IsDead) { if (characterInfo.CauseOfDeath == null) { statusText = TextManager.Get("CauseOfDeathDescription.Unknown"); } else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null) { string errorMsg = "Character \"" + character.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified)."; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); statusText = TextManager.Get("CauseOfDeathDescription.Unknown"); } else { statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ? characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription : TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString()); } statusColor = Color.DarkRed; } else { if (character.IsUnconscious) { statusText = TextManager.Get("Unconscious"); statusColor = Color.DarkOrange; } else if (character.Vitality / character.MaxVitality < 0.8f) { statusText = TextManager.Get("Injured"); statusColor = Color.DarkOrange; } } var textHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), characterFrame.RectTransform, Anchor.BottomCenter), style: "InnerGlow", color: statusColor); new GUITextBlock(new RectTransform(Vector2.One, textHolder.RectTransform, Anchor.Center), statusText, Color.White, textAlignment: Alignment.Center, wrap: true, font: GUI.SmallFont, style: null); } new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.BottomRight) { RelativeSpacing = 0.05f, UserData = "buttonarea" }; paddedFrame.Recalculate(); foreach (GUIComponent child in infoTextBox.Content.Children) { child.CanBeFocused = false; if (child is GUITextBlock textBlock) { textBlock.CalculateHeightFromText(); } } return(frame); }
public override bool TryPutItem(Item item, int index, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false) { if (index < 0 || index >= slots.Length) { string errorMsg = "CharacterInventory.TryPutItem failed: index was out of range(" + index + ").\n" + Environment.StackTrace.CleanupStackTrace(); GameAnalyticsManager.AddErrorEventOnce("CharacterInventory.TryPutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return(false); } #if CLIENT if (PersonalSlots.HasFlag(SlotTypes[index])) { hidePersonalSlots = false; } #endif //there's already an item in the slot if (slots[index].Any()) { if (slots[index].Contains(item)) { return(false); } return(base.TryPutItem(item, index, allowSwapping, allowCombine, user, createNetworkEvent, ignoreCondition)); } if (SlotTypes[index] == InvSlotType.Any) { if (!item.GetComponents <Pickable>().Any(p => p.AllowedSlots.Contains(InvSlotType.Any))) { return(false); } if (slots[index].Any()) { return(slots[index].Contains(item)); } PutItem(item, index, user, true, createNetworkEvent); return(true); } InvSlotType placeToSlots = InvSlotType.None; bool slotsFree = true; foreach (Pickable pickable in item.GetComponents <Pickable>()) { foreach (InvSlotType allowedSlot in pickable.AllowedSlots) { if (!allowedSlot.HasFlag(SlotTypes[index])) { continue; } #if CLIENT if (PersonalSlots.HasFlag(allowedSlot)) { hidePersonalSlots = false; } #endif for (int i = 0; i < capacity; i++) { if (allowedSlot.HasFlag(SlotTypes[i]) && slots[i].Any() && !slots[i].Contains(item)) { slotsFree = false; break; } placeToSlots = allowedSlot; } } } if (!slotsFree) { return(false); } return(TryPutItem(item, user, new List <InvSlotType>() { placeToSlots }, createNetworkEvent, ignoreCondition)); }
public static VertexPositionTexture[] GenerateWallShapes(List <VoronoiCell> cells, Level level) { float outWardThickness = 30.0f; List <VertexPositionTexture> verticeList = new List <VertexPositionTexture>(); foreach (VoronoiCell cell in cells) { CompareCCW compare = new CompareCCW(cell.Center); foreach (GraphEdge edge in cell.Edges) { if (edge.Cell1 != null && edge.Cell1.Body == null && edge.Cell1.CellType != CellType.Empty) { edge.Cell1 = null; } if (edge.Cell2 != null && edge.Cell2.Body == null && edge.Cell2.CellType != CellType.Empty) { edge.Cell2 = null; } if (compare.Compare(edge.Point1, edge.Point2) == -1) { var temp = edge.Point1; edge.Point1 = edge.Point2; edge.Point2 = temp; } } } foreach (VoronoiCell cell in cells) { foreach (GraphEdge edge in cell.Edges) { if (!edge.IsSolid) { continue; } GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1 == e.Point1 || edge.Point1 == e.Point2)); GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2 == e.Point1 || edge.Point2 == e.Point2)); Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero; float inwardThickness1 = 100; float inwardThickness2 = 100; if (leftEdge != null && !leftEdge.IsSolid) { leftNormal = edge.Point1 == leftEdge.Point1 ? Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) : Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2); inwardThickness1 = Vector2.Distance(leftEdge.Point1, leftEdge.Point2) / 2; } else { leftNormal = Vector2.Normalize(cell.Center - edge.Point1); inwardThickness1 = Vector2.Distance(edge.Point1, cell.Center) / 2; } if (!MathUtils.IsValid(leftNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid left normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { GameMain.World.RemoveBody(cell.Body); cell.Body = null; } leftNormal = Vector2.UnitX; break; } if (rightEdge != null && !rightEdge.IsSolid) { rightNormal = edge.Point2 == rightEdge.Point1 ? Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) : Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2); inwardThickness2 = Vector2.Distance(rightEdge.Point1, rightEdge.Point2) / 2; } else { rightNormal = Vector2.Normalize(cell.Center - edge.Point2); inwardThickness2 = Vector2.Distance(edge.Point2, cell.Center) / 2; } if (!MathUtils.IsValid(rightNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid right normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { GameMain.World.RemoveBody(cell.Body); cell.Body = null; } rightNormal = Vector2.UnitX; break; } float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - cell.Center)); float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - cell.Center)); //handle wrapping around 0/360 if (point1UV - point2UV > MathHelper.Pi) { point2UV += MathHelper.TwoPi; } //the texture wraps around the cell 4 times //TODO: define the uv scale in level generation parameters? point1UV = point1UV / MathHelper.TwoPi * 4; point2UV = point2UV / MathHelper.TwoPi * 4; for (int i = 0; i < 2; i++) { Vector2[] verts = new Vector2[3]; VertexPositionTexture[] vertPos = new VertexPositionTexture[3]; if (i == 0) { verts[0] = edge.Point1 - leftNormal * outWardThickness; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point1 + leftNormal * inwardThickness1; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.0f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point1UV, 0.5f)); } else { verts[0] = edge.Point1 + leftNormal * inwardThickness1; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point2 + rightNormal * inwardThickness2; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.5f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point2UV, 0.5f)); } verticeList.AddRange(vertPos); } } } return(verticeList.ToArray()); }
private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox) { GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style: "ListBoxElement") { CanBeFocused = false, UserData = characterInfo, Color = (Character.Controlled?.Info == characterInfo) ? TabMenu.OwnCharacterBGColor : Color.Transparent }; var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true) { AbsoluteSpacing = 2, Stretch = true }; new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => characterInfo.DrawJobIcon(sb, component.Rect)) { ToolTip = characterInfo.Job.Name ?? "", HoverColor = Color.White, SelectedColor = Color.White }; GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), ToolBox.LimitString(characterInfo.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor); string statusText = TextManager.Get("StatusOK"); Color statusColor = GUI.Style.Green; Character character = characterInfo.Character; if (character == null || character.IsDead) { if (character == null && characterInfo.IsNewHire) { statusText = TextManager.Get("CampaignCrew.NewHire"); statusColor = GUI.Style.Blue; } else if (characterInfo.CauseOfDeath == null) { statusText = TextManager.Get("CauseOfDeathDescription.Unknown"); statusColor = Color.DarkRed; } else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null) { string errorMsg = "Character \"" + characterInfo.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified)."; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); statusText = TextManager.Get("CauseOfDeathDescription.Unknown"); statusColor = GUI.Style.Red; } else { statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ? characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription : TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString()); statusColor = Color.DarkRed; } } else { if (character.IsUnconscious) { statusText = TextManager.Get("Unconscious"); statusColor = Color.DarkOrange; } else if (character.Vitality / character.MaxVitality < 0.8f) { statusText = TextManager.Get("Injured"); statusColor = Color.DarkOrange; } } GUITextBlock statusBlock = new GUITextBlock(new RectTransform(new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), ToolBox.LimitString(statusText, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: statusColor); }
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 && Character.Controlled.KnockbackCooldownTimer <= 0.0f) { GameMain.GameScreen.Cam.Shake = Math.Max(impact * 10.0f, GameMain.GameScreen.Cam.Shake); if (submarine.Info.Type == SubmarineType.Player && !submarine.DockedTo.Any(s => s.Info.Type != 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; } if (c.KnockbackCooldownTimer > 0.0f) { continue; } c.KnockbackCooldownTimer = Character.KnockbackCooldown; foreach (Limb limb in c.AnimController.Limbs) { if (limb.IsSevered) { continue; } limb.body.ApplyLinearImpulse(limb.Mass * impulse, 10.0f); } bool holdingOntoSomething = false; if (c.SelectedConstruction != null) { holdingOntoSomething = c.SelectedConstruction.GetComponent <Ladder>() != null || (c.SelectedConstruction.GetComponent <Controller>()?.LimbPositions.Any() ?? false); } if (!holdingOntoSomething) { c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 10.0f); //stun for up to 2 second if the impact equal or higher to the maximum impact if (impact >= MaxCollisionImpact) { c.AddDamage(impactPos, AfflictionPrefab.ImpactDamage.Instantiate(3.0f).ToEnumerable(), stun: Math.Min(impulse.Length() * 0.2f, 2.0f), playSound: true); } } } 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); item.PositionUpdateInterval = 0.0f; } float dmg = applyDamage ? impact * ImpactDamageMultiplier : 0.0f; var damagedStructures = Explosion.RangedStructureDamage( ConvertUnits.ToDisplayUnits(impactPos), impact * 50.0f, dmg, dmg); #if CLIENT PlayDamageSounds(damagedStructures, impactPos, impact, "StructureBlunt"); #endif }
public void CreateSettingsFrame(Tab selectedTab = Tab.Graphics) { settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center)); var settingsFramePadding = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.01f, IsHorizontal = true }; /// General tab -------------------------------------------------------------- var leftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 1.0f), settingsFramePadding.RectTransform, Anchor.TopLeft)); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform), TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont); var generalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), leftPanel.RectTransform, Anchor.TopLeft)); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("ContentPackages")); var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.75f), generalLayoutGroup.RectTransform)) { CanBeFocused = false, ScrollBarVisible = true }; foreach (ContentPackage contentPackage in ContentPackage.List) { var tickBox = new GUITickBox(new RectTransform(new Point(32, 32), contentPackageList.Content.RectTransform), contentPackage.Name) { UserData = contentPackage, OnSelected = SelectContentPackage, Selected = SelectedContentPackages.Contains(contentPackage) }; if (!contentPackage.IsCompatible()) { tickBox.TextColor = Color.Red; tickBox.Enabled = false; tickBox.ToolTip = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage") .Replace("[packagename]", contentPackage.Name) .Replace("[packageversion]", contentPackage.GameVersion.ToString()) .Replace("[gameversion]", GameMain.Version.ToString()); } else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List <ContentType> missingContentTypes)) { tickBox.TextColor = Color.Red; tickBox.Enabled = false; tickBox.ToolTip = TextManager.Get("ContentPackageMissingCoreFiles") .Replace("[packagename]", contentPackage.Name) .Replace("[missingfiletypes]", string.Join(", ", missingContentTypes)); } } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.045f), generalLayoutGroup.RectTransform), TextManager.Get("Language")); var languageDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.045f), generalLayoutGroup.RectTransform)); foreach (string language in TextManager.AvailableLanguages) { languageDD.AddItem(TextManager.Get("Language." + language), language); } languageDD.SelectItem(TextManager.Language); languageDD.OnSelected = (guiComponent, obj) => { string newLanguage = obj as string; if (newLanguage == Language) { return(true); } UnsavedSettings = true; Language = newLanguage; new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage")); return(true); }; var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.99f - leftPanel.RectTransform.RelativeSize.X, 0.95f), settingsFramePadding.RectTransform, Anchor.TopLeft)); var tabButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), rightPanel.RectTransform, Anchor.TopCenter), isHorizontal: true); var paddedFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), rightPanel.RectTransform, Anchor.Center), style: null); tabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length]; tabButtons = new GUIButton[tabs.Length]; foreach (Tab tab in Enum.GetValues(typeof(Tab))) { tabs[(int)tab] = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.91f), paddedFrame.RectTransform), style: "InnerFrame") { UserData = tab }; tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform), TextManager.Get("SettingsTab." + tab.ToString()), style: "GUITabButton") { UserData = tab, OnClicked = (bt, userdata) => { SelectTab((Tab)userdata); return(true); } }; } var buttonArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.08f), paddedFrame.RectTransform, Anchor.BottomCenter), style: null); /// Graphics tab -------------------------------------------------------------- var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.TopLeft) { RelativeOffset = new Vector2(0.025f, 0.02f) }) { RelativeSpacing = 0.01f }; var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.025f, 0.02f) }) { RelativeSpacing = 0.01f }; var supportedDisplayModes = new List <DisplayMode>(); foreach (DisplayMode mode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes) { if (supportedDisplayModes.Any(m => m.Width == mode.Width && m.Height == mode.Height)) { continue; } #if OSX // Monogame currently doesn't support retina displays // so we need to disable resolutions above the viewport size. // In a bundled .app you just disable HiDPI in the info.plist // but that's probably not gonna happen. if (mode.Width > GameMain.Instance.GraphicsDevice.DisplayMode.Width || mode.Height > GameMain.Instance.GraphicsDevice.DisplayMode.Height) { continue; } #endif supportedDisplayModes.Add(mode); } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("Resolution")); var resolutionDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), elementCount: supportedDisplayModes.Count) { OnSelected = SelectResolution, #if OSX ButtonEnabled = GameMain.Config.WindowMode == WindowMode.Windowed #endif }; foreach (DisplayMode mode in supportedDisplayModes) { if (mode.Width < MinSupportedResolution.X || mode.Height < MinSupportedResolution.Y) { continue; } resolutionDD.AddItem(mode.Width + "x" + mode.Height, mode); if (GraphicsWidth == mode.Width && GraphicsHeight == mode.Height) { resolutionDD.SelectItem(mode); } } if (resolutionDD.SelectedItemData == null) { resolutionDD.SelectItem(GraphicsAdapter.DefaultAdapter.SupportedDisplayModes.Last()); } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("DisplayMode")); var displayModeDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform)); displayModeDD.AddItem(TextManager.Get("Fullscreen"), WindowMode.Fullscreen); displayModeDD.AddItem(TextManager.Get("Windowed"), WindowMode.Windowed); #if (!OSX) displayModeDD.AddItem(TextManager.Get("BorderlessWindowed"), WindowMode.BorderlessWindowed); displayModeDD.SelectItem(GameMain.Config.WindowMode); #else // Fullscreen option will just set itself to borderless on macOS. if (GameMain.Config.WindowMode == WindowMode.BorderlessWindowed) { displayModeDD.SelectItem(WindowMode.Fullscreen); } else { displayModeDD.SelectItem(GameMain.Config.WindowMode); } #endif displayModeDD.OnSelected = (guiComponent, obj) => { UnsavedSettings = true; GameMain.Config.WindowMode = (WindowMode)guiComponent.UserData; #if OSX resolutionDD.ButtonEnabled = GameMain.Config.WindowMode == WindowMode.Windowed; #endif return(true); }; GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("EnableVSync")) { ToolTip = TextManager.Get("EnableVSyncToolTip"), OnSelected = (GUITickBox box) => { VSyncEnabled = box.Selected; GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = VSyncEnabled; GameMain.GraphicsDeviceManager.ApplyChanges(); UnsavedSettings = true; return(true); }, Selected = VSyncEnabled }; GUITextBlock particleLimitText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ParticleLimit")); GUIScrollBar particleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f) { UserData = particleLimitText, BarScroll = (ParticleLimit - 200) / 1300.0f, OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); ParticleLimit = 200 + (int)(scroll * 1300.0f); return(true); }, Step = 0.1f }; particleScrollBar.OnMoved(particleScrollBar, particleScrollBar.BarScroll); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LosEffect")); var losModeDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform)); losModeDD.AddItem(TextManager.Get("LosModeNone"), LosMode.None); losModeDD.AddItem(TextManager.Get("LosModeTransparent"), LosMode.Transparent); losModeDD.AddItem(TextManager.Get("LosModeOpaque"), LosMode.Opaque); losModeDD.SelectItem(GameMain.Config.LosMode); losModeDD.OnSelected = (guiComponent, obj) => { UnsavedSettings = true; GameMain.Config.LosMode = (LosMode)guiComponent.UserData; //don't allow changing los mode when playing as a client if (GameMain.Client == null) { GameMain.LightManager.LosMode = GameMain.Config.LosMode; } return(true); }; GUITextBlock LightText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LightMapScale")) { ToolTip = TextManager.Get("LightMapScaleToolTip") }; GUIScrollBar lightScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f) { UserData = LightText, ToolTip = TextManager.Get("LightMapScaleToolTip"), BarScroll = MathUtils.InverseLerp(0.2f, 1.0f, LightMapScale), OnMoved = (scrollBar, barScroll) => { ChangeSliderText(scrollBar, barScroll); LightMapScale = MathHelper.Lerp(0.2f, 1.0f, barScroll); UnsavedSettings = true; return(true); }, Step = 0.25f }; lightScrollBar.OnMoved(lightScrollBar, lightScrollBar.BarScroll); new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("SpecularLighting")) { ToolTip = TextManager.Get("SpecularLightingToolTip"), Selected = SpecularityEnabled, OnSelected = (tickBox) => { SpecularityEnabled = tickBox.Selected; UnsavedSettings = true; return(true); } }; new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("ChromaticAberration")) { ToolTip = TextManager.Get("ChromaticAberrationToolTip"), Selected = ChromaticAberrationEnabled, OnSelected = (tickBox) => { ChromaticAberrationEnabled = tickBox.Selected; UnsavedSettings = true; return(true); } }; GUITextBlock HUDScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("HUDScale")); GUIScrollBar HUDScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f) { UserData = HUDScaleText, BarScroll = (HUDScale - MinHUDScale) / (MaxHUDScale - MinHUDScale), OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); HUDScale = MathHelper.Lerp(MinHUDScale, MaxHUDScale, scroll); UnsavedSettings = true; OnHUDScaleChanged?.Invoke(); return(true); }, Step = 0.05f }; HUDScaleScrollBar.OnMoved(HUDScaleScrollBar, HUDScaleScrollBar.BarScroll); GUITextBlock inventoryScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("InventoryScale")); GUIScrollBar inventoryScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f) { UserData = inventoryScaleText, BarScroll = (InventoryScale - MinInventoryScale) / (MaxInventoryScale - MinInventoryScale), OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); InventoryScale = MathHelper.Lerp(MinInventoryScale, MaxInventoryScale, scroll); UnsavedSettings = true; return(true); }, Step = 0.05f }; inventoryScaleScrollBar.OnMoved(inventoryScaleScrollBar, inventoryScaleScrollBar.BarScroll); /// Audio tab ---------------------------------------------------------------- var audioSliders = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.02f) }) { RelativeSpacing = 0.01f }; GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("SoundVolume")); GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), barSize: 0.05f) { UserData = soundVolumeText, BarScroll = SoundVolume, OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); SoundVolume = scroll; return(true); }, Step = 0.05f }; soundScrollBar.OnMoved(soundScrollBar, soundScrollBar.BarScroll); GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("MusicVolume")); GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), barSize: 0.05f) { UserData = musicVolumeText, BarScroll = MusicVolume, OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); MusicVolume = scroll; return(true); }, Step = 0.05f }; musicScrollBar.OnMoved(musicScrollBar, musicScrollBar.BarScroll); GUITextBlock voiceChatVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChatVolume")); GUIScrollBar voiceChatScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), barSize: 0.05f) { UserData = voiceChatVolumeText, BarScroll = VoiceChatVolume, OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); VoiceChatVolume = scroll; return(true); }, Step = 0.05f }; voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll); GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get("MuteOnFocusLost")); muteOnFocusLostBox.Selected = MuteOnFocusLost; muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip"); muteOnFocusLostBox.OnSelected = (tickBox) => { MuteOnFocusLost = tickBox.Selected; UnsavedSettings = true; return(true); }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChat")); IList <string> deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier); foreach (string name in deviceNames) { DebugConsole.NewMessage(name + " " + name.Length.ToString(), Color.Lime); } if (string.IsNullOrWhiteSpace(VoiceCaptureDevice)) { VoiceCaptureDevice = deviceNames[0]; } #if (!OSX) var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), VoiceCaptureDevice, deviceNames.Count); foreach (string name in deviceNames) { deviceList.AddItem(name, name); } deviceList.OnSelected = (GUIComponent selected, object obj) => { string name = obj as string; if (VoiceCaptureDevice == name) { return(true); } VoipCapture.ChangeCaptureDevice(name); return(true); }; #else var suavemente = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("CurrentDevice") + ": " + VoiceCaptureDevice) { ToolTip = TextManager.Get("CurrentDeviceToolTip.OSX"), TextAlignment = Alignment.CenterX }; new GUIButton(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform), TextManager.Get("RefreshDefaultDevice")) { ToolTip = TextManager.Get("RefreshDefaultDeviceToolTip"), OnClicked = (bt, userdata) => { deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier); if (VoiceCaptureDevice == deviceNames[0]) { return(true); } VoipCapture.ChangeCaptureDevice(deviceNames[0]); suavemente.Text = TextManager.Get("CurrentDevice") + ": " + VoiceCaptureDevice; suavemente.Flash(Color.Blue); return(true); } }; #endif //var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.12f), audioSliders.RectTransform)); GUIRadioButtonGroup voiceMode = new GUIRadioButtonGroup(); for (int i = 0; i < 3; i++) { string langStr = "VoiceMode." + ((VoiceMode)i).ToString(); var tick = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get(langStr)) { ToolTip = TextManager.Get(langStr + "ToolTip") }; voiceMode.AddRadioButton((VoiceMode)i, tick); } var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("MicrophoneVolume")); var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), barSize: 0.05f) { UserData = micVolumeText, BarScroll = (float)Math.Sqrt(MathUtils.InverseLerp(0.2f, 5.0f, MicrophoneVolume)), OnMoved = (scrollBar, scroll) => { MicrophoneVolume = MathHelper.Lerp(0.2f, 5.0f, scroll * scroll); MicrophoneVolume = (float)Math.Round(MicrophoneVolume, 1); ChangeSliderText(scrollBar, MicrophoneVolume); scrollBar.Step = 0.05f; return(true); }, Step = 0.05f }; micVolumeSlider.OnMoved(micVolumeSlider, micVolumeSlider.BarScroll); var extraVoiceSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), audioSliders.RectTransform, Anchor.BottomCenter), style: null); var voiceInputContainer = new GUILayoutGroup(new RectTransform(Vector2.One, extraVoiceSettingsContainer.RectTransform, Anchor.BottomCenter)); new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.25f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice") + ": "); var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 0.25f), voiceInputContainer.RectTransform, Anchor.TopRight), text: keyMapping[(int)InputType.Voice].ToString()) { UserData = InputType.Voice }; voiceKeyBox.OnSelected += KeyBoxSelected; voiceKeyBox.SelectedColor = Color.Gold * 0.3f; var voiceActivityGroup = new GUILayoutGroup(new RectTransform(Vector2.One, extraVoiceSettingsContainer.RectTransform)); GUITextBlock noiseGateText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), voiceActivityGroup.RectTransform), TextManager.Get("NoiseGateThreshold")) { TextGetter = () => { return(TextManager.Get("NoiseGateThreshold") + " " + ((int)NoiseGateThreshold).ToString() + " dB"); } }; var dbMeter = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.25f), voiceActivityGroup.RectTransform), 0.0f, Color.Lime); dbMeter.ProgressGetter = () => { if (VoipCapture.Instance == null) { return(0.0f); } dbMeter.Color = VoipCapture.Instance.LastdB > NoiseGateThreshold ? Color.Lime : Color.Orange; //TODO: i'm a filthy hack return(((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f); }; var noiseGateSlider = new GUIScrollBar(new RectTransform(Vector2.One, dbMeter.RectTransform, Anchor.Center), color: Color.White, barSize: 0.03f); noiseGateSlider.Frame.Visible = false; noiseGateSlider.Step = 0.01f; noiseGateSlider.Range = new Vector2(-100.0f, 0.0f); noiseGateSlider.BarScrollValue = NoiseGateThreshold; noiseGateSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) => { NoiseGateThreshold = scrollBar.BarScrollValue; UnsavedSettings = true; return(true); }; voiceMode.OnSelect = (GUIRadioButtonGroup rbg, Enum value) => { if (rbg.Selected != null && rbg.Selected.Equals(value)) { return; } try { VoiceMode vMode = (VoiceMode)value; VoiceSetting = vMode; if (vMode == VoiceMode.Activity) { voiceActivityGroup.Visible = true; if (GameMain.Client == null && VoipCapture.Instance == null) { VoipCapture.Create(GameMain.Config.VoiceCaptureDevice); if (VoipCapture.Instance == null) { VoiceSetting = vMode = VoiceMode.Disabled; voiceInputContainer.Visible = false; voiceActivityGroup.Visible = false; return; } } } else { voiceActivityGroup.Visible = false; if (GameMain.Client == null) { VoipCapture.Instance?.Dispose(); } } voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk); UnsavedSettings = true; } catch (Exception e) { DebugConsole.ThrowError("Failed to set voice capture mode.", e); GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace); VoiceSetting = VoiceMode.Disabled; } }; voiceMode.Selected = VoiceSetting; /// Controls tab ------------------------------------------------------------- var controlsLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.Controls].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.02f) }) { RelativeSpacing = 0.01f }; GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform), TextManager.Get("AimAssist")) { ToolTip = TextManager.Get("AimAssistToolTip") }; GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform), barSize: 0.05f) { UserData = aimAssistText, BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount), ToolTip = TextManager.Get("AimAssistToolTip"), OnMoved = (scrollBar, scroll) => { ChangeSliderText(scrollBar, scroll); AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll); return(true); }, Step = 0.1f }; aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll); new GUITickBox(new RectTransform(new Point(32, 32), controlsLayoutGroup.RectTransform), TextManager.Get("EnableMouseLook")) { ToolTip = TextManager.Get("EnableMouseLookToolTip"), Selected = EnableMouseLook, OnSelected = (tickBox) => { EnableMouseLook = tickBox.Selected; UnsavedSettings = true; return(true); } }; var inputFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f), controlsLayoutGroup.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.03f }; var inputColumnLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), inputFrame.RectTransform)) { Stretch = true, RelativeSpacing = 0.02f }; var inputColumnRight = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), inputFrame.RectTransform)) { Stretch = true, RelativeSpacing = 0.02f }; var inputNames = Enum.GetValues(typeof(InputType)); for (int i = 0; i < inputNames.Length; i++) { var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), (i <= (inputNames.Length / 2.2f) ? inputColumnLeft : inputColumnRight).RectTransform)) { Stretch = true, IsHorizontal = true, RelativeSpacing = 0.05f, Color = new Color(12, 14, 15, 215) }; new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(150, 0) }, TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont) { ForceUpperCase = true }; var keyBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1.0f), inputContainer.RectTransform), text: keyMapping[i].ToString(), font: GUI.SmallFont) { UserData = i }; keyBox.OnSelected += KeyBoxSelected; keyBox.SelectedColor = Color.Gold * 0.3f; } var resetControlsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), controlsLayoutGroup.RectTransform), isHorizontal: true) { RelativeSpacing = 0.02f }; new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), resetControlsHolder.RectTransform), TextManager.Get("SetDefaultBindings")) { ToolTip = TextManager.Get("SetDefaultBindingsToolTip"), OnClicked = (button, data) => { ResetControls(legacy: false); return(true); } }; new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), resetControlsHolder.RectTransform), TextManager.Get("SetLegacyBindings")) { ToolTip = TextManager.Get("SetLegacyBindingsToolTip"), OnClicked = (button, data) => { ResetControls(legacy: true); return(true); } }; //spacing new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null); new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft), TextManager.Get("Cancel"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, OnClicked = (x, y) => { if (UnsavedSettings) { LoadPlayerConfig(); } if (Screen.Selected == GameMain.MainMenuScreen) { GameMain.MainMenuScreen.ReturnToMainMenu(null, null); } GUI.SettingsMenuOpen = false; return(true); } }; new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonArea.RectTransform, Anchor.BottomCenter), TextManager.Get("Reset"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, OnClicked = (button, data) => { // TODO: add a prompt LoadDefaultConfig(); CheckBindings(true); RefreshItemMessages(); ApplySettings(); if (Screen.Selected == GameMain.MainMenuScreen) { GameMain.MainMenuScreen.ResetSettingsFrame(currentTab); } else { ResetSettingsFrame(); CreateSettingsFrame(currentTab); } return(true); } }; applyButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonArea.RectTransform, Anchor.BottomRight), TextManager.Get("ApplySettingsButton"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, Enabled = false }; applyButton.OnClicked = ApplyClicked; UnsavedSettings = false; // Reset unsaved settings to false once the UI has been created SelectTab(selectedTab); }
public static Body GeneratePolygons(List<VoronoiCell> cells, Level level, out List<Vector2[]> renderTriangles) { renderTriangles = new List<Vector2[]>(); List<Vector2> tempVertices = new List<Vector2>(); List<Vector2> bodyPoints = new List<Vector2>(); Body cellBody = new Body(GameMain.World) { SleepingAllowed = false, BodyType = BodyType.Static, CollisionCategories = Physics.CollisionLevel }; for (int n = cells.Count - 1; n >= 0; n-- ) { VoronoiCell cell = cells[n]; bodyPoints.Clear(); tempVertices.Clear(); foreach (GraphEdge ge in cell.Edges) { if (Vector2.DistanceSquared(ge.Point1, ge.Point2) < 0.01f) continue; if (!tempVertices.Any(v => Vector2.DistanceSquared(ge.Point1, v) < 1.0f)) { tempVertices.Add(ge.Point1); bodyPoints.Add(ge.Point1); } if (!tempVertices.Any(v => Vector2.DistanceSquared(ge.Point2, v) < 1.0f)) { tempVertices.Add(ge.Point2); bodyPoints.Add(ge.Point2); } } if (tempVertices.Count < 3 || bodyPoints.Count < 2) { cells.RemoveAt(n); continue; } renderTriangles.AddRange(MathUtils.TriangulateConvexHull(tempVertices, cell.Center)); if (bodyPoints.Count < 2) continue; if (bodyPoints.Count < 3) { foreach (Vector2 vertex in tempVertices) { if (bodyPoints.Contains(vertex)) continue; bodyPoints.Add(vertex); break; } } for (int i = 0; i < bodyPoints.Count; i++) { cell.BodyVertices.Add(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); } if (cell.CellType == CellType.Empty) continue; cellBody.UserData = cell; var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); for (int i = 0; i < triangles.Count; i++) { //don't create a triangle if the area of the triangle is too small //(apparently Farseer doesn't like polygons with a very small area, see Shape.ComputeProperties) Vector2 a = triangles[i][0]; Vector2 b = triangles[i][1]; Vector2 c = triangles[i][2]; float area = Math.Abs(a.X * (b.Y - c.Y) + b.X * (c.Y - a.Y) + c.X * (a.Y - b.Y)) / 2.0f; if (area < 1.0f) continue; Vertices bodyVertices = new Vertices(triangles[i]); var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); newFixture.UserData = cell; if (newFixture.Shape.MassData.Area < FarseerPhysics.Settings.Epsilon) { DebugConsole.ThrowError("Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + ")"); GameAnalyticsManager.AddErrorEventOnce( "CaveGenerator.GeneratePolygons:InvalidTriangle", GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + "). Seed: " + level.Seed); } } cell.Body = cellBody; } return cellBody; }
private static void UpdateWaterAmbience(float ambienceVolume, float deltaTime) { if (GameMain.SoundManager.Disabled) { return; } //how fast the sub is moving, scaled to 0.0 -> 1.0 float movementSoundVolume = 0.0f; float insideSubFactor = 0.0f; foreach (Submarine sub in Submarine.Loaded) { float movementFactor = (sub.Velocity == Vector2.Zero) ? 0.0f : sub.Velocity.Length() / 10.0f; movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f); if (Character.Controlled == null || Character.Controlled.Submarine != sub) { float dist = Vector2.Distance(GameMain.GameScreen.Cam.WorldViewCenter, sub.WorldPosition); movementFactor /= Math.Max(dist / 1000.0f, 1.0f); insideSubFactor = Math.Max(1.0f / Math.Max(dist / 1000.0f, 1.0f), insideSubFactor); } else { insideSubFactor = 1.0f; } movementSoundVolume = Math.Max(movementSoundVolume, movementFactor); if (!MathUtils.IsValid(movementSoundVolume)) { string errorMsg = "Failed to update water ambience volume - submarine's movement value invalid (" + movementSoundVolume + ", sub velocity: " + sub.Velocity + ")"; DebugConsole.Log(errorMsg); GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); movementSoundVolume = 0.0f; } } for (int i = 0; i < 3; i++) { float volume = 0.0f; Sound sound = null; switch (i) { case 0: volume = ambienceVolume * (1.0f - movementSoundVolume) * insideSubFactor; sound = waterAmbienceIn; break; case 1: volume = ambienceVolume * movementSoundVolume * insideSubFactor; sound = waterAmbienceMoving; break; case 2: volume = 1.0f - insideSubFactor; sound = waterAmbienceOut; break; } if ((waterAmbienceChannels[i] == null || !waterAmbienceChannels[i].IsPlaying) && volume > 0.01f) { waterAmbienceChannels[i] = sound.Play(volume, "waterambience"); waterAmbienceChannels[i].Looping = true; } else if (waterAmbienceChannels[i] != null) { waterAmbienceChannels[i].Gain += deltaTime * Math.Sign(volume - waterAmbienceChannels[i].Gain); if (waterAmbienceChannels[i].Gain < 0.01f) { waterAmbienceChannels[i].FadeOutAndDispose(); } } } }
//constructors & generation ---------------------------------------------------- public Submarine(string filePath, string hash = "", bool tryLoad = true) : base(null) { this.filePath = filePath; try { name = System.IO.Path.GetFileNameWithoutExtension(filePath); } catch (Exception e) { DebugConsole.ThrowError("Error loading submarine " + filePath + "!", e); } if (hash != "") { this.hash = new Md5Hash(hash); } if (tryLoad) { XDocument doc = OpenFile(filePath); if (doc != null && doc.Root != null) { Description = doc.Root.GetAttributeString("description", ""); Enum.TryParse(doc.Root.GetAttributeString("tags", ""), out tags); Dimensions = doc.Root.GetAttributeVector2("dimensions", Vector2.Zero); RecommendedCrewSizeMin = doc.Root.GetAttributeInt("recommendedcrewsizemin", 0); RecommendedCrewSizeMax = doc.Root.GetAttributeInt("recommendedcrewsizemax", 0); RecommendedCrewExperience = doc.Root.GetAttributeString("recommendedcrewexperience", "Unknown"); string[] contentPackageNames = doc.Root.GetAttributeStringArray("compatiblecontentpackages", new string[0]); foreach (string contentPackageName in contentPackageNames) { CompatibleContentPackages.Add(contentPackageName); } #if CLIENT string previewImageData = doc.Root.GetAttributeString("previewimage", ""); if (!string.IsNullOrEmpty(previewImageData)) { try { using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData))) { PreviewImage = new Sprite(TextureLoader.FromStream(mem), null, null); } } catch (Exception e) { DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e); GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted."); PreviewImage = null; } } #endif } } DockedTo = new List <Submarine>(); ID = ushort.MaxValue; FreeID(); }
private void UpdateLocationView(Location location) { if (location == null) { string errorMsg = "Failed to update CampaignUI location view (location was null)\n" + Environment.StackTrace; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("CampaignUI.UpdateLocationView:LocationNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } if (characterPreviewFrame != null) { characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame); characterPreviewFrame = null; } if (characterList != null) { if (Campaign is SinglePlayerCampaign) { var hireableCharacters = location.GetHireableCharacters(); foreach (GUIComponent child in characterList.Content.Children.ToList()) { if (child.UserData is CharacterInfo character) { if (GameMain.GameSession.CrewManager != null) { if (GameMain.GameSession.CrewManager.GetCharacterInfos().Contains(character)) { continue; } } } else if (child.UserData as string == "mycrew" || child.UserData as string == "hire") { continue; } characterList.RemoveChild(child); } if (!hireableCharacters.Any()) { new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), characterList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center) { CanBeFocused = false }; } else { foreach (CharacterInfo c in hireableCharacters) { var frame = c.CreateCharacterFrame(characterList.Content, c.Name + " (" + c.Job.Name + ")", c); new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.TopRight), c.Salary.ToString(), textAlignment: Alignment.CenterRight); } } } characterList.UpdateScrollBarSize(); } RefreshMyItems(); bool purchaseableItemsFound = false; foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List) { if (!(mapEntityPrefab is ItemPrefab itemPrefab)) { continue; } PriceInfo priceInfo = itemPrefab.GetPrice(Campaign.Map.CurrentLocation); if (priceInfo != null) { purchaseableItemsFound = true; break; } } //disable store tab if there's nothing to buy tabButtons.Find(btn => (Tab)btn.UserData == Tab.Store).Enabled = purchaseableItemsFound; if (selectedTab == Tab.Store && !purchaseableItemsFound) { //switch out from store tab if there's nothing to buy SelectTab(Tab.Map); } else { //refresh store view FillStoreItemList(); MapEntityCategory?category = null; //only select a specific category if the search box is empty //(items from all categories are shown when searching) if (string.IsNullOrEmpty(searchBox.Text)) { category = selectedItemCategory; } FilterStoreItems(category, searchBox.Text); } }
public static List <MapEntity> Clone(List <MapEntity> entitiesToClone) { List <MapEntity> clones = new List <MapEntity>(); foreach (MapEntity e in entitiesToClone) { Debug.Assert(e != null); try { clones.Add(e.Clone()); } catch (Exception ex) { DebugConsole.ThrowError("Cloning entity \"" + e.Name + "\" failed.", ex); GameAnalyticsManager.AddErrorEventOnce( "MapEntity.Clone:" + e.Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Cloning entity \"" + e.Name + "\" failed (" + ex.Message + ").\n" + ex.StackTrace); return(clones); } Debug.Assert(clones.Last() != null); } Debug.Assert(clones.Count == entitiesToClone.Count); //clone links between the entities for (int i = 0; i < clones.Count; i++) { if (entitiesToClone[i].linkedTo == null) { continue; } foreach (MapEntity linked in entitiesToClone[i].linkedTo) { if (!entitiesToClone.Contains(linked)) { continue; } clones[i].linkedTo.Add(clones[entitiesToClone.IndexOf(linked)]); } } //connect clone wires to the clone items and refresh links between doors and gaps for (int i = 0; i < clones.Count; i++) { var cloneItem = clones[i] as Item; if (cloneItem == null) { continue; } var door = cloneItem.GetComponent <Door>(); if (door != null) { door.RefreshLinkedGap(); } var cloneWire = cloneItem.GetComponent <Wire>(); if (cloneWire == null) { continue; } var originalWire = ((Item)entitiesToClone[i]).GetComponent <Wire>(); cloneWire.SetNodes(originalWire.GetNodes()); for (int n = 0; n < 2; n++) { if (originalWire.Connections[n] == null) { continue; } var connectedItem = originalWire.Connections[n].Item; if (connectedItem == null) { continue; } //index of the item the wire is connected to int itemIndex = entitiesToClone.IndexOf(connectedItem); if (itemIndex < 0) { DebugConsole.ThrowError("Error while cloning wires - item \"" + connectedItem.Name + "\" was not found in entities to clone."); GameAnalyticsManager.AddErrorEventOnce("MapEntity.Clone:ConnectedNotFound" + connectedItem.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Error while cloning wires - item \"" + connectedItem.Name + "\" was not found in entities to clone."); continue; } //index of the connection in the connectionpanel of the target item int connectionIndex = connectedItem.Connections.IndexOf(originalWire.Connections[n]); if (connectionIndex < 0) { DebugConsole.ThrowError("Error while cloning wires - connection \"" + originalWire.Connections[n].Name + "\" was not found in connected item \"" + connectedItem.Name + "\"."); GameAnalyticsManager.AddErrorEventOnce("MapEntity.Clone:ConnectionNotFound" + connectedItem.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Error while cloning wires - connection \"" + originalWire.Connections[n].Name + "\" was not found in connected item \"" + connectedItem.Name + "\"."); continue; } (clones[itemIndex] as Item).Connections[connectionIndex].TryAddLink(cloneWire); cloneWire.Connect((clones[itemIndex] as Item).Connections[connectionIndex], false); } } return(clones); }
private static void Place(IEnumerable <Submarine> subs) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { DebugConsole.ThrowError("Clients are not allowed to use AutoItemPlacer.\n" + Environment.StackTrace.CleanupStackTrace()); return; } int itemCountApprox = MapEntityPrefab.List.Count() / 3; var containers = new List <ItemContainer>(70 + 30 * subs.Count()); var prefabsWithContainer = new List <ItemPrefab>(itemCountApprox / 3); var prefabsWithoutContainer = new List <ItemPrefab>(itemCountApprox); var removals = new List <ItemPrefab>(); foreach (Item item in Item.ItemList) { if (!subs.Contains(item.Submarine)) { continue; } if (item.GetRootInventoryOwner() is Character) { continue; } containers.AddRange(item.GetComponents <ItemContainer>()); } containers.Shuffle(Rand.RandSync.Server); foreach (MapEntityPrefab prefab in MapEntityPrefab.List) { if (!(prefab is ItemPrefab ip)) { continue; } if (ip.ConfigElement.Elements().Any(e => string.Equals(e.Name.ToString(), typeof(ItemContainer).Name.ToString(), StringComparison.OrdinalIgnoreCase))) { prefabsWithContainer.Add(ip); } else { prefabsWithoutContainer.Add(ip); } } spawnedItems.Clear(); var validContainers = new Dictionary <ItemContainer, PreferredContainer>(); prefabsWithContainer.Shuffle(Rand.RandSync.Server); // Spawn items that have an ItemContainer component first so we can fill them up with items if needed (oxygen tanks inside the spawned diving masks, etc) for (int i = 0; i < prefabsWithContainer.Count; i++) { var itemPrefab = prefabsWithContainer[i]; if (itemPrefab == null) { continue; } if (SpawnItems(itemPrefab)) { removals.Add(itemPrefab); } } // Remove containers that we successfully spawned items into so that they are not counted in in the second pass. removals.ForEach(i => prefabsWithContainer.Remove(i)); // Another pass for items with containers because also they can spawn inside other items (like smg magazine) prefabsWithContainer.ForEach(i => SpawnItems(i)); // Spawn items that don't have containers last prefabsWithoutContainer.Shuffle(Rand.RandSync.Server); prefabsWithoutContainer.ForEach(i => SpawnItems(i)); if (OutputDebugInfo) { var subNames = subs.Select(s => s.Info.Name).ToList(); DebugConsole.NewMessage($"Automatically placed items in { string.Join(", ", subNames) }:"); foreach (string itemName in spawnedItems.Select(it => it.Name).Distinct()) { DebugConsole.NewMessage(" - " + itemName + " x" + spawnedItems.Count(it => it.Name == itemName)); } } if (GameMain.GameSession?.Level != null && GameMain.GameSession.Level.Type == LevelData.LevelType.Outpost && GameMain.GameSession.StartLocation?.TakenItems != null) { foreach (Location.TakenItem takenItem in GameMain.GameSession.StartLocation.TakenItems) { var matchingItem = spawnedItems.Find(it => takenItem.Matches(it)); if (matchingItem == null) { continue; } var containedItems = spawnedItems.FindAll(it => it.ParentInventory?.Owner == matchingItem); matchingItem.Remove(); spawnedItems.Remove(matchingItem); foreach (Item containedItem in containedItems) { containedItem.Remove(); spawnedItems.Remove(containedItem); } } } #if SERVER foreach (Item spawnedItem in spawnedItems) { Entity.Spawner.CreateNetworkEvent(spawnedItem, remove: false); } #endif bool SpawnItems(ItemPrefab itemPrefab) { if (itemPrefab == null) { string errorMsg = "Error in AutoItemPlacer.SpawnItems - itemPrefab was null.\n" + Environment.StackTrace.CleanupStackTrace(); DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("AutoItemPlacer.SpawnItems:ItemNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return(false); } bool success = false; foreach (PreferredContainer preferredContainer in itemPrefab.PreferredContainers) { if (preferredContainer.SpawnProbability <= 0.0f || preferredContainer.MaxAmount <= 0) { continue; } validContainers = GetValidContainers(preferredContainer, containers, validContainers, primary: true); if (validContainers.None()) { validContainers = GetValidContainers(preferredContainer, containers, validContainers, primary: false); } foreach (var validContainer in validContainers) { if (SpawnItem(itemPrefab, containers, validContainer)) { success = true; } } } return(success); } }
protected override void Draw(SpriteBatch spriteBatch) { if (!Visible) { return; } if (ProgressGetter != null) { float newSize = MathHelper.Clamp(ProgressGetter(), 0.0f, 1.0f); if (!MathUtils.IsValid(newSize)) { GameAnalyticsManager.AddErrorEventOnce( "GUIProgressBar.Draw:GetProgress", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace); } else { BarSize = newSize; } } Rectangle sliderRect = new Rectangle( frame.Rect.X, (int)(frame.Rect.Y + (isHorizontal ? 0 : frame.Rect.Height * (1.0f - barSize))), isHorizontal ? (int)((frame.Rect.Width) * barSize) : frame.Rect.Width, isHorizontal ? (int)(frame.Rect.Height) : (int)(frame.Rect.Height * barSize)); frame.Visible = true; slider.Visible = true; if (AutoDraw) { frame.DrawAuto(spriteBatch); } else { frame.DrawManually(spriteBatch); } Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle; if (BarSize <= 1.0f) { spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, sliderRect); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); } Color currColor = GetCurrentColor(state); slider.Color = currColor; if (AutoDraw) { slider.DrawAuto(spriteBatch); } else { slider.DrawManually(spriteBatch); } //hide the slider, we've already drawn it manually frame.Visible = false; slider.Visible = false; if (BarSize <= 1.0f) { spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect; } }
protected virtual void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true) { if (i < 0 || i >= slots.Length) { string errorMsg = "Inventory.PutItem failed: index was out of range(" + i + ").\n" + Environment.StackTrace.CleanupStackTrace(); GameAnalyticsManager.AddErrorEventOnce("Inventory.PutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } if (Owner == null) { return; } Inventory prevInventory = item.ParentInventory; Inventory prevOwnerInventory = item.FindParentInventory(inv => inv is CharacterInventory); if (createNetworkEvent) { CreateNetworkEvent(); //also delay syncing the inventory the item was inside if (prevInventory != null && prevInventory != this) { prevInventory.syncItemsDelay = 1.0f; } } if (removeItem) { item.Drop(user); if (item.ParentInventory != null) { item.ParentInventory.RemoveItem(item); } } slots[i].Add(item); item.ParentInventory = this; #if CLIENT if (visualSlots != null) { visualSlots[i]?.ShowBorderHighlight(Color.White, 0.1f, 0.4f); } #endif if (item.body != null) { item.body.Enabled = false; item.body.BodyType = FarseerPhysics.BodyType.Dynamic; } #if SERVER if (prevOwnerInventory is CharacterInventory characterInventory && characterInventory != this && Owner == user) { var client = GameMain.Server?.ConnectedClients?.Find(cl => cl.Character == user); GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(characterInventory, client, item); } #endif if (this is CharacterInventory) { if (prevInventory != this && prevOwnerInventory != this) { HumanAIController.ItemTaken(item, user); } } else { if (item.FindParentInventory(inv => inv is CharacterInventory) is CharacterInventory currentInventory) { if (currentInventory != prevInventory) { HumanAIController.ItemTaken(item, user); } } } }
private void HandleLimbCollision(Impact collision, Limb limb) { if (limb?.body?.FarseerBody == null || limb.character == null) { return; } if (limb.Mass > MinImpactLimbMass) { Vector2 normal = Vector2.DistanceSquared(Body.SimPosition, limb.SimPosition) < 0.0001f ? Vector2.UnitY : Vector2.Normalize(Body.SimPosition - limb.SimPosition); float impact = Math.Min(Vector2.Dot(collision.Velocity, -normal), 50.0f) * Math.Min(limb.Mass / 100.0f, 1); ApplyImpact(impact, -normal, collision.ImpactPos, applyDamage: false); foreach (Submarine dockedSub in submarine.DockedTo) { dockedSub.SubBody.ApplyImpact(impact, -normal, collision.ImpactPos, applyDamage: false); } } //find all contacts between the limb and level walls List <Contact> levelContacts = new List <Contact>(); ContactEdge contactEdge = limb.body.FarseerBody.ContactList; while (contactEdge?.Contact != null) { if (contactEdge.Contact.Enabled && contactEdge.Contact.IsTouching && contactEdge.Other?.UserData is VoronoiCell) { levelContacts.Add(contactEdge.Contact); } contactEdge = contactEdge.Next; } if (levelContacts.Count == 0) { return; } //if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it //not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete), //but more realistic than bouncing and prevents using characters as "bumpers" that prevent all collision damage Vector2 avgContactNormal = Vector2.Zero; foreach (Contact levelContact in levelContacts) { levelContact.GetWorldManifold(out Vector2 contactNormal, out FixedArray2 <Vector2> temp); //if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ? ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData); var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center; if (Vector2.Dot(contactNormal, cellDiff) < 0) { contactNormal = -contactNormal; } avgContactNormal += contactNormal; //apply impacts at the positions where this sub is touching the limb ApplyImpact((Vector2.Dot(-collision.Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, collision.ImpactPos, applyDamage: false); } avgContactNormal /= levelContacts.Count; float contactDot = Vector2.Dot(Body.LinearVelocity, -avgContactNormal); if (contactDot > 0.001f) { Vector2 velChange = Vector2.Normalize(Body.LinearVelocity) * contactDot; if (!MathUtils.IsValid(velChange)) { GameAnalyticsManager.AddErrorEventOnce( "SubmarineBody.HandleLimbCollision:" + submarine.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Invalid velocity change in SubmarineBody.HandleLimbCollision (submarine velocity: " + Body.LinearVelocity + ", avgContactNormal: " + avgContactNormal + ", contactDot: " + contactDot + ", velChange: " + velChange + ")"); return; } Body.LinearVelocity -= velChange; float damageAmount = contactDot * Body.Mass / limb.character.Mass; limb.character.LastDamageSource = submarine; limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(collision.ImpactPos), limb, AfflictionPrefab.ImpactDamage.Instantiate(damageAmount).ToEnumerable(), 0.0f, true, 0.0f); if (limb.character.IsDead) { foreach (LimbJoint limbJoint in limb.character.AnimController.LimbJoints) { if (limbJoint.IsSevered || (limbJoint.LimbA != limb && limbJoint.LimbB != limb)) { continue; } limb.character.AnimController.SeverLimbJoint(limbJoint); } } } }
public void Save(string filePath) { UnsavedSettings = false; XDocument doc = new XDocument(); if (doc.Root == null) { doc.Add(new XElement("config")); } doc.Root.Add( new XAttribute("masterserverurl", MasterServerUrl), new XAttribute("autocheckupdates", AutoCheckUpdates), new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), new XAttribute("verboselogging", VerboseLogging), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), new XAttribute("enablesplashscreen", EnableSplashScreen)); if (!ShowUserStatisticsPrompt) { doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics)); } if (WasGameUpdated) { doc.Root.Add(new XAttribute("wasgameupdated", true)); } XElement gMode = doc.Root.Element("graphicsmode"); if (gMode == null) { gMode = new XElement("graphicsmode"); doc.Root.Add(gMode); } if (GraphicsWidth == 0 || GraphicsHeight == 0) { gMode.ReplaceAttributes(new XAttribute("displaymode", windowMode)); } else { gMode.ReplaceAttributes( new XAttribute("width", GraphicsWidth), new XAttribute("height", GraphicsHeight), new XAttribute("vsync", VSyncEnabled), new XAttribute("displaymode", windowMode)); } if (SelectedContentPackage != null) { doc.Root.Add(new XElement("contentpackage", new XAttribute("path", SelectedContentPackage.Path))); } var keyMappingElement = new XElement("keymapping"); doc.Root.Add(keyMappingElement); for (int i = 0; i < keyMapping.Length; i++) { if (keyMapping[i].MouseButton == null) { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].Key)); } else { keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), keyMapping[i].MouseButton)); } } var gameplay = new XElement("gameplay"); var jobPreferences = new XElement("jobpreferences"); foreach (string jobName in JobNamePreferences) { jobPreferences.Add(new XElement("job", new XAttribute("name", jobName))); } gameplay.Add(jobPreferences); doc.Root.Add(gameplay); var playerElement = new XElement("player", new XAttribute("name", defaultPlayerName ?? ""), new XAttribute("headindex", characterHeadIndex), new XAttribute("gender", characterGender)); doc.Root.Add(playerElement); try { doc.Save(filePath); } catch (Exception e) { DebugConsole.ThrowError("Saving game settings failed.", e); GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace); } }
protected override void Draw(SpriteBatch spriteBatch) { if (!Visible) { return; } if (ProgressGetter != null) { float newSize = MathHelper.Clamp(ProgressGetter(), 0.0f, 1.0f); if (!MathUtils.IsValid(newSize)) { GameAnalyticsManager.AddErrorEventOnce( "GUIProgressBar.Draw:GetProgress", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace.CleanupStackTrace()); } else { BarSize = newSize; } } var sliderRect = GetSliderRect(barSize); slider.RectTransform.AbsoluteOffset = new Point((int)style.Padding.X, (int)style.Padding.Y); slider.RectTransform.MaxSize = new Point( (int)(Rect.Width - style.Padding.X + style.Padding.Z), (int)(Rect.Height - style.Padding.Y + style.Padding.W)); frame.Visible = showFrame; slider.Visible = BarSize > 0.0f; if (showFrame) { if (AutoDraw) { frame.DrawAuto(spriteBatch); } else { frame.DrawManually(spriteBatch); } } Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle; if (BarSize <= 1.0f) { spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, sliderRect); spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); } Color currColor = GetColor(State); slider.Color = currColor; if (AutoDraw) { slider.DrawAuto(spriteBatch); } else { slider.DrawManually(spriteBatch); } //hide the slider, we've already drawn it manually frame.Visible = false; slider.Visible = false; if (BarSize <= 1.0f) { spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect; } }
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 == SubmarineType.Player && !submarine.DockedTo.Any(s => s.Info.Type != 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) { if (limb.IsSevered) { continue; } 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 }
public static void RemoveAll() { List <Entity> list = new List <Entity>(dictionary.Values); foreach (Entity e in list) { try { e.Remove(); } catch (Exception exception) { DebugConsole.ThrowError("Error while removing entity \"" + e.ToString() + "\"", exception); GameAnalyticsManager.AddErrorEventOnce( "Entity.RemoveAll:Exception" + e.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Error while removing entity \"" + e.ToString() + " (" + exception.Message + ")\n" + exception.StackTrace); } } StringBuilder errorMsg = new StringBuilder(); if (dictionary.Count > 0) { errorMsg.AppendLine("Some entities were not removed in Entity.RemoveAll:"); foreach (Entity e in dictionary.Values) { errorMsg.AppendLine(" - " + e.ToString() + "(ID " + e.id + ")"); } } if (Item.ItemList.Count > 0) { errorMsg.AppendLine("Some items were not removed in Entity.RemoveAll:"); foreach (Item item in Item.ItemList) { errorMsg.AppendLine(" - " + item.Name + "(ID " + item.id + ")"); } var items = new List <Item>(Item.ItemList); foreach (Item item in items) { try { item.Remove(); } catch (Exception exception) { DebugConsole.ThrowError("Error while removing item \"" + item.ToString() + "\"", exception); } } Item.ItemList.Clear(); } if (Character.CharacterList.Count > 0) { errorMsg.AppendLine("Some characters were not removed in Entity.RemoveAll:"); foreach (Character character in Character.CharacterList) { errorMsg.AppendLine(" - " + character.Name + "(ID " + character.id + ")"); } var characters = new List <Character>(Character.CharacterList); foreach (Character character in characters) { try { character.Remove(); } catch (Exception exception) { DebugConsole.ThrowError("Error while removing character \"" + character.ToString() + "\"", exception); } } Character.CharacterList.Clear(); } if (!string.IsNullOrEmpty(errorMsg.ToString())) { foreach (string errorLine in errorMsg.ToString().Split('\n')) { DebugConsole.ThrowError(errorLine); } GameAnalyticsManager.AddErrorEventOnce("Entity.RemoveAll", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg.ToString()); } dictionary.Clear(); }
public override bool TryPutItem(Item item, int index, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true) { if (index < 0 || index >= Items.Length) { string errorMsg = "CharacterInventory.TryPutItem failed: index was out of range(" + index + ").\n" + Environment.StackTrace; GameAnalyticsManager.AddErrorEventOnce("CharacterInventory.TryPutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return(false); } //there's already an item in the slot if (Items[index] != null) { if (Items[index] == item) { return(false); } return(base.TryPutItem(item, index, allowSwapping, allowCombine, user, createNetworkEvent)); } if (SlotTypes[index] == InvSlotType.Any) { if (!item.AllowedSlots.Contains(InvSlotType.Any)) { return(false); } if (Items[index] != null) { return(Items[index] == item); } PutItem(item, index, user, true, createNetworkEvent); return(true); } InvSlotType placeToSlots = InvSlotType.None; bool slotsFree = true; List <InvSlotType> allowedSlots = item.AllowedSlots; foreach (InvSlotType allowedSlot in allowedSlots) { if (!allowedSlot.HasFlag(SlotTypes[index])) { continue; } for (int i = 0; i < capacity; i++) { if (allowedSlot.HasFlag(SlotTypes[i]) && Items[i] != null && Items[i] != item) { slotsFree = false; break; } placeToSlots = allowedSlot; } } if (!slotsFree) { return(false); } return(TryPutItem(item, user, new List <InvSlotType>() { placeToSlots }, createNetworkEvent)); }