From 044fd3344b37f0a1a188257fe58b8a67740da42e Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 18 Mar 2019 21:42:26 +0200 Subject: [PATCH] 2f107db...5202af9 --- .../BarotraumaClient/BarotraumaClient.csproj | 917 +-- .../BarotraumaClient.csproj.user | 37 +- .../BarotraumaClient/GlobalSuppressions.cs | 8 + .../MonoGame.Framework.dll.config | 4 +- Barotrauma/BarotraumaClient/OpenTK.dll.config | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../Source/Characters/AI/EnemyAIController.cs | 6 +- .../Source/Characters/AI/HumanAIController.cs | 55 +- .../Source/Characters/AICharacter.cs | 28 - .../Animation/HumanoidAnimParams.cs | 48 + .../Source/Characters/Animation/Ragdoll.cs | 233 +- .../Source/Characters/Character.cs | 206 +- .../Source/Characters/CharacterHUD.cs | 61 +- .../Source/Characters/CharacterHealth.cs | 21 +- .../Source/Characters/CharacterInfo.cs | 53 +- .../Source/Characters/CharacterNetworking.cs | 180 +- .../Source/Characters/CharacterSound.cs | 7 +- .../Characters/Health/AfflictionHusk.cs | 34 + .../Characters/Health/CharacterHealth.cs | 22 + .../Characters/Health/DamageModifier.cs | 12 + .../Source/Characters/Limb.cs | 106 +- .../BarotraumaClient/Source/DebugConsole.cs | 556 +- .../Source/EventInput/EventInput.cs | 3 +- .../Source/EventInput/KeyboardDispatcher.cs | 3 +- .../Source/Events/EventManager.cs | 5 +- .../Source/Events/Missions/CombatMission.cs | 22 + .../Source/Events/Missions/Mission.cs | 3 +- .../Source/Events/Missions/MissionMode.cs | 2 + .../BarotraumaClient/Source/GUI/ChatBox.cs | 4 +- Barotrauma/BarotraumaClient/Source/GUI/GUI.cs | 37 +- .../Source/GUI/GUIDropDown.cs | 6 + .../Source/GUI/GUIRadioButtonGroup.cs | 74 + .../Source/GUI/GUIScrollBar.cs | 41 +- .../Source/GUI/GUITextBlock.cs | 32 +- .../BarotraumaClient/Source/GUI/GUITextBox.cs | 26 +- .../BarotraumaClient/Source/GUI/GUITickBox.cs | 37 +- .../Source/GUI/HUDLayoutSettings.cs | 4 +- .../Source/GUI/LoadingScreen.cs | 122 +- .../Source/GUI/ShapeExtensions.cs | 4 +- .../BarotraumaClient/Source/GameMain.cs | 214 +- .../Source/GameSession/CrewManager.cs | 270 +- .../GameModes/MultiPlayerCampaign.cs | 117 +- .../GameModes/SinglePlayerCampaign.cs | 16 +- .../GameModes/Tutorials/BasicTutorial.cs | 2 +- .../GameModes/Tutorials/ContextualTutorial.cs | 6 +- .../GameModes/Tutorials/ScenarioTutorial.cs | 4 +- .../GameModes/Tutorials/Tutorial.cs | 8 +- .../Source/GameSession/GameSession.cs | 40 +- .../Source/GameSession/RoundSummary.cs | 14 +- .../BarotraumaClient/Source/GameSettings.cs | 514 +- .../Source/Items/CharacterInventory.cs | 2 +- .../Source/Items/Components/Door.cs | 62 +- .../Source/Items/Components/ItemComponent.cs | 23 +- .../Source/Items/Components/ItemContainer.cs | 13 +- .../Source/Items/Components/ItemLabel.cs | 1 + .../Source/Items/Components/LightComponent.cs | 5 + .../Items/Components/Machines/Controller.cs | 2 +- .../Components/Machines/Deconstructor.cs | 8 +- .../Items/Components/Machines/Engine.cs | 14 +- .../Items/Components/Machines/Fabricator.cs | 13 +- .../Items/Components/Machines/MiniMap.cs | 2 +- .../Source/Items/Components/Machines/Pump.cs | 15 +- .../Items/Components/Machines/Reactor.cs | 16 - .../Source/Items/Components/Machines/Sonar.cs | 120 +- .../Items/Components/Machines/Steering.cs | 26 +- .../Items/Components/Power/PowerContainer.cs | 13 +- .../Source/Items/Components/Power/Powered.cs | 3 +- .../Source/Items/Components/RepairTool.cs | 4 +- .../Source/Items/Components/Repairable.cs | 2 +- .../Items/Components/Signal/Connection.cs | 7 +- .../Components/Signal/CustomInterface.cs | 2 +- .../Items/Components/Signal/MotionSensor.cs | 5 + .../Items/Components/Signal/WifiComponent.cs | 5 + .../Source/Items/Components/Signal/Wire.cs | 7 +- .../Source/Items/Components/StatusHUD.cs | 14 +- .../Source/Items/Components/Turret.cs | 20 + .../Source/Items/DockingPort.cs | 7 +- .../Source/Items/Inventory.cs | 24 +- .../BarotraumaClient/Source/Items/Item.cs | 200 +- .../Source/Items/ItemInventory.cs | 23 +- .../BarotraumaClient/Source/Items/Rope.cs | 6 + Barotrauma/BarotraumaClient/Source/Map/Gap.cs | 7 +- .../BarotraumaClient/Source/Map/Hull.cs | 129 +- .../Source/Map/Levels/Level.cs | 2 - .../Map/Levels/LevelObjects/LevelObject.cs | 1 + .../Source/Map/Levels/LevelRenderer.cs | 8 +- .../Source/Map/Levels/WaterRenderer.cs | 5 +- .../Source/Map/Lights/LightManager.cs | 85 +- .../Source/Map/Lights/LightSource.cs | 6 +- .../BarotraumaClient/Source/Map/Map/Map.cs | 4 +- .../BarotraumaClient/Source/Map/MapEntity.cs | 5 + .../BarotraumaClient/Source/Map/Structure.cs | 51 +- .../BarotraumaClient/Source/Map/Submarine.cs | 113 +- .../Source/Map/SubmarineBody.cs | 61 + .../BarotraumaClient/Source/Map/WayPoint.cs | 5 + .../BarotraumaClient/Source/Media/Video.cs | 298 + .../Source/Networking/BanList.cs | 113 +- .../Source/Networking/ChatMessage.cs | 4 +- .../Source/Networking/Client.cs | 137 + .../Source/Networking/EntitySpawner.cs | 2 - .../Networking/FileTransfer/FileReceiver.cs | 10 - .../Source/Networking/GameClient.cs | 1100 ++- .../Source/Networking/GameServer.cs | 244 - .../Source/Networking/GameServerSettings.cs | 649 -- .../Source/Networking/NetStats.cs | 16 +- .../Source/Networking/NetworkMember.cs | 315 - .../Source/Networking/RespawnManager.cs | 15 + .../Source/Networking/ServerInfo.cs | 54 +- .../Source/Networking/ServerLog.cs | 8 +- .../Source/Networking/SteamManager.cs | 879 +++ .../Source/Networking/Voip/VoipCapture.cs | 208 + .../Source/Networking/Voip/VoipClient.cs | 127 + .../Source/Networking/Voip/VoipConfig.cs | 44 + .../Source/Networking/Voting.cs | 59 +- .../Source/Networking/WhiteList.cs | 159 +- .../Source/Physics/PhysicsBody.cs | 63 +- .../BarotraumaClient/Source/PlayerInput.cs | 86 +- Barotrauma/BarotraumaClient/Source/Program.cs | 30 +- .../Source/Screens/CampaignSetupUI.cs | 66 +- .../Source/Screens/CampaignUI.cs | 40 +- .../Source/Screens/CharacterEditorScreen.cs | 467 +- .../Source/Screens/GameScreen.cs | 18 +- .../Source/Screens/MainMenuScreen.cs | 339 +- .../Source/Screens/NetLobbyScreen.cs | 832 ++- .../Source/Screens/ServerListScreen.cs | 13 +- .../Source/Screens/SteamWorkshopScreen.cs | 74 +- .../Source/Screens/SubEditorScreen.cs | 34 +- .../Serialization/SerializableEntityEditor.cs | 51 +- .../Source/Sounds/OggSound.cs | 53 +- .../BarotraumaClient/Source/Sounds/Sound.cs | 84 +- .../Source/Sounds/SoundChannel.cs | 300 +- .../Source/Sounds/SoundFilters.cs | 492 ++ .../Source/Sounds/SoundManager.cs | 224 +- .../Source/Sounds/SoundPlayer.cs | 29 +- .../Source/Sounds/VideoSound.cs | 113 + .../Source/Sounds/VoipSound.cs | 141 + .../DeformAnimations/NoiseDeformation.cs | 2 +- .../Source/Sprite/DeformableSprite.cs | 2 +- .../BarotraumaClient/Source/Sprite/Sprite.cs | 12 +- .../Source/Utils/TextureLoader.cs | 64 +- .../BarotraumaClient/Source/Utils/ToolBox.cs | 42 +- Barotrauma/BarotraumaClient/app.config | 35 + .../libopenal.1.dylib | Bin Barotrauma/BarotraumaClient/libvlc.dll | Bin 0 -> 187592 bytes Barotrauma/BarotraumaClient/libvlc.dylib | Bin 0 -> 42426416 bytes Barotrauma/BarotraumaClient/libvlccore.dll | Bin 0 -> 2798792 bytes Barotrauma/BarotraumaClient/packages.config | 51 +- .../plugins/access/libfilesystem_plugin.dll | Bin 0 -> 67272 bytes .../audio_filter/libaudio_format_plugin.dll | Bin 0 -> 62152 bytes .../audio_filter/libugly_resampler_plugin.dll | Bin 0 -> 37576 bytes .../plugins/audio_output/libamem_plugin.dll | Bin 0 -> 39112 bytes .../plugins/demux/libmp4_plugin.dll | Bin 0 -> 317640 bytes .../libpacketizer_mpeg4audio_plugin.dll | Bin 0 -> 89288 bytes .../libpacketizer_mpeg4video_plugin.dll | Bin 0 -> 52424 bytes .../plugins/video_chroma/librv32_plugin.dll | Bin 0 -> 37064 bytes .../video_chroma/libswscale_plugin.dll | Bin 0 -> 926920 bytes .../plugins/video_output/libvmem_plugin.dll | Bin 0 -> 40136 bytes .../BarotraumaServer/BarotraumaServer.csproj | 422 +- .../Properties/AssemblyInfo.cs | 4 +- .../Source/Characters/Character.cs | 53 +- .../Source/Characters/CharacterInfo.cs | 40 + .../Source/Characters/CharacterNetworking.cs | 483 ++ .../BarotraumaServer/Source/DebugConsole.cs | 1478 +++- .../Source/Events/Missions/CombatMission.cs | 103 + .../BarotraumaServer/Source/GameMain.cs | 136 +- .../Source/GameSession/CrewManager.cs | 23 + .../GameModes/CharacterCampaignData.cs | 31 + .../GameModes/MultiPlayerCampaign.cs | 206 + .../GameSession/GameModes/TraitorManager.cs | 51 +- .../Source/GameSession/MultiPlayerCampaign.cs | 57 - .../Source/Items/Components/Door.cs | 33 + .../Components/Machines/Deconstructor.cs | 27 + .../Items/Components/Machines/Engine.cs | 36 + .../Items/Components/Machines/Fabricator.cs | 43 + .../Source/Items/Components/Machines/Pump.cs | 42 + .../Items/Components/Machines/Reactor.cs | 53 + .../Items/Components/Power/PowerContainer.cs | 32 + .../Source/Items/Components/Repairable.cs | 18 + .../Components/Signal/ConnectionPanel.cs | 153 + .../Components/Signal/CustomInterface.cs | 63 + .../Source/Items/Components/Signal/Wire.cs | 41 + .../Source/Items/Inventory.cs | 138 + .../BarotraumaServer/Source/Items/Item.cs | 294 + .../BarotraumaServer/Source/Map/Hull.cs | 110 +- .../BarotraumaServer/Source/Map/Structure.cs | 36 + .../BarotraumaServer/Source/Map/Submarine.cs | 18 + .../Source/Networking/BanList.cs | 315 + .../Source/Networking/ChatMessage.cs | 180 + .../Source/Networking/Client.cs | 172 + .../Source/Networking/EntitySpawner.cs | 44 + .../Networking/FileTransfer/FileSender.cs | 40 +- .../Source/Networking/GameClient.cs | 12 - .../Source/Networking/GameServer.cs | 2751 +++++++- .../ServerEntityEventManager.cs | 108 +- .../Source/Networking/NetworkMember.cs | 18 - .../Source/Networking/OrderChatMessage.cs | 29 + .../Source/Networking/RespawnManager.cs | 235 + .../Source/Networking/SteamManager.cs | 103 + .../Source/Networking/Voip/VoipServer.cs | 100 + .../Source/Networking/Voting.cs | 122 +- .../Source/Networking/WhiteList.cs | 209 + .../Source/Physics/PhysicsBody.cs | 51 + .../BarotraumaServer/Source/PlayerInput.cs | 32 +- Barotrauma/BarotraumaServer/Source/Program.cs | 12 +- .../Source/Screens/NetLobbyScreen.cs | 22 +- .../Source/Utils/XnaToConsoleColor.cs | 76 +- .../BarotraumaShared.projitems | 6281 +++++++++-------- .../BarotraumaShared/BarotraumaShared.shproj | 1 + .../Data/ContentPackages/Vanilla 0.9.xml | 6 +- .../Data/permissionpresets.xml | 4 +- Barotrauma/BarotraumaShared/Mods/info.txt | 6 +- .../Source/Characters/AI/AIController.cs | 17 +- .../Source/Characters/AI/AITarget.cs | 25 +- .../Source/Characters/AI/EnemyAIController.cs | 131 +- .../Source/Characters/AI/HumanAIController.cs | 30 +- .../Characters/AI/IndoorsSteeringManager.cs | 8 +- .../Source/Characters/AI/NPCConversation.cs | 81 +- .../AI/Objectives/AIObjectiveCombat.cs | 4 +- .../AI/Objectives/AIObjectiveDecontainItem.cs | 1 - .../Objectives/AIObjectiveFindDivingGear.cs | 3 +- .../AI/Objectives/AIObjectiveFixLeak.cs | 3 +- .../AI/Objectives/AIObjectiveFixLeaks.cs | 10 +- .../AI/Objectives/AIObjectiveGoTo.cs | 25 +- .../AI/Objectives/AIObjectiveManager.cs | 3 +- .../AI/Objectives/AIObjectiveRepairItem.cs | 2 +- .../AI/Objectives/AIObjectiveRepairItems.cs | 2 +- .../AI/Objectives/AIObjectiveRescue.cs | 2 +- .../Source/Characters/AI/Order.cs | 6 +- .../Source/Characters/AICharacter.cs | 12 +- .../Animation/FishAnimController.cs | 51 +- .../Animation/HumanoidAnimController.cs | 78 +- .../Animation/HumanoidAnimParams.cs | 150 + .../Params/Animation/AnimationParams.cs | 2 +- .../Animation/Params/Ragdoll/RagdollParams.cs | 4 +- .../Source/Characters/Animation/Ragdoll.cs | 343 +- .../Source/Characters/Attack.cs | 10 + .../Source/Characters/Character.cs | 538 +- .../Source/Characters/CharacterInfo.cs | 364 +- .../Source/Characters/CharacterNetworking.cs | 541 +- .../Health/Afflictions/Affliction.cs | 187 + .../Health/Afflictions/AfflictionBleeding.cs | 20 + .../{ => Afflictions}/AfflictionHusk.cs | 119 +- .../Health/Afflictions/AfflictionPrefab.cs | 355 + .../Health/Afflictions/AfflictionPsychosis.cs | 27 + .../Health/Buffs/BuffDurationIncrease.cs | 53 + .../Characters/Health/CharacterHealth.cs | 79 +- .../Characters/Health/DamageModifier.cs | 15 +- .../Source/Characters/Jobs/Job.cs | 10 +- .../Source/Characters/Jobs/JobPrefab.cs | 15 +- .../Source/Characters/Jobs/SkillPrefab.cs | 18 +- .../Source/Characters/Limb.cs | 61 +- .../BarotraumaShared/Source/ContentPackage.cs | 11 + .../Source/CoroutineManager.cs | 90 +- .../BarotraumaShared/Source/DebugConsole.cs | 1776 +---- .../Source/Events/ArtifactEvent.cs | 2 + .../Source/Events/EventManager.cs | 10 +- .../Source/Events/Missions/CombatMission.cs | 178 +- .../Source/Events/Missions/Mission.cs | 19 +- .../Source/Events/Missions/MissionPrefab.cs | 4 +- .../Source/Events/Missions/MonsterMission.cs | 6 +- .../Source/Events/MonsterEvent.cs | 24 +- .../Source/GameSession/CargoManager.cs | 12 + .../Source/GameSession/CrewManager.cs | 22 +- .../GameSession/GameModes/CampaignMode.cs | 33 +- .../GameModes/CharacterCampaignData.cs | 101 +- .../GameSession/GameModes/GameModePreset.cs | 7 +- .../GameModes/MultiPlayerCampaign.cs | 242 +- .../Source/GameSession/GameSession.cs | 113 +- .../Source/GameSession/HireManager.cs | 2 +- .../BarotraumaShared/Source/GameSettings.cs | 598 +- .../Source/Items/CharacterInventory.cs | 4 +- .../Source/Items/Components/DockingPort.cs | 41 +- .../Source/Items/Components/Door.cs | 157 +- .../Items/Components/Holdable/Holdable.cs | 13 +- .../Components/Holdable/LevelResource.cs | 3 +- .../Items/Components/Holdable/MeleeWeapon.cs | 10 +- .../Items/Components/Holdable/Pickable.cs | 8 +- .../Items/Components/Holdable/RangedWeapon.cs | 29 +- .../Items/Components/Holdable/RepairTool.cs | 98 +- .../Items/Components/Holdable/Throwable.cs | 4 +- .../Source/Items/Components/ItemComponent.cs | 15 +- .../Source/Items/Components/ItemContainer.cs | 25 + .../Source/Items/Components/ItemLabel.cs | 10 +- .../Components/Machines/Deconstructor.cs | 25 +- .../Items/Components/Machines/Engine.cs | 4 +- .../Items/Components/Machines/Fabricator.cs | 48 +- .../Items/Components/Machines/MiniMap.cs | 2 +- .../Components/Machines/OxygenGenerator.cs | 4 +- .../Source/Items/Components/Machines/Pump.cs | 42 +- .../Items/Components/Machines/Reactor.cs | 85 +- .../Source/Items/Components/Machines/Sonar.cs | 5 +- .../Items/Components/Machines/Steering.cs | 2 + .../Items/Components/Power/PowerContainer.cs | 59 +- .../Items/Components/Power/PowerTransfer.cs | 28 +- .../Source/Items/Components/Repairable.cs | 21 +- .../Items/Components/Signal/Connection.cs | 2 +- .../Components/Signal/ConnectionPanel.cs | 139 - .../Components/Signal/CustomInterface.cs | 52 - .../Items/Components/Signal/LightComponent.cs | 27 +- .../Items/Components/Signal/MotionSensor.cs | 11 +- .../Items/Components/Signal/RelayComponent.cs | 9 +- .../Items/Components/Signal/WaterDetector.cs | 39 +- .../Items/Components/Signal/WifiComponent.cs | 9 +- .../Source/Items/Components/Signal/Wire.cs | 89 +- .../Source/Items/Components/Turret.cs | 71 +- .../Source/Items/Components/Wearable.cs | 15 +- .../Source/Items/Inventory.cs | 160 +- .../BarotraumaShared/Source/Items/Item.cs | 695 +- .../Source/Items/ItemInventory.cs | 18 +- .../Source/Items/ItemPrefab.cs | 4 +- .../Source/Items/RelatedItem.cs | 2 +- .../BarotraumaShared/Source/Map/Explosion.cs | 38 +- .../BarotraumaShared/Source/Map/FireSource.cs | 17 +- .../BarotraumaShared/Source/Map/Hull.cs | 125 +- .../Source/Map/Levels/Level.cs | 6 +- .../Map/Levels/LevelGenerationParams.cs | 8 + .../Map/Levels/LevelObjects/LevelObject.cs | 3 + .../Levels/LevelObjects/LevelObjectManager.cs | 8 +- .../Map/Levels/LevelObjects/LevelTrigger.cs | 10 +- .../Source/Map/Levels/Ruins/RuinGenerator.cs | 8 +- .../Source/Map/Map/Location.cs | 2 +- .../Source/Map/Map/LocationConnection.cs | 27 +- .../Source/Map/Map/LocationType.cs | 28 +- .../Source/Map/Map/LocationTypeChange.cs | 14 +- .../BarotraumaShared/Source/Map/Map/Map.cs | 21 +- .../BarotraumaShared/Source/Map/MapEntity.cs | 7 +- .../BarotraumaShared/Source/Map/Md5Hash.cs | 36 +- .../BarotraumaShared/Source/Map/Structure.cs | 155 +- .../BarotraumaShared/Source/Map/Submarine.cs | 139 +- .../Source/Map/SubmarineBody.cs | 89 +- .../Source/Networking/BanList.cs | 225 +- .../Source/Networking/ChatMessage.cs | 230 +- .../Source/Networking/Client.cs | 243 +- .../Source/Networking/ClientPermissions.cs | 23 +- .../Source/Networking/EntitySpawner.cs | 94 +- .../Networking/FileTransfer/FileTransfer.cs | 17 + .../Source/Networking/GameServer.cs | 2710 ------- .../Source/Networking/GameServerLogin.cs | 462 -- .../Source/Networking/GameServerSettings.cs | 715 -- .../Source/Networking/INetSerializable.cs | 4 + .../Source/Networking/NetConfig.cs | 52 +- .../NetEntityEvent/NetEntityEvent.cs | 34 - .../Source/Networking/NetworkMember.cs | 82 +- .../Source/Networking/OrderChatMessage.cs | 21 +- .../Source/Networking/RespawnManager.cs | 310 +- .../Source/Networking/ServerLog.cs | 15 +- .../Source/Networking/ServerSettings.cs | 704 ++ .../Source/Networking/SteamManager.cs | 936 +-- .../Source/Networking/Voip/VoipConfig.cs | 14 + .../Source/Networking/Voip/VoipQueue.cs | 161 + .../Source/Networking/Voting.cs | 123 - .../Source/Networking/WhiteList.cs | 106 +- .../Source/Physics/PhysicsBody.cs | 163 +- .../BarotraumaShared/Source/PlayerInput.cs | 76 +- .../Source/Screens/GameScreen.cs | 7 +- .../Source/Screens/NetLobbyScreen.cs | 62 +- .../Serialization/SerializableProperty.cs | 253 +- .../Source/Serialization/XMLExtensions.cs | 33 + .../Source/Sprite/ConditionalSprite.cs | 25 + .../BarotraumaShared/Source/Sprite/Sprite.cs | 30 +- .../Source/StatusEffects/DelayedEffect.cs | 22 +- .../StatusEffects/PropertyConditional.cs | 24 +- .../Source/StatusEffects/StatusEffect.cs | 255 +- .../Source/SteamAchievementManager.cs | 64 +- .../BarotraumaShared/Source/TextManager.cs | 135 +- .../BarotraumaShared/Source/TextPack.cs | 83 + .../BarotraumaShared/Source/Utils/MTRandom.cs | 3 - .../Source/Utils/MathUtils.cs | 20 + .../BarotraumaShared/Source/Utils/Rand.cs | 24 +- .../BarotraumaShared/Source/Utils/SaveUtil.cs | 10 +- .../BarotraumaShared/Source/Utils/ToolBox.cs | 93 + .../BarotraumaShared/Submarines/Humpback.sub | Bin 80644 -> 76454 bytes .../BarotraumaShared/Submarines/Muikku.sub | Bin 59146 -> 70650 bytes .../BarotraumaShared/Submarines/Orca.sub | Bin 83060 -> 83570 bytes .../BarotraumaShared/Submarines/Remora.sub | Bin 0 -> 122355 bytes .../Submarines/RemoraDrone.sub | Bin 0 -> 50237 bytes .../BarotraumaShared/Submarines/Typhon.sub | Bin 103766 -> 103895 bytes Barotrauma/BarotraumaShared/changelog.txt | 103 + Barotrauma/BarotraumaShared/config.xml | 13 +- Barotrauma/BarotraumaShared/libopenal.so.1 | Bin 0 -> 634399 bytes .../BarotraumaShared/libsteam_api.dylib | Bin 0 -> 609216 bytes Barotrauma/BarotraumaShared/libsteam_api64.so | Bin 0 -> 370330 bytes Barotrauma/Launcher/Launcher.csproj | 60 +- Barotrauma/Launcher/LauncherMain.cs | 32 +- Barotrauma/Launcher/app.config | 35 + Barotrauma/Launcher/packages.config | 15 +- Barotrauma_Solution.sln | 10 +- CONTRIBUTING.md | 8 +- .../Farseer Physics MonoGame.csproj | 10 +- .../Farseer Physics.csproj | 2 +- .../Hyper.ComponentModel.csproj | 2 +- .../Lidgren.Network/Lidgren.Network.csproj | 2 +- .../Source/SharpFont/SharpFont.csproj | 2 +- .../SharpFontShared/SharpFontShared.shproj | 2 +- README.md | 5 +- 395 files changed, 27417 insertions(+), 19754 deletions(-) create mode 100644 Barotrauma/BarotraumaClient/GlobalSuppressions.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Characters/Animation/HumanoidAnimParams.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Characters/Health/DamageModifier.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Events/Missions/CombatMission.cs create mode 100644 Barotrauma/BarotraumaClient/Source/GUI/GUIRadioButtonGroup.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Map/SubmarineBody.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Media/Video.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/Client.cs delete mode 100644 Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs delete mode 100644 Barotrauma/BarotraumaClient/Source/Networking/GameServerSettings.cs delete mode 100644 Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/RespawnManager.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipCapture.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipClient.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipConfig.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Sounds/SoundFilters.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Sounds/VideoSound.cs create mode 100644 Barotrauma/BarotraumaClient/Source/Sounds/VoipSound.cs create mode 100644 Barotrauma/BarotraumaClient/app.config rename Barotrauma/{BarotraumaShared => BarotraumaClient}/libopenal.1.dylib (100%) create mode 100644 Barotrauma/BarotraumaClient/libvlc.dll create mode 100644 Barotrauma/BarotraumaClient/libvlc.dylib create mode 100644 Barotrauma/BarotraumaClient/libvlccore.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/access/libfilesystem_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/audio_filter/libaudio_format_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/audio_filter/libugly_resampler_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/audio_output/libamem_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/demux/libmp4_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/packetizer/libpacketizer_mpeg4audio_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/packetizer/libpacketizer_mpeg4video_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/video_chroma/librv32_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/video_chroma/libswscale_plugin.dll create mode 100644 Barotrauma/BarotraumaClient/plugins/video_output/libvmem_plugin.dll create mode 100644 Barotrauma/BarotraumaServer/Source/Characters/CharacterInfo.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Events/Missions/CombatMission.cs create mode 100644 Barotrauma/BarotraumaServer/Source/GameSession/CrewManager.cs create mode 100644 Barotrauma/BarotraumaServer/Source/GameSession/GameModes/CharacterCampaignData.cs create mode 100644 Barotrauma/BarotraumaServer/Source/GameSession/GameModes/MultiPlayerCampaign.cs rename Barotrauma/{BarotraumaShared => BarotraumaServer}/Source/GameSession/GameModes/TraitorManager.cs (79%) delete mode 100644 Barotrauma/BarotraumaServer/Source/GameSession/MultiPlayerCampaign.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Door.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Deconstructor.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Engine.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Fabricator.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Pump.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Reactor.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Power/PowerContainer.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Repairable.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Signal/ConnectionPanel.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Signal/CustomInterface.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Components/Signal/Wire.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Inventory.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Items/Item.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Map/Structure.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Map/Submarine.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/BanList.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/ChatMessage.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/Client.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/EntitySpawner.cs rename Barotrauma/{BarotraumaShared => BarotraumaServer}/Source/Networking/FileTransfer/FileSender.cs (91%) delete mode 100644 Barotrauma/BarotraumaServer/Source/Networking/GameClient.cs rename Barotrauma/{BarotraumaShared => BarotraumaServer}/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs (81%) create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/OrderChatMessage.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/Voip/VoipServer.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Networking/WhiteList.cs create mode 100644 Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimParams.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/Affliction.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionBleeding.cs rename Barotrauma/BarotraumaShared/Source/Characters/Health/{ => Afflictions}/AfflictionHusk.cs (63%) create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionPrefab.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionPsychosis.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/Health/Buffs/BuffDurationIncrease.cs rename Barotrauma/{BarotraumaClient => BarotraumaShared}/Source/GameSession/HireManager.cs (96%) create mode 100644 Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileTransfer.cs delete mode 100644 Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs delete mode 100644 Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs delete mode 100644 Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Networking/ServerSettings.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Networking/Voip/VoipConfig.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Networking/Voip/VoipQueue.cs create mode 100644 Barotrauma/BarotraumaShared/Source/Sprite/ConditionalSprite.cs create mode 100644 Barotrauma/BarotraumaShared/Submarines/Remora.sub create mode 100644 Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub create mode 100755 Barotrauma/BarotraumaShared/libopenal.so.1 create mode 100644 Barotrauma/BarotraumaShared/libsteam_api.dylib create mode 100644 Barotrauma/BarotraumaShared/libsteam_api64.so create mode 100644 Barotrauma/Launcher/app.config diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index 565cfd2ae..116f3c867 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -1,412 +1,507 @@ - - - - ReleaseLinux - x86 - 8.0.30703 - 2.0 - {008C0F83-E914-4966-9135-EA885059EDD8} - WinExe - Properties - Barotrauma - Barotrauma - 512 - false - v4.5 - - 0.7.0.1 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 0.1.0.%2a - false - true - - - ..\BarotraumaShared\Icon.ico - - - true - ..\bin\ReleaseLinux\ - TRACE;LINUX;CLIENT - true - pdbonly - x64 - MinimumRecommendedRules.ruleset - true - - - true - ..\bin\DebugLinux\ - TRACE;LINUX;CLIENT;DEBUG - full - x64 - MinimumRecommendedRules.ruleset - true - - - true - ..\bin\ReleaseMac\ - TRACE;OSX;CLIENT - true - pdbonly - x64 - MinimumRecommendedRules.ruleset - true - - - true - ..\bin\DebugMac\ - TRACE;OSX;CLIENT;DEBUG - full - x64 - MinimumRecommendedRules.ruleset - true - - - true - ..\bin\ReleaseWindows\ - TRACE;WINDOWS;CLIENT - true - pdbonly - x64 - MinimumRecommendedRules.ruleset - true - - - true - ..\bin\DebugWindows\ - TRACE;WINDOWS;CLIENT;DEBUG - full - x64 - MinimumRecommendedRules.ruleset - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll - - - ..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\MonoGame.Framework.dll - - - ..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll - - - - ..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\SharpDX.dll - - - ..\..\Libraries\NuGet\NVorbis.0.8.5.0\lib\NVorbis.dll - - - False - ..\..\Libraries\NuGet\OpenTK.2.0.0\lib\net20\OpenTK.dll - - - - ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll - - - - - - - ..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.6.0.1625\lib\net40\MonoGame.Framework.dll - - - ..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 4.5 - true - - - - - {3af0347c-5a9b-4421-868c-8ee3dbfaebc6} - Facepunch.Steamworks - - - {3b8f9edb-6e5e-450c-abc2-ec49075d0b50} - Hyper.ComponentModel - - - {49ba1c69-6104-41ac-a5d8-b54fa9f696e8} - Lidgren.Network - - - {c293db32-fa42-486d-b128-5a12522fae4e} - SharpFont - - - {0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7} - Farseer Physics MonoGame - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + ReleaseLinux + x64 + 8.0.30703 + 2.0 + {008C0F83-E914-4966-9135-EA885059EDD8} + WinExe + Properties + Barotrauma + Barotrauma + 512 + false + v4.5 + + 0.9.0.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 0.1.0.%2a + false + true + + + + + ..\BarotraumaShared\Icon.ico + + + true + ..\bin\ReleaseLinux\ + TRACE;LINUX;CLIENT + true + pdbonly + x64 + MinimumRecommendedRules.ruleset + true + + + true + ..\bin\DebugLinux\ + TRACE;LINUX;CLIENT;DEBUG + full + x64 + MinimumRecommendedRules.ruleset + true + + + true + ..\bin\ReleaseMac\ + TRACE;OSX;CLIENT + true + pdbonly + x64 + MinimumRecommendedRules.ruleset + true + + + true + ..\bin\DebugMac\ + TRACE;OSX;CLIENT;DEBUG + full + x64 + MinimumRecommendedRules.ruleset + true + + + true + ..\bin\ReleaseWindows\ + TRACE;WINDOWS;CLIENT + true + pdbonly + x64 + MinimumRecommendedRules.ruleset + true + + + true + ..\bin\DebugWindows\ + TRACE;WINDOWS;CLIENT;DEBUG + full + x64 + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\Libraries\NuGet\Concentus.1.1.7\lib\portable-net45+win+wpa81+wp80\Concentus.dll + + + ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll + + + ..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.7.1.189\lib\net45\MonoGame.Framework.dll + + + ..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll + + + ..\..\Libraries\NuGet\nVLC.3.0.0\lib\net40\nVLC.dll + + + ..\..\Libraries\NuGet\NVorbis.0.8.6\lib\net35\NVorbis.dll + + + ..\..\Libraries\NuGet\OpenTK.3.0.1\lib\net20\OpenTK.dll + + + + ..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll + + + ..\..\Libraries\NuGet\SharpDX.4.2.0\lib\net45\SharpDX.dll + + + ..\..\Libraries\NuGet\SharpDX.Direct2D1.4.2.0\lib\net45\SharpDX.Direct2D1.dll + + + ..\..\Libraries\NuGet\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll + + + ..\..\Libraries\NuGet\SharpDX.Direct3D9.4.2.0\lib\net45\SharpDX.Direct3D9.dll + + + ..\..\Libraries\NuGet\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll + + + ..\..\Libraries\NuGet\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll + + + ..\..\Libraries\NuGet\SharpDX.MediaFoundation.4.2.0\lib\net45\SharpDX.MediaFoundation.dll + + + ..\..\Libraries\NuGet\SharpDX.XAudio2.4.2.0\lib\net45\SharpDX.XAudio2.dll + + + ..\..\Libraries\NuGet\SharpDX.XInput.4.2.0\lib\net45\SharpDX.XInput.dll + + + + + ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll + + + + + + + ..\..\Libraries\NuGet\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + + + + + + ..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.7.1.189\lib\net45\MonoGame.Framework.dll + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + {3af0347c-5a9b-4421-868c-8ee3dbfaebc6} + Facepunch.Steamworks + + + {3b8f9edb-6e5e-450c-abc2-ec49075d0b50} + Hyper.ComponentModel + + + {49ba1c69-6104-41ac-a5d8-b54fa9f696e8} + Lidgren.Network + + + {c293db32-fa42-486d-b128-5a12522fae4e} + SharpFont + + + {0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7} + Farseer Physics MonoGame + + + + + + PreserveNewest + + + + PreserveNewest + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj.user b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj.user index 1782abafa..e376804a0 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj.user +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj.user @@ -1,18 +1,21 @@ - - - - publish\ - - - - - - en-US - false - ShowAllFiles - - - - - + + + + publish\ + + + + + + en-US + false + ShowAllFiles + + + + + + + false + \ No newline at end of file diff --git a/Barotrauma/BarotraumaClient/GlobalSuppressions.cs b/Barotrauma/BarotraumaClient/GlobalSuppressions.cs new file mode 100644 index 000000000..0798ca60a --- /dev/null +++ b/Barotrauma/BarotraumaClient/GlobalSuppressions.cs @@ -0,0 +1,8 @@ + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "", Scope = "member", Target = "~M:Barotrauma.GameSettings.CreateSettingsFrame")] + diff --git a/Barotrauma/BarotraumaClient/MonoGame.Framework.dll.config b/Barotrauma/BarotraumaClient/MonoGame.Framework.dll.config index f8abd6e60..d6478f30b 100644 --- a/Barotrauma/BarotraumaClient/MonoGame.Framework.dll.config +++ b/Barotrauma/BarotraumaClient/MonoGame.Framework.dll.config @@ -2,8 +2,8 @@ - + - + diff --git a/Barotrauma/BarotraumaClient/OpenTK.dll.config b/Barotrauma/BarotraumaClient/OpenTK.dll.config index 7098d39e9..140d56665 100644 --- a/Barotrauma/BarotraumaClient/OpenTK.dll.config +++ b/Barotrauma/BarotraumaClient/OpenTK.dll.config @@ -6,7 +6,7 @@ - + diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 2b59d689b..860f23719 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.9.3")] -[assembly: AssemblyFileVersion("0.8.9.3")] +[assembly: AssemblyVersion("0.8.9.4")] +[assembly: AssemblyFileVersion("0.8.9.4")] diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs index 2f25f0131..ae5be6c5d 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs @@ -14,9 +14,9 @@ namespace Barotrauma Vector2 pos = Character.WorldPosition; pos.Y = -pos.Y; - if (selectedAiTarget?.Entity != null) + if (SelectedAiTarget?.Entity != null) { - GUI.DrawLine(spriteBatch, pos, new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5); + GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5); if (wallTarget != null) { @@ -27,7 +27,7 @@ namespace Barotrauma GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5); } - GUI.Font.DrawString(spriteBatch, $"{selectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red); + GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red); } /*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs index fcee0c544..ef94cab43 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs @@ -1,4 +1,6 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Networking; +using Microsoft.Xna.Framework; +using System.Linq; namespace Barotrauma { @@ -21,11 +23,11 @@ namespace Barotrauma public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) { - if (selectedAiTarget?.Entity != null) + if (SelectedAiTarget?.Entity != null) { GUI.DrawLine(spriteBatch, new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y), - new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red); + new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red); } IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager; @@ -50,5 +52,52 @@ namespace Barotrauma Color.LightGreen); } } + + //TODO: move this to the shared project, otherwise bots won't be able to report things in multiplayer + partial void ReportProblems() + { + if (GameMain.Client != null) return; + + Order newOrder = null; + if (Character.CurrentHull != null) + { + if (Character.CurrentHull.FireSources.Count > 0) + { + var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportfire"); + newOrder = new Order(orderPrefab, Character.CurrentHull, null); + } + + if (Character.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.ConnectedDoor == null && g.Open > 0.0f)) + { + var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach"); + newOrder = new Order(orderPrefab, Character.CurrentHull, null); + } + + foreach (Character c in Character.CharacterList) + { + if (c.CurrentHull == Character.CurrentHull && !c.IsDead && + (c.AIController is EnemyAIController || c.TeamID != Character.TeamID)) + { + var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders"); + newOrder = new Order(orderPrefab, Character.CurrentHull, null); + } + } + } + + if (Character.CurrentHull != null && (Character.Bleeding > 1.0f || Character.Vitality < Character.MaxVitality * 0.1f)) + { + var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid"); + newOrder = new Order(orderPrefab, Character.CurrentHull, null); + } + + if (newOrder != null) + { + if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime)) + { + Character.Speak( + newOrder.GetChatMessage("", Character.CurrentHull?.RoomName, givingOrderToSelf: false), ChatMessageType.Order); + } + } + } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AICharacter.cs b/Barotrauma/BarotraumaClient/Source/Characters/AICharacter.cs index 352b29000..09b09288b 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AICharacter.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AICharacter.cs @@ -2,38 +2,10 @@ { partial class AICharacter : Character { - partial void InitProjSpecific() - { - soundTimer = Rand.Range(0.0f, soundInterval); - } - - partial void SoundUpdate(float deltaTime) - { - if (soundTimer > 0) - { - soundTimer -= deltaTime; - } - else - { - switch (aiController.State) - { - case AIController.AIState.Attack: - PlaySound(CharacterSound.SoundType.Attack); - break; - default: - PlaySound(CharacterSound.SoundType.Idle); - break; - } - soundTimer = soundInterval; - } - } - public override void DrawFront(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Camera cam) { base.DrawFront(spriteBatch, cam); - if (GameMain.DebugDraw && !IsDead) aiController.DebugDraw(spriteBatch); } - } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/HumanoidAnimParams.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/HumanoidAnimParams.cs new file mode 100644 index 000000000..235ca3035 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/HumanoidAnimParams.cs @@ -0,0 +1,48 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace Barotrauma +{ + partial class HumanoidAnimParams : ISerializableEntity + { + private static GUIListBox editor; + public static GUIListBox Editor + { + get + { + if (editor == null) + { + editor = new GUIListBox(new RectTransform(new Vector2(0.3f, 1), GUI.Canvas)); + //editor.AddChild(new SerializableEntityEditor(editor.RectTransform, WalkInstance, false, true, elementHeight: 20)); + //editor.AddChild(new SerializableEntityEditor(editor.RectTransform, RunInstance, false, true, elementHeight: 20)); + } + return editor; + } + } + + public void Save() + { + XDocument doc = XMLExtensions.TryLoadXml(filePath); + if (doc == null || doc.Root == null) return; + + SerializableProperty.SerializeProperties(this, doc.Root, true); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + settings.OmitXmlDeclaration = true; + settings.NewLineOnAttributes = true; + + using (var writer = XmlWriter.Create(filePath, settings)) + { + doc.WriteTo(writer); + writer.Flush(); + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index 8fda7c3ac..c491acea1 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -7,9 +7,9 @@ using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; +using System.Linq; using System.Collections.Generic; using Barotrauma.Particles; -using System.Linq; namespace Barotrauma { @@ -17,6 +17,233 @@ namespace Barotrauma { public HashSet SpriteDeformations { get; protected set; } = new HashSet(); + /// + /// Inversed draw order, which is used for drawing the limbs in 3d (deformable sprites). + /// + protected Limb[] inversedLimbDrawOrder; + + partial void UpdateNetPlayerPositionProjSpecific(float deltaTime, float lowestSubPos) + { + if (character != GameMain.Client.Character || !character.AllowInput) + { + //remove states without a timestamp (there may still be ID-based states + //in the list when the controlled character switches to timestamp-based interpolation) + character.MemState.RemoveAll(m => m.Timestamp == 0.0f); + + //use simple interpolation for other players' characters and characters that can't move + if (character.MemState.Count > 0) + { + CharacterStateInfo serverPos = character.MemState.Last(); + if (!character.isSynced) + { + SetPosition(serverPos.Position, false); + Collider.LinearVelocity = Vector2.Zero; + character.MemLocalState.Clear(); + character.LastNetworkUpdateID = serverPos.ID; + character.isSynced = true; + return; + } + + if (character.MemState[0].Interact == null || character.MemState[0].Interact.Removed) + { + character.DeselectCharacter(); + character.SelectedConstruction = null; + } + else if (character.MemState[0].Interact is Character) + { + character.SelectCharacter((Character)character.MemState[0].Interact); + } + else if (character.MemState[0].Interact is Item newSelectedConstruction) + { + if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction) + { + foreach (var ic in newSelectedConstruction.Components) + { + if (ic.CanBeSelected) ic.Select(character); + } + } + character.SelectedConstruction = newSelectedConstruction; + } + + if (character.MemState[0].Animation == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.CPR; + } + else if (character.AnimController.Anim == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.None; + } + + Vector2 newVelocity = Collider.LinearVelocity; + Vector2 newPosition = Collider.SimPosition; + float newRotation = Collider.Rotation; + float newAngularVelocity = Collider.AngularVelocity; + Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity); + + newVelocity = newVelocity.ClampLength(100.0f); + if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; } + overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero; + + Collider.LinearVelocity = newVelocity; + Collider.AngularVelocity = newAngularVelocity; + + float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition); + float errorTolerance = character.AllowInput ? 0.01f : 0.1f; + if (distSqrd > errorTolerance) + { + if (distSqrd > 10.0f || !character.AllowInput) + { + Collider.TargetRotation = newRotation; + SetPosition(newPosition, lerp: distSqrd < 1.0f); + } + else + { + Collider.TargetRotation = newRotation; + Collider.TargetPosition = newPosition; + Collider.MoveToTargetPosition(true); + } + } + + //unconscious/dead characters can't correct their position using AnimController movement + // -> we need to correct it manually + if (!character.AllowInput) + { + MainLimb.PullJointWorldAnchorB = Collider.SimPosition; + MainLimb.PullJointEnabled = true; + } + } + character.MemLocalState.Clear(); + } + else + { + //remove states with a timestamp (there may still timestamp-based states + //in the list if the controlled character switches from timestamp-based interpolation to ID-based) + character.MemState.RemoveAll(m => m.Timestamp > 0.0f); + + for (int i = 0; i < character.MemLocalState.Count; i++) + { + if (character.Submarine == null) + { + //transform in-sub coordinates to outside coordinates + if (character.MemLocalState[i].Position.Y > lowestSubPos) + { + character.MemLocalState[i].TransformInToOutside(); + } + } + else if (currentHull?.Submarine != null) + { + //transform outside coordinates to in-sub coordinates + if (character.MemLocalState[i].Position.Y < lowestSubPos) + { + character.MemLocalState[i].TransformOutToInside(currentHull.Submarine); + } + } + } + + if (character.MemState.Count < 1) return; + + overrideTargetMovement = Vector2.Zero; + + CharacterStateInfo serverPos = character.MemState.Last(); + + if (!character.isSynced) + { + SetPosition(serverPos.Position, false); + Collider.LinearVelocity = Vector2.Zero; + character.MemLocalState.Clear(); + character.LastNetworkUpdateID = serverPos.ID; + character.isSynced = true; + return; + } + + int localPosIndex = character.MemLocalState.FindIndex(m => m.ID == serverPos.ID); + if (localPosIndex > -1) + { + CharacterStateInfo localPos = character.MemLocalState[localPosIndex]; + + //the entity we're interacting with doesn't match the server's + if (localPos.Interact != serverPos.Interact) + { + if (serverPos.Interact == null || serverPos.Interact.Removed) + { + character.DeselectCharacter(); + character.SelectedConstruction = null; + } + else if (serverPos.Interact is Character) + { + character.SelectCharacter((Character)serverPos.Interact); + } + else + { + var newSelectedConstruction = (Item)serverPos.Interact; + if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction) + { + newSelectedConstruction.TryInteract(character, true, true); + } + character.SelectedConstruction = newSelectedConstruction; + } + } + + if (localPos.Animation != serverPos.Animation) + { + if (serverPos.Animation == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.CPR; + } + else if (character.AnimController.Anim == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.None; + } + } + + Hull serverHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(serverPos.Position), character.CurrentHull, serverPos.Position.Y < lowestSubPos); + Hull clientHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(localPos.Position), serverHull, localPos.Position.Y < lowestSubPos); + + if (serverHull != null && clientHull != null && serverHull.Submarine != clientHull.Submarine) + { + //hull subs don't match => teleport the camera to the other sub + character.Submarine = serverHull.Submarine; + character.CurrentHull = currentHull = serverHull; + SetPosition(serverPos.Position); + character.MemLocalState.Clear(); + } + else + { + Vector2 positionError = serverPos.Position - localPos.Position; + float rotationError = serverPos.Rotation - localPos.Rotation; + + for (int i = localPosIndex; i < character.MemLocalState.Count; i++) + { + Hull pointHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(character.MemLocalState[i].Position), clientHull, character.MemLocalState[i].Position.Y < lowestSubPos); + if (pointHull != clientHull && ((pointHull == null) || (clientHull == null) || (pointHull.Submarine == clientHull.Submarine))) break; + character.MemLocalState[i].Translate(positionError, rotationError); + } + + float errorMagnitude = positionError.Length(); + if (errorMagnitude > 0.01f) + { + Collider.TargetPosition = Collider.SimPosition + positionError; + Collider.TargetRotation = Collider.Rotation + rotationError; + Collider.MoveToTargetPosition(lerp: true); + if (errorMagnitude > 0.5f) + { + character.MemLocalState.Clear(); + foreach (Limb limb in Limbs) + { + limb.body.TargetPosition = limb.body.SimPosition + positionError; + limb.body.MoveToTargetPosition(lerp: true); + } + } + } + } + + } + + if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120); + character.MemState.Clear(); + } + } + partial void ImpactProjSpecific(float impact, Body body) { float volume = Math.Min(impact - 3.0f, 1.0f); @@ -42,7 +269,7 @@ namespace Barotrauma } else if (body.UserData is Limb || body == Collider.FarseerBody) { - if (!character.IsRemotePlayer || GameMain.Server != null) + if (!character.IsRemotePlayer) { if (impact > ImpactTolerance) { @@ -115,7 +342,7 @@ namespace Barotrauma depthSortedLimbs.Reverse(); inversedLimbDrawOrder = depthSortedLimbs.ToArray(); } - + partial void UpdateProjSpecific(float deltaTime) { LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime)); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs index afdac4fb0..672fd2872 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs @@ -1,5 +1,6 @@ using Barotrauma.Networking; using Barotrauma.Particles; +using Barotrauma.Sounds; using FarseerPhysics; using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; @@ -22,6 +23,8 @@ namespace Barotrauma protected float hudInfoTimer; protected bool hudInfoVisible; + private float findFocusedTimer; + protected float lastRecvPositionUpdateTime; private float hudInfoHeight; @@ -39,7 +42,6 @@ namespace Barotrauma if (controlled == value) return; controlled = value; if (controlled != null) controlled.Enabled = true; - GameMain.GameSession?.CrewManager?.SetCharacterSelected(controlled); CharacterHealth.OpenHealthWindow = null; } @@ -107,13 +109,7 @@ namespace Barotrauma partial void InitProjSpecific(XDocument doc) { soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f); - - keys = new Key[Enum.GetNames(typeof(InputType)).Length]; - - for (int i = 0; i < Enum.GetNames(typeof(InputType)).Length; i++) - { - keys[i] = new Key((InputType)i); - } + soundTimer = Rand.Range(0.0f, soundInterval); BloodDecalName = doc.Root.GetAttributeString("blooddecal", ""); @@ -140,6 +136,13 @@ namespace Barotrauma hudProgressBars = new Dictionary(); } + partial void UpdateLimbLightSource(Limb limb) + { + if (limb.LightSource != null) + { + limb.LightSource.Enabled = enabled; + } + } /// /// Control the Character according to player input @@ -196,7 +199,7 @@ namespace Barotrauma { cam.OffsetAmount = 0.0f; } - else if (SelectedConstruction != null && SelectedConstruction.components.Any(ic => (ic.GuiFrame != null && GUI.IsMouseOn(ic.GuiFrame)))) + else if (SelectedConstruction != null && SelectedConstruction.Components.Any(ic => (ic.GuiFrame != null && GUI.IsMouseOn(ic.GuiFrame)))) { cam.OffsetAmount = 0.0f; } @@ -229,7 +232,7 @@ namespace Barotrauma partial void UpdateControlled(float deltaTime, Camera cam) { if (controlled != this) return; - + ControlLocalPlayer(deltaTime, cam); Lights.LightManager.ViewTarget = this; @@ -257,7 +260,17 @@ namespace Barotrauma } } - partial void KillProjSpecific() + partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult) + { + if (attackResult.Damage <= 0) { return; } + if (soundTimer < soundInterval * 0.5f) + { + PlaySound(CharacterSound.SoundType.Damage); + soundTimer = soundInterval; + } + } + + partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction) { if (GameMain.NetworkMember != null && controlled == this) { @@ -285,13 +298,159 @@ namespace Barotrauma GameMain.GameSession.CrewManager.RemoveCharacter(this); } - if (GameMain.NetworkMember?.Character == this) GameMain.NetworkMember.Character = null; + if (GameMain.Client?.Character == this) GameMain.Client.Character = null; if (Lights.LightManager.ViewTarget == this) Lights.LightManager.ViewTarget = null; } + + private List debugInteractablesInRange = new List(); + private List debugInteractablesAtCursor = new List(); + private List> debugInteractablesNearCursor = new List>(); + + /// + /// Finds the front (lowest depth) interactable item at a position. "Interactable" in this case means that the character can "reach" the item. + /// + /// The Character who is looking for the interactable item, only items that are close enough to this character are returned + /// The item at the simPosition, with the lowest depth, is returned + /// If this is true and an item cannot be found at simPosition then a nearest item will be returned if possible + /// If a hull is specified, only items within that hull are returned + public Item FindItemAtPosition(Vector2 simPosition, float aimAssistModifier = 0.0f, Item[] ignoredItems = null) + { + if (Submarine != null) + { + simPosition += Submarine.SimPosition; + } + + debugInteractablesInRange.Clear(); + debugInteractablesAtCursor.Clear(); + debugInteractablesNearCursor.Clear(); + + //reduce the amount of aim assist if an item has been selected + //= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item + //otherwise it would be too easy to accidentally switch the selected item when rewiring items + float aimAssistAmount = SelectedConstruction == null ? 100.0f * aimAssistModifier : 1.0f; + + Vector2 displayPosition = ConvertUnits.ToDisplayUnits(simPosition); + + //use the list of visible entities if it exists + var entityList = Submarine.VisibleEntities ?? Item.ItemList; + + Item closestItem = null; + float closestItemDistance = aimAssistAmount; + foreach (MapEntity entity in entityList) + { + if (!(entity is Item item)) + { + continue; + } + if (item.body != null && !item.body.Enabled) continue; + if (item.ParentInventory != null) continue; + if (ignoredItems != null && ignoredItems.Contains(item)) continue; + + float distanceToItem = float.PositiveInfinity; + if (item.IsInsideTrigger(displayPosition, out Rectangle transformedTrigger)) + { + debugInteractablesAtCursor.Add(item); + //distance is between 0-1 when the cursor is directly on the item + distanceToItem = + Math.Abs(transformedTrigger.Center.X - displayPosition.X) / transformedTrigger.Width + + Math.Abs((transformedTrigger.Y - transformedTrigger.Height / 2.0f) - displayPosition.Y) / transformedTrigger.Height; + //modify the distance based on the size of the trigger (preferring smaller items) + distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (transformedTrigger.Width + transformedTrigger.Height) / 250.0f); + } + else + { + Rectangle itemDisplayRect = new Rectangle(item.InteractionRect.X, item.InteractionRect.Y - item.InteractionRect.Height, item.InteractionRect.Width, item.InteractionRect.Height); + + if (itemDisplayRect.Contains(displayPosition)) + { + debugInteractablesAtCursor.Add(item); + //distance is between 0-1 when the cursor is directly on the item + distanceToItem = + Math.Abs(itemDisplayRect.Center.X - displayPosition.X) / itemDisplayRect.Width + + Math.Abs(itemDisplayRect.Center.Y - displayPosition.Y) / itemDisplayRect.Height; + //modify the distance based on the size of the item (preferring smaller ones) + distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (itemDisplayRect.Width + itemDisplayRect.Height) / 250.0f); + } + else + { + if (closestItemDistance < 2.0f) { continue; } + //get the point on the itemDisplayRect which is closest to the cursor + Vector2 rectIntersectionPoint = new Vector2( + MathHelper.Clamp(displayPosition.X, itemDisplayRect.X, itemDisplayRect.Right), + MathHelper.Clamp(displayPosition.Y, itemDisplayRect.Y, itemDisplayRect.Bottom)); + distanceToItem = 2.0f + Vector2.Distance(rectIntersectionPoint, displayPosition); + } + } + + if (distanceToItem > closestItemDistance) { continue; } + if (!CanInteractWith(item)) { continue; } + + debugInteractablesNearCursor.Add(new Pair(item, 1.0f - distanceToItem / (100.0f * aimAssistModifier))); + closestItem = item; + closestItemDistance = distanceToItem; + } + + return closestItem; + } + + private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = 150.0f) + { + Character closestCharacter = null; + float closestDist = 0.0f; + + maxDist = ConvertUnits.ToSimUnits(maxDist); + + foreach (Character c in CharacterList) + { + if (!CanInteractWith(c)) continue; + + float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition); + if (dist < maxDist * maxDist && (closestCharacter == null || dist < closestDist)) + { + closestCharacter = c; + closestDist = dist; + } + + /*FarseerPhysics.Common.Transform transform; + c.AnimController.Collider.FarseerBody.GetTransform(out transform); + for (int i = 0; i < c.AnimController.Collider.FarseerBody.FixtureList.Count; i++) + { + if (c.AnimController.Collider.FarseerBody.FixtureList[i].Shape.TestPoint(ref transform, ref mouseSimPos)) + { + Console.WriteLine("Hit: " + i); + closestCharacter = c; + } + }*/ + } + + return closestCharacter; + } + + partial void UpdateProjSpecific(float deltaTime, Camera cam) { + if (!IsDead && !IsUnconscious) + { + if (soundTimer > 0) + { + soundTimer -= deltaTime; + } + else if (AIController != null) + { + switch (AIController.State) + { + case AIController.AIState.Attack: + PlaySound(CharacterSound.SoundType.Attack); + break; + default: + PlaySound(CharacterSound.SoundType.Idle); + break; + } + } + } + if (info != null || Vitality < MaxVitality * 0.98f) { hudInfoTimer -= deltaTime; @@ -421,7 +580,7 @@ namespace Barotrauma float cursorDist = Vector2.Distance(WorldPosition, cam.ScreenToWorld(PlayerInput.MousePosition)); float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f); - if (hudInfoVisible && info != null && + if (!GUI.DisableCharacterNames && hudInfoVisible && info != null && (controlled == null || this != controlled.focusedCharacter)) { string name = Info.DisplayName; @@ -440,7 +599,7 @@ namespace Barotrauma Color nameColor = Color.White; if (Controlled != null && TeamID != Controlled.TeamID) { - nameColor = Color.Red; + nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : Color.Red; } GUI.Font.DrawString(spriteBatch, name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f); GUI.Font.DrawString(spriteBatch, name, namePos, nameColor * hudInfoAlpha, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f); @@ -471,8 +630,7 @@ namespace Barotrauma { if (controlled != this) return null; - HUDProgressBar progressBar = null; - if (!hudProgressBars.TryGetValue(linkedObject, out progressBar)) + if (!hudProgressBars.TryGetValue(linkedObject, out HUDProgressBar progressBar)) { progressBar = new HUDProgressBar(worldPosition, Submarine, emptyColor, fullColor); hudProgressBars.Add(linkedObject, progressBar); @@ -485,15 +643,21 @@ namespace Barotrauma return progressBar; } + private SoundChannel soundChannel; public void PlaySound(CharacterSound.SoundType soundType) { - if (sounds == null || sounds.Count == 0) return; + if (sounds == null || sounds.Count == 0) { return; } + if (soundChannel != null && soundChannel.IsPlaying) { return; } - var matchingSounds = sounds.FindAll(s => s.Type == soundType); - if (matchingSounds.Count == 0) return; + var matchingSounds = sounds.Where(s => + s.Type == soundType && + (s.Gender == Gender.None || (info != null && info.Gender == s.Gender))); + if (!matchingSounds.Any()) { return; } - var selectedSound = matchingSounds[Rand.Int(matchingSounds.Count)]; - SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, AnimController.WorldPosition, CurrentHull); + var matchingSoundsList = matchingSounds.ToList(); + var selectedSound = matchingSoundsList[Rand.Int(matchingSoundsList.Count)]; + soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, AnimController.WorldPosition, CurrentHull); + soundTimer = soundInterval; } partial void ImplodeFX() diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs index c1cc93752..5ef2693ce 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs @@ -60,7 +60,7 @@ namespace Barotrauma var item = character.Inventory.Items[i]; if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue; - foreach (ItemComponent ic in item.components) + foreach (ItemComponent ic in item.Components) { if (ic.DrawHudWhenEquipped) ic.AddToGUIUpdateList(); } @@ -94,7 +94,7 @@ namespace Barotrauma var item = character.Inventory.Items[i]; if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue; - foreach (ItemComponent ic in item.components) + foreach (ItemComponent ic in item.Components) { if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character, deltaTime, cam); } @@ -188,8 +188,14 @@ namespace Barotrauma } Vector2 textPos = startPos; textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20); + + Color nameColor = Color.White; + if (character.TeamID != character.FocusedCharacter.TeamID) + { + nameColor = character.FocusedCharacter.TeamID == Character.TeamType.FriendlyNPC ? Color.SkyBlue : Color.Red; + } - GUI.DrawString(spriteBatch, textPos, focusName, Color.White, Color.Black * 0.7f, 2); + GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2); textPos.Y += 20; if (character.FocusedCharacter.CanInventoryBeAccessed) { @@ -237,30 +243,35 @@ namespace Barotrauma scale: scale); } - var hudTexts = focusedItem.GetHUDTexts(character); - - int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X); - Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition); - startPos.Y -= (hudTexts.Count + 1) * 20; - if (focusedItem.Sprite != null) + if (!GUI.DisableItemHighlights) { - startPos.X += (int)(circleSize * 0.4f * dir); - startPos.Y -= (int)(circleSize * 0.4f); + var hudTexts = focusedItem.GetHUDTexts(character); + + int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X); + Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition); + startPos.Y -= (hudTexts.Count + 1) * 20; + if (focusedItem.Sprite != null) + { + startPos.X += (int)(circleSize * 0.4f * dir); + startPos.Y -= (int)(circleSize * 0.4f); + } + + Vector2 textPos = startPos; + if (dir == -1) textPos.X -= (int)GUI.Font.MeasureString(focusedItem.Name).X; + + float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f); + + GUI.DrawString(spriteBatch, textPos, focusedItem.Name, Color.White * alpha, Color.Black * alpha * 0.7f, 2); + textPos.Y += 20.0f; + foreach (ColoredText coloredText in hudTexts) + { + if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X); + GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont); + textPos.Y += 20; + } } - Vector2 textPos = startPos; - if (dir == -1) textPos.X -= (int)GUI.Font.MeasureString(focusedItem.Name).X; - - float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f); - - GUI.DrawString(spriteBatch, textPos, focusedItem.Name, Color.White * alpha, Color.Black * alpha * 0.7f, 2); - textPos.Y += 20.0f; - foreach (ColoredText coloredText in hudTexts) - { - if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X); - GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont); - textPos.Y += 20; - } + } foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values) @@ -282,7 +293,7 @@ namespace Barotrauma var item = character.Inventory.Items[i]; if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue; - foreach (ItemComponent ic in item.components) + foreach (ItemComponent ic in item.Components) { if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character); } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs index ef0f43c1d..4fb00dc00 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs @@ -397,9 +397,10 @@ namespace Barotrauma partial void UpdateOxygenProjSpecific(float prevOxygen) { - if (prevOxygen > 0.0f && OxygenAmount <= 0.0f && Character.Controlled == Character) + if (prevOxygen > 0.0f && OxygenAmount <= 0.0f && + Character.Controlled == Character) { - SoundPlayer.PlaySound("drown"); + SoundPlayer.PlaySound(Character.Info != null && Character.Info.Gender == Gender.Female ? "drownfemale" : "drownmale"); } } @@ -1110,7 +1111,7 @@ namespace Barotrauma return medicalItems.Distinct().ToList(); } - + private void UpdateLimbIndicators(float deltaTime, Rectangle drawArea) { limbIndicatorOverlayAnimState += deltaTime * 8.0f; @@ -1261,8 +1262,8 @@ namespace Barotrauma private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction, GUIComponentStyle slotStyle, float iconScale, ref Vector2 iconPos) { - Vector2 iconSize = (affliction.Prefab.Icon.size * iconScale); if (affliction.Strength < affliction.Prefab.ShowIconThreshold) return; + Vector2 iconSize = (affliction.Prefab.Icon.size * iconScale); //afflictions that have a strength of less than 10 are faded out slightly float alpha = MathHelper.Lerp(0.3f, 1.0f, @@ -1293,10 +1294,10 @@ namespace Barotrauma byte afflictionCount = inc.ReadByte(); for (int i = 0; i < afflictionCount; i++) { - int afflictionPrefabIndex = inc.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1); - float afflictionStrength = inc.ReadSingle(); + AfflictionPrefab afflictionPrefab = AfflictionPrefab.List[inc.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1)]; + float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8); - newAfflictions.Add(new Pair(AfflictionPrefab.List[afflictionPrefabIndex], afflictionStrength)); + newAfflictions.Add(new Pair(afflictionPrefab, afflictionStrength)); } foreach (Affliction affliction in afflictions) @@ -1327,10 +1328,10 @@ namespace Barotrauma for (int i = 0; i < limbAfflictionCount; i++) { int limbIndex = inc.ReadRangedInteger(0, limbHealths.Count - 1); - int afflictionPrefabIndex = inc.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1); - float afflictionStrength = inc.ReadSingle(); + AfflictionPrefab afflictionPrefab = AfflictionPrefab.List[inc.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1)]; + float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8); - newLimbAfflictions.Add(new Triplet(limbHealths[limbIndex], AfflictionPrefab.List[afflictionPrefabIndex], afflictionStrength)); + newLimbAfflictions.Add(new Triplet(limbHealths[limbIndex], afflictionPrefab, afflictionStrength)); } foreach (LimbHealth limbHealth in limbHealths) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs index 832c86fe6..a4eb436a9 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs @@ -1,9 +1,10 @@ +using Barotrauma.Extensions; +using Lidgren.Network; using System; using System.Linq; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Barotrauma.Extensions; namespace Barotrauma { @@ -219,5 +220,55 @@ namespace Barotrauma } attachment.Sprite.Draw(spriteBatch, drawPos, Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects); } + + + public static CharacterInfo ClientRead(string configPath, NetBuffer inc) + { + ushort infoID = inc.ReadUInt16(); + string newName = inc.ReadString(); + int gender = inc.ReadByte(); + int race = inc.ReadByte(); + int headSpriteID = inc.ReadByte(); + int hairIndex = inc.ReadByte(); + int beardIndex = inc.ReadByte(); + int moustacheIndex = inc.ReadByte(); + int faceAttachmentIndex = inc.ReadByte(); + string ragdollFile = inc.ReadString(); + + string jobIdentifier = inc.ReadString(); + JobPrefab jobPrefab = null; + Dictionary skillLevels = new Dictionary(); + if (!string.IsNullOrEmpty(jobIdentifier)) + { + jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier); + for (int i = 0; i < jobPrefab.Skills.Count; i++) + { + float skillLevel = inc.ReadSingle(); + skillLevels.Add(jobPrefab.Skills[i].Identifier, skillLevel); + } + } + + // TODO: animations + CharacterInfo ch = new CharacterInfo(configPath, newName, jobPrefab, ragdollFile) + { + ID = infoID, + }; + ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex); + System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count); + if (ch.Job != null) + { + foreach (KeyValuePair skill in skillLevels) + { + Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key); + if (matchingSkill == null) + { + DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\""); + continue; + } + matchingSkill.Level = skill.Value; + } + } + return ch; + } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs index 641ae6932..983ffb1a5 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -9,10 +9,88 @@ namespace Barotrauma { partial class Character { + partial void UpdateNetInput() + { + if (GameMain.Client != null) + { + if (this != Controlled) + { + //freeze AI characters if more than 1 seconds have passed since last update from the server + if (lastRecvPositionUpdateTime < NetTime.Now - 1.0f) + { + AnimController.Frozen = true; + memState.Clear(); + //hide after 2 seconds + if (lastRecvPositionUpdateTime < NetTime.Now - 2.0f) + { + Enabled = false; + return; + } + } + } + else + { + var posInfo = new CharacterStateInfo( + SimPosition, + AnimController.Collider.Rotation, + LastNetworkUpdateID, + AnimController.TargetDir, + SelectedCharacter == null ? (Entity)SelectedConstruction : (Entity)SelectedCharacter, + AnimController.Anim); + + memLocalState.Add(posInfo); + + InputNetFlags newInput = InputNetFlags.None; + if (IsKeyDown(InputType.Left)) newInput |= InputNetFlags.Left; + if (IsKeyDown(InputType.Right)) newInput |= InputNetFlags.Right; + if (IsKeyDown(InputType.Up)) newInput |= InputNetFlags.Up; + if (IsKeyDown(InputType.Down)) newInput |= InputNetFlags.Down; + if (IsKeyDown(InputType.Run)) newInput |= InputNetFlags.Run; + if (IsKeyDown(InputType.Crouch)) newInput |= InputNetFlags.Crouch; + if (IsKeyHit(InputType.Select)) newInput |= InputNetFlags.Select; //TODO: clean up the way this input is registered + if (IsKeyHit(InputType.Health)) newInput |= InputNetFlags.Health; + if (IsKeyHit(InputType.Grab)) newInput |= InputNetFlags.Grab; + if (IsKeyDown(InputType.Use)) newInput |= InputNetFlags.Use; + if (IsKeyDown(InputType.Aim)) newInput |= InputNetFlags.Aim; + if (IsKeyDown(InputType.Attack)) newInput |= InputNetFlags.Attack; + if (IsKeyDown(InputType.Ragdoll)) newInput |= InputNetFlags.Ragdoll; + + if (AnimController.TargetDir == Direction.Left) newInput |= InputNetFlags.FacingLeft; + + Vector2 relativeCursorPos = cursorPosition - AimRefPosition; + relativeCursorPos.Normalize(); + UInt16 intAngle = (UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)); + + NetInputMem newMem = new NetInputMem + { + states = newInput, + intAim = intAngle + }; + if (focusedItem != null && (!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health))) + { + newMem.interact = focusedItem.ID; + } + else if (focusedCharacter != null) + { + newMem.interact = focusedCharacter.ID; + } + + memInput.Insert(0, newMem); + LastNetworkUpdateID++; + if (memInput.Count > 60) + { + memInput.RemoveRange(60, memInput.Count - 60); + } + } + } + else //this == Character.Controlled && GameMain.Client == null + { + AnimController.Frozen = false; + } + } + public virtual void ClientWrite(NetBuffer msg, object[] extraData = null) { - if (GameMain.Server != null) return; - if (extraData != null) { switch ((NetEntityEvent.Type)extraData[0]) @@ -63,8 +141,6 @@ namespace Barotrauma public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) { - if (GameMain.Server != null) return; - switch (type) { case ServerNetObject.ENTITY_POSITION: @@ -97,13 +173,9 @@ namespace Barotrauma keys[(int)InputType.Crouch].SetState(false, crouching); } - bool hasAttackLimb = msg.ReadBoolean(); - if (hasAttackLimb) - { - bool attackInput = msg.ReadBoolean(); - keys[(int)InputType.Attack].Held = attackInput; - keys[(int)InputType.Attack].SetState(false, attackInput); - } + bool attackInput = msg.ReadBoolean(); + keys[(int)InputType.Attack].Held = attackInput; + keys[(int)InputType.Attack].SetState(false, attackInput); if (aimInput) { @@ -139,28 +211,44 @@ namespace Barotrauma Vector2 pos = new Vector2( msg.ReadFloat(), msg.ReadFloat()); + float MaxVel = NetConfig.MaxPhysicsBodyVelocity; + Vector2 linearVelocity = new Vector2( + msg.ReadRangedSingle(-MaxVel, MaxVel, 12), + msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); - float rotation = msg.ReadFloat(); + bool fixedRotation = msg.ReadBoolean(); + float rotation = AnimController.Collider.Rotation; + float angularVelocity = AnimController.Collider.AngularVelocity; + if (!fixedRotation) + { + rotation = msg.ReadFloat(); + float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; + angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); + } - ReadStatus(msg); + bool readStatus = msg.ReadBoolean(); + if (readStatus) + { + ReadStatus(msg); + } msg.ReadPadBits(); int index = 0; - if (GameMain.NetworkMember.Character == this && AllowInput) + if (GameMain.Client.Character == this && AllowInput) { var posInfo = new CharacterStateInfo(pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) index++; - memState.Insert(index, posInfo); } else { - var posInfo = new CharacterStateInfo(pos, rotation, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + var posInfo = new CharacterStateInfo(pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) index++; - memState.Insert(index, posInfo); } @@ -198,10 +286,13 @@ namespace Barotrauma GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; } - else if (controlled == this) + else { - Controlled = null; - IsRemotePlayer = ownerID > 0; + if (controlled == this) + { + Controlled = null; + IsRemotePlayer = ownerID > 0; + } } break; case 2: @@ -221,45 +312,59 @@ namespace Barotrauma break; } } + public static Character ReadSpawnData(NetBuffer inc, bool spawn = true) { DebugConsole.NewMessage("READING CHARACTER SPAWN DATA", Color.Cyan); - if (GameMain.Server != null) return null; + if (GameMain.Client == null) return null; - bool noInfo = inc.ReadBoolean(); - ushort id = inc.ReadUInt16(); - string configPath = inc.ReadString(); - string seed = inc.ReadString(); + bool noInfo = inc.ReadBoolean(); + ushort id = inc.ReadUInt16(); + string speciesName = inc.ReadString(); + string seed = inc.ReadString(); Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat()); bool enabled = inc.ReadBoolean(); - DebugConsole.Log("Received spawn data for " + configPath); + DebugConsole.Log("Received spawn data for " + speciesName); + + string configPath = GetConfigFile(speciesName); + if (string.IsNullOrEmpty(configPath)) + { + throw new Exception("Error in character spawn data - could not find a config file for the character \"" + configPath + "\"!"); + } Character character = null; if (noInfo) { if (!spawn) return null; - character = Character.Create(configPath, position, seed, null, true); + character = Create(configPath, position, seed, null, true); character.ID = id; } else { - bool hasOwner = inc.ReadBoolean(); - int ownerId = hasOwner ? inc.ReadByte() : -1; - byte teamID = inc.ReadByte(); - bool hasAi = inc.ReadBoolean(); - + bool hasOwner = inc.ReadBoolean(); + int ownerId = hasOwner ? inc.ReadByte() : -1; + byte teamID = inc.ReadByte(); + bool hasAi = inc.ReadBoolean(); + string infoSpeciesName = inc.ReadString(); + if (!spawn) return null; - CharacterInfo info = CharacterInfo.ClientRead(configPath, inc); + string infoConfigPath = GetConfigFile(infoSpeciesName); + if (string.IsNullOrEmpty(infoConfigPath)) + { + throw new Exception("Error in character spawn data - could not find a config file for the character info \"" + configPath + "\"!"); + } + + CharacterInfo info = CharacterInfo.ClientRead(infoConfigPath, inc); character = Create(configPath, position, seed, info, GameMain.Client.ID != ownerId, hasAi); character.ID = id; - character.TeamID = teamID; + character.TeamID = (TeamType)teamID; if (configPath == HumanConfigFile) { @@ -267,7 +372,7 @@ namespace Barotrauma GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo); GameMain.GameSession.CrewManager.AddCharacter(character); } - + if (GameMain.Client.ID == ownerId) { GameMain.Client.HasSpawned = true; @@ -286,7 +391,7 @@ namespace Barotrauma return character; } - + private void ReadStatus(NetBuffer msg) { bool isDead = msg.ReadBoolean(); @@ -324,9 +429,6 @@ namespace Barotrauma if (IsDead) Revive(); CharacterHealth.ClientRead(msg); - - bool ragdolled = msg.ReadBoolean(); - IsRagdolled = ragdolled; } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterSound.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterSound.cs index c154fc677..469e7944e 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterSound.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterSound.cs @@ -8,7 +8,7 @@ namespace Barotrauma { public enum SoundType { - Idle, Attack, Die + Idle, Attack, Die, Damage } private readonly RoundSound roundSound; @@ -28,10 +28,13 @@ namespace Barotrauma get { return roundSound.Sound; } } + public readonly Gender Gender; + public CharacterSound(XElement element) { roundSound = Submarine.LoadRoundSound(element); - Enum.TryParse(element.GetAttributeString("state", "Idle"), true, out Type); + Enum.TryParse(element.GetAttributeString("state", "Idle"), true, out Type); + Enum.TryParse(element.GetAttributeString("gender", "None"), true, out Gender); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs new file mode 100644 index 000000000..727aea035 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs @@ -0,0 +1,34 @@ +using Microsoft.Xna.Framework; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace Barotrauma +{ + partial class AfflictionHusk : Affliction + { + partial void UpdateMessages(float prevStrength, Character character) + { + if (Strength < Prefab.MaxStrength * 0.5f) + { + if (prevStrength % 10.0f > 0.05f && Strength % 10.0f < 0.05f) + { + GUI.AddMessage(TextManager.Get("HuskDormant"), Color.Red); + } + } + else if (Strength < Prefab.MaxStrength) + { + if (state == InfectionState.Dormant && Character.Controlled == character) + { + GUI.AddMessage(TextManager.Get("HuskCantSpeak"), Color.Red); + } + } + else if (state != InfectionState.Active && Character.Controlled == character) + { + GUI.AddMessage(TextManager.Get("HuskActivate").Replace("[Attack]", GameMain.Config.KeyBind(InputType.Attack).ToString()), + Color.Red); + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs new file mode 100644 index 000000000..a43ee6069 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs @@ -0,0 +1,22 @@ +namespace Barotrauma +{ + partial class CharacterHealth + { + partial void UpdateLimbAfflictionOverlays() + { + foreach (Limb limb in Character.AnimController.Limbs) + { + limb.BurnOverlayStrength = 0.0f; + limb.DamageOverlayStrength = 0.0f; + if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue; + foreach (Affliction a in limbHealths[limb.HealthIndex].Afflictions) + { + limb.BurnOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.BurnOverlayAlpha; + limb.DamageOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.DamageOverlayAlpha; + } + limb.BurnOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count; + limb.DamageOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count; + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/DamageModifier.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/DamageModifier.cs new file mode 100644 index 000000000..316872df3 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/DamageModifier.cs @@ -0,0 +1,12 @@ +namespace Barotrauma +{ + partial class DamageModifier + { + [Serialize("", false)] + public string DamageSound + { + get; + private set; + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs index acd599422..4c4f87b42 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs @@ -110,11 +110,28 @@ namespace Barotrauma public Sprite Sprite { get; protected set; } public DeformableSprite DeformSprite { get; protected set; } - public Sprite ActiveSprite => DeformSprite != null ? DeformSprite.Sprite : Sprite; - + public Sprite ActiveSprite + { + get + { + // TODO: should we optimize this? No need to check all the conditionals each time the property is accessed. + var conditionalSprite = ConditionalSprites.FirstOrDefault(c => c.IsActive); + if (conditionalSprite != null) + { + return conditionalSprite; + } + else + { + return DeformSprite != null ? DeformSprite.Sprite : Sprite; + } + } + } + public float TextureScale => limbParams.Ragdoll.TextureScale; - public Sprite DamagedSprite { get; set; } + public Sprite DamagedSprite { get; private set; } + + public List ConditionalSprites { get; private set; } = new List(); public Color InitialLightSourceColor { @@ -156,6 +173,9 @@ namespace Barotrauma case "damagedsprite": DamagedSprite = new Sprite(subElement, "", GetSpritePath(subElement)); break; + case "conditionalsprite": + ConditionalSprites.Add(new ConditionalSprite(subElement, character, file: GetSpritePath(subElement))); + break; case "deformablesprite": DeformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement)); foreach (XElement animationElement in subElement.Elements()) @@ -241,28 +261,28 @@ namespace Barotrauma DeformSprite?.Sprite.LoadParams(limbParams.deformSpriteParams, isFlipped); } - partial void AddDamageProjSpecific(Vector2 position, List afflictions, bool playSound, List appliedDamageModifiers) + partial void AddDamageProjSpecific(Vector2 simPosition, List afflictions, bool playSound, List appliedDamageModifiers) { - float bleedingDamage = afflictions.FindAll(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth)); + float bleedingDamage = character.CharacterHealth.DoesBleed ? afflictions.FindAll(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth)) : 0; float damage = afflictions.FindAll(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth)); - + float damageMultiplier = 1; if (playSound) { string damageSoundType = (bleedingDamage > damage) ? "LimbSlash" : "LimbBlunt"; - foreach (DamageModifier damageModifier in appliedDamageModifiers) { if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound)) { damageSoundType = damageModifier.DamageSound; + SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition); + damageMultiplier *= damageModifier.DamageMultiplier; break; } } - - SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), position); } - float damageParticleAmount = Math.Min(damage / 10, 1.0f); + // Always spawn damage particles + float damageParticleAmount = Math.Min(damage / 10, 1.0f) * damageMultiplier; foreach (ParticleEmitter emitter in character.DamageEmitters) { if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue; @@ -271,20 +291,25 @@ namespace Barotrauma emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount); } - float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f); - float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f); - foreach (ParticleEmitter emitter in character.BloodEmitters) + if (bleedingDamage > 0) { - if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue; - if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue; + float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * damageMultiplier; + float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f); - emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount); + foreach (ParticleEmitter emitter in character.BloodEmitters) + { + if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue; + if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue; + + emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount); + } + + if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName)) + { + character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f)); + } } - - if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName)) - { - character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f)); - } + } partial void UpdateProjSpecific(float deltaTime) @@ -353,7 +378,8 @@ namespace Barotrauma if (!hideLimb) { - if (DeformSprite != null) + var activeSprite = ActiveSprite; + if (DeformSprite != null && activeSprite == DeformSprite.Sprite) { if (Deformations != null && Deformations.Any()) { @@ -368,7 +394,7 @@ namespace Barotrauma } else { - body.Draw(spriteBatch, Sprite, color, null, Scale * TextureScale); + body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale); } } @@ -401,11 +427,12 @@ namespace Barotrauma { float depth = ActiveSprite.Depth - 0.0000015f; - DamagedSprite.Draw(spriteBatch, - new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), - color * Math.Min(damageOverlayStrength / 50.0f, 1.0f), ActiveSprite.Origin, - -body.DrawRotation, - 1.0f, spriteEffect, depth); + // TODO: enable when the damage overlay textures have been remade. + //DamagedSprite.Draw(spriteBatch, + // new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), + // color * Math.Min(damageOverlayStrength, 1.0f), ActiveSprite.Origin, + // -body.DrawRotation, + // 1.0f, spriteEffect, depth); } if (GameMain.DebugDraw) @@ -415,6 +442,8 @@ namespace Barotrauma Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB); GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true); } + var bodyDrawPos = body.DrawPosition; + bodyDrawPos.Y = -bodyDrawPos.Y; if (IsStuck) { Vector2 from = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorA); @@ -424,9 +453,7 @@ namespace Barotrauma var localFront = body.GetLocalFront(MathHelper.ToRadians(limbParams.Ragdoll.SpritesheetOrientation)); var front = ConvertUnits.ToDisplayUnits(body.FarseerBody.GetWorldPoint(localFront)); front.Y = -front.Y; - var drawPos = body.DrawPosition; - drawPos.Y = -drawPos.Y; - GUI.DrawLine(spriteBatch, drawPos, front, Color.Yellow, width: 2); + GUI.DrawLine(spriteBatch, bodyDrawPos, front, Color.Yellow, width: 2); GUI.DrawLine(spriteBatch, from, to, Color.Red, width: 1); GUI.DrawRectangle(spriteBatch, new Rectangle((int)from.X, (int)from.Y, 12, 12), Color.White, true); GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 12, 12), Color.White, true); @@ -440,7 +467,19 @@ namespace Barotrauma //mainLimbDrawPos.Y = -mainLimbDrawPos.Y; //GUI.DrawLine(spriteBatch, mainLimbDrawPos, mainLimbFront, Color.White, width: 5); //GUI.DrawRectangle(spriteBatch, new Rectangle((int)mainLimbFront.X, (int)mainLimbFront.Y, 10, 10), Color.Yellow, true); - + } + foreach (var modifier in damageModifiers) + { + //float midAngle = MathUtils.GetMidAngle(modifier.ArmorSector.X, modifier.ArmorSector.Y); + //float spritesheetOrientation = MathHelper.ToRadians(limbParams.Ragdoll.SpritesheetOrientation); + //float offset = -body.Rotation - (midAngle + spritesheetOrientation) * Dir; + float offset = GetArmorSectorRotationOffset(modifier.ArmorSector, -body.Rotation); + Vector2 forward = Vector2.Transform(-Vector2.UnitY, Matrix.CreateRotationZ(offset)); + float size = ConvertUnits.ToDisplayUnits(body.GetSize().Length() / 2); + color = modifier.DamageMultiplier > 1 ? Color.Red : Color.GreenYellow; + GUI.DrawLine(spriteBatch, bodyDrawPos, bodyDrawPos + Vector2.Normalize(forward) * size, color, width: (int)Math.Round(4 / cam.Zoom)); + if (Dir == -1) { offset += MathHelper.Pi; } + ShapeExtensions.DrawSector(spriteBatch, bodyDrawPos, size, GetArmorSectorSize(modifier.ArmorSector) * Dir, 40, color, offset + MathHelper.Pi, thickness: 2 / cam.Zoom); } } } @@ -521,6 +560,9 @@ namespace Barotrauma DeformSprite?.Sprite?.Remove(); DeformSprite = null; + ConditionalSprites.ForEach(s => s.Remove()); + ConditionalSprites.Clear(); + LightSource?.Remove(); LightSource = null; diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index a79157757..96d53ee97 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Xml.Linq; using System.Globalization; @@ -14,13 +15,43 @@ namespace Barotrauma { static partial class DebugConsole { + public partial class Command + { + /// + /// Executed when a client uses the command. If not set, the command is relayed to the server as-is. + /// + public Action OnClientExecute; + + public bool RelayToServer = true; + + public void ClientExecute(string[] args) + { + if (!CheatsEnabled && IsCheat) + { + NewMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", Color.Red); + if (GameMain.Config.UseSteam) + { + NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red); + } + return; + } + + if (OnClientExecute != null) + { + OnClientExecute(args); + } + else + { + OnExecute(args); + } + } + } + private static bool isOpen; public static bool IsOpen => isOpen; - - private static Queue queuedMessages = new Queue(); - + private static GUITextBlock activeQuestionText; - + private static GUIFrame frame; private static GUIListBox listBox; private static GUITextBox textBox; @@ -29,7 +60,7 @@ namespace Barotrauma public static void Init() { - frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.45f), GUI.Canvas) { MinSize = new Point(400, 300), AbsoluteOffset = new Point(10, 10) }, + frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.45f), GUI.Canvas) { MinSize = new Point(400, 300), AbsoluteOffset = new Point(10, 10) }, color: new Color(0.4f, 0.4f, 0.4f, 0.8f)); var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), frame.RectTransform, Anchor.Center), style: null); @@ -116,7 +147,7 @@ namespace Barotrauma } else if (PlayerInput.KeyHit(Keys.Tab)) { - textBox.Text = AutoComplete(textBox.Text); + textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 ); } if (PlayerInput.KeyHit(Keys.Enter)) @@ -211,7 +242,7 @@ namespace Barotrauma selectedIndex = Messages.Count; } - private static void AddHelpMessage(Command command) + static partial void ShowHelpMessage(Command command) { if (listBox.Content.CountChildren > MaxMessages) { @@ -233,15 +264,40 @@ namespace Barotrauma textBlock.SetTextPos(); var nameBlock = new GUITextBlock(new RectTransform(new Point(150, textContainer.Rect.Height), textContainer.RectTransform), command.names[0], textAlignment: Alignment.TopLeft); - + listBox.UpdateScrollBarSize(); listBox.BarScroll = 1.0f; selectedIndex = Messages.Count; } + private static void AssignOnClientExecute(string names, Action onClientExecute) + { + Command command = commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0); + command.OnClientExecute = onClientExecute; + command.RelayToServer = false; + } + + private static void AssignRelayToServer(string names, bool relay) + { + commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0).RelayToServer = relay; + } + private static void InitProjectSpecific() { +#if WINDOWS + commands.Add(new Command("copyitemnames", "", (string[] args) => + { + StringBuilder sb = new StringBuilder(); + foreach (MapEntityPrefab mp in MapEntityPrefab.List) + { + if (!(mp is ItemPrefab)) continue; + sb.AppendLine(mp.Name); + } + System.Windows.Clipboard.SetText(sb.ToString()); + })); +#endif + commands.Add(new Command("autohull", "", (string[] args) => { if (Screen.Selected != GameMain.SubEditorScreen) return; @@ -249,10 +305,10 @@ namespace Barotrauma if (MapEntity.mapEntityList.Any(e => e is Hull || e is Gap)) { ShowQuestionPrompt("This submarine already has hulls and/or gaps. This command will delete them. Do you want to continue? Y/N", - (option) => + (option) => { ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N", - (option2) => + (option2) => { if (option2.ToLower() == "y") { GameMain.SubEditorScreen.AutoHull(); } }); @@ -271,8 +327,19 @@ namespace Barotrauma if (GameMain.Client == null) { - GameMain.NetworkMember = new GameClient("Name"); - GameMain.Client.ConnectToServer(args[0]); + GameMain.Client = new GameClient("Name", args[0]); + } + })); + + + commands.Add(new Command("enablecheats", "enablecheats: Enables cheat commands and disables Steam achievements during this play session.", (string[] args) => + { + CheatsEnabled = true; + SteamAchievementManager.CheatsEnabled = true; + NewMessage("Enabled cheat commands.", Color.Red); + if (GameMain.Config.UseSteam) + { + NewMessage("Steam achievements have been disabled during this play session.", Color.Red); } })); @@ -323,41 +390,62 @@ namespace Barotrauma GameMain.CharacterEditorScreen.Select(); })); - commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character.", (string[] args) => + AssignRelayToServer("kick", false); + AssignRelayToServer("kickid", false); + AssignRelayToServer("ban", false); + AssignRelayToServer("banid", false); + AssignRelayToServer("dumpids", false); + AssignRelayToServer("findentityids", false); + AssignRelayToServer("campaigninfo", false); + AssignRelayToServer("help", false); + AssignRelayToServer("verboselogging", false); + AssignRelayToServer("freecam", false); + + commands.Add(new Command("clientlist", "", (string[] args) => { })); + AssignRelayToServer("clientlist", true); + + AssignOnExecute("control", (string[] args) => { if (args.Length < 1) return; - var character = FindMatchingCharacter(args, true); - if (character != null) { Character.Controlled = character; } - }, - () => - { - return new string[][] - { - Character.CharacterList.Select(c => c.Name).Distinct().ToArray() - }; - }, isCheat: true)); + }); + AssignRelayToServer("control", true); commands.Add(new Command("shake", "", (string[] args) => { GameMain.GameScreen.Cam.Shake = 10.0f; })); - commands.Add(new Command("los", "los: Toggle the line of sight effect on/off.", (string[] args) => - { - GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled; - NewMessage("Line of sight effect " + (GameMain.LightManager.LosEnabled ? "enabled" : "disabled"), Color.White); - }, isCheat: true)); + AssignOnExecute("los", (string[] args) => + { + GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled; + NewMessage("Line of sight effect " + (GameMain.LightManager.LosEnabled ? "enabled" : "disabled"), Color.White); + }); + AssignRelayToServer("los", false); - commands.Add(new Command("lighting|lights", "Toggle lighting on/off.", (string[] args) => + AssignOnExecute("lighting|lights", (string[] args) => { GameMain.LightManager.LightingEnabled = !GameMain.LightManager.LightingEnabled; NewMessage("Lighting " + (GameMain.LightManager.LightingEnabled ? "enabled" : "disabled"), Color.White); - }, isCheat: true)); + }); + AssignRelayToServer("lighting|lights", false); + + AssignOnExecute("ambientlight", (string[] args) => + { + if (Level.Loaded == null) + { + ThrowError("Could not set ambient light color (no level loaded)."); + return; + } + Color color = XMLExtensions.ParseColor(string.Join("", args)); + Level.Loaded.GenerationParams.AmbientLightColor = color; + NewMessage("Set ambient light color to " + color + ".", Color.White); + }); + AssignRelayToServer("ambientlight", false); commands.Add(new Command("multiplylights", "Multiplies the colors of all the static lights in the sub with the given Vector4 value (for example, 1,1,1,0.5).", (string[] args) => { @@ -373,9 +461,9 @@ namespace Barotrauma { if (item.ParentInventory != null || item.body != null) continue; var lightComponent = item.GetComponent(); - if (lightComponent != null) lightComponent.LightColor = + if (lightComponent != null) lightComponent.LightColor = new Color( - (lightComponent.LightColor.R / 255.0f) * value.X, + (lightComponent.LightColor.R / 255.0f) * value.X, (lightComponent.LightColor.G / 255.0f) * value.Y, (lightComponent.LightColor.B / 255.0f) * value.Z, (lightComponent.LightColor.A / 255.0f) * value.W); @@ -434,7 +522,7 @@ namespace Barotrauma } } }, isCheat: true)); - + commands.Add(new Command("alpha", "Change the alpha (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) => { if (Screen.Selected == GameMain.SubEditorScreen) @@ -548,11 +636,12 @@ namespace Barotrauma new GUIMessageBox("", string.Join(" ", args)); })); - commands.Add(new Command("debugdraw", "debugdraw: Toggle the debug drawing mode on/off.", (string[] args) => + AssignOnExecute("debugdraw", (string[] args) => { GameMain.DebugDraw = !GameMain.DebugDraw; NewMessage("Debug draw mode " + (GameMain.DebugDraw ? "enabled" : "disabled"), Color.White); - }, isCheat: true)); + }); + AssignRelayToServer("debugdraw", false); commands.Add(new Command("fpscounter", "fpscounter: Toggle the FPS counter.", (string[] args) => { @@ -565,6 +654,12 @@ namespace Barotrauma NewMessage("Performance statistics " + (GameMain.ShowPerf ? "enabled" : "disabled"), Color.White); })); + AssignOnClientExecute("netstats", (string[] args) => + { + if (GameMain.Client == null) return; + GameMain.Client.ShowNetStats = !GameMain.Client.ShowNetStats; + }); + commands.Add(new Command("hudlayoutdebugdraw|debugdrawhudlayout", "hudlayoutdebugdraw: Toggle the debug drawing mode of HUD layout areas on/off.", (string[] args) => { HUDLayoutSettings.DebugDraw = !HUDLayoutSettings.DebugDraw; @@ -577,24 +672,72 @@ namespace Barotrauma NewMessage("Interact debug draw mode " + (Character.DebugDrawInteract ? "enabled" : "disabled"), Color.White); }, isCheat: true)); - commands.Add(new Command("togglehud|hud", "togglehud/hud: Toggle the character HUD (inventories, icons, buttons, etc) on/off.", (string[] args) => + AssignOnExecute("togglehud|hud", (string[] args) => { GUI.DisableHUD = !GUI.DisableHUD; GameMain.Instance.IsMouseVisible = !GameMain.Instance.IsMouseVisible; NewMessage(GUI.DisableHUD ? "Disabled HUD" : "Enabled HUD", Color.White); - })); + }); + AssignRelayToServer("togglehud|hud", false); - commands.Add(new Command("followsub", "followsub: Toggle whether the camera should follow the nearest submarine.", (string[] args) => + AssignOnExecute("toggleupperhud", (string[] args) => + { + GUI.DisableUpperHUD = !GUI.DisableUpperHUD; + NewMessage(GUI.DisableUpperHUD ? "Disabled upper HUD" : "Enabled upper HUD", Color.White); + }); + AssignRelayToServer("toggleupperhud", false); + + AssignOnExecute("toggleitemhighlights", (string[] args) => + { + GUI.DisableItemHighlights = !GUI.DisableItemHighlights; + NewMessage(GUI.DisableItemHighlights ? "Disabled item highlights" : "Enabled item highlights", Color.White); + }); + AssignRelayToServer("toggleitemhighlights", false); + + AssignOnExecute("togglecharacternames", (string[] args) => + { + GUI.DisableCharacterNames = !GUI.DisableCharacterNames; + NewMessage(GUI.DisableCharacterNames ? "Disabled character names" : "Enabled character names", Color.White); + }); + AssignRelayToServer("togglecharacternames", false); + + AssignOnExecute("followsub", (string[] args) => { Camera.FollowSub = !Camera.FollowSub; NewMessage(Camera.FollowSub ? "Set the camera to follow the closest submarine" : "Disabled submarine following.", Color.White); - })); + }); + AssignRelayToServer("followsub", false); - commands.Add(new Command("toggleaitargets|aitargets", "toggleaitargets/aitargets: Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from).", (string[] args) => + AssignOnExecute("toggleaitargets|aitargets", (string[] args) => { AITarget.ShowAITargets = !AITarget.ShowAITargets; NewMessage(AITarget.ShowAITargets ? "Enabled AI target drawing" : "Disabled AI target drawing", Color.White); - }, isCheat: true)); + }); + AssignRelayToServer("toggleaitargets|aitargets", false); + + AssignRelayToServer("water|editwater", false); + AssignRelayToServer("fire|editfire", false); + + commands.Add(new Command("mute", "mute [name]: Prevent the client from speaking to anyone through the voice chat. Using this command requires a permission from the server host.", + null, + () => + { + if (GameMain.Client == null) return null; + return new string[][] + { + GameMain.Client.ConnectedClients.Select(c => c.Name).ToArray() + }; + })); + commands.Add(new Command("unmute", "unmute [name]: Allow the client to speak to anyone through the voice chat. Using this command requires a permission from the server host.", + null, + () => + { + if (GameMain.Client == null) return null; + return new string[][] + { + GameMain.Client.ConnectedClients.Select(c => c.Name).ToArray() + }; + })); commands.Add(new Command("checkcrafting", "checkcrafting: Checks item deconstruction & crafting recipes for inconsistencies.", (string[] args) => { @@ -696,7 +839,6 @@ namespace Barotrauma } }, isCheat: false)); - #if DEBUG commands.Add(new Command("spamchatmessages", "", (string[] args) => { @@ -707,11 +849,7 @@ namespace Barotrauma for (int i = 0; i < msgCount; i++) { - if (GameMain.Server != null) - { - GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default); - } - else if (GameMain.Client != null) + if (GameMain.Client != null) { GameMain.Client.SendChatMessage(ToolBox.RandomSeed(msgLength)); } @@ -739,7 +877,7 @@ namespace Barotrauma Screen.Selected.Cam.MinZoom = minZoom; Screen.Selected.Cam.MaxZoom = maxZoom; })); - + commands.Add(new Command("waterparams", "waterparams [distortionscalex] [distortionscaley] [distortionstrengthx] [distortionstrengthy] [bluramount]: default 0.5 0.5 0.5 0.5 1", (string[] args) => { float distortScaleX = 0.5f, distortScaleY = 0.5f; @@ -753,8 +891,7 @@ namespace Barotrauma WaterRenderer.DistortionScale = new Vector2(distortScaleX, distortScaleY); WaterRenderer.DistortionStrength = new Vector2(distortStrengthX, distortStrengthY); WaterRenderer.BlurAmount = blurAmount; - }, - null, null)); + })); commands.Add(new Command("refreshrect", "Updates the dimensions of the selected items to match the ones defined in the prefab. Applied only in the subeditor.", (string[] args) => @@ -767,13 +904,13 @@ namespace Barotrauma ThrowError("You have to select item(s) first!"); } else - { + { foreach (var mapEntity in MapEntity.SelectedList) { if (mapEntity is Item item) { - item.Rect = new Rectangle(item.Rect.X, item.Rect.Y, - (int)(item.Prefab.sprite.size.X * item.Prefab.Scale), + item.Rect = new Rectangle(item.Rect.X, item.Rect.Y, + (int)(item.Prefab.sprite.size.X * item.Prefab.Scale), (int)(item.Prefab.sprite.size.Y * item.Prefab.Scale)); } else if (mapEntity is Structure structure) @@ -875,7 +1012,7 @@ namespace Barotrauma destinationElement.AddAfterSelf(element); } XNode nextNode = destinationElement.NextNode; - while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode; + while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode; destinationElement = nextNode as XElement; } destinationDoc.Save(destinationPath); @@ -901,7 +1038,97 @@ namespace Barotrauma } File.WriteAllLines(filePath, lines); })); +#if DEBUG + commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) => + { + if (args.Length != 1) return; + TextManager.CheckForDuplicates(args[0]); + })); + commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) => + { + TextManager.WriteToCSV(); + NPCConversation.WriteToCSV(); + })); + + commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) => + { + float defaultZoom = Screen.Selected.Cam.DefaultZoom; + if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out defaultZoom); + + float zoomSmoothness = Screen.Selected.Cam.ZoomSmoothness; + if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out zoomSmoothness); + float moveSmoothness = Screen.Selected.Cam.MoveSmoothness; + if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out moveSmoothness); + + float minZoom = Screen.Selected.Cam.MinZoom; + if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out minZoom); + float maxZoom = Screen.Selected.Cam.MaxZoom; + if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out maxZoom); + + Screen.Selected.Cam.DefaultZoom = defaultZoom; + Screen.Selected.Cam.ZoomSmoothness = zoomSmoothness; + Screen.Selected.Cam.MoveSmoothness = moveSmoothness; + Screen.Selected.Cam.MinZoom = minZoom; + Screen.Selected.Cam.MaxZoom = maxZoom; + })); + + commands.Add(new Command("waterparams", "waterparams [distortionscalex] [distortionscaley] [distortionstrengthx] [distortionstrengthy] [bluramount]: default 0.5 0.5 0.5 0.5 1", (string[] args) => + { + float distortScaleX = 0.5f, distortScaleY = 0.5f; + float distortStrengthX = 0.5f, distortStrengthY = 0.5f; + float blurAmount = 0.0f; + if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleX); + if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleY); + if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthX); + if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthY); + if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out blurAmount); + WaterRenderer.DistortionScale = new Vector2(distortScaleX, distortScaleY); + WaterRenderer.DistortionStrength = new Vector2(distortStrengthX, distortStrengthY); + WaterRenderer.BlurAmount = blurAmount; + }, + null, null)); + + + commands.Add(new Command("refreshrect", "Updates the dimensions of the selected items to match the ones defined in the prefab. Applied only in the subeditor.", (string[] args) => + { + //TODO: maybe do this automatically during loading when possible? + if (Screen.Selected == GameMain.SubEditorScreen) + { + if (!MapEntity.SelectedAny) + { + ThrowError("You have to select item(s) first!"); + } + else + { + foreach (var mapEntity in MapEntity.SelectedList) + { + if (mapEntity is Item item) + { + item.Rect = new Rectangle(item.Rect.X, item.Rect.Y, + (int)(item.Prefab.sprite.size.X * item.Prefab.Scale), + (int)(item.Prefab.sprite.size.Y * item.Prefab.Scale)); + } + else if (mapEntity is Structure structure) + { + if (!structure.ResizeHorizontal) + { + structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y, + (int)structure.Prefab.ScaledSize.X, + structure.Rect.Height); + } + if (!structure.ResizeVertical) + { + structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y, + structure.Rect.Width, + (int)structure.Prefab.ScaledSize.Y); + } + } + } + } + } + }, isCheat: false)); +#endif commands.Add(new Command("cleanbuild", "", (string[] args) => { @@ -924,7 +1151,7 @@ namespace Barotrauma ThrowError("MasterServerUrl \"" + GameMain.Config.MasterServerUrl + "\"!"); } - GameMain.Config.Save(); + GameMain.Config.SaveNewPlayerConfig(); var saveFiles = System.IO.Directory.GetFiles(SaveUtil.SaveFolder); @@ -970,7 +1197,7 @@ namespace Barotrauma NewMessage("Deleted TutorialSub from the submarine folder", Color.Green); } - if (System.IO.File.Exists(GameServer.SettingsFile)) + /*if (System.IO.File.Exists(GameServer.SettingsFile)) { System.IO.File.Delete(GameServer.SettingsFile); NewMessage("Deleted server settings", Color.Green); @@ -980,7 +1207,7 @@ namespace Barotrauma { System.IO.File.Delete(GameServer.ClientPermissionsFile); NewMessage("Deleted client permission file", Color.Green); - } + }*/ if (System.IO.File.Exists("crashreport.log")) { @@ -993,6 +1220,221 @@ namespace Barotrauma ThrowError("TutorialSub.sub not found!"); } })); + + AssignOnClientExecute( + "giveperm", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + NewMessage("Valid permissions are:", Color.White); + foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions))) + { + NewMessage(" - " + permission.ToString(), Color.White); + } + ShowQuestionPrompt("Permission to grant to client #" + id + "?", (perm) => + { + GameMain.Client.SendConsoleCommand("giveperm " + id + " " + perm); + }); + } + ); + + AssignOnClientExecute( + "revokeperm", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + NewMessage("Valid permissions are:", Color.White); + foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions))) + { + NewMessage(" - " + permission.ToString(), Color.White); + } + + ShowQuestionPrompt("Permission to revoke from client #" + id + "?", (perm) => + { + GameMain.Client.SendConsoleCommand("revokeperm " + id + " " + perm); + }); + } + ); + + AssignOnClientExecute( + "giverank", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + NewMessage("Valid ranks are:", Color.White); + foreach (PermissionPreset permissionPreset in PermissionPreset.List) + { + NewMessage(" - " + permissionPreset.Name, Color.White); + } + ShowQuestionPrompt("Rank to grant to client #" + id + "?", (rank) => + { + GameMain.Client.SendConsoleCommand("giverank " + id + " " + rank); + }); + } + ); + + AssignOnClientExecute( + "givecommandperm", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + ShowQuestionPrompt("Console command permissions to grant to client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) => + { + GameMain.Client.SendConsoleCommand("givecommandperm " + id + " " + commandNames); + }); + } + ); + + AssignOnClientExecute( + "revokecommandperm", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + ShowQuestionPrompt("Console command permissions to revoke from client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) => + { + GameMain.Client.SendConsoleCommand("revokecommandperm " + id + " " + commandNames); + }); + } + ); + + AssignOnClientExecute( + "showperm", + (string[] args) => + { + if (args.Length < 1) return; + + if (!int.TryParse(args[0], out int id)) + { + ThrowError("\"" + id + "\" is not a valid client ID."); + return; + } + + GameMain.Client.SendConsoleCommand("showperm " + id); + } + ); + + AssignOnClientExecute( + "banip", + (string[] args) => + { + if (GameMain.Client == null || args.Length == 0) return; + ShowQuestionPrompt("Reason for banning the ip \"" + args[0] + "\"?", (reason) => + { + ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => + { + TimeSpan? banDuration = null; + if (!string.IsNullOrWhiteSpace(duration)) + { + if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration)) + { + ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); + return; + } + banDuration = parsedBanDuration; + } + + GameMain.Client.SendConsoleCommand( + "banip " + + args[0] + " " + + (banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " + + reason); + }); + }); + } + ); + + commands.Add(new Command("unban", "unban [name]: Unban a specific client.", (string[] args) => + { + if (GameMain.Client == null || args.Length == 0) return; + string clientName = string.Join(" ", args); + GameMain.Client.UnbanPlayer(clientName, ""); + })); + + commands.Add(new Command("unbanip", "unbanip [ip]: Unban a specific IP.", (string[] args) => + { + if (GameMain.Client == null || args.Length == 0) return; + GameMain.Client.UnbanPlayer("", args[0]); + })); + + AssignOnClientExecute( + "campaigndestination|setcampaigndestination", + (string[] args) => + { + var campaign = GameMain.GameSession?.GameMode as CampaignMode; + if (campaign == null) + { + ThrowError("No campaign active!"); + return; + } + + if (args.Length == 0) + { + int i = 0; + foreach (LocationConnection connection in campaign.Map.CurrentLocation.Connections) + { + NewMessage(" " + i + ". " + connection.OtherLocation(campaign.Map.CurrentLocation).Name, Color.White); + i++; + } + ShowQuestionPrompt("Select a destination (0 - " + (campaign.Map.CurrentLocation.Connections.Count - 1) + "):", (string selectedDestination) => + { + int destinationIndex = -1; + if (!int.TryParse(selectedDestination, out destinationIndex)) return; + if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count) + { + NewMessage("Index out of bounds!", Color.Red); + return; + } + GameMain.Client.SendConsoleCommand("campaigndestination " + destinationIndex); + }); + } + else + { + int destinationIndex = -1; + if (!int.TryParse(args[0], out destinationIndex)) return; + if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count) + { + NewMessage("Index out of bounds!", Color.Red); + return; + } + GameMain.Client.SendConsoleCommand("campaigndestination " + destinationIndex); + } + } + ); commands.Add(new Command("limbscale", "Define the limbscale for the controlled character. Provide id or name if you want to target another character. Note: the changes are not saved!", (string[] args) => { diff --git a/Barotrauma/BarotraumaClient/Source/EventInput/EventInput.cs b/Barotrauma/BarotraumaClient/Source/EventInput/EventInput.cs index 13cbed6d6..bba13d136 100644 --- a/Barotrauma/BarotraumaClient/Source/EventInput/EventInput.cs +++ b/Barotrauma/BarotraumaClient/Source/EventInput/EventInput.cs @@ -178,11 +178,12 @@ namespace EventInput private static void ReceiveInput(object sender, TextInputEventArgs e) { OnCharEntered(e.Character); + KeyDown?.Invoke(sender, new KeyEventArgs(e.Key)); } public static void OnCharEntered(char character) { - if (CharEntered != null) CharEntered(null, new CharacterEventArgs(character, 0)); + CharEntered?.Invoke(null, new CharacterEventArgs(character, 0)); } #if WINDOWS static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) diff --git a/Barotrauma/BarotraumaClient/Source/EventInput/KeyboardDispatcher.cs b/Barotrauma/BarotraumaClient/Source/EventInput/KeyboardDispatcher.cs index 812cc7a5c..102efe9d7 100644 --- a/Barotrauma/BarotraumaClient/Source/EventInput/KeyboardDispatcher.cs +++ b/Barotrauma/BarotraumaClient/Source/EventInput/KeyboardDispatcher.cs @@ -27,7 +27,7 @@ namespace EventInput EventInput.KeyDown += EventInput_KeyDown; } - void EventInput_KeyDown(object sender, KeyEventArgs e) + public void EventInput_KeyDown(object sender, KeyEventArgs e) { if (_subscriber == null) return; @@ -74,6 +74,7 @@ namespace EventInput get { return _subscriber; } set { + if (_subscriber == value) return; if (_subscriber != null) _subscriber.Selected = false; _subscriber = value; diff --git a/Barotrauma/BarotraumaClient/Source/Events/EventManager.cs b/Barotrauma/BarotraumaClient/Source/Events/EventManager.cs index 4e0bdae4e..cfb46a25c 100644 --- a/Barotrauma/BarotraumaClient/Source/Events/EventManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Events/EventManager.cs @@ -17,8 +17,9 @@ namespace Barotrauma Vector2 drawPos = ev.DebugDrawPos; drawPos.Y = -drawPos.Y; - GUI.SubmarineIcon.Draw(spriteBatch, drawPos, Color.White * 0.5f, GUI.SubmarineIcon.size / 2, 0.0f, 40.0f); - GUI.DrawString(spriteBatch, drawPos, ev.ToString(), Color.White, Color.Black, 0, GUI.LargeFont); + var textOffset = new Vector2(-150, 0); + ShapeExtensions.DrawCircle(spriteBatch, drawPos, 600, 6, Color.White, thickness: 20); + GUI.DrawString(spriteBatch, drawPos + textOffset, ev.ToString(), Color.White, Color.Black, 0, GUI.LargeFont); } } diff --git a/Barotrauma/BarotraumaClient/Source/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaClient/Source/Events/Missions/CombatMission.cs new file mode 100644 index 000000000..8a69ad19e --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Events/Missions/CombatMission.cs @@ -0,0 +1,22 @@ +namespace Barotrauma +{ + partial class CombatMission + { + public override string Description + { + get + { + if (descriptions == null) return ""; + + if (GameMain.Client?.Character == null) + { + //non-team-specific description + return descriptions[0]; + } + + //team specific + return descriptions[GameMain.Client.Character.TeamID == Character.TeamType.Team1 ? 1 : 2]; + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs b/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs index 6a204e249..0174c2246 100644 --- a/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs @@ -11,7 +11,8 @@ namespace Barotrauma string header = index < Headers.Count ? Headers[index] : ""; string message = index < Messages.Count ? Messages[index] : ""; - GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage); + //TODO: reimplement + //GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage); new GUIMessageBox(header, message); } diff --git a/Barotrauma/BarotraumaClient/Source/Events/Missions/MissionMode.cs b/Barotrauma/BarotraumaClient/Source/Events/Missions/MissionMode.cs index 263c82826..fab117041 100644 --- a/Barotrauma/BarotraumaClient/Source/Events/Missions/MissionMode.cs +++ b/Barotrauma/BarotraumaClient/Source/Events/Missions/MissionMode.cs @@ -9,8 +9,10 @@ var missionMsg = new GUIMessageBox(mission.Name, mission.Description, 400, 400); missionMsg.UserData = "missionstartmessage"; +#if SERVER Networking.GameServer.Log(TextManager.Get("Mission") + ": " + mission.Name, Networking.ServerLog.MessageType.ServerMessage); Networking.GameServer.Log(mission.Description, Networking.ServerLog.MessageType.ServerMessage); +#endif } } } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs index ea6090c79..ff3c8fa55 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs @@ -172,7 +172,7 @@ namespace Barotrauma float prevSize = chatBox.BarSize; - string displayedText = message.Text; + string displayedText = message.TranslatedText; string senderName = ""; if (!string.IsNullOrWhiteSpace(message.SenderName)) { @@ -245,7 +245,7 @@ namespace Barotrauma if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f; - GUISoundType soundType = GUISoundType.Message; + GUISoundType soundType = GUISoundType.ChatMessage; if (message.Type == ChatMessageType.Radio) { soundType = GUISoundType.RadioMessage; diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index 09de753bf..3b01f8020 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -13,7 +13,8 @@ namespace Barotrauma { public enum GUISoundType { - Message, + UIMessage, + ChatMessage, RadioMessage, DeadMessage, Click, @@ -58,7 +59,7 @@ namespace Barotrauma private static GUIFrame pauseMenu; private static Sprite arrow, lockIcon, checkmarkIcon, timerIcon; - public static KeyboardDispatcher KeyboardDispatcher { get; private set; } + public static KeyboardDispatcher KeyboardDispatcher { get; set; } /// /// Has the selected Screen changed since the last time the GUI was drawn. @@ -131,12 +132,11 @@ namespace Barotrauma set; } - public static bool DisableHUD; + public static bool DisableHUD, DisableUpperHUD, DisableItemHighlights, DisableCharacterNames; public static void Init(GameWindow window, IEnumerable selectedContentPackages, GraphicsDevice graphicsDevice) { GUI.graphicsDevice = graphicsDevice; - KeyboardDispatcher = new KeyboardDispatcher(window); var uiStyles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle).ToList(); if (uiStyles.Count == 0) { @@ -157,14 +157,15 @@ namespace Barotrauma { sounds = new Sound[Enum.GetValues(typeof(GUISoundType)).Length]; - sounds[(int)GUISoundType.Message] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/UImsg.ogg", false); - sounds[(int)GUISoundType.RadioMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/radiomsg.ogg", false); - sounds[(int)GUISoundType.DeadMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/deadmsg.ogg", false); - sounds[(int)GUISoundType.Click] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/beep-shinymetal.ogg", false); + sounds[(int)GUISoundType.UIMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/UImsg.ogg", false); + sounds[(int)GUISoundType.ChatMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/ChatMsg.ogg", false); + sounds[(int)GUISoundType.RadioMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/RadioMsg.ogg", false); + sounds[(int)GUISoundType.DeadMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/DeadMsg.ogg", false); + sounds[(int)GUISoundType.Click] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/Click.ogg", false); - sounds[(int)GUISoundType.PickItem] = GameMain.SoundManager.LoadSound("Content/Sounds/pickItem.ogg", false); - sounds[(int)GUISoundType.PickItemFail] = GameMain.SoundManager.LoadSound("Content/Sounds/pickItemFail.ogg", false); - sounds[(int)GUISoundType.DropItem] = GameMain.SoundManager.LoadSound("Content/Sounds/dropItem.ogg", false); + sounds[(int)GUISoundType.PickItem] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItem.ogg", false); + sounds[(int)GUISoundType.PickItemFail] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItemFail.ogg", false); + sounds[(int)GUISoundType.DropItem] = GameMain.SoundManager.LoadSound("Content/Sounds/DropItem.ogg", false); } // create 1x1 texture for line drawing t = new Texture2D(GraphicsDevice, 1, 1); @@ -290,7 +291,7 @@ namespace Barotrauma { Color clr = Color.White; string soundStr = i + ": "; - SoundChannel playingSoundChannel = GameMain.SoundManager.GetSoundChannelFromIndex(i); + SoundChannel playingSoundChannel = GameMain.SoundManager.GetSoundChannelFromIndex(SoundManager.SourcePoolIndex.Default, i); if (playingSoundChannel == null) { soundStr += "none"; @@ -363,7 +364,7 @@ namespace Barotrauma if (HUDLayoutSettings.DebugDraw) HUDLayoutSettings.Draw(spriteBatch); - if (GameMain.NetworkMember != null) GameMain.NetworkMember.Draw(spriteBatch); + if (GameMain.Client != null) GameMain.Client.Draw(spriteBatch); if (Character.Controlled?.Inventory != null) { @@ -1527,10 +1528,10 @@ namespace Barotrauma SaveUtil.SaveGame(GameMain.GameSession.SavePath); } - if (GameMain.NetworkMember != null) + if (GameMain.Client != null) { - GameMain.NetworkMember.Disconnect(); - GameMain.NetworkMember = null; + GameMain.Client.Disconnect(); + GameMain.Client = null; } CoroutineManager.StopCoroutines("EndCinematic"); @@ -1563,13 +1564,13 @@ namespace Barotrauma { if (messages.Any(msg => msg.Text == message)) { return; } messages.Add(new GUIMessage(message, color, lifeTime ?? MathHelper.Clamp(message.Length / 5.0f, 3.0f, 10.0f), font ?? LargeFont)); - if (playSound) PlayUISound(GUISoundType.Message); + if (playSound) PlayUISound(GUISoundType.UIMessage); } public static void AddMessage(string message, Color color, Vector2 worldPos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true) { messages.Add(new GUIMessage(message, color, worldPos, velocity, lifeTime, Alignment.Center, LargeFont)); - if (playSound) PlayUISound(GUISoundType.Message); + if (playSound) PlayUISound(GUISoundType.UIMessage); } public static void ClearMessages() diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs index 0f6f280d2..e1063b2da 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs @@ -36,6 +36,12 @@ namespace Barotrauma set { listBox.Enabled = value; } } + public bool ButtonEnabled + { + get { return button.Enabled; } + set { button.Enabled = value; } + } + public GUIComponent Selected { get { return listBox.SelectedComponent; } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIRadioButtonGroup.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIRadioButtonGroup.cs new file mode 100644 index 000000000..4fb882dbc --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIRadioButtonGroup.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; + +namespace Barotrauma +{ + public class GUIRadioButtonGroup : GUIComponent + { + private Dictionary radioButtons; //TODO: use children list instead? + + public GUIRadioButtonGroup() : base("GUIFrame") + { + radioButtons = new Dictionary(); + } + + public void AddRadioButton(Enum key, GUITickBox radioButton) + { + if (selected == key) radioButton.Selected = true; + else if (radioButton.Selected) selected = key; + + radioButton.SetRadioButtonGroup(this); + radioButtons.Add(key, radioButton); + } + + public delegate void RadioButtonGroupDelegate(GUIRadioButtonGroup rbg, Enum val); + public RadioButtonGroupDelegate OnSelect = null; + + public void SelectRadioButton(GUITickBox radioButton) + { + foreach (KeyValuePair rbPair in radioButtons) + { + if (radioButton == rbPair.Value) + { + Selected = rbPair.Key; + return; + } + } + } + + private Enum selected; + public Enum Selected + { + get + { + return selected; + } + set + { + OnSelect?.Invoke(this, value); + if (selected != null && selected.Equals((Enum)value)) return; + selected = value; + foreach (KeyValuePair radioButton in radioButtons) + { + if (radioButton.Key.Equals((Enum)value)) + { + radioButton.Value.Selected = true; + } + else if (radioButton.Value.Selected) radioButton.Value.Selected = false; + } + } + } + + public GUITickBox SelectedRadioButton + { + get + { + return radioButtons[selected]; + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIScrollBar.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIScrollBar.cs index de47ceb33..02856e82d 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIScrollBar.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIScrollBar.cs @@ -20,6 +20,7 @@ namespace Barotrauma public delegate bool OnMovedHandler(GUIScrollBar scrollBar, float barScroll); public OnMovedHandler OnMoved; + public OnMovedHandler OnReleased; public bool IsBooleanSwitch; @@ -87,6 +88,39 @@ namespace Barotrauma } } + private Vector2 range; + public Vector2 Range + { + get + { + return range; + } + set + { + float oldBarScrollValue = BarScrollValue; + range = value; + BarScrollValue = oldBarScrollValue; + } + } + + public delegate float ScrollConversion(GUIScrollBar scrollBar, float f); + public ScrollConversion ScrollToValue = null; + public ScrollConversion ValueToScroll = null; + + public float BarScrollValue + { + get + { + if (ScrollToValue==null) return (BarScroll * (Range.Y - Range.X)) + Range.X; + return ScrollToValue(this, BarScroll); + } + set + { + if (ValueToScroll==null) BarScroll = (value - Range.X) / (Range.Y - Range.X); + else BarScroll = ValueToScroll(this, value); + } + } + public float BarScroll { get { return step == 0.0f ? barScroll : MathUtils.RoundTowardsClosest(barScroll, step); } @@ -187,7 +221,11 @@ namespace Barotrauma if (draggingBar == this) { - if (!PlayerInput.LeftButtonHeld()) draggingBar = null; + if (!PlayerInput.LeftButtonHeld()) + { + OnReleased?.Invoke(this, BarScroll); + draggingBar = null; + } if ((isHorizontal && PlayerInput.MousePosition.X > Rect.X && PlayerInput.MousePosition.X < Rect.Right) || (!isHorizontal && PlayerInput.MousePosition.Y > Rect.Y && PlayerInput.MousePosition.Y < Rect.Bottom)) { @@ -198,6 +236,7 @@ namespace Barotrauma { if (PlayerInput.LeftButtonClicked()) { + draggingBar?.OnReleased?.Invoke(draggingBar, draggingBar.BarScroll); MoveButton(new Vector2( Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width, Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height)); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs index a93e8cc3f..f55e4b318 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System; namespace Barotrauma { @@ -216,25 +217,36 @@ namespace Barotrauma if (autoScale && textScale > 0.1f && (TextSize.X * textScale > rect.Width - padding.X - padding.Z || TextSize.Y * textScale > rect.Height - padding.Y - padding.W)) { - TextScale -= 0.05f; + TextScale = Math.Max(0.1f, Math.Min( + (rect.Width - padding.X - padding.Z) / TextSize.X, + (rect.Height - padding.Y - padding.W) / TextSize.Y)) - 0.01f; return; } textPos = new Vector2(rect.Width / 2.0f, rect.Height / 2.0f); - origin = TextSize / textScale * 0.5f; + origin = TextSize * 0.5f; if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive) - origin.X += (rect.Width / 2.0f - TextSize.X / 2) / textScale - padding.X; - + { + textPos.X = padding.X; + origin.X = 0; + } if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive) - origin.X -= (rect.Width / 2.0f - TextSize.X / 2) / textScale - padding.Z; - + { + textPos.X = rect.Width - padding.Z; + origin.X = TextSize.X; + } if (textAlignment.HasFlag(Alignment.Top)) - origin.Y += (rect.Height / 2.0f - TextSize.Y / 2) / textScale - padding.Y; - + { + textPos.Y = padding.Y; + origin.Y = 0; + } if (textAlignment.HasFlag(Alignment.Bottom)) - origin.Y -= (rect.Height / 2.0f - TextSize.Y / 2) / textScale - padding.W; - + { + textPos.Y = rect.Height - padding.W; + origin.Y = TextSize.Y; + } + origin.X = (int)(origin.X); origin.Y = (int)(origin.Y); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs index 03bcd33aa..5e24b6e9e 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs @@ -15,7 +15,7 @@ namespace Barotrauma { public event TextBoxEvent OnSelected; public event TextBoxEvent OnDeselected; - + bool caretVisible; float caretTimer; @@ -76,10 +76,24 @@ namespace Barotrauma set { textBlock.TextGetter = value; } } + private bool selected; public bool Selected { - get; - set; + get + { + return selected; + } + set + { + if (!selected && value) + { + Select(); + } + else if (selected && !value) + { + Deselect(); + } + } } public bool Wrap @@ -326,9 +340,9 @@ namespace Barotrauma { memento.Store(Text); } - Selected = true; CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition); ClearSelection(); + selected = true; GUI.KeyboardDispatcher.Subscriber = this; OnSelected?.Invoke(this, Keys.None); } @@ -336,7 +350,8 @@ namespace Barotrauma public void Deselect() { memento.Clear(); - Selected = false; + selected = false; + if (GUI.KeyboardDispatcher.Subscriber == this) { GUI.KeyboardDispatcher.Subscriber = null; @@ -382,6 +397,7 @@ namespace Barotrauma } else { + if (PlayerInput.LeftButtonClicked() && selected) Deselect(); isSelecting = false; state = ComponentState.None; } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITickBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITickBox.cs index b410e8129..5dfa73ba9 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITickBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITickBox.cs @@ -14,7 +14,7 @@ namespace Barotrauma public static int size = 20; - private List radioButtonGroup; + private GUIRadioButtonGroup radioButtonGroup; private bool selected; @@ -24,30 +24,21 @@ namespace Barotrauma set { if (value == selected) return; - if (radioButtonGroup != null && !value) return; - + if (radioButtonGroup != null && radioButtonGroup.SelectedRadioButton == this) + { + selected = true; + return; + } + selected = value; state = (selected) ? ComponentState.Selected : ComponentState.None; box.State = state; - if (radioButtonGroup != null) + if (value && radioButtonGroup != null) { - foreach (GUITickBox tickBox in radioButtonGroup) - { - if (tickBox == this) continue; - tickBox.selected = false; - tickBox.state = tickBox.box.State = ComponentState.None; - } + radioButtonGroup.SelectRadioButton(this); } OnSelected?.Invoke(this); - if (radioButtonGroup != null) - { - foreach (GUITickBox tickBox in radioButtonGroup) - { - if (tickBox == this) continue; - tickBox.OnSelected?.Invoke(tickBox); - } - } } } @@ -123,14 +114,10 @@ namespace Barotrauma rectT.ScaleChanged += ResizeBox; rectT.SizeChanged += ResizeBox; } - - public static void CreateRadioButtonGroup(IEnumerable tickBoxes) + + public void SetRadioButtonGroup(GUIRadioButtonGroup rbg) { - var group = new List(tickBoxes); - foreach (GUITickBox tickBox in tickBoxes) - { - tickBox.radioButtonGroup = group; - } + radioButtonGroup = rbg; } private void ResizeBox() diff --git a/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs b/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs index 76cf3374a..199cdb9d6 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs @@ -140,8 +140,8 @@ namespace Barotrauma } AfflictionAreaRight = new Rectangle(HealthBarAreaRight.X, HealthBarAreaRight.Y - Padding - afflictionAreaHeight, healthBarWidth, afflictionAreaHeight); - int messageAreaPos = GameMain.GraphicsWidth - HealthBarAreaRight.X; - MessageAreaTop = new Rectangle(messageAreaPos + Padding, ButtonAreaTop.Bottom, GameMain.GraphicsWidth - (messageAreaPos + Padding) * 2, ButtonAreaTop.Height); + int messageAreaWidth = GameMain.GraphicsWidth / 3; + MessageAreaTop = new Rectangle((GameMain.GraphicsWidth - messageAreaWidth) / 2, ButtonAreaTop.Bottom, messageAreaWidth, ButtonAreaTop.Height); //slice for the upper slots of the inventory (clothes, id card, headset) int inventoryAreaUpperWidth = (int)(GameMain.GraphicsWidth * 0.2f); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/LoadingScreen.cs b/Barotrauma/BarotraumaClient/Source/GUI/LoadingScreen.cs index 020cab90b..3792df034 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/LoadingScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/LoadingScreen.cs @@ -1,10 +1,10 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; -using Microsoft.Xna.Framework.Media; using System; using System.Collections.Generic; using System.Xml.Linq; +using Barotrauma.Media; namespace Barotrauma { @@ -14,6 +14,25 @@ namespace Barotrauma private RenderTarget2D renderTarget; + private Video splashScreen; + public Video SplashScreen + { + get + { + lock (loadMutex) + { + return splashScreen; + } + } + set + { + lock (loadMutex) + { + splashScreen = value; + } + } + } + private float state; private string selectedTip; @@ -22,11 +41,9 @@ namespace Barotrauma public Vector2 TitlePosition; + private object loadMutex = new object(); private float? loadState; -#if !(LINUX || OSX) - Video splashScreenVideo; - VideoPlayer videoPlayer; -#endif + public Vector2 TitleSize { get { return new Vector2(titleTexture.Width, titleTexture.Height); } @@ -40,15 +57,20 @@ namespace Barotrauma public float? LoadState { - get { return loadState; } + get + { + lock (loadMutex) + { + return loadState; + } + } set { - loadState = value; - if (GameSettings.VerboseLogging) + lock (loadMutex) { - DebugConsole.NewMessage("Loading: " + value.ToString() + "%", Color.Yellow); + loadState = value; + DrawLoadingText = true; } - DrawLoadingText = true; } } @@ -60,24 +82,6 @@ namespace Barotrauma public LoadingScreen(GraphicsDevice graphics) { -#if !(LINUX || OSX) - - if (GameMain.Config.EnableSplashScreen) - { - try - { - splashScreenVideo = GameMain.Instance.Content.Load