(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
Binary file not shown.
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
# MonoKickstart Shell Script
# Written by Ethan "flibitijibibo" Lee
# Move to script's directory
cd "`dirname "$0"`"
# Get the system architecture
UNAME=`uname`
ARCH=`uname -m`
# MonoKickstart picks the right libfolder, so just execute the right binary.
if [ "$UNAME" == "Darwin" ]; then
# ... Except on OSX.
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./osx/
# El Capitan is a total idiot and wipes this variable out, making the
# Steam overlay disappear. This sidesteps "System Integrity Protection"
# and resets the variable with Valve's own variable (they provided this
# fix by the way, thanks Valve!). Note that you will need to update your
# launch configuration to the script location, NOT just the app location
# (i.e. Kick.app/Contents/MacOS/Kick, not just Kick.app).
# -flibit
if [ "$STEAM_DYLD_INSERT_LIBRARIES" != "" ] && [ "$DYLD_INSERT_LIBRARIES" == "" ]; then
export DYLD_INSERT_LIBRARIES="$STEAM_DYLD_INSERT_LIBRARIES"
fi
./Barotrauma.bin.osx $@
else
if [ "$ARCH" == "x86_64" ]; then
./Barotrauma.bin.x86_64 $@
else
./Barotrauma.bin.x86 $@
fi
fi
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,242 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>51aff563-4982-474d-a92f-50b06db05b3d</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>ClientCode</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Source\Camera.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AICharacter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\AIController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\AITarget.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\EnemyAIController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\HumanAIController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\Ragdoll.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Attack.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Character.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\CharacterHealth.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterHUD.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterNetworking.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionHusk.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionPsychosis.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\DamageModifier.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\HUDProgressBar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Jobs\JobPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Limb.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\DebugConsole.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\EventInput\EventInput.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\EventInput\KeyboardDispatcher.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\EventManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\CombatMission.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\Mission.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\MissionMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\MissionPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Fonts\ScalableFont.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameMain.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\CrewManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\CampaignMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\SinglePlayerCampaign.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\BasicTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\CaptainTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\DoctorTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\EditorTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\EngineerTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\MechanicTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\OfficerTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\ScenarioTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\Tutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\TutorialMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameSession.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\RoundSummary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSettings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ChatBox.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ComponentStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\Graph.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUI.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIButton.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUICanvas.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUICustomComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIDropDown.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIFrame.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIImage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUILayoutGroup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIListBox.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIMessageBox.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUINumberInput.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIProgressBar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIRadioButtonGroup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIScrollBar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUIStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUITextBlock.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUITextBox.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\GUITickBox.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\HUDLayoutSettings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\LoadingScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ParamsEditor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\RectTransform.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ShapeExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\UISprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\VideoPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\Widget.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\CharacterInventory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Door.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\ElectricalDischarger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\ItemComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\ItemContainer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\ItemLabel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\LevelResource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\LightComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Controller.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Deconstructor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Engine.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Fabricator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\MiniMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Pump.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Reactor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Sonar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Machines\Steering.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Power\PowerContainer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Power\Powered.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Power\PowerTransfer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Repairable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\RepairTool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\Connection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\ConnectionPanel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\CustomInterface.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\MotionSensor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\WifiComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\Wire.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\StatusHUD.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Turret.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\DockingPort.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Inventory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Item.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\ItemInventory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\ItemPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Rope.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Explosion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\FireSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Gap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Hull.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\ItemAssemblyPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\BackgroundCreatures\BackgroundCreature.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\BackgroundCreatures\BackgroundCreatureManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\BackgroundCreatures\BackgroundCreaturePrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\CaveGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\Level.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelObjects\LevelObject.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelObjects\LevelObjectManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelObjects\LevelObjectPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelObjects\LevelTrigger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelRenderer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\LevelWall.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\Ruins\RuinGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Levels\WaterRenderer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Lights\ConvexHull.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Lights\LightManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Lights\LightSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\LinkedSubmarine.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\MapEntity.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\MapEntityPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Map\Location.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Map\Map.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Structure.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\StructurePrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\Submarine.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\SubmarineBody.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Map\WayPoint.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Media\Video.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\BanList.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ChatMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Client.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\EntitySpawner.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\FileTransfer\FileReceiver.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\GameClient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\KarmaManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\ClientEntityEventManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetStats.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\OrderChatMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\ClientPeer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\LidgrenClientPeer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\SteamP2PClientPeer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\SteamP2POwnerPeer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\RespawnManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ServerInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ServerLog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ServerSettings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\SteamManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Voip\VoipCapture.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Voip\VoipClient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Voip\VoipConfig.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Voting.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\WhiteList.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\Decal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\DecalManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\DecalPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\Particle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\ParticleEmitter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\ParticleManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Particles\ParticlePrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Physics\PhysicsBody.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\PlayerInput.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Program.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\BlurEffect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CampaignSetupUI.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CampaignUI.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CharacterEditor\CharacterEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CharacterEditor\Wizard.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CreditsPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\GameScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\LevelEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\LobbyScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\MainMenuScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\NetLobbyScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\ParticleEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\Screen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\ServerListScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\SpriteEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\SteamWorkshopScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\SubEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Serialization\SerializableEntityEditor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\OggSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\OpenAL\Al.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\OpenAL\Alc.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\Sound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\SoundChannel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\SoundFilters.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\SoundManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\SoundPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\VideoSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\VoipSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\ConditionalSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DecorativeSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformableSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\CustomDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\Inflate.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\JointBendDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\NoiseDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\PositionalDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\SpriteDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\Sprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\SpriteSheet.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\StatusEffects\StatusEffect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Traitors\TraitorMissionPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\CrossThread.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\LocalizationCSVtoXML.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\MathUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\OpenFileDialog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\TextureLoader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\ToolBox.cs" />
</ItemGroup>
</Project>
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>51aff563-4982-474d-a92f-50b06db05b3d</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<ReleaseVersion>0.9.0.0</ReleaseVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="ClientCode.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
@@ -311,7 +311,7 @@ namespace Barotrauma
{
Freeze = true;
}
if (CharacterHealth.OpenHealthWindow != null)
if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen)
{
offset *= 0;
Freeze = false;
@@ -335,7 +335,8 @@ namespace Barotrauma
//an ad-hoc way of allowing the players to have roughly the same maximum view distance regardless of the resolution,
//while still keeping the zoom around 1.0 when not looking further away (because otherwise we'd always be downsampling
//on lower resolutions, which doesn't look that good)
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom, (float)Math.Sqrt(zoomOutAmount));
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom,
(GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(zoomOutAmount) : 0.3f);
Zoom += (newZoom - zoom) / ZoomSmoothness;
@@ -9,7 +9,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch)
{
if (!ShowAITargets) return;
if (!ShowAITargets) { return; }
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
if (soundRange > 0.0f)
{
@@ -28,6 +28,7 @@ namespace Barotrauma
}
ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
ShapeExtensions.DrawCircle(spriteBatch, pos, 3, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
GUI.DrawLine(spriteBatch, pos, pos + Vector2.UnitY * SoundRange, color, width: (int)(1 / Screen.Selected.Cam.Zoom) + 1);
}
if (sightRange > 0.0f)
{
@@ -39,17 +40,16 @@ namespace Barotrauma
else if (Entity is Item)
{
color = Color.CadetBlue;
// disable the indicators for items, because they clutter the debug view
return;
}
else
{
color = Color.WhiteSmoke;
//color = Color.WhiteSmoke;
// disable the indicators for structures, because they clutter the debug view
return;
}
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
ShapeExtensions.DrawCircle(spriteBatch, pos, 6, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
GUI.DrawLine(spriteBatch, pos, pos + Vector2.UnitY * SightRange, color, width: (int)(1 / Screen.Selected.Cam.Zoom) + 1);
}
}
}
@@ -17,7 +17,7 @@ namespace Barotrauma
if (State == AIState.Idle && PreviousState == AIState.Attack)
{
var target = _selectedAiTarget ?? _lastAiTarget;
if (target != null)
if (target != null && target.Entity != null)
{
var memory = GetTargetMemory(target);
Vector2 targetPos = memory.Location;
@@ -34,7 +34,7 @@ namespace Barotrauma
targetPos = attackWorldPos;
}
targetPos.Y = -targetPos.Y;
GUI.DrawLine(spriteBatch, pos, targetPos, Color.Red * 0.5f, 0, 4);
GUI.DrawLine(spriteBatch, pos, targetPos, GUI.Style.Red * 0.5f, 0, 4);
if (wallTarget != null)
{
Vector2 wallTargetPos = wallTarget.Position;
@@ -43,19 +43,19 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({GetTargetMemory(SelectedAiTarget).Priority.FormatZeroDecimal()})", Color.Red, Color.Black);
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 40.0f, $"({targetValue.FormatZeroDecimal()})", Color.Red, Color.Black);
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({GetTargetMemory(SelectedAiTarget).Priority.FormatZeroDecimal()})", GUI.Style.Red, Color.Black);
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 40.0f, $"({targetValue.FormatZeroDecimal()})", GUI.Style.Red, Color.Black);
}
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
GUI.Font.DrawString(spriteBatch, "updatetargets: " + MathUtils.Round(updateTargetsTimer, 0.1f), pos - Vector2.UnitY * 100.0f, Color.Red);
GUI.Font.DrawString(spriteBatch, "cooldown: " + MathUtils.Round(coolDownTimer, 0.1f), pos - Vector2.UnitY * 120.0f, Color.Red);*/
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, GUI.Style.Red);
GUI.Font.DrawString(spriteBatch, "updatetargets: " + MathUtils.Round(updateTargetsTimer, 0.1f), pos - Vector2.UnitY * 100.0f, GUI.Style.Red);
GUI.Font.DrawString(spriteBatch, "cooldown: " + MathUtils.Round(coolDownTimer, 0.1f), pos - Vector2.UnitY * 120.0f, GUI.Style.Red);*/
Color stateColor = Color.White;
switch (State)
{
case AIState.Attack:
stateColor = IsCoolDownRunning ? Color.Orange : Color.Red;
stateColor = IsCoolDownRunning ? Color.Orange : GUI.Style.Red;
break;
case AIState.Escape:
stateColor = Color.LightBlue;
@@ -75,13 +75,13 @@ namespace Barotrauma
{
GUI.DrawLine(spriteBatch,
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Green, 0, 4);
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), GUI.Style.Green, 0, 4);
}
if (LatchOntoAI.WallAttachPos.HasValue)
{
//GUI.DrawLine(spriteBatch, pos,
// ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.WallAttachPos.Value.X, -LatchOntoAI.WallAttachPos.Value.Y)), Color.Green, 0, 3);
// ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.WallAttachPos.Value.X, -LatchOntoAI.WallAttachPos.Value.Y)), GUI.Style.Green, 0, 3);
}
}
@@ -105,12 +105,12 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch,
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
Color.Red * 0.5f, 0, 3);
GUI.Style.Red * 0.5f, 0, 3);
GUI.SmallFont.DrawString(spriteBatch,
currentNode.ID.ToString(),
new Vector2(currentNode.DrawPosition.X - 10, -currentNode.DrawPosition.Y - 30),
Color.Red);
GUI.Style.Red);
}
}
}
@@ -121,7 +121,7 @@ namespace Barotrauma
Vector2 hitPos = ConvertUnits.ToDisplayUnits(steeringManager.AvoidRayCastHitPosition);
hitPos.Y = -hitPos.Y;
GUI.DrawLine(spriteBatch, hitPos, hitPos + new Vector2(steeringManager.AvoidDir.X, -steeringManager.AvoidDir.Y) * 100, Color.Red, width: 5);
GUI.DrawLine(spriteBatch, hitPos, hitPos + new Vector2(steeringManager.AvoidDir.X, -steeringManager.AvoidDir.Y) * 100, GUI.Style.Red, width: 5);
//GUI.DrawLine(spriteBatch, pos, ConvertUnits.ToDisplayUnits(steeringManager.AvoidLookAheadPos.X, -steeringManager.AvoidLookAheadPos.Y), Color.Orange, width: 4);
}
}
@@ -16,11 +16,6 @@ namespace Barotrauma
}*/
}
partial void SetOrderProjSpecific(Order order)
{
GameMain.GameSession.CrewManager.DisplayCharacterOrder(Character, order);
}
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
{
Vector2 pos = Character.WorldPosition;
@@ -29,7 +24,7 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null)
{
//GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red);
//GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), GUI.Style.Red);
//GUI.DrawString(spriteBatch, pos + textOffset, $"AI TARGET: {SelectedAiTarget.Entity.ToString()}", Color.White, Color.Black);
}
@@ -40,7 +35,7 @@ namespace Barotrauma
var currentOrder = ObjectiveManager.CurrentOrder;
if (currentOrder != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
else if (ObjectiveManager.WaitTimer > 0)
{
@@ -51,17 +46,17 @@ namespace Barotrauma
{
if (currentOrder == null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var subObjective = currentObjective.SubObjectives.FirstOrDefault();
var subObjective = currentObjective.CurrentSubObjective;
if (subObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var activeObjective = ObjectiveManager.GetActiveObjective();
if (activeObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
}
}
@@ -362,9 +362,9 @@ namespace Barotrauma
inversedLimbDrawOrder = depthSortedLimbs.ToArray();
}
partial void UpdateProjSpecific(float deltaTime)
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
if (!character.Enabled || SimplePhysicsEnabled) { return; }
if (!character.IsVisible) { return; }
LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime));
foreach (var deformation in SpriteDeformations)
@@ -396,7 +396,7 @@ namespace Barotrauma
}
}
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint, bool playSound = true)
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint, bool playSound)
{
foreach (Limb limb in new Limb[] { limbJoint.LimbA, limbJoint.LimbB })
{
@@ -421,9 +421,9 @@ namespace Barotrauma
}
}
public virtual void Draw(SpriteBatch spriteBatch, Camera cam)
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (simplePhysicsEnabled) return;
if (simplePhysicsEnabled) { return; }
Collider.UpdateDrawPosition();
@@ -439,16 +439,53 @@ namespace Barotrauma
Color? color = null;
if (character.ExternalHighlight)
{
color = Color.Lerp(Color.White, Color.OrangeRed, (float)Math.Sin(Timing.TotalTime * 3.5f));
color = Color.Lerp(Color.White, GUI.Style.Orange, (float)Math.Sin(Timing.TotalTime * 3.5f));
}
float depthOffset = GetDepthOffset();
for (int i = 0; i < limbs.Length; i++)
{
if (depthOffset != 0.0f) { inversedLimbDrawOrder[i].ActiveSprite.Depth += depthOffset; }
inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color);
if (depthOffset != 0.0f) { inversedLimbDrawOrder[i].ActiveSprite.Depth -= depthOffset; }
}
LimbJoints.ForEach(j => j.Draw(spriteBatch));
}
/// <summary>
/// Offset added to the default draw depth of the character's limbs. For example, climbing on ladders affects the depth of the character to get it to render behind the ladders.
/// </summary>
public float GetDepthOffset()
{
float depthOffset = 0.0f;
var ladder = character.SelectedConstruction?.GetComponent<Ladder>();
if (ladder != null)
{
float maxDepth = 0.0f;
float minDepth = 1.0f;
foreach (Limb limb in Limbs)
{
var activeSprite = limb.ActiveSprite;
if (activeSprite != null)
{
maxDepth = Math.Max(activeSprite.Depth, maxDepth);
minDepth = Math.Min(activeSprite.Depth, minDepth);
}
}
if (character.WorldPosition.X < character.SelectedConstruction.WorldPosition.X)
{
//at the left side of the ladder, needs to be drawn in front of the rungs
depthOffset = Math.Max(ladder.BackgroundSpriteDepth - 0.01f - maxDepth, 0.0f);
}
else
{
//at the right side of the ladder, needs to be drawn behind the rungs
depthOffset = Math.Max(ladder.BackgroundSpriteDepth + 0.01f - minDepth, 0.0f);
}
}
return depthOffset;
}
public void DebugDraw(SpriteBatch spriteBatch)
{
if (!GameMain.DebugDraw || !character.Enabled) return;
@@ -461,13 +498,13 @@ namespace Barotrauma
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Red, true, 0.01f);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), GUI.Style.Red, true, 0.01f);
}
limb.body.DebugDraw(spriteBatch, inWater ? Color.Cyan : Color.White);
limb.body.DebugDraw(spriteBatch, inWater ? (currentHull == null ? Color.Blue : Color.Cyan) : Color.White);
}
Collider.DebugDraw(spriteBatch, frozen ? Color.Red : (inWater ? Color.SkyBlue : Color.Gray));
Collider.DebugDraw(spriteBatch, frozen ? GUI.Style.Red : (inWater ? Color.SkyBlue : Color.Gray));
GUI.Font.DrawString(spriteBatch, Collider.LinearVelocity.X.FormatSingleDecimal(), new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), Color.Orange);
foreach (RevoluteJoint joint in LimbJoints)
@@ -495,19 +532,9 @@ namespace Barotrauma
if (this is HumanoidAnimController humanoid)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(humanoid.RightHandIKPos);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), Color.Green, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
pos = ConvertUnits.ToDisplayUnits(humanoid.LeftHandIKPos);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), Color.Green, true);
}
if (outsideCollisionBlocker.Enabled && currentHull?.Submarine != null)
{
var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape;
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + currentHull.Submarine.Position;
Vector2 endPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex2)) + currentHull.Submarine.Position;
startPos.Y = -startPos.Y;
endPos.Y = -endPos.Y;
GUI.DrawLine(spriteBatch, startPos, endPos, Color.Gray, 0, 5);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
}
if (character.MemState.Count > 1)
@@ -529,7 +556,15 @@ namespace Barotrauma
}
}
if (ignorePlatforms)
if (currentHull != null)
{
Vector2 displayFloorPos = ConvertUnits.ToDisplayUnits(new Vector2(Collider.SimPosition.X, floorY));
if (currentHull?.Submarine != null) { displayFloorPos += currentHull.Submarine.DrawPosition; }
displayFloorPos.Y = -displayFloorPos.Y;
GUI.DrawLine(spriteBatch, displayFloorPos, displayFloorPos + new Vector2(floorNormal.X, -floorNormal.Y) * 50.0f, Color.Cyan * 0.5f, 0, 2);
}
if (IgnorePlatforms)
{
GUI.DrawLine(spriteBatch,
new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y),
@@ -1,3 +1,4 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Barotrauma.Particles;
using Barotrauma.Sounds;
@@ -32,12 +33,21 @@ namespace Barotrauma
private float hudInfoHeight;
private List<CharacterSound> sounds;
public bool ExternalHighlight;
/// <summary>
/// Is the character currently visible on the camera. Refresh the value by calling DoVisibilityCheck.
/// </summary>
public bool IsVisible
{
get;
private set;
} = true;
//the Character that the player is currently controlling
private static Character controlled;
public static Character Controlled
{
get { return controlled; }
@@ -49,9 +59,9 @@ namespace Barotrauma
CharacterHealth.OpenHealthWindow = null;
}
}
private Dictionary<object, HUDProgressBar> hudProgressBars;
private List<KeyValuePair<object, HUDProgressBar>> progressBarRemovals = new List<KeyValuePair<object, HUDProgressBar>>();
private readonly List<KeyValuePair<object, HUDProgressBar>> progressBarRemovals = new List<KeyValuePair<object, HUDProgressBar>>();
public Dictionary<object, HUDProgressBar> HUDProgressBars
{
@@ -87,20 +97,20 @@ namespace Barotrauma
}
public string BloodDecalName => Params.BloodDecal;
private List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
private readonly List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> BloodEmitters
{
get { return bloodEmitters; }
}
private List<ParticleEmitter> damageEmitters = new List<ParticleEmitter>();
private readonly List<ParticleEmitter> damageEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> DamageEmitters
{
get { return damageEmitters; }
}
private List<ParticleEmitter> gibEmitters = new List<ParticleEmitter>();
private readonly List<ParticleEmitter> gibEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> GibEmitters
{
get { return gibEmitters; }
@@ -127,7 +137,7 @@ namespace Barotrauma
}
}
private List<ObjectiveEntity> activeObjectiveEntities = new List<ObjectiveEntity>();
private readonly List<ObjectiveEntity> activeObjectiveEntities = new List<ObjectiveEntity>();
public IEnumerable<ObjectiveEntity> ActiveObjectiveEntities
{
get { return activeObjectiveEntities; }
@@ -267,7 +277,7 @@ namespace Barotrauma
{
cam.OffsetAmount = targetOffsetAmount = 0.0f;
}
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
else if (Lights.LightManager.ViewTarget == this)
{
if (GUI.PauseMenuOpen || IsUnconscious)
{
@@ -276,7 +286,7 @@ namespace Barotrauma
cam.OffsetAmount = targetOffsetAmount = 0.0f;
}
}
else
else if (Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
{
Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
Structure structure = body?.UserData as Structure;
@@ -291,8 +301,14 @@ namespace Barotrauma
}
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, targetOffsetAmount, 0.05f);
DoInteractionUpdate(deltaTime, mouseSimPos);
}
if (SelectedConstruction != null && SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)))
if (!GUI.PauseMenuOpen && !GUI.SettingsMenuOpen)
{
if (SelectedConstruction != null &&
(SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)) ||
((ViewTarget as Item)?.Prefab.FocusOnSelected ?? false) && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)))
{
if (GameMain.Client != null)
{
@@ -302,12 +318,10 @@ namespace Barotrauma
}
//reset focus to prevent us from accidentally interacting with another entity
focusedItem = null;
focusedCharacter = null;
FocusedCharacter = null;
findFocusedTimer = 0.2f;
SelectedConstruction = null;
}
DoInteractionUpdate(deltaTime, mouseSimPos);
}
DisableControls = false;
@@ -521,6 +535,17 @@ namespace Barotrauma
return closestCharacter;
}
public bool ShouldLockHud()
{
if (this != controlled) { return false; }
//lock if using a controller, except if we're also using a connection panel in the same item
return
SelectedConstruction != null &&
SelectedConstruction?.GetComponent<Controller>()?.User == this &&
SelectedConstruction?.GetComponent<ConnectionPanel>()?.User != this;
}
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
@@ -578,6 +603,11 @@ namespace Barotrauma
}
}
partial void SetOrderProjSpecific(Order order, string orderOption)
{
GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption);
}
public static void AddAllToGUIUpdateList()
{
for (int i = 0; i < CharacterList.Count; i++)
@@ -594,11 +624,26 @@ namespace Barotrauma
CharacterHealth.AddToGUIUpdateList();
}
}
public void DoVisibilityCheck(Camera cam)
{
IsVisible = false;
if (!Enabled || AnimController.SimplePhysicsEnabled) { return; }
foreach (Limb limb in AnimController.Limbs)
{
float maxExtent = ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent());
if (limb.LightSource != null) { maxExtent = Math.Max(limb.LightSource.Range, maxExtent); }
if (limb.body.DrawPosition.X < cam.WorldView.X - maxExtent || limb.body.DrawPosition.X > cam.WorldView.Right + maxExtent) { continue; }
if (limb.body.DrawPosition.Y < cam.WorldView.Y - cam.WorldView.Height - maxExtent || limb.body.DrawPosition.Y > cam.WorldView.Y + maxExtent) { continue; }
IsVisible = true;
return;
}
}
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) return;
if (!Enabled) { return; }
AnimController.Draw(spriteBatch, cam);
}
@@ -610,17 +655,43 @@ namespace Barotrauma
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) return;
if (!Enabled) { return; }
if (GameMain.DebugDraw)
{
AnimController.DebugDraw(spriteBatch);
if (aiTarget != null) aiTarget.Draw(spriteBatch);
}
if (GUI.DisableHUD) return;
if (Controlled != null &&
Controlled != this &&
Submarine != null &&
Controlled.Submarine == Submarine &&
GameMain.Config.LosMode != LosMode.None)
{
float yPos = Controlled.AnimController.FloorY - 1.5f;
if (Controlled.AnimController.Stairs != null)
{
yPos = Controlled.AnimController.Stairs.SimPosition.Y - Controlled.AnimController.Stairs.RectHeight * 0.5f;
}
foreach (var ladder in Ladder.List)
{
if (CanInteractWith(ladder.Item) && Controlled.CanInteractWith(ladder.Item))
{
float xPos = ladder.Item.SimPosition.X;
if (Math.Abs(xPos - SimPosition.X) < 3.0)
{
yPos = ladder.Item.SimPosition.Y - ladder.Item.RectHeight * 0.5f;
}
break;
}
}
if (AnimController.FloorY < yPos) { return; }
}
Vector2 pos = DrawPosition;
pos.Y += hudInfoHeight;
@@ -665,7 +736,7 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch,
cursorPos,
new Vector2(item.First.DrawPosition.X, -item.First.DrawPosition.Y),
ToolBox.GradientLerp(item.Second, Color.Red, Color.Orange, Color.Green), width: 2);
ToolBox.GradientLerp(item.Second, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green), width: 2);
}
}
return;
@@ -677,7 +748,7 @@ namespace Barotrauma
float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f);
if (!GUI.DisableCharacterNames && hudInfoVisible && info != null &&
(controlled == null || this != controlled.focusedCharacter))
(controlled == null || this != controlled.FocusedCharacter))
{
string name = Info.DisplayName;
if (controlled == null && name != Info.Name) name += " " + TextManager.Get("Disguised");
@@ -695,7 +766,7 @@ namespace Barotrauma
Color nameColor = Color.White;
if (Controlled != null && TeamID != Controlled.TeamID)
{
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : Color.Red;
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.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);
@@ -715,7 +786,7 @@ namespace Barotrauma
Vector2 healthBarPos = new Vector2(pos.X - 50, -pos.Y);
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
CharacterHealth.DisplayedVitality / MaxVitality,
Color.Lerp(Color.Red, Color.Green, CharacterHealth.DisplayedVitality / MaxVitality) * 0.8f * hudInfoAlpha,
Color.Lerp(GUI.Style.Red, GUI.Style.Green, CharacterHealth.DisplayedVitality / MaxVitality) * 0.8f * hudInfoAlpha,
new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
}
}
@@ -37,6 +37,15 @@ namespace Barotrauma
}
}
private static bool ShouldDrawInventory(Character character)
{
return
character?.Inventory != null &&
character.AllowInput &&
!character.LockHands &&
character.SelectedConstruction?.GetComponent<Controller>()?.User != character;
}
private static string GetCachedHudText(string textTag, string keyBind)
{
if (cachedHudTexts.TryGetValue(textTag + keyBind, out string text))
@@ -80,16 +89,24 @@ namespace Barotrauma
public static void Update(float deltaTime, Character character, Camera cam)
{
if (GUI.DisableHUD) { return; }
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null)
{
bool mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null;
if (mouseOnPortrait && PlayerInput.PrimaryMouseButtonClicked())
{
CharacterHealth.OpenHealthWindow = character.CharacterHealth;
}
}
if (character.Inventory != null)
{
if (!LockInventory(character))
{
character.Inventory.Update(deltaTime, cam);
}
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
{
var item = character.Inventory.Items[i];
@@ -137,7 +154,7 @@ namespace Barotrauma
brokenItemsCheckTimer = 1.0f;
foreach (Item item in Item.ItemList)
{
if (!item.Repairables.Any(r => item.ConditionPercentage < r.ShowRepairUIThreshold)) { continue; }
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.AIRepairThreshold)) { continue; }
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
Vector2 diff = item.WorldPosition - character.WorldPosition;
@@ -151,9 +168,9 @@ namespace Barotrauma
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
{
if (GUI.DisableHUD) return;
if (GUI.DisableHUD) { return; }
character.CharacterHealth.Alignment = Alignment.Right;
character.CharacterHealth.Alignment = Alignment.Right;
if (GameMain.GameSession?.CrewManager != null)
{
@@ -181,54 +198,17 @@ namespace Barotrauma
float alpha = Math.Min((1000.0f - dist) / 1000.0f * 2.0f, 1.0f);
if (alpha <= 0.0f) continue;
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, GUI.BrokenIcon,
Color.Lerp(Color.DarkRed, Color.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
}
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
{
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
startPos = cam.WorldToScreen(startPos);
string focusName = character.FocusedCharacter.DisplayName;
if (character.FocusedCharacter.Info != null)
{
focusName = character.FocusedCharacter.Info.DisplayName;
}
Vector2 textPos = startPos;
Vector2 offset = GUI.Font.MeasureString(focusName);
textPos -= new Vector2(offset.X / 2, offset.Y);
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, nameColor, Color.Black * 0.7f, 2);
textPos.Y += offset.Y;
if (character.FocusedCharacter.CanBeDragged)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBind(InputType.Grab).ToString()),
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += offset.Y;
}
if (character.FocusedCharacter.CharacterHealth.UseHealthWindow && character.CanInteractWith(character.FocusedCharacter, 160f, false))
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBind(InputType.Health).ToString()),
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += offset.Y;
}
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
{
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += offset.Y;
}
DrawCharacterHoverTexts(spriteBatch, cam, character);
}
float circleSize = 1.0f;
float circleSize;
if (character.FocusedItem != null)
{
if (focusedItem != character.FocusedItem)
@@ -261,9 +241,11 @@ namespace Barotrauma
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
Vector2 offset = GUI.Font.MeasureString(focusedItem.Name);
Vector2 textSize = GUI.Font.MeasureString(focusedItem.Name);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusedItem.Name);
Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition);
startPos.Y -= (hudTexts.Count + 1) * offset.Y;
startPos.Y -= (hudTexts.Count + 1) * textSize.Y;
if (focusedItem.Sprite != null)
{
startPos.X += (int)(circleSize * 0.4f * dir);
@@ -271,17 +253,19 @@ namespace Barotrauma
}
Vector2 textPos = startPos;
if (dir == -1) textPos.X -= offset.X;
if (dir == -1) { textPos.X -= largeTextSize.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 += offset.Y;
GUI.DrawString(spriteBatch, textPos, focusedItem.Name, GUI.Style.TextColor * alpha, Color.Black * alpha * 0.7f, 2, font: GUI.SubHeadingFont);
startPos.X += dir * 10.0f * GUI.Scale;
textPos.X += dir * 10.0f * GUI.Scale;
textPos.Y += largeTextSize.Y;
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 += offset.Y;
textPos.Y += textSize.Y;
}
}
}
@@ -311,18 +295,29 @@ namespace Barotrauma
}
}
}
bool drawPortraitToolTip = false;
bool mouseOnPortrait = false;
if (character.Stun <= 0.1f && !character.IsDead)
{
if (CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null)
{
if (character.Info != null)
if (character.Info != null && !character.ShouldLockHud())
{
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), targetWidth: HUDLayoutSettings.PortraitArea.Width);
character.Info.DrawBackground(spriteBatch);
character.Info.DrawJobIcon(spriteBatch,
new Rectangle(
(int)(HUDLayoutSettings.BottomRightInfoArea.X + HUDLayoutSettings.BottomRightInfoArea.Width * 0.05f),
(int)(HUDLayoutSettings.BottomRightInfoArea.Y + HUDLayoutSettings.BottomRightInfoArea.Height * 0.1f),
(int)(HUDLayoutSettings.BottomRightInfoArea.Width / 2),
(int)(HUDLayoutSettings.BottomRightInfoArea.Height * 0.7f)));
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2(-12 * GUI.Scale, 4 * GUI.Scale), targetWidth: HUDLayoutSettings.PortraitArea.Width, true);
}
mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud();
if (mouseOnPortrait)
{
GUI.UIGlow.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea, GUI.Style.Green * 0.5f);
}
drawPortraitToolTip = HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition);
}
if (character.Inventory != null && !character.LockHands)
if (ShouldDrawInventory(character))
{
character.Inventory.Locked = LockInventory(character);
character.Inventory.DrawOwn(spriteBatch);
@@ -358,7 +353,7 @@ namespace Barotrauma
}
}
if (drawPortraitToolTip)
if (mouseOnPortrait)
{
GUIComponent.DrawToolTip(
spriteBatch,
@@ -367,15 +362,64 @@ namespace Barotrauma
}
}
private static void DrawCharacterHoverTexts(SpriteBatch spriteBatch, Camera cam, Character character)
{
foreach (Item item in character.Inventory.Items)
{
var statusHUD = item?.GetComponent<StatusHUD>();
if (statusHUD != null && statusHUD.IsActive && statusHUD.VisibleCharacters.Contains(character.FocusedCharacter))
{
return;
}
}
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
startPos = cam.WorldToScreen(startPos);
string focusName = character.FocusedCharacter.DisplayName;
if (character.FocusedCharacter.Info != null)
{
focusName = character.FocusedCharacter.Info.DisplayName;
}
Vector2 textPos = startPos;
Vector2 textSize = GUI.Font.MeasureString(focusName);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusName);
textPos -= new Vector2(textSize.X / 2, textSize.Y);
Color nameColor = GUI.Style.TextColor;
if (character.TeamID != character.FocusedCharacter.TeamID)
{
nameColor = character.FocusedCharacter.TeamID == Character.TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
}
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
textPos.X += 10.0f * GUI.Scale;
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
if (character.FocusedCharacter.CanBeDragged)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
textPos.Y += largeTextSize.Y;
}
if (character.FocusedCharacter.CharacterHealth.UseHealthWindow && character.CanInteractWith(character.FocusedCharacter, 160f, false))
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBindText(InputType.Health)),
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
textPos.Y += textSize.Y;
}
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
{
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
textPos.Y += textSize.Y;
}
}
private static bool LockInventory(Character character)
{
if (character?.Inventory == null || !character.AllowInput || character.LockHands) { return true; }
//lock if using a controller, except if we're also using a connection panel in the same item
return
character.SelectedConstruction != null &&
character.SelectedConstruction?.GetComponent<Controller>()?.User == character &&
character.SelectedConstruction?.GetComponent<ConnectionPanel>()?.User != character;
return character.ShouldLockHud();
}
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f)
@@ -10,9 +10,18 @@ namespace Barotrauma
{
partial class CharacterInfo
{
private static Sprite infoAreaPortraitBG;
public static void Init()
{
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.Sprites[GUIComponent.ComponentState.None][0].Sprite;
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
}
public GUIFrame CreateInfoFrame(GUIFrame frame)
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.7f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) })
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) })
{
Stretch = true,
RelativeSpacing = 0.03f
@@ -41,7 +50,7 @@ namespace Barotrauma
Name, textColor: nameColor, font: GUI.LargeFont)
{
Padding = Vector4.Zero,
AutoScale = true
AutoScaleHorizontal = true
};
if (Job != null)
@@ -103,7 +112,7 @@ namespace Barotrauma
{
GUI.AddMessage(
"+" + ((int)((newLevel - prevLevel) * 100.0f)).ToString() + " XP",
Color.Green,
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f);
}
@@ -111,7 +120,7 @@ namespace Barotrauma
{
GUI.AddMessage(
"+10 XP",
Color.Green,
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f);
}
@@ -121,7 +130,7 @@ namespace Barotrauma
GUI.AddMessage(
TextManager.GetWithVariables("SkillIncreased", new string[3] { "[name]", "[skillname]", "[newlevel]" },
new string[3] { Name, TextManager.Get("SkillName." + skillIdentifier), ((int)newLevel).ToString() },
new bool[3] { false, true, false }), Color.Green);
new bool[3] { false, true, false }), GUI.Style.Green);
}
}
@@ -160,30 +169,32 @@ namespace Barotrauma
sprite.SourceRect = new Rectangle(location, sprite.SourceRect.Size);
}
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, float targetWidth)
public void DrawBackground(SpriteBatch spriteBatch)
{
if (infoAreaPortraitBG == null) { return; }
infoAreaPortraitBG.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(), Color.White, Vector2.Zero, 0.0f,
scale: new Vector2(
HUDLayoutSettings.BottomRightInfoArea.Width / (float)infoAreaPortraitBG.SourceRect.Width,
HUDLayoutSettings.BottomRightInfoArea.Height / (float)infoAreaPortraitBG.SourceRect.Height));
}
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 offset, float targetWidth, bool flip = false)
{
float backgroundScale = 1;
if (PortraitBackground != null)
{
backgroundScale = targetWidth / PortraitBackground.size.X;
PortraitBackground.Draw(spriteBatch, screenPos, scale: backgroundScale);
}
if (Portrait != null)
{
// Scale down the head sprite 10%
float scale = targetWidth * 0.9f / Portrait.size.X;
Vector2 offset = Portrait.size * backgroundScale / 4;
if (Head.SheetIndex.HasValue)
{
Portrait.SourceRect = new Rectangle(CalculateOffset(Portrait, Head.SheetIndex.Value.ToPoint()), Portrait.SourceRect.Size);
}
Portrait.Draw(spriteBatch, screenPos + offset, scale: scale, spriteEffect: SpriteEffects.FlipHorizontally);
Portrait.Draw(spriteBatch, screenPos + offset, Color.White, Portrait.Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
if (AttachmentSprites != null)
{
float depthStep = 0.000001f;
foreach (var attachment in AttachmentSprites)
{
DrawAttachmentSprite(spriteBatch, attachment, Portrait, screenPos + offset, scale, depthStep, SpriteEffects.FlipHorizontally);
DrawAttachmentSprite(spriteBatch, attachment, Portrait, screenPos + offset, scale, depthStep, flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
depthStep += depthStep;
}
}
@@ -213,6 +224,22 @@ namespace Barotrauma
}
}
public void DrawJobIcon(SpriteBatch spriteBatch, Vector2 pos, float scale = 1.0f)
{
var icon = Job?.Prefab?.Icon;
if (icon == null) { return; }
icon.Draw(spriteBatch, pos, Job.Prefab.UIColor, scale: scale);
}
public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area)
{
var icon = Job?.Prefab?.Icon;
if (icon == null) { return; }
icon.Draw(spriteBatch,
area.Center.ToVector2(),
Job.Prefab.UIColor,
scale: Math.Min(area.Width / (float)icon.SourceRect.Width, area.Height / (float)icon.SourceRect.Height));
}
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
{
if (attachment.InheritSourceRect)
@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
@@ -79,9 +80,9 @@ namespace Barotrauma
{
newMem.interact = focusedItem.ID;
}
else if (focusedCharacter != null)
else if (FocusedCharacter != null)
{
newMem.interact = focusedCharacter.ID;
newMem.interact = FocusedCharacter.ID;
}
memInput.Insert(0, newMem);
@@ -288,6 +289,7 @@ namespace Barotrauma
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
//read anyway to prevent messing up reading the rest of the message
UInt16 lastEventID = msg.ReadUInt16();
byte itemCount = msg.ReadByte();
for (int i = 0; i < itemCount; i++)
{
@@ -364,7 +366,11 @@ namespace Barotrauma
{
character = Create(speciesName, position, seed, null, true);
character.ID = id;
character.ReadStatus(inc);
bool containsStatusData = inc.ReadBoolean();
if (containsStatusData)
{
character.ReadStatus(inc);
}
}
else
{
@@ -379,7 +385,42 @@ namespace Barotrauma
character = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
character.ID = id;
character.TeamID = (TeamType)teamID;
character.ReadStatus(inc);
// Check if the character has a current order
if (inc.ReadBoolean())
{
int orderPrefabIndex = inc.ReadByte();
Entity targetEntity = FindEntityByID(inc.ReadUInt16());
Character orderGiver = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
int orderOptionIndex = inc.ReadByte();
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
{
var orderPrefab = Order.PrefabList[orderPrefabIndex];
if ((orderPrefab.ItemComponentType == null && orderPrefab.ItemIdentifiers.None()) ||
(targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
{
character.SetOrder(
new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
orderGiver, speak: false);
}
else
{
DebugConsole.ThrowError("Could not set order \"" + orderPrefab.Identifier + "\" for character \"" + character.Name + "\" because required target entity was not found.");
}
}
else
{
DebugConsole.ThrowError("Invalid order prefab index - index (" + orderPrefabIndex + ") out of bounds.");
}
}
bool containsStatusData = inc.ReadBoolean();
if (containsStatusData)
{
character.ReadStatus(inc);
}
if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC && !character.IsDead)
{
@@ -416,16 +457,16 @@ namespace Barotrauma
AfflictionPrefab causeOfDeathAffliction = null;
if (causeOfDeathType == CauseOfDeathType.Affliction)
{
int afflictionIndex = msg.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1);
if (afflictionIndex < 0 || afflictionIndex >= AfflictionPrefab.List.Count)
string afflictionName = msg.ReadString();
if (!AfflictionPrefab.Prefabs.ContainsKey(afflictionName))
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction index out of bounds (index: {afflictionIndex}, affliction count: {AfflictionPrefab.List.Count})";
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction not found ({afflictionName})";
causeOfDeathType = CauseOfDeathType.Unknown;
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
else
{
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
causeOfDeathAffliction = AfflictionPrefab.Prefabs[afflictionName];
}
}
@@ -14,8 +14,8 @@ namespace Barotrauma
public SoundType Type => Params.State;
public Gender Gender => Params.Gender;
public float Volume => roundSound.Volume;
public float Range => roundSound.Range;
public float Volume => roundSound == null ? 0.0f : roundSound.Volume;
public float Range => roundSound == null ? 0.0f : roundSound.Range;
public Sound Sound => roundSound?.Sound;
public CharacterSound(CharacterParams.SoundParams soundParams)
@@ -41,7 +41,7 @@ namespace Barotrauma
private Submarine parentSub;
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine = null)
: this(worldPosition, parentSubmarine, Color.Red, Color.Green)
: this(worldPosition, parentSubmarine, GUI.Style.Red, GUI.Style.Green)
{
}
@@ -14,20 +14,20 @@ namespace Barotrauma
{
if (prevStrength % 10.0f > 0.05f && Strength % 10.0f < 0.05f)
{
GUI.AddMessage(TextManager.Get("HuskDormant"), Color.Red);
GUI.AddMessage(TextManager.Get("HuskDormant"), GUI.Style.Red);
}
}
else if (Strength < Prefab.MaxStrength)
{
if (state == InfectionState.Dormant && Character.Controlled == character)
{
GUI.AddMessage(TextManager.Get("HuskCantSpeak"), Color.Red);
GUI.AddMessage(TextManager.Get("HuskCantSpeak"), GUI.Style.Red);
}
}
else if (state != InfectionState.Active && Character.Controlled == character)
{
GUI.AddMessage(TextManager.GetWithVariable("HuskActivate", "[Attack]", GameMain.Config.KeyBind(InputType.Attack).ToString()),
Color.Red);
GUI.AddMessage(TextManager.GetWithVariable("HuskActivate", "[Attack]", GameMain.Config.KeyBindText(InputType.Attack)),
GUI.Style.Red);
}
}
}
@@ -0,0 +1,125 @@
using Microsoft.Xna.Framework;
using System.Linq;
using System;
using System.Xml.Linq;
using System.Collections.Generic;
namespace Barotrauma
{
partial class JobPrefab : IPrefab, IDisposable
{
public GUIButton CreateInfoFrame(int variant)
{
int width = 500, height = 400;
GUIButton backFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, height), backFrame.RectTransform, Anchor.Center));
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Name, font: GUI.LargeFont);
var descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) },
Description, font: GUI.SmallFont, wrap: true);
var skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.5f), paddedFrame.RectTransform)
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) });
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
TextManager.Get("Skills"), font: GUI.LargeFont);
foreach (SkillPrefab skill in Skills)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + skill.Identifier), (int)skill.LevelRange.X + " - " + (int)skill.LevelRange.Y),
font: GUI.SmallFont);
}
/*if (!ItemIdentifiers.TryGetValue(variant, out var itemIdentifiers)) { return backFrame; }
var itemContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.5f), paddedFrame.RectTransform, Anchor.TopRight)
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) })
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
TextManager.Get("Items", fallBackTag: "mapentitycategory.equipment"), font: GUI.LargeFont);
foreach (string identifier in itemIdentifiers.Distinct())
{
if (!(MapEntityPrefab.Find(name: null, identifier: identifier) is ItemPrefab itemPrefab)) { continue; }
int count = itemIdentifiers.Count(i => i == identifier);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
" - " + (count == 1 ? itemPrefab.Name : itemPrefab.Name + " x" + count),
font: GUI.SmallFont);
}*/
return backFrame;
}
public class OutfitPreview
{
/// <summary>
/// Pair.First = sprite, Pair.Second = draw offset
/// </summary>
public readonly List<Pair<Sprite, Vector2>> Sprites;
public Vector2 Dimensions;
public OutfitPreview()
{
Sprites = new List<Pair<Sprite, Vector2>>();
Dimensions = Vector2.One;
}
public void AddSprite(Sprite sprite, Vector2 drawOffset)
{
Sprites.Add(new Pair<Sprite, Vector2>(sprite, drawOffset));
}
}
public List<OutfitPreview> GetJobOutfitSprites(Gender gender, bool useInventoryIcon, out Vector2 maxDimensions)
{
List<OutfitPreview> outfitPreviews = new List<OutfitPreview>();
maxDimensions = Vector2.One;
var equipIdentifiers = Element.GetChildElements("ItemSet").Elements().Where(e => e.GetAttributeBool("outfit", false)).Select(e => e.GetAttributeString("identifier", ""));
var outfitPrefabs = ItemPrefab.Prefabs.Where(itemPrefab => equipIdentifiers.Contains(itemPrefab.Identifier)).ToList();
if (!outfitPrefabs.Any()) { return null; }
for (int i = 0; i < outfitPrefabs.Count; i++)
{
var outfitPreview = new OutfitPreview();
if (!ItemSets.TryGetValue(i, out var itemSetElement)) { continue; }
var previewElement = itemSetElement.GetChildElement("PreviewSprites");
if (previewElement == null || useInventoryIcon)
{
if (outfitPrefabs[i] is ItemPrefab prefab && prefab.InventoryIcon != null)
{
outfitPreview.AddSprite(prefab.InventoryIcon, Vector2.Zero);
outfitPreview.Dimensions = prefab.InventoryIcon.SourceRect.Size.ToVector2();
maxDimensions.X = MathHelper.Max(maxDimensions.X, outfitPreview.Dimensions.X);
maxDimensions.Y = MathHelper.Max(maxDimensions.Y, outfitPreview.Dimensions.Y);
}
outfitPreviews.Add(outfitPreview);
continue;
}
var children = previewElement.Elements().ToList();
for (int n = 0; n < children.Count; n++)
{
XElement spriteElement = children[n];
string spriteTexture = spriteElement.GetAttributeString("texture", "").Replace("[GENDER]", (gender == Gender.Female) ? "female" : "male");
var sprite = new Sprite(spriteElement, file: spriteTexture);
sprite.size = new Vector2(sprite.SourceRect.Width, sprite.SourceRect.Height);
outfitPreview.AddSprite(sprite, children[n].GetAttributeVector2("offset", Vector2.Zero));
}
outfitPreview.Dimensions = previewElement.GetAttributeVector2("dims", Vector2.One);
maxDimensions.X = MathHelper.Max(maxDimensions.X, outfitPreview.Dimensions.X);
maxDimensions.Y = MathHelper.Max(maxDimensions.Y, outfitPreview.Dimensions.Y);
outfitPreviews.Add(outfitPreview);
}
return outfitPreviews;
}
}
}
@@ -12,7 +12,6 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -82,7 +81,7 @@ namespace Barotrauma
//{
// var pos = ConvertUnits.ToDisplayUnits(mouthPos.Value);
// pos.Y = -pos.Y;
// ShapeExtensions.DrawPoint(spriteBatch, pos, Color.Red, size: 5);
// ShapeExtensions.DrawPoint(spriteBatch, pos, GUI.Style.Red, size: 5);
//}
return;
// A debug visualisation on the bezier curve between limbs.
@@ -99,7 +98,7 @@ namespace Barotrauma
//GUI.DrawLine(spriteBatch, start, end, Color.White);
//GUI.DrawLine(spriteBatch, start, control, Color.Black);
//GUI.DrawLine(spriteBatch, control, end, Color.Black);
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, Color.Red);
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, GUI.Style.Red);
}
}
@@ -182,6 +181,11 @@ namespace Barotrauma
get;
private set;
}
public float? InitialLightSpriteAlpha
{
get;
private set;
}
public LightSource LightSource
{
@@ -205,6 +209,36 @@ namespace Barotrauma
public string HitSoundTag => Params?.Sound?.Tag;
private List<WearableSprite> wearableTypeHidingSprites = new List<WearableSprite>();
private List<WearableType> wearableTypesToHide = new List<WearableType>();
private bool enableHuskSprite;
public bool EnableHuskSprite
{
get
{
return enableHuskSprite;
}
set
{
if (HuskSprite != null && value != enableHuskSprite)
{
if (value)
{
List<WearableSprite> otherWearablesWithHusk = new List<WearableSprite>() { HuskSprite };
otherWearablesWithHusk.AddRange(OtherWearables);
OtherWearables = otherWearablesWithHusk;
UpdateWearableTypesToHide();
}
else
{
OtherWearables.Remove(HuskSprite);
UpdateWearableTypesToHide();
}
}
enableHuskSprite = value;
}
}
partial void InitProjSpecific(XElement element)
{
for (int i = 0; i < Params.decorativeSpriteParams.Count; i++)
@@ -243,8 +277,13 @@ namespace Barotrauma
CreateDeformations(subElement);
break;
case "lightsource":
LightSource = new LightSource(subElement);
LightSource = new LightSource(subElement)
{
ParentBody = body,
SpriteScale = Vector2.One * Scale * TextureScale
};
InitialLightSourceColor = LightSource.Color;
InitialLightSpriteAlpha = LightSource.OverrideLightSpriteAlpha;
break;
}
@@ -394,14 +433,17 @@ namespace Barotrauma
SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition);
}
// Always spawn damage particles
// spawn damage particles
float damageParticleAmount = Math.Min(damage / 10, 1.0f) * damageMultiplier;
foreach (ParticleEmitter emitter in character.DamageEmitters)
if (damageParticleAmount > 0.001f)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
foreach (ParticleEmitter emitter in character.DamageEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
}
}
if (bleedingDamage > 0)
@@ -462,6 +504,10 @@ namespace Barotrauma
{
LightSource.ParentSub = body.Submarine;
LightSource.Rotation = (dir == Direction.Right) ? body.Rotation : body.Rotation - MathHelper.Pi;
if (LightSource.LightSprite != null)
{
LightSource.LightSprite.Depth = ActiveSprite.Depth;
}
}
UpdateSpriteStates(deltaTime);
@@ -478,6 +524,7 @@ namespace Barotrauma
{
if (severedFadeOutTimer > SeveredFadeOutTime)
{
if (LightSource != null) { LightSource.Enabled = false; }
return;
}
else if (severedFadeOutTimer > SeveredFadeOutTime - 1.0f)
@@ -488,11 +535,9 @@ namespace Barotrauma
body.Dir = Dir;
bool enableHuskSprite = character.IsHusk || character.CharacterHealth.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
bool hideLimb = Params.Hide ||
enableHuskSprite && HuskSprite != null && HuskSprite.HideLimb ||
bool hideLimb = Params.Hide ||
OtherWearables.Any(w => w.HideLimb) ||
wearingItems.Any(w => w != null && w.HideLimb);
@@ -501,8 +546,7 @@ namespace Barotrauma
{
CalculateHeadPosition(activeSprite);
}
// TODO: there's now two calls to this, because body.Draw() method calls this too -> is this an issue?
body.UpdateDrawPosition();
if (!hideLimb)
@@ -529,8 +573,6 @@ namespace Barotrauma
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (LightSource != null)
{
LightSource.Position = body.DrawPosition;
if (LightSource.ParentSub != null) { LightSource.Position -= LightSource.ParentSub.DrawPosition; }
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
}
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
@@ -566,19 +608,14 @@ namespace Barotrauma
}
if (onlyDrawable == null)
{
if (HerpesSprite != null)
if (HerpesSprite != null && !wearableTypesToHide.Contains(WearableType.Herpes))
{
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
depthStep += step;
}
if (HuskSprite != null && enableHuskSprite)
{
DrawWearable(HuskSprite, depthStep, spriteBatch, color, spriteEffect);
depthStep += step;
}
foreach (WearableSprite wearable in OtherWearables)
{
if (wearable.Type == WearableType.Beard && enableHuskSprite && HuskSprite != null) { continue; }
if (wearableTypesToHide.Contains(wearable.Type)) { continue; }
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += step;
@@ -597,7 +634,7 @@ namespace Barotrauma
if (pullJoint != null)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), GUI.Style.Red, true);
}
var bodyDrawPos = body.DrawPosition;
bodyDrawPos.Y = -bodyDrawPos.Y;
@@ -611,11 +648,11 @@ namespace Barotrauma
var front = ConvertUnits.ToDisplayUnits(body.FarseerBody.GetWorldPoint(localFront));
front.Y = -front.Y;
GUI.DrawLine(spriteBatch, bodyDrawPos, front, Color.Yellow, width: 2);
GUI.DrawLine(spriteBatch, from, to, Color.Red, width: 1);
GUI.DrawLine(spriteBatch, from, to, GUI.Style.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);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)from.X, (int)from.Y, 10, 10), Color.Blue, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 10, 10), Color.Red, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 10, 10), GUI.Style.Red, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)front.X, (int)front.Y, 10, 10), Color.Yellow, true);
//Vector2 mainLimbFront = ConvertUnits.ToDisplayUnits(ragdoll.MainLimb.body.FarseerBody.GetWorldPoint(ragdoll.MainLimb.body.GetFrontLocal(MathHelper.ToRadians(limbParams.Orientation))));
@@ -625,7 +662,37 @@ namespace Barotrauma
//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);
}
DrawDamageModifiers(spriteBatch, cam, bodyDrawPos, isScreenSpace: false);
//DrawDamageModifiers(spriteBatch, cam, bodyDrawPos, isScreenSpace: false);
}
}
public void UpdateWearableTypesToHide()
{
wearableTypeHidingSprites.Clear();
if (WearingItems != null && WearingItems.Count > 0)
{
wearableTypeHidingSprites.AddRange(
WearingItems.FindAll(w => w.HideWearablesOfType != null && w.HideWearablesOfType.Count > 0));
}
if (OtherWearables != null && OtherWearables.Count > 0)
{
wearableTypeHidingSprites.AddRange(
OtherWearables.FindAll(w => w.HideWearablesOfType != null && w.HideWearablesOfType.Count > 0));
}
wearableTypesToHide.Clear();
if (wearableTypeHidingSprites.Count > 0)
{
foreach (WearableSprite sprite in wearableTypeHidingSprites)
{
foreach (WearableType type in sprite.HideWearablesOfType)
{
if (!wearableTypesToHide.Contains(type))
{
wearableTypesToHide.Add(type);
}
}
}
}
}
@@ -676,7 +743,7 @@ namespace Barotrauma
public void DrawDamageModifiers(SpriteBatch spriteBatch, Camera cam, Vector2 startPos, bool isScreenSpace)
{
foreach (var modifier in damageModifiers)
foreach (var modifier in DamageModifiers)
{
//Vector2 up = VectorExtensions.Backward(-body.TransformedRotation + Params.GetSpriteOrientation() * Dir);
//int width = 4;
@@ -684,8 +751,8 @@ namespace Barotrauma
//{
// width = (int)Math.Round(width / cam.Zoom);
//}
//GUI.DrawLine(spriteBatch, startPos, startPos + Vector2.Normalize(up) * size, Color.Red, width: width);
Color color = modifier.DamageMultiplier > 1 ? Color.Red : Color.GreenYellow;
//GUI.DrawLine(spriteBatch, startPos, startPos + Vector2.Normalize(up) * size, GUI.Style.Red, width: width);
Color color = modifier.DamageMultiplier > 1 ? GUI.Style.Red : GUI.Style.Green;
float size = ConvertUnits.ToDisplayUnits(body.GetSize().Length() / 2);
if (isScreenSpace)
{
@@ -0,0 +1,192 @@
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Networking;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
// TODO decide what folder this falls under. Utils? GUI? or just leave where it is. Also probably a better class name name [<- no need to create a separate namespace, maybe a folder?]
/// <summary>
/// A class used for handling special key actions in chat boxes.
/// For example tab completion or up/down arrow key history.
/// </summary>
public class ChatManager
{
private readonly bool loop;
// Maximum items we want to store in the history
private readonly short maxCount = 10;
// List of previously stored messages
private readonly List<string> messageList = new List<string> { string.Empty };
/// Keep track of the registered fields so we don't register them twice
/// I couldn't figure out where to register this in <see cref="NetLobbyScreen"/> where it wouldn't register twice
/// It's probably not the most optimal way of doing this so feel free to change this
/// <seealso cref="NetLobbyScreen.Select"/> where I'm utilizing this
private readonly List<GUITextBox> registers = new List<GUITextBox>();
// Selector index
private int index;
// Local changes we've made into previously stored messages
private string[] localChanges;
public ChatManager(bool loop, short maxCount)
{
this.loop = loop;
this.maxCount = maxCount;
localChanges = new string[maxCount];
}
public ChatManager()
{
localChanges = new string[maxCount];
}
/// <summary>
/// Registers special input actions to the selected input field
/// </summary>
/// <param name="element">GUI Element we want to register</param>
/// <param name="manager">Instance</param>
public static void RegisterKeys(GUITextBox element, ChatManager manager)
{
// If already registered then don't register it again
if (manager.registers.Any(p => element == p)) { return; }
element.OnKeyHit += (sender, key) =>
{
switch (key)
{
// Up/Down Arrow key history action
case Keys.Up:
case Keys.Down:
{
// Up arrow key? go up. Down arrow key? go down. Everything else gets binned
Direction direction = key == Keys.Up ? Direction.Up : (key == Keys.Down ? Direction.Down : Direction.Other);
string newMessage = manager.SelectMessage(direction, element.Text);
// Don't do anything if we didn't find anything
if (newMessage == null) { return; }
element.Text = newMessage;
break;
}
case Keys.Tab:
// TODO tab completion behavior, maybe?
break;
}
};
manager.registers.Add(element);
}
// Store a new message
public void Store(string message)
{
Clear();
var strip = StripMessage(message);
if (string.IsNullOrWhiteSpace(strip)) { return; }
if (messageList.Count > 1 && messageList[1] == message) { return; }
// insert to the second position as the first position is reserved for the original message if any
messageList.Insert(1, message);
// we don't want to add too many messages
if (messageList.Count > maxCount)
{
messageList.RemoveAt(messageList.Count - 1);
}
// [It's also possible to lambdas too in short methods, if you like: string StripMessage(string text) => ChatMessage.GetChatMessageCommand(text, out string msg);]
static string StripMessage(string text)
{
ChatMessage.GetChatMessageCommand(text, out string msg);
return msg;
}
}
/// <summary>
/// Call this function whenever we should stop doing special stuff and return normal behavior.
/// For example when you deselect the chat box.
/// </summary>
public void Clear()
{
index = 0;
localChanges = new string[maxCount];
}
/// <summary>
/// Scroll up or down on the message history and return a message
/// </summary>
/// <param name="direction">Direction we want to scroll the stack</param>
/// <param name="original">Leftover text that is in the chat box when we override it</param>
/// <returns>A message or null</returns>
private string SelectMessage(Direction direction, string original)
{
var originalIndex = index;
while (true)
{
if (direction == Direction.Other)
{
return null;
}
// temporarily save our changes in case we fat-finger and want to go back
localChanges[index] = original;
var dir = (int) direction;
var nextIndex = (index + dir);
if (loop && messageList.Count > 1)
{
nextIndex = LoopAround(nextIndex);
}
else
{
if (nextIndex > messageList.Count - 1)
{
return null;
}
}
if (nextIndex >= 0 && EntryAt(nextIndex) == original && nextIndex != originalIndex && originalIndex != 0)
{
index = nextIndex;
continue;
}
return nextIndex < 0 ? localChanges.FirstOrDefault() : EntryAt(index = nextIndex);
string EntryAt(int i)
{
// if we've previously edited the entry then give us that, else give us the original message
return localChanges[i] ?? messageList[i];
}
int LoopAround(int next)
{
if (next > (messageList.Count - 1))
{
return 1;
}
if (next < 1)
{
return messageList.Count - 1;
}
return next;
}
}
}
// Used for Up/Down arrow key action
private enum Direction
{
Up = 1,
Down = -1,
Other = 0
}
}
}
@@ -10,6 +10,7 @@ using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
using FarseerPhysics;
using Barotrauma.Extensions;
namespace Barotrauma
@@ -30,10 +31,9 @@ namespace Barotrauma
if (!CheatsEnabled && IsCheat)
{
NewMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", Color.Red);
if (Steam.SteamManager.USE_STEAM)
{
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
}
#if USE_STEAM
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
#endif
return;
}
@@ -60,6 +60,8 @@ namespace Barotrauma
private const int maxLength = 1000;
public static GUITextBox TextBox => textBox;
private static readonly ChatManager chatManager = new ChatManager(true, 64);
public static void Init()
{
@@ -102,6 +104,8 @@ namespace Barotrauma
ResetAutoComplete();
}
};
ChatManager.RegisterKeys(textBox, chatManager);
}
public static void AddToGUIUpdateList()
@@ -152,15 +156,7 @@ namespace Barotrauma
Character.DisableControls = true;
if (PlayerInput.KeyHit(Keys.Up))
{
textBox.Text = SelectMessage(-1, textBox.Text);
}
else if (PlayerInput.KeyHit(Keys.Down))
{
textBox.Text = SelectMessage(1, textBox.Text);
}
else if (PlayerInput.KeyHit(Keys.Tab))
if (PlayerInput.KeyHit(Keys.Tab))
{
textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 );
}
@@ -177,6 +173,7 @@ namespace Barotrauma
if (PlayerInput.KeyHit(Keys.Enter))
{
chatManager.Store(textBox.Text);
ExecuteCommand(textBox.Text);
textBox.Text = "";
}
@@ -249,7 +246,7 @@ namespace Barotrauma
ThrowError("Failed to add a message to the debug console.", e);
}
selectedIndex = Messages.Count;
chatManager.Clear();
}
static partial void ShowHelpMessage(Command command)
@@ -278,7 +275,7 @@ namespace Barotrauma
listBox.UpdateScrollBarSize();
listBox.BarScroll = 1.0f;
selectedIndex = Messages.Count;
chatManager.Clear();
}
private static void AssignOnClientExecute(string names, Action<string[]> onClientExecute)
@@ -312,9 +309,8 @@ namespace Barotrauma
commands.Add(new Command("copyitemnames", "", (string[] args) =>
{
StringBuilder sb = new StringBuilder();
foreach (MapEntityPrefab mp in MapEntityPrefab.List)
foreach (ItemPrefab mp in ItemPrefab.Prefabs)
{
if (!(mp is ItemPrefab)) continue;
sb.AppendLine(mp.Name);
}
Clipboard.SetText(sb.ToString());
@@ -367,10 +363,9 @@ namespace Barotrauma
CheatsEnabled = true;
SteamAchievementManager.CheatsEnabled = true;
NewMessage("Enabled cheat commands.", Color.Red);
if (Steam.SteamManager.USE_STEAM)
{
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
}
#if USE_STEAM
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
#endif
}));
commands.Add(new Command("mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
@@ -402,7 +397,7 @@ namespace Barotrauma
Submarine.Load(string.Join(" ", args), true);
}
GameMain.SubEditorScreen.Select();
}));
}, isCheat: true));
commands.Add(new Command("editparticles|particleeditor", "editparticles/particleeditor: Switch to the Particle Editor to edit particle effects.", (string[] args) =>
{
@@ -445,12 +440,14 @@ namespace Barotrauma
AssignRelayToServer("ban", false);
AssignRelayToServer("banid", false);
AssignRelayToServer("dumpids", false);
AssignRelayToServer("dumptofile", false);
AssignRelayToServer("findentityids", false);
AssignRelayToServer("campaigninfo", false);
AssignRelayToServer("help", false);
AssignRelayToServer("verboselogging", false);
AssignRelayToServer("freecam", false);
#if DEBUG
AssignRelayToServer("crash", false);
AssignRelayToServer("simulatedlatency", false);
AssignRelayToServer("simulatedloss", false);
AssignRelayToServer("simulatedduplicateschance", false);
@@ -485,6 +482,39 @@ namespace Barotrauma
GameMain.GameScreen.Cam.Shake = 10.0f;
}));
AssignOnExecute("explosion", (string[] args) =>
{
Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
float range = 500, force = 10, damage = 50, structureDamage = 10, empStrength = 0.0f;
if (args.Length > 0) float.TryParse(args[0], out range);
if (args.Length > 1) float.TryParse(args[1], out force);
if (args.Length > 2) float.TryParse(args[2], out damage);
if (args.Length > 3) float.TryParse(args[3], out structureDamage);
if (args.Length > 4) float.TryParse(args[4], out empStrength);
new Explosion(range, force, damage, structureDamage, empStrength).Explode(explosionPos, null);
});
AssignOnExecute("teleportcharacter|teleport", (string[] args) =>
{
Character tpCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, false);
if (tpCharacter == null) return;
var cam = GameMain.GameScreen.Cam;
tpCharacter.AnimController.CurrentHull = null;
tpCharacter.Submarine = null;
tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)));
tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true);
});
AssignOnExecute("spawn|spawncharacter", (string[] args) =>
{
SpawnCharacter(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), out string errorMsg);
if (!string.IsNullOrWhiteSpace(errorMsg))
{
ThrowError(errorMsg);
}
});
AssignOnExecute("los", (string[] args) =>
{
if (args.None() || !bool.TryParse(args[0], out bool state))
@@ -754,17 +784,20 @@ namespace Barotrauma
commands.Add(new Command("lobby|lobbyscreen", "", (string[] args) =>
{
if (GameMain.Client != null)
{
ThrowError("This command cannot be used in multiplayer.");
return;
}
GameMain.LobbyScreen.Select();
}));
commands.Add(new Command("save|savesub", "save [submarine name]: Save the currently loaded submarine using the specified name.", (string[] args) =>
{
if (args.Length < 1) return;
if (args.Length < 1) { return; }
if (GameMain.SubEditorScreen.CharacterMode)
{
GameMain.SubEditorScreen.SetCharacterMode(false);
}
GameMain.SubEditorScreen.SetMode(SubEditorScreen.Mode.Default);
string fileName = string.Join(" ", args);
if (fileName.Contains("../"))
@@ -937,90 +970,84 @@ namespace Barotrauma
commands.Add(new Command("checkcrafting", "checkcrafting: Checks item deconstruction & crafting recipes for inconsistencies.", (string[] args) =>
{
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
{
if (mapEntityPrefab is ItemPrefab itemPrefab)
{
fabricableItems.AddRange(itemPrefab.FabricationRecipes);
}
fabricableItems.AddRange(itemPrefab.FabricationRecipes);
}
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
{
if (mapEntityPrefab is ItemPrefab itemPrefab)
{
int? minCost = itemPrefab.GetPrices()?.Min(p => p.BuyPrice);
int? fabricationCost = null;
int? deconstructProductCost = null;
int? minCost = itemPrefab.GetPrices()?.Min(p => p.BuyPrice);
int? fabricationCost = null;
int? deconstructProductCost = null;
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
if (fabricationRecipe != null)
{
foreach (var ingredient in fabricationRecipe.RequiredItems)
{
int? ingredientPrice = ingredient.ItemPrefab.GetPrices()?.Min(p => p.BuyPrice);
if (ingredientPrice.HasValue)
{
if (!fabricationCost.HasValue) { fabricationCost = 0; }
float useAmount = ingredient.UseCondition ? ingredient.MinCondition : 1.0f;
fabricationCost += (int)(ingredientPrice.Value * ingredient.Amount * useAmount);
}
}
}
foreach (var deconstructItem in itemPrefab.DeconstructItems)
{
var targetItem = MapEntityPrefab.Find(null, deconstructItem.ItemIdentifier, showErrorMessages: false) as ItemPrefab;
if (targetItem == null)
{
ThrowError("Error in item \"" + itemPrefab.Name + "\" - could not find deconstruct item \"" + deconstructItem.ItemIdentifier + "\"!");
continue;
}
int? deconstructProductPrice = targetItem.GetPrices()?.Min(p => p.BuyPrice);
if (deconstructProductPrice.HasValue)
{
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
deconstructProductCost += (int)(deconstructProductPrice * deconstructItem.OutCondition);
}
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
if (fabricationRecipe != null)
{
foreach (var ingredient in fabricationRecipe.RequiredItems)
if (!fabricationRecipe.RequiredItems.Any(r => r.ItemPrefab == targetItem))
{
int? ingredientPrice = ingredient.ItemPrefab.GetPrices()?.Min(p => p.BuyPrice);
if (ingredientPrice.HasValue)
{
if (!fabricationCost.HasValue) { fabricationCost = 0; }
float useAmount = ingredient.UseCondition ? ingredient.MinCondition : 1.0f;
fabricationCost += (int)(ingredientPrice.Value * ingredient.Amount * useAmount);
}
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Orange);
}
}
}
foreach (var deconstructItem in itemPrefab.DeconstructItems)
if (fabricationCost.HasValue && minCost.HasValue)
{
if (fabricationCost.Value < minCost * 0.9f)
{
var targetItem = MapEntityPrefab.Find(null, deconstructItem.ItemIdentifier, showErrorMessages: false) as ItemPrefab;
if (targetItem == null)
{
ThrowError("Error in item \"" + itemPrefab.Name + "\" - could not find deconstruct item \"" + deconstructItem.ItemIdentifier + "\"!");
continue;
}
int? deconstructProductPrice = targetItem.GetPrices()?.Min(p => p.BuyPrice);
if (deconstructProductPrice.HasValue)
{
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
deconstructProductCost += (int)(deconstructProductPrice * deconstructItem.OutCondition);
}
if (fabricationRecipe != null)
{
if (!fabricationRecipe.RequiredItems.Any(r => r.ItemPrefab == targetItem))
{
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Orange);
}
}
float ratio = (float)fabricationCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" only cost " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
}
if (fabricationCost.HasValue && minCost.HasValue)
else if (fabricationCost.Value > minCost * 1.1f)
{
if (fabricationCost.Value < minCost * 0.9f)
{
float ratio = (float)fabricationCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" only cost " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
}
else if (fabricationCost.Value > minCost * 1.1f)
{
float ratio = (float)fabricationCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" cost " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
}
float ratio = (float)fabricationCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" cost " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
}
if (deconstructProductCost.HasValue && minCost.HasValue)
}
if (deconstructProductCost.HasValue && minCost.HasValue)
{
if (deconstructProductCost.Value < minCost * 0.8f)
{
if (deconstructProductCost.Value < minCost * 0.8f)
{
float ratio = (float)deconstructProductCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is only worth " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
}
else if (deconstructProductCost.Value > minCost * 1.1f)
{
float ratio = (float)deconstructProductCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is worth " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
}
float ratio = (float)deconstructProductCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is only worth " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
}
else if (deconstructProductCost.Value > minCost * 1.1f)
{
float ratio = (float)deconstructProductCost.Value / minCost.Value;
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is worth " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
}
}
}
@@ -1031,35 +1058,75 @@ namespace Barotrauma
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
foreach (MapEntity me in MapEntity.SelectedList)
{
if (me is ISerializableEntity serializableEntity)
bool propertyFound = false;
if (!(me is ISerializableEntity serializableEntity)) { continue; }
if (serializableEntity.SerializableProperties == null) { continue; }
if (serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
{
if (serializableEntity.SerializableProperties == null)
propertyFound = true;
object prevValue = property.GetValue(me);
if (property.TrySetValue(me, args[1]))
{
continue;
NewMessage($"Changed the value \"{args[0]}\" from {(prevValue?.ToString() ?? null)} to {args[1]} on entity \"{me.ToString()}\".", Color.LightGreen);
}
if (!serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
else
{
NewMessage("Property \"" + args[0] + "\" not found in the entity \"" + me.ToString() + "\".", Color.Orange);
continue;
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the entity \"{me.ToString()}\".", Color.Orange);
}
if (!property.TrySetValue(me, args[1]))
}
if (me is Item item)
{
foreach (ItemComponent ic in item.Components)
{
NewMessage("Failed to set the value of \"" + args[0] + "\" to \"" + args[1] + "\" on the entity \"" + me.ToString() + "\".", Color.Orange);
ic.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty componentProperty);
if (componentProperty == null) { continue; }
propertyFound = true;
object prevValue = componentProperty.GetValue(ic);
if (componentProperty.TrySetValue(ic, args[1]))
{
NewMessage($"Changed the value \"{args[0]}\" from {prevValue} to {args[1]} on item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.LightGreen);
}
else
{
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.Orange);
}
}
}
if (!propertyFound)
{
NewMessage($"Property \"{args[0]}\" not found in the entity \"{me.ToString()}\".", Color.Orange);
}
}
},
() =>
{
List<string> propertyList = new List<string>();
foreach (MapEntity me in MapEntity.SelectedList)
{
if (!(me is ISerializableEntity serializableEntity)) { continue; }
if (serializableEntity.SerializableProperties == null) { continue; }
propertyList.AddRange(serializableEntity.SerializableProperties.Select(p => p.Key));
if (me is Item item)
{
foreach (ItemComponent ic in item.Components)
{
propertyList.AddRange(ic.SerializableProperties.Select(p => p.Key));
}
}
}
}));
#if DEBUG
commands.Add(new Command("printreceivertransfers", "", (string[] args) =>
{
GameMain.Client.PrintReceiverTransters();
return new string[][]
{
propertyList.Distinct().ToArray(),
new string[0]
};
}));
commands.Add(new Command("checkmissingloca", "", (string[] args) =>
{
//key = text tag, value = list of languages the tag is missing from
Dictionary<string, List<string>> missingTags = new Dictionary<string, List<string>>();
Dictionary<string, HashSet<string>> missingTags = new Dictionary<string, HashSet<string>>();
Dictionary<string, HashSet<string>> tags = new Dictionary<string, HashSet<string>>();
foreach (string language in TextManager.AvailableLanguages)
{
@@ -1067,31 +1134,104 @@ namespace Barotrauma
tags.Add(language, new HashSet<string>(TextManager.GetAllTagTextPairs().Select(t => t.Key)));
}
foreach (string language in TextManager.AvailableLanguages)
{
//check missing mission texts
foreach (var missionPrefab in MissionPrefab.List)
{
string nameIdentifier = "missionname." + missionPrefab.Identifier;
if (!tags[language].Contains(nameIdentifier))
{
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
missingTags[nameIdentifier].Add(language);
}
string descriptionIdentifier = "missiondescription." + missionPrefab.Identifier;
if (!tags[language].Contains(descriptionIdentifier))
{
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
missingTags[descriptionIdentifier].Add(language);
}
}
foreach (Submarine sub in Submarine.SavedSubmarines)
{
string nameIdentifier = "submarine.name." + sub.Name.ToLowerInvariant();
if (!tags[language].Contains(nameIdentifier))
{
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
missingTags[nameIdentifier].Add(language);
}
string descriptionIdentifier = "submarine.description." + sub.Name.ToLowerInvariant();
if (!tags[language].Contains(descriptionIdentifier))
{
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
missingTags[descriptionIdentifier].Add(language);
}
}
foreach (AfflictionPrefab affliction in AfflictionPrefab.List)
{
string nameIdentifier = "afflictionname." + affliction.Identifier;
if (!tags[language].Contains(nameIdentifier))
{
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
missingTags[nameIdentifier].Add(language);
}
string descriptionIdentifier = "afflictiondescription." + affliction.Identifier;
if (!tags[language].Contains(descriptionIdentifier))
{
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
missingTags[descriptionIdentifier].Add(language);
}
}
//check missing entity names
foreach (MapEntityPrefab me in MapEntityPrefab.List)
{
string nameIdentifier = "entityname." + me.Identifier;
if (tags[language].Contains(nameIdentifier)) { continue; }
if (me is ItemPrefab itemPrefab)
{
nameIdentifier = itemPrefab.ConfigElement?.GetAttributeString("nameidentifier", null) ?? nameIdentifier;
if (nameIdentifier != null)
{
if (tags[language].Contains("entityname." + nameIdentifier)) { continue; }
}
}
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
missingTags[nameIdentifier].Add(language);
}
}
foreach (string englishTag in tags["English"])
{
if (englishTag == "entitydescription.reinforceddoor")
{
int asdfsdf = 1;
}
foreach (string language in TextManager.AvailableLanguages)
{
if (language == "English") { continue; }
if (!tags[language].Contains(englishTag))
{
if (!missingTags.ContainsKey(englishTag))
{
missingTags[englishTag] = new List<string>();
}
if (!missingTags.ContainsKey(englishTag)) { missingTags[englishTag] = new HashSet<string>(); }
missingTags[englishTag].Add(language);
}
}
}
List<string> lines = missingTags.Select(t => "\"" + t.Key + "\"\n missing from " + string.Join(", ", t.Value)).ToList();
string filePath = "missingloca.txt";
File.WriteAllLines(filePath, missingTags.Select(t => "\""+t.Key + "\"\n missing from " + string.Join(", ", t.Value)));
System.Diagnostics.Process.Start(Path.GetFullPath(filePath));
File.WriteAllLines(filePath, lines);
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
TextManager.Language = "English";
}));
#if DEBUG
commands.Add(new Command("printreceivertransfers", "", (string[] args) =>
{
GameMain.Client.PrintReceiverTransters();
}));
commands.Add(new Command("spamchatmessages", "", (string[] args) =>
{
int msgCount = 1000;
@@ -1108,6 +1248,15 @@ namespace Barotrauma
}
}));
commands.Add(new Command("getprefabinfo", "", (string[] args) =>
{
var prefab = MapEntityPrefab.Find(null, args[0]);
if (prefab != null)
{
DebugConsole.NewMessage(prefab.Name + " " + prefab.Identifier + " " + prefab.GetType().ToString());
}
}));
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;
@@ -1194,6 +1343,10 @@ namespace Barotrauma
{
(Character.Controlled?.AnimController as FishAnimController)?.Mirror(lerp: false);
}, isCheat: false));
commands.Add(new Command("forcetimeout", "Immediately cause the client to time out if one is running.", (string[] args) =>
{
GameMain.Client?.ForceTimeOut();
}, isCheat: false));
#endif
@@ -1211,7 +1364,7 @@ namespace Barotrauma
},
() =>
{
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
var files = TextManager.GetTextFiles().Select(f => f.CleanUpPath());
return new string[][]
{
TextManager.GetTextFiles().Where(f => Path.GetExtension(f)==".xml").ToArray()
@@ -1250,7 +1403,7 @@ namespace Barotrauma
},
() =>
{
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
var files = TextManager.GetTextFiles().Select(f => f.CleanUpPath());
return new string[][]
{
files.Where(f => Path.GetExtension(f)==".txt").ToArray(),
@@ -1285,7 +1438,7 @@ namespace Barotrauma
},
() =>
{
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.Replace("\\", "/")).ToArray();
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.CleanUpPath()).ToArray();
return new string[][]
{
files,
@@ -1416,9 +1569,20 @@ namespace Barotrauma
lines.Add("");
}
File.WriteAllLines(filePath, lines);
System.Diagnostics.Process.Start(Path.GetFullPath(filePath));
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
}));
#if DEBUG
commands.Add(new Command("querylobbies", "Queries all SteamP2P lobbies", (args) =>
{
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide();
Steamworks.Data.Lobby[] lobbies = lobbyQuery.RequestAsync().Result;
foreach (var lobby in lobbies)
{
DebugConsole.NewMessage(lobby.GetData("name") + ", " + lobby.GetData("lobbyowner"));
}
}));
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
{
if (args.Length != 1) return;
@@ -1433,8 +1597,70 @@ namespace Barotrauma
commands.Add(new Command("csvtoxml", "csvtoxml [language] -> Converts .csv localization files in Content/NPCConversations & Content/Texts to .xml for use in-game.", (string[] args) =>
{
if (args.Length == 0) return;
LocalizationCSVtoXML.Convert(args[0]);
LocalizationCSVtoXML.Convert();
}));
commands.Add(new Command("printproperties", "Goes through the currently collected property list for missing localizations and writes them to a file.", (string[] args) =>
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\propertylocalization.txt";
File.WriteAllLines(path, SerializableEntityEditor.MissingLocalizations);
}));
commands.Add(new Command("getproperties", "Goes through the MapEntity prefabs and checks their serializable properties for localization issues.", (string[] args) =>
{
if (Screen.Selected != GameMain.SubEditorScreen) return;
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
{
ep.DebugCreateInstance();
}
for (int i = 0; i < MapEntity.mapEntityList.Count; i++)
{
var entity = MapEntity.mapEntityList[i] as ISerializableEntity;
if (entity != null)
{
List<Pair<object, SerializableProperty>> allProperties = new List<Pair<object, SerializableProperty>>();
if (entity is Item item)
{
allProperties.AddRange(item.GetProperties<Editable>());
allProperties.AddRange(item.GetProperties<InGameEditable>());
}
else
{
var properties = new List<SerializableProperty>();
properties.AddRange(SerializableProperty.GetProperties<Editable>(entity));
properties.AddRange(SerializableProperty.GetProperties<InGameEditable>(entity));
for (int k = 0; k < properties.Count; k++)
{
allProperties.Add(new Pair<object, SerializableProperty>(entity, properties[k]));
}
}
for (int j = 0; j < allProperties.Count; j++)
{
var property = allProperties[j].Second;
string propertyName = (allProperties[j].First.GetType().Name + "." + property.PropertyInfo.Name).ToLowerInvariant();
string displayName = TextManager.Get($"sp.{propertyName}.name", returnNull: true);
if (displayName == null)
{
displayName = property.Name.FormatCamelCaseWithSpaces();
Editable editable = property.GetAttribute<Editable>();
if (editable != null)
{
if (!SerializableEntityEditor.MissingLocalizations.Contains($"sp.{propertyName}.name|{displayName}"))
{
NewMessage("Missing Localization for property: " + propertyName);
SerializableEntityEditor.MissingLocalizations.Add($"sp.{propertyName}.name|{displayName}");
SerializableEntityEditor.MissingLocalizations.Add($"sp.{propertyName}.description|{property.GetAttribute<Serialize>().Description}");
}
}
}
}
}
}
}));
#endif
@@ -1530,28 +1756,61 @@ namespace Barotrauma
ThrowError("TutorialSub.sub not found!");
}
}));
commands.Add(new Command("reloadcorepackage", "", (string[] args) =>
{
if (args.Length < 1)
{
if (Screen.Selected == GameMain.GameScreen)
{
ThrowError("Reloading the core package while in GameScreen WILL break everything; to do it anyway, type 'reloadcorepackage force'");
return;
}
if (Screen.Selected == GameMain.SubEditorScreen)
{
ThrowError("Reloading the core package while in sub editor WILL break everything; to do it anyway, type 'reloadcorepackage force'");
return;
}
}
if (GameMain.NetworkMember != null)
{
ThrowError("Cannot change content packages while playing online");
return;
}
GameMain.Config.SelectCorePackage(GameMain.Config.SelectedContentPackages.First(cp => cp.CorePackage), true);
}));
commands.Add(new Command("ingamemodswap", "", (string[] args) =>
{
ContentPackage.IngameModSwap = !ContentPackage.IngameModSwap;
if (ContentPackage.IngameModSwap)
{
NewMessage("Enabled ingame mod swapping");
}
else
{
NewMessage("Disabled ingame mod swapping");
}
}));
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) =>
ShowQuestionPrompt("Permission to grant to client " + args[0] + "?", (perm) =>
{
GameMain.Client?.SendConsoleCommand("giveperm " + id + " " + perm);
});
GameMain.Client?.SendConsoleCommand("giveperm " + args[0] + " " + perm);
}, args, 1);
}
);
@@ -1561,22 +1820,16 @@ namespace Barotrauma
{
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) =>
ShowQuestionPrompt("Permission to revoke from client " + args[0] + "?", (perm) =>
{
GameMain.Client?.SendConsoleCommand("revokeperm " + id + " " + perm);
});
GameMain.Client?.SendConsoleCommand("revokeperm " + args[0] + " " + perm);
}, args, 1);
}
);
@@ -1586,21 +1839,15 @@ namespace Barotrauma
{
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) =>
ShowQuestionPrompt("Rank to grant to client " + args[0] + "?", (rank) =>
{
GameMain.Client?.SendConsoleCommand("giverank " + id + " " + rank);
});
GameMain.Client?.SendConsoleCommand("giverank " + args[0] + " " + rank);
}, args, 1);
}
);
@@ -1610,16 +1857,10 @@ namespace Barotrauma
{
if (args.Length < 1) return;
if (!int.TryParse(args[0], out int id))
ShowQuestionPrompt("Console command permissions to grant to client " + args[0] + "? You may enter multiple commands separated with a space.", (commandNames) =>
{
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);
});
GameMain.Client?.SendConsoleCommand("givecommandperm " + args[0] + " " + commandNames);
}, args, 1);
}
);
@@ -1629,16 +1870,10 @@ namespace Barotrauma
{
if (args.Length < 1) return;
if (!int.TryParse(args[0], out int id))
ShowQuestionPrompt("Console command permissions to revoke from client " + args[0] + "? You may enter multiple commands separated with a space.", (commandNames) =>
{
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);
});
GameMain.Client?.SendConsoleCommand("revokecommandperm " + args[0] + " " + commandNames);
}, args, 1);
}
);
@@ -1648,13 +1883,7 @@ namespace Barotrauma
{
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);
GameMain.Client.SendConsoleCommand("showperm " + args[0]);
}
);
@@ -2076,6 +2305,18 @@ namespace Barotrauma
DebugConsole.NewMessage("Cannot pause when a multiplayer session is active.");
}
}));
AssignOnClientExecute("showseed|showlevelseed", (string[] args) =>
{
if (Level.Loaded == null)
{
ThrowError("No level loaded.");
}
else
{
NewMessage("Level seed: " + Level.Loaded.Seed);
}
});
}
private static void ReloadWearables(Character character, int variant = 0)
@@ -2119,7 +2360,7 @@ namespace Barotrauma
switch (firstArg)
{
case "name":
var sprites = Sprite.LoadedSprites.Where(s => s.Name?.ToLowerInvariant() == secondArg.ToLowerInvariant());
var sprites = Sprite.LoadedSprites.Where(s => s.Name != null && s.Name.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
if (sprites.Any())
{
foreach (var s in sprites)
@@ -2135,7 +2376,7 @@ namespace Barotrauma
}
case "identifier":
case "id":
sprites = Sprite.LoadedSprites.Where(s => s.EntityID?.ToLowerInvariant() == secondArg.ToLowerInvariant());
sprites = Sprite.LoadedSprites.Where(s => s.EntityID != null && s.EntityID.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
if (sprites.Any())
{
foreach (var s in sprites)
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Barotrauma
{
@@ -12,7 +13,7 @@ namespace Barotrauma
public void DebugDraw(SpriteBatch spriteBatch)
{
foreach (ScriptedEvent ev in events)
foreach (ScriptedEvent ev in activeEvents)
{
Vector2 drawPos = ev.DebugDrawPos;
drawPos.Y = -drawPos.Y;
@@ -27,14 +28,14 @@ namespace Barotrauma
{
GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + eventCoolDown, Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)(currentIntensity * 100), Color.Lerp(Color.White, Color.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)(targetIntensity * 100), Color.Lerp(Color.White, Color.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)(avgCrewHealth * 100), Color.Lerp(Color.Red, Color.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)(avgHullIntegrity * 100), Color.Lerp(Color.Red, Color.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)(floodingAmount * 100), Color.Lerp(Color.Green, Color.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)(fireAmount * 100), Color.Lerp(Color.Green, Color.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)(enemyDanger * 100), Color.Lerp(Color.Green, Color.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
#if DEBUG
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
@@ -61,8 +62,8 @@ namespace Barotrauma
Rectangle graphRect = new Rectangle(15, y + 150, 150, 50);
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true);
intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, Color.Red, currentIntensity));
targetIntensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, Color.Red, targetIntensity) * 0.5f);
intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, currentIntensity));
targetIntensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, targetIntensity) * 0.5f);
GUI.DrawLine(spriteBatch,
new Vector2(graphRect.Right, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)),
@@ -80,7 +81,7 @@ namespace Barotrauma
"Intensity too high for new events: " + (int)(currentIntensity * 100) + "%/" + (int)(eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
y += 15;
}
foreach (ScriptedEventSet eventSet in selectedEventSets)
foreach (ScriptedEventSet eventSet in pendingEventSets)
{
float distanceTraveled = MathHelper.Clamp(
(Submarine.MainSub.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X),
@@ -113,11 +114,11 @@ namespace Barotrauma
y += 15;
}
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont);
y += 12;
foreach (ScriptedEvent scriptedEvent in events )
foreach (ScriptedEvent scriptedEvent in activeEvents)
{
if (scriptedEvent.IsFinished) { continue; }
GUI.DrawString(spriteBatch, new Vector2(graphRect.X + 5, y), scriptedEvent.ToString(), Color.White * 0.8f, null, 0, GUI.SmallFont);
@@ -0,0 +1,25 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class CargoMission : Mission
{
public override void ClientReadInitial(IReadMessage msg)
{
ushort itemCount = msg.ReadUInt16();
for (int i = 0; i < itemCount; i++)
{
items.Add(Item.ReadSpawnData(msg));
}
if (items.Contains(null))
{
throw new System.Exception("Error in CargoMission.ClientReadInitial: item list contains null (mission: " + Prefab.Identifier + ")");
}
if (items.Count != itemCount)
{
throw new System.Exception("Error in CargoMission.ClientReadInitial: item count does not match the server count (" + itemCount + " != " + items.Count + "mission: " + Prefab.Identifier + ")");
}
if (requiredDeliveryAmount == 0) { requiredDeliveryAmount = items.Count; }
}
}
}
@@ -1,4 +1,6 @@
namespace Barotrauma
using Barotrauma.Networking;
namespace Barotrauma
{
partial class CombatMission
{
@@ -18,5 +20,10 @@
return descriptions[GameMain.Client.Character.TeamID == Character.TeamType.Team1 ? 1 : 2];
}
}
public override void ClientReadInitial(IReadMessage msg)
{
//do nothing
}
}
}
@@ -0,0 +1,29 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class Mission
{
partial void ShowMessageProjSpecific(int missionState)
{
int messageIndex = missionState - 1;
if (messageIndex >= Headers.Count && messageIndex >= Messages.Count) { return; }
if (messageIndex < 0) { return; }
string header = messageIndex < Headers.Count ? Headers[messageIndex] : "";
string message = messageIndex < Messages.Count ? Messages[messageIndex] : "";
new GUIMessageBox(header, message, buttons: new string[0], type: GUIMessageBox.Type.InGame, icon: Prefab.Icon)
{
IconColor = Prefab.IconColor
};
}
public void ClientRead(IReadMessage msg)
{
State = msg.ReadInt16();
}
public abstract void ClientReadInitial(IReadMessage msg);
}
}
@@ -24,7 +24,7 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "icon") { continue; }
if (!subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase)) { continue; }
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
}
@@ -0,0 +1,25 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class MonsterMission : Mission
{
public override void ClientReadInitial(IReadMessage msg)
{
byte monsterCount = msg.ReadByte();
for (int i = 0; i < monsterCount; i++)
{
monsters.Add(Character.ReadSpawnData(msg));
}
if (monsters.Contains(null))
{
throw new System.Exception("Error in MonsterMission.ClientReadInitial: monster list contains null (mission: " + Prefab.Identifier + ")");
}
if (monsters.Count != monsterCount)
{
throw new System.Exception("Error in MonsterMission.ClientReadInitial: monster count does not match the server count (" + monsterCount + " != " + monsters.Count + "mission: " + Prefab.Identifier + ")");
}
InitializeMonsters(monsters);
}
}
}
@@ -0,0 +1,19 @@
using Barotrauma.Networking;
using FarseerPhysics;
namespace Barotrauma
{
partial class SalvageMission : Mission
{
public override void ClientReadInitial(IReadMessage msg)
{
item = Item.ReadSpawnData(msg);
if (item == null)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
}
item.body.FarseerBody.BodyType = BodyType.Kinematic;
}
}
}
@@ -0,0 +1,20 @@
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma.Extensions
{
public static class ColorExtensions
{
public static Color Multiply(this Color color, float value, bool onlyAlpha = false)
{
return onlyAlpha ?
new Color(color.R, color.G, color.B, (byte)(color.A * value)) :
new Color((byte)(color.R * value), (byte)(color.G * value), (byte)(color.B * value), (byte)(color.A * value));
}
public static Color Opaque(this Color color)
{
return new Color(color.R, color.G, color.B, (byte)255);
}
}
}
@@ -7,6 +7,76 @@ using System.Xml.Linq;
namespace Barotrauma
{
public class ColorData
{
public int StartIndex, EndIndex;
public Color Color;
private const char colorDefinitionIndicator = '‖';
private const char lineChangeIndicator = '\n';
private const string colorDefinitionStartString = "‖color:";
private const string coloringEndDefinition = "‖color:end‖";
public static List<ColorData> GetColorData(string text, out string sanitizedText)
{
List<ColorData> textColors = null;
if (text != null && text.IndexOf(colorDefinitionIndicator) != -1 && text.Contains(colorDefinitionStartString))
{
textColors = new List<ColorData>();
List<int> lineChangeIndexes = null;
int currentIndex = text.IndexOf(lineChangeIndicator);
if (currentIndex != -1)
{
lineChangeIndexes = new List<int>();
lineChangeIndexes.Add(currentIndex);
int startIndex = currentIndex + 1;
while (true)
{
if (startIndex >= text.Length) break;
currentIndex = text.IndexOf(lineChangeIndicator, startIndex);
if (currentIndex == -1) break;
lineChangeIndexes.Add(currentIndex);
startIndex = currentIndex + 1;
}
}
while (text.IndexOf(colorDefinitionStartString) != -1)
{
ColorData colorData = new ColorData();
int colorDefinitionStartIndex = text.IndexOf(colorDefinitionStartString);
int colorDefinitionEndIndex = text.IndexOf(colorDefinitionIndicator, colorDefinitionStartIndex + 1);
string[] colorDefinition = text.Substring(colorDefinitionStartIndex + colorDefinitionStartString.Length, colorDefinitionEndIndex - colorDefinitionStartIndex - colorDefinitionStartString.Length).Split(',');
colorData.StartIndex = colorDefinitionStartIndex;
colorData.Color = new Color(int.Parse(colorDefinition[0]), int.Parse(colorDefinition[1]), int.Parse(colorDefinition[2]));
text = text.Remove(colorDefinitionStartIndex, colorDefinitionEndIndex - colorDefinitionStartIndex + 1);
colorData.EndIndex = text.IndexOf(coloringEndDefinition);
text = text.Remove(colorData.EndIndex, coloringEndDefinition.Length);
if (lineChangeIndexes != null)
{
for (int i = 0; i < lineChangeIndexes.Count; i++)
{
if (colorData.StartIndex > lineChangeIndexes[i])
{
colorData.StartIndex--;
colorData.EndIndex--;
}
}
}
textColors.Add(colorData);
}
}
sanitizedText = text;
return textColors;
}
}
public class ScalableFont : IDisposable
{
private static List<ScalableFont> FontList = new List<ScalableFont>();
@@ -128,10 +198,6 @@ namespace Barotrauma
this.texDims = texDims;
this.baseChar = baseChar;
lock (mutex)
{
face.SetPixelSizes(0, size);
}
textures.ForEach(t => t.Dispose());
textures.Clear();
texCoords.Clear();
@@ -153,17 +219,15 @@ namespace Barotrauma
lock (mutex)
{
face.SetPixelSizes(0, size);
face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
baseHeight = face.Glyph.Metrics.Height.ToInt32();
}
//lineHeight = baseHeight;
for (int i = 0; i < charRanges.Length; i += 2)
{
uint start = charRanges[i];
uint end = charRanges[i + 1];
for (uint j = start; j <= end; j++)
for (int i = 0; i < charRanges.Length; i += 2)
{
lock (mutex)
uint start = charRanges[i];
uint end = charRanges[i + 1];
for (uint j = start; j <= end; j++)
{
uint glyphIndex = face.GetCharIndex(j);
if (glyphIndex == 0) continue;
@@ -231,113 +295,124 @@ namespace Barotrauma
for (int x = 0; x < glyphWidth; x++)
{
byte byteColor = bitmap[x + y * glyphWidth];
pixelBuffer[((int)currentCoords.X + x) + ((int)currentCoords.Y + y) * texDims] = (uint)(byteColor << 24 | byteColor << 16 | byteColor << 8 | byteColor);
pixelBuffer[((int)currentCoords.X + x) + ((int)currentCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
}
}
currentCoords.X += glyphWidth + 2;
}
CrossThread.RequestExecutionOnMainThread(() =>
{
textures[texIndex].SetData<uint>(pixelBuffer);
});
}
CrossThread.RequestExecutionOnMainThread(() =>
{
textures[texIndex].SetData<uint>(pixelBuffer);
});
}
}
public void DynamicRenderAtlas(GraphicsDevice gd, uint character, int texDims = 1024, uint baseChar = 0x54)
{
if (textures.Count == 0)
if (System.Threading.Thread.CurrentThread != GameMain.MainThread)
{
this.texDims = texDims;
this.baseChar = baseChar;
lock (mutex) { face.SetPixelSizes(0, size); }
face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
baseHeight = face.Glyph.Metrics.Height.ToInt32();
CrossThread.RequestExecutionOnMainThread(() =>
{
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
DynamicRenderAtlas(gd, character, texDims, baseChar);
});
}
uint glyphIndex = face.GetCharIndex(character);
if (glyphIndex == 0) { return; }
lock (mutex) { face.SetPixelSizes(0, size); }
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
{
if (face.Glyph.Metrics.HorizontalAdvance > 0)
{
//glyph is empty, but char still applies advance
GlyphData blankData = new GlyphData();
blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance;
blankData.texIndex = -1; //indicates no texture because the glyph is empty
texCoords.Add(character, blankData);
}
return;
}
//stacktrace doesn't really work that well when RenderGlyph throws an exception
face.Glyph.RenderGlyph(RenderMode.Normal);
byte[] bitmap = face.Glyph.Bitmap.BufferData;
int glyphWidth = face.Glyph.Bitmap.Width;
int glyphHeight = bitmap.Length / glyphWidth;
byte[] bitmap;
int glyphWidth; int glyphHeight;
Fixed26Dot6 horizontalAdvance;
Vector2 drawOffset;
if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
lock (mutex)
{
throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions");
}
currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2);
if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1)
{
currentDynamicAtlasCoords.X = 0;
currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY;
currentDynamicAtlasNextY = 0;
}
//no more room in current texture atlas, create a new one
if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1)
{
currentDynamicAtlasCoords.X = 0;
currentDynamicAtlasCoords.Y = 0;
currentDynamicAtlasNextY = 0;
CrossThread.RequestExecutionOnMainThread(() =>
if (texCoords.ContainsKey(character)) { return; }
if (textures.Count == 0)
{
this.texDims = texDims;
this.baseChar = baseChar;
face.SetPixelSizes(0, size);
face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
baseHeight = face.Glyph.Metrics.Height.ToInt32();
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
});
currentDynamicPixelBuffer = null;
}
GlyphData newData = new GlyphData
{
advance = (float)face.Glyph.Metrics.HorizontalAdvance,
texIndex = textures.Count - 1,
texCoords = new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop)
};
texCoords.Add(character, newData);
if (currentDynamicPixelBuffer == null)
{
currentDynamicPixelBuffer = new uint[texDims * texDims];
textures[newData.texIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
}
for (int y = 0; y < glyphHeight; y++)
{
for (int x = 0; x < glyphWidth; x++)
{
byte byteColor = bitmap[x + y * glyphWidth];
currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | byteColor << 16 | byteColor << 8 | byteColor);
}
}
CrossThread.RequestExecutionOnMainThread(() =>
{
textures[newData.texIndex].SetData<uint>(currentDynamicPixelBuffer);
});
currentDynamicAtlasCoords.X += glyphWidth + 2;
uint glyphIndex = face.GetCharIndex(character);
if (glyphIndex == 0) { return; }
face.SetPixelSizes(0, size);
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
{
if (face.Glyph.Metrics.HorizontalAdvance > 0)
{
//glyph is empty, but char still applies advance
GlyphData blankData = new GlyphData();
blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance;
blankData.texIndex = -1; //indicates no texture because the glyph is empty
texCoords.Add(character, blankData);
}
return;
}
//stacktrace doesn't really work that well when RenderGlyph throws an exception
face.Glyph.RenderGlyph(RenderMode.Normal);
bitmap = (byte[])face.Glyph.Bitmap.BufferData.Clone();
glyphWidth = face.Glyph.Bitmap.Width;
glyphHeight = bitmap.Length / glyphWidth;
horizontalAdvance = face.Glyph.Metrics.HorizontalAdvance;
drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop);
if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
{
throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions");
}
currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2);
if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1)
{
currentDynamicAtlasCoords.X = 0;
currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY;
currentDynamicAtlasNextY = 0;
}
//no more room in current texture atlas, create a new one
if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1)
{
currentDynamicAtlasCoords.X = 0;
currentDynamicAtlasCoords.Y = 0;
currentDynamicAtlasNextY = 0;
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
currentDynamicPixelBuffer = null;
}
GlyphData newData = new GlyphData
{
advance = (float)horizontalAdvance,
texIndex = textures.Count - 1,
texCoords = new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
drawOffset = drawOffset
};
texCoords.Add(character, newData);
if (currentDynamicPixelBuffer == null)
{
currentDynamicPixelBuffer = new uint[texDims * texDims];
textures[newData.texIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
}
for (int y = 0; y < glyphHeight; y++)
{
for (int x = 0; x < glyphWidth; x++)
{
byte byteColor = bitmap[x + y * glyphWidth];
currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
}
}
textures[newData.texIndex].SetData<uint>(currentDynamicPixelBuffer);
currentDynamicAtlasCoords.X += glyphWidth + 2;
}
}
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
@@ -359,7 +434,7 @@ namespace Barotrauma
}
uint charIndex = text[i];
if (DynamicLoading && !texCoords.ContainsKey(charIndex))
if (DynamicLoading)
{
DynamicRenderAtlas(graphicsDevice, charIndex);
}
@@ -400,7 +475,7 @@ namespace Barotrauma
}
uint charIndex = text[i];
if (DynamicLoading && !texCoords.ContainsKey(charIndex))
if (DynamicLoading)
{
DynamicRenderAtlas(graphicsDevice, charIndex);
}
@@ -416,7 +491,73 @@ namespace Barotrauma
}
}
}
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, List<ColorData> colorData)
{
DrawStringWithColors(sb, text, position, color, rotation, origin, new Vector2(scale), se, layerDepth, colorData);
}
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth, List<ColorData> colorData)
{
if (textures.Count == 0 && !DynamicLoading) { return; }
int lineNum = 0;
Vector2 currentPos = position;
Vector2 advanceUnit = rotation == 0.0f ? Vector2.UnitX : new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
int colorDataIndex = 0;
ColorData currentColorData = colorData[colorDataIndex];
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\n')
{
lineNum++;
currentPos = position;
currentPos.X -= baseHeight * 1.8f * lineNum * advanceUnit.Y * scale.Y;
currentPos.Y += baseHeight * 1.8f * lineNum * advanceUnit.X * scale.Y;
continue;
}
uint charIndex = text[i];
if (DynamicLoading && !texCoords.ContainsKey(charIndex))
{
DynamicRenderAtlas(graphicsDevice, charIndex);
}
Color currentTextColor;
if (currentColorData != null && i > currentColorData.EndIndex + lineNum)
{
colorDataIndex++;
currentColorData = colorDataIndex < colorData.Count ? colorData[colorDataIndex] : null;
}
if (currentColorData != null && currentColorData.StartIndex + lineNum <= i && i <= currentColorData.EndIndex + lineNum)
{
currentTextColor = currentColorData.Color;
}
else
{
currentTextColor = color;
}
if (texCoords.TryGetValue(charIndex, out GlyphData gd) || texCoords.TryGetValue(9633, out gd)) //9633 = white square
{
if (gd.texIndex >= 0)
{
Texture2D tex = textures[gd.texIndex];
Vector2 drawOffset;
drawOffset.X = gd.drawOffset.X * advanceUnit.X * scale.X - gd.drawOffset.Y * advanceUnit.Y * scale.Y;
drawOffset.Y = gd.drawOffset.X * advanceUnit.Y * scale.Y + gd.drawOffset.Y * advanceUnit.X * scale.X;
sb.Draw(tex, currentPos + drawOffset, gd.texCoords, currentTextColor, rotation, origin, scale, se, layerDepth);
}
currentPos += gd.advance * advanceUnit * scale.X;
}
}
}
public Vector2 MeasureString(string text)
{
if (text == null)
@@ -6,15 +6,19 @@ using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
class ChatBox
{
private static Sprite radioIcon;
public const string RadioChatString = "r; ";
private GUIListBox chatBox;
private Point screenResolution;
public readonly ChatManager ChatManager = new ChatManager();
public bool IsSinglePlayer { get; private set; }
private bool _toggleOpen = true;
@@ -23,17 +27,14 @@ namespace Barotrauma
get { return _toggleOpen; }
set
{
if (_toggleOpen == value) { return; }
_toggleOpen = GameMain.Config.ChatOpen = value;
foreach (GUIComponent child in ToggleButton.Children)
{
child.SpriteEffects = _toggleOpen == (HUDLayoutSettings.ChatBoxAlignment == Alignment.Right) ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
if (value) hideableElements.Visible = true;
}
}
private float openState;
public bool CloseAfterMessageSent;
private float prevUIScale;
//individual message texts that pop up when the chatbox is hidden
@@ -51,54 +52,66 @@ namespace Barotrauma
public GUITextBox InputBox { get; private set; }
public GUIButton ToggleButton { get; private set; }
public GUIButton ToggleButton;
private GUIButton showNewMessagesButton;
private GUIFrame hideableElements;
public const int ToggleButtonWidthRaw = 30;
private int popupMessageOffset;
public ChatBox(GUIComponent parent, bool isSinglePlayer)
{
this.IsSinglePlayer = isSinglePlayer;
if (radioIcon == null)
{
radioIcon = new Sprite("Content/UI/inventoryAtlas.png", new Rectangle(527, 952, 38, 52), null);
radioIcon.Origin = radioIcon.size / 2;
}
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
int toggleButtonWidth = (int)(30 * GUI.Scale);
int toggleButtonWidth = (int)(ToggleButtonWidthRaw * GUI.Scale);
GUIFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ChatBoxArea, parent.RectTransform), style: null);
var chatBoxHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.875f), GUIFrame.RectTransform), style: "ChatBox");
hideableElements = new GUIFrame(new RectTransform(Vector2.One, GUIFrame.RectTransform), style: null);
var chatBoxHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.875f), hideableElements.RectTransform), style: "ChatBox");
chatBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), chatBoxHolder.RectTransform, Anchor.CenterRight), style: null);
ToggleButton = new GUIButton(new RectTransform(new Point(toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Height), parent.RectTransform),
style: "UIToggleButton");
ToggleButton.OnClicked += (GUIButton btn, object userdata) =>
{
ToggleOpen = !ToggleOpen;
return true;
};
InputBox = new GUITextBox(new RectTransform(new Vector2(0.925f, 0.125f), GUIFrame.RectTransform, Anchor.BottomLeft),
InputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft),
style: "ChatTextBox")
{
OverflowClip = true,
Font = GUI.SmallFont,
MaxTextLength = ChatMessage.MaxLength
};
ChatManager.RegisterKeys(InputBox, ChatManager);
InputBox.OnDeselected += (gui, Keys) =>
{
ChatManager.Clear();
ChatMessage.GetChatMessageCommand(InputBox.Text, out var message);
if (string.IsNullOrEmpty(message))
{
if (CloseAfterMessageSent)
{
_toggleOpen = false;
CloseAfterMessageSent = false;
}
}
//gui.Text = "";
};
var chatSendButton = new GUIButton(new RectTransform(new Vector2(0.075f, 0.125f), GUIFrame.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.0f, -0.01f) }, ">");
var chatSendButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.7f), InputBox.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight), style: "GUIButtonToggleRight");
chatSendButton.OnClicked += (GUIButton btn, object userdata) =>
{
InputBox.OnEnterPressed(InputBox, InputBox.Text);
return true;
};
chatSendButton.RectTransform.AbsoluteOffset = new Point((int)(InputBox.Rect.Height * 0.15f), 0);
InputBox.TextBlock.RectTransform.MaxSize
= new Point((int)(InputBox.Rect.Width - chatSendButton.Rect.Width * 1.25f - InputBox.TextBlock.Padding.Z), int.MaxValue);
showNewMessagesButton = new GUIButton(new RectTransform(new Vector2(1f, 0.125f), GUIFrame.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0.0f, -0.125f) }, TextManager.Get("chat.shownewmessages"));
showNewMessagesButton = new GUIButton(new RectTransform(new Vector2(1f, 0.075f), GUIFrame.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0.0f, 0.125f) }, TextManager.Get("chat.shownewmessages"));
showNewMessagesButton.OnClicked += (GUIButton btn, object userdata) =>
{
chatBox.ScrollBar.BarScrollValue = 1f;
@@ -236,23 +249,32 @@ namespace Barotrauma
{
var popupMsg = new GUIFrame(new RectTransform(Vector2.One, GUIFrame.RectTransform), style: "GUIToolTip")
{
Visible = false
Visible = false,
CanBeFocused = false
};
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), popupMsg.RectTransform, Anchor.TopRight),
senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), popupMsg.RectTransform, Anchor.Center));
Vector2 senderTextSize = Vector2.Zero;
if (!string.IsNullOrEmpty(senderName))
{
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
senderName, textColor: senderColor, style: null, font: GUI.SmallFont)
{
CanBeFocused = false
};
senderTextSize = senderText.Font.MeasureString(senderText.WrappedText);
senderText.RectTransform.MinSize = new Point(0, senderText.Rect.Height);
}
var msgPopupText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.BottomLeft, style: null, wrap: true)
{
CanBeFocused = false
};
var msgPopupText = new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.0f), popupMsg.RectTransform, Anchor.TopRight)
{ AbsoluteOffset = new Point(0, senderText.Rect.Height) },
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.TopRight, style: null, wrap: true)
{
CanBeFocused = false
};
int textWidth = (int)Math.Max(
msgPopupText.Font.MeasureString(msgPopupText.WrappedText).X,
senderText.Font.MeasureString(senderText.WrappedText).X);
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgPopupText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
msgPopupText.RectTransform.MinSize = new Point(0, msgPopupText.Rect.Height);
Vector2 msgSize = msgPopupText.Font.MeasureString(msgPopupText.WrappedText);
int textWidth = (int)Math.Max(msgSize.X + msgPopupText.Padding.X + msgPopupText.Padding.Z, senderTextSize.X) + 10;
popupMsg.RectTransform.Resize(new Point((int)(textWidth / content.RectTransform.RelativeSize.X) , (int)((senderTextSize.Y + msgSize.Y) / content.RectTransform.RelativeSize.Y)), resizeChildren: true);
popupMsg.RectTransform.IsFixedSize = true;
content.Recalculate();
popupMessages.Enqueue(popupMsg);
}
@@ -271,6 +293,11 @@ namespace Barotrauma
GUI.PlayUISound(soundType);
}
public void SetVisibility(bool visible)
{
GUIFrame.Parent.Visible = visible;
}
private IEnumerable<object> UpdateMessageAnimation(GUIComponent message, float animDuration)
{
float timer = 0.0f;
@@ -294,18 +321,11 @@ namespace Barotrauma
HUDLayoutSettings.ChatBoxArea.Y / (float)GameMain.GraphicsHeight);
GUIFrame.RectTransform.NonScaledSize = HUDLayoutSettings.ChatBoxArea.Size;
int toggleButtonWidth = (int)(30 * GUI.Scale);
//make room for the toggle button
if (HUDLayoutSettings.ChatBoxAlignment == Alignment.Left)
{
GUIFrame.RectTransform.AbsoluteOffset += new Point(toggleButtonWidth, 0);
}
int toggleButtonWidth = (int)(ToggleButtonWidthRaw * GUI.Scale);
GUIFrame.RectTransform.NonScaledSize -= new Point(toggleButtonWidth, 0);
GUIFrame.RectTransform.AbsoluteOffset += new Point(toggleButtonWidth, 0);
ToggleButton.RectTransform.NonScaledSize = new Point(toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Height);
ToggleButton.RectTransform.AbsoluteOffset = HUDLayoutSettings.ChatBoxAlignment == Alignment.Left ?
new Point(HUDLayoutSettings.ChatBoxArea.X, HUDLayoutSettings.ChatBoxArea.Y) :
new Point(HUDLayoutSettings.ChatBoxArea.Right - toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Y);
popupMessageOffset = GameMain.GameSession.CrewManager.ReportButtonFrame.Rect.Width + GUIFrame.Rect.Width + (int)(20 * GUI.Scale);
}
public void Update(float deltaTime)
@@ -317,12 +337,28 @@ namespace Barotrauma
prevUIScale = GUI.Scale;
}
//hide chatbox when accessing the inventory of another character to prevent overlaps
if (Character.Controlled?.SelectedCharacter?.Inventory != null &&
Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
{
SetVisibility(false);
}
else
{
SetVisibility(true);
}
if (showNewMessagesButton.Visible && chatBox.ScrollBar.BarScroll == 1f)
{
showNewMessagesButton.Visible = false;
}
if (ToggleOpen || (InputBox != null && InputBox.Selected))
if (ToggleButton != null)
{
ToggleButton.RectTransform.AbsoluteOffset = new Point(GUIFrame.Rect.Right, GUIFrame.Rect.Y + HUDLayoutSettings.ChatBoxArea.Height - ToggleButton.Rect.Height);
}
if (ToggleOpen)
{
openState += deltaTime * 5.0f;
//delete all popup messages when the chatbox is open
@@ -340,7 +376,6 @@ namespace Barotrauma
var popupMsg = popupMessages.Count > 0 ? popupMessages.Peek() : null;
if (popupMsg != null)
{
int offset = -popupMsg.Rect.Width - ToggleButton.Rect.Width * 2 - (int)(50 * GUI.Scale) - (GUIFrame.Rect.X - GameMain.GraphicsWidth);
popupMsg.Visible = true;
//popup messages appear and disappear faster when there's more pending messages
popupMessageTimer += deltaTime * popupMessages.Count * popupMessages.Count;
@@ -348,7 +383,7 @@ namespace Barotrauma
{
//move the message out of the screen and delete it
popupMsg.RectTransform.ScreenSpaceOffset =
new Point((int)MathHelper.SmoothStep(offset, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
new Point((int)MathHelper.SmoothStep(popupMessageOffset, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
if (popupMessageTimer > PopupMessageDuration + 1.0f)
{
popupMessageTimer = 0.0f;
@@ -359,15 +394,16 @@ namespace Barotrauma
else
{
//move the message on the screen
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
(int)MathHelper.SmoothStep(0, offset, popupMessageTimer * 5.0f), 0);
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
(int)MathHelper.SmoothStep(0, popupMessageOffset, popupMessageTimer * 5.0f), 0);
}
}
}
openState = MathHelper.Clamp(openState, 0.0f, 1.0f);
int hiddenBoxOffset = GUIFrame.Rect.Width + ToggleButton.Rect.Width;
int hiddenBoxOffset = -(GUIFrame.Rect.Width);
GUIFrame.RectTransform.AbsoluteOffset =
new Point((int)MathHelper.SmoothStep(hiddenBoxOffset * (HUDLayoutSettings.ChatBoxAlignment == Alignment.Left ? -1 : 1), 0, openState), 0);
new Point((int)MathHelper.SmoothStep(hiddenBoxOffset, 0, openState), 0);
hideableElements.Visible = openState > 0.0f;
}
}
}
@@ -0,0 +1,176 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma
{
public enum TransitionMode
{
Linear,
Smooth,
Smoother,
EaseIn,
EaseOut,
Exponential
}
public enum SpriteFallBackState
{
None,
Hover,
Pressed,
Selected,
HoverSelected,
Toggle
}
public class GUIComponentStyle
{
public readonly Vector4 Padding;
public readonly Color Color;
public readonly Color HoverColor;
public readonly Color SelectedColor;
public readonly Color PressedColor;
public readonly Color DisabledColor;
public readonly Color TextColor;
public readonly Color HoverTextColor;
public readonly Color SelectedTextColor;
public readonly Color DisabledTextColor;
public readonly float SpriteCrossFadeTime;
public readonly float ColorCrossFadeTime;
public readonly TransitionMode TransitionMode;
public readonly string Font;
public readonly bool ForceUpperCase;
public readonly Color OutlineColor;
public readonly XElement Element;
public readonly Dictionary<GUIComponent.ComponentState, List<UISprite>> Sprites;
public SpriteFallBackState FallBackState;
public Dictionary<string, GUIComponentStyle> ChildStyles;
public readonly GUIStyle Style;
public readonly string Name;
public int? Width { get; private set; }
public int? Height { get; private set; }
public GUIComponentStyle(XElement element, GUIStyle style)
{
Name = element.Name.LocalName;
Style = style;
Element = element;
Sprites = new Dictionary<GUIComponent.ComponentState, List<UISprite>>();
foreach (GUIComponent.ComponentState state in Enum.GetValues(typeof(GUIComponent.ComponentState)))
{
Sprites[state] = new List<UISprite>();
}
ChildStyles = new Dictionary<string, GUIComponentStyle>();
Padding = element.GetAttributeVector4("padding", Vector4.Zero);
Color = element.GetAttributeColor("color", Color.Transparent);
HoverColor = element.GetAttributeColor("hovercolor", Color);
SelectedColor = element.GetAttributeColor("selectedcolor", Color);
DisabledColor = element.GetAttributeColor("disabledcolor", Color);
PressedColor = element.GetAttributeColor("pressedcolor", Color);
OutlineColor = element.GetAttributeColor("outlinecolor", Color.Transparent);
TextColor = element.GetAttributeColor("textcolor", Color.Black);
HoverTextColor = element.GetAttributeColor("hovertextcolor", TextColor);
DisabledTextColor = element.GetAttributeColor("disabledtextcolor", TextColor);
SelectedTextColor = element.GetAttributeColor("selectedtextcolor", TextColor);
SpriteCrossFadeTime = element.GetAttributeFloat("spritefadetime", SpriteCrossFadeTime);
ColorCrossFadeTime = element.GetAttributeFloat("colorfadetime", ColorCrossFadeTime);
if (Enum.TryParse(element.GetAttributeString("colortransition", string.Empty), ignoreCase: true, out TransitionMode transition))
{
TransitionMode = transition;
}
if (Enum.TryParse(element.GetAttributeString("fallbackstate", GUIComponent.ComponentState.None.ToString()), ignoreCase: true, out SpriteFallBackState s))
{
FallBackState = s;
}
Font = element.GetAttributeString("font", "");
ForceUpperCase = element.GetAttributeBool("forceuppercase", false);
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sprite":
UISprite newSprite = new UISprite(subElement);
GUIComponent.ComponentState spriteState = GUIComponent.ComponentState.None;
if (subElement.Attribute("state") != null)
{
string stateStr = subElement.GetAttributeString("state", "None");
Enum.TryParse(stateStr, out spriteState);
Sprites[spriteState].Add(newSprite);
//use the same sprite for Hover and HoverSelected if latter is not specified
if (spriteState == GUIComponent.ComponentState.HoverSelected && !Sprites.ContainsKey(GUIComponent.ComponentState.HoverSelected))
{
Sprites[GUIComponent.ComponentState.HoverSelected].Add(newSprite);
}
}
else
{
foreach (GUIComponent.ComponentState state in Enum.GetValues(typeof(GUIComponent.ComponentState)))
{
Sprites[state].Add(newSprite);
}
}
break;
case "size":
break;
default:
string styleName = subElement.Name.ToString().ToLowerInvariant();
if (ChildStyles.ContainsKey(styleName))
{
DebugConsole.ThrowError("UI style \"" + element.Name.ToString() + "\" contains multiple child styles with the same name (\"" + styleName + "\")!");
ChildStyles[styleName] = new GUIComponentStyle(subElement, style);
}
else
{
ChildStyles.Add(styleName, new GUIComponentStyle(subElement, style));
}
break;
}
}
GetSize(element);
}
public void GetSize(XElement element)
{
Point size = new Point(0, 0);
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{
size = new Point(
subElement.GetAttributeInt("width", 0),
subElement.GetAttributeInt("height", 0));
break;
}
}
if (size.X > 0) { Width = size.X; }
if (size.Y > 0) { Height = size.Y; }
}
}
}
@@ -0,0 +1,405 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Barotrauma
{
public static class FileSelection
{
private static bool open;
public static bool Open
{
get
{
return open;
}
set
{
if (value && backgroundFrame == null) { Init(); }
if (!value)
{
fileSystemWatcher?.Dispose();
fileSystemWatcher = null;
}
open = value;
}
}
private static GUIFrame backgroundFrame;
private static GUIFrame window;
private static GUIListBox sidebar;
private static GUIListBox fileList;
private static GUITextBox directoryBox;
private static GUITextBox filterBox;
private static GUITextBox fileBox;
private static GUIDropDown fileTypeDropdown;
private static GUIButton openButton;
private static FileSystemWatcher fileSystemWatcher;
private static string currentFileTypePattern;
private static readonly string[] ignoredDrivePrefixes = new string[]
{
"/sys/", "/snap/"
};
private static string currentDirectory;
public static string CurrentDirectory
{
get
{
return currentDirectory;
}
set
{
string[] dirSplit = value.Replace('\\', '/').Split('/');
List<string> dirs = new List<string>();
for (int i = 0; i < dirSplit.Length; i++)
{
if (dirSplit[i].Trim() == "..")
{
if (dirs.Count > 1)
{
dirs.RemoveAt(dirs.Count - 1);
}
}
else if (dirSplit[i].Trim() != ".")
{
dirs.Add(dirSplit[i]);
}
}
currentDirectory = string.Join("/", dirs);
if (!currentDirectory.EndsWith("/"))
{
currentDirectory += "/";
}
fileSystemWatcher?.Dispose();
fileSystemWatcher = new FileSystemWatcher(currentDirectory)
{
Filter = "*",
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
};
fileSystemWatcher.Created += OnFileSystemChanges;
fileSystemWatcher.Deleted += OnFileSystemChanges;
fileSystemWatcher.Renamed += OnFileSystemChanges;
fileSystemWatcher.EnableRaisingEvents = true;
RefreshFileList();
}
}
public static Action<string> OnFileSelected
{
get;
set;
}
private static void OnFileSystemChanges(object sender, FileSystemEventArgs e)
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Created:
{
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), e.Name)
{
UserData = (bool?)Directory.Exists(e.FullPath)
};
if ((itemFrame.UserData as bool?) ?? false)
{
itemFrame.Text += "/";
}
fileList.Content.RectTransform.SortChildren(SortFiles);
}
break;
case WatcherChangeTypes.Deleted:
{
var itemFrame = fileList.Content.FindChild(c => (c is GUITextBlock tb) && (tb.Text == e.Name || tb.Text == e.Name + "/"));
if (itemFrame != null) { fileList.RemoveChild(itemFrame); }
}
break;
case WatcherChangeTypes.Renamed:
{
RenamedEventArgs renameArgs = e as RenamedEventArgs;
var itemFrame = fileList.Content.FindChild(c => (c is GUITextBlock tb) && (tb.Text == renameArgs.OldName || tb.Text == renameArgs.OldName + "/")) as GUITextBlock;
itemFrame.UserData = (bool?)Directory.Exists(e.FullPath);
itemFrame.Text = renameArgs.Name;
if ((itemFrame.UserData as bool?) ?? false)
{
itemFrame.Text += "/";
}
fileList.Content.RectTransform.SortChildren(SortFiles);
}
break;
}
}
private static int SortFiles(RectTransform r1, RectTransform r2)
{
string file1 = (r1.GUIComponent as GUITextBlock)?.Text ?? "";
string file2 = (r2.GUIComponent as GUITextBlock)?.Text ?? "";
bool dir1 = (r1.GUIComponent.UserData as bool?) ?? false;
bool dir2 = (r2.GUIComponent.UserData as bool?) ?? false;
if (dir1 && !dir2)
{
return -1;
}
else if (!dir1 && dir2)
{
return 1;
}
return string.Compare(file1, file2);
}
public static void Init()
{
backgroundFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
{
Color = Color.Black * 0.5f,
HoverColor = Color.Black * 0.5f,
SelectedColor = Color.Black * 0.5f,
PressedColor = Color.Black * 0.5f,
};
window = new GUIFrame(new RectTransform(Vector2.One * 0.8f, backgroundFrame.RectTransform, Anchor.Center));
var horizontalLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.9f, window.RectTransform, Anchor.Center), true);
sidebar = new GUIListBox(new RectTransform(new Vector2(0.29f, 1.0f), horizontalLayout.RectTransform));
var drives = DriveInfo.GetDrives();
foreach (var drive in drives)
{
if (drive.DriveType == DriveType.Ram) { continue; }
if (ignoredDrivePrefixes.Any(p => drive.Name.StartsWith(p))) { continue; }
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), sidebar.Content.RectTransform), drive.Name.Replace('\\','/'));
}
sidebar.OnSelected = (child, userdata) =>
{
CurrentDirectory = (child as GUITextBlock).Text;
return false;
};
//spacing between sidebar and fileListLayout
new GUIFrame(new RectTransform(new Vector2(0.01f, 1.0f), horizontalLayout.RectTransform), style: null);
var fileListLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 1.0f), horizontalLayout.RectTransform));
var firstRow = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), fileListLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUIButton(new RectTransform(new Vector2(0.05f, 1.0f), firstRow.RectTransform), "^")
{
OnClicked = MoveToParentDirectory
};
directoryBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1.0f), firstRow.RectTransform))
{
OverflowClip = true,
OnEnterPressed = (tb, txt) =>
{
if (Directory.Exists(txt))
{
CurrentDirectory = txt;
return true;
}
else
{
tb.Text = CurrentDirectory;
return false;
}
}
};
filterBox = new GUITextBox(new RectTransform(new Vector2(0.25f, 1.0f), firstRow.RectTransform))
{
OverflowClip = true
};
firstRow.RectTransform.MinSize = new Point(0, firstRow.RectTransform.Children.Max(c => c.MinSize.Y));
filterBox.OnTextChanged += (txtbox, txt) =>
{
RefreshFileList();
return true;
};
//spacing between rows
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), fileListLayout.RectTransform), style: null);
fileList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.85f), fileListLayout.RectTransform))
{
OnSelected = (child, userdata) =>
{
if (userdata == null) { return false; }
var fileName = (child as GUITextBlock).Text;
fileBox.Text = fileName;
if (PlayerInput.DoubleClicked())
{
bool isDir = (userdata as bool?).Value;
if (isDir)
{
CurrentDirectory += fileName;
}
else
{
OnFileSelected?.Invoke(CurrentDirectory + fileName);
Open = false;
}
}
return true;
}
};
//spacing between rows
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), fileListLayout.RectTransform), style: null);
var thirdRow = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), fileListLayout.RectTransform), true);
fileBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1.0f), thirdRow.RectTransform))
{
OnEnterPressed = (tb, txt) => openButton?.OnClicked?.Invoke(openButton, null) ?? false
};
fileTypeDropdown = new GUIDropDown(new RectTransform(new Vector2(0.3f, 1.0f), thirdRow.RectTransform), dropAbove: true)
{
OnSelected = (child, userdata) =>
{
currentFileTypePattern = (child as GUITextBlock).UserData as string;
RefreshFileList();
return true;
}
};
fileTypeDropdown.Select(4);
//spacing between rows
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), fileListLayout.RectTransform), style: null);
var fourthRow = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), fileListLayout.RectTransform), true);
//padding for open/cancel buttons
new GUIFrame(new RectTransform(new Vector2(0.7f, 1.0f), fourthRow.RectTransform), style: null);
openButton = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), fourthRow.RectTransform), TextManager.Get("opensubbutton"))
{
OnClicked = (btn, obj) =>
{
if (Directory.Exists(Path.Combine(CurrentDirectory, fileBox.Text)))
{
CurrentDirectory += fileBox.Text;
}
if (!File.Exists(CurrentDirectory + fileBox.Text)) { return false; }
OnFileSelected?.Invoke(CurrentDirectory + fileBox.Text);
Open = false;
return false;
}
};
new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), fourthRow.RectTransform), TextManager.Get("cancel"))
{
OnClicked = (btn, obj) =>
{
Open = false;
return false;
}
};
CurrentDirectory = Directory.GetCurrentDirectory();
}
public static void ClearFileTypeFilters()
{
if (backgroundFrame == null) { Init(); }
fileTypeDropdown.ClearChildren();
}
public static void AddFileTypeFilter(string name, string pattern)
{
if (backgroundFrame == null) { Init(); }
fileTypeDropdown.AddItem(name + " (" + pattern + ")", pattern);
}
public static void SelectFileTypeFilter(string pattern)
{
if (backgroundFrame == null) { Init(); }
fileTypeDropdown.SelectItem(pattern);
}
public static void RefreshFileList()
{
fileList.Content.ClearChildren();
fileList.BarScroll = 0.0f;
try
{
var directories = Directory.EnumerateDirectories(currentDirectory, "*" + filterBox.Text + "*");
foreach (var directory in directories)
{
string txt = directory;
if (txt.StartsWith(currentDirectory)) { txt = txt.Substring(currentDirectory.Length); }
if (!txt.EndsWith("/")) { txt += "/"; }
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), txt)
{
UserData = (bool?)true
};
var folderIcon = new GUIImage(new RectTransform(new Point((int)(itemFrame.Rect.Height * 0.8f)), itemFrame.RectTransform, Anchor.CenterLeft)
{
AbsoluteOffset = new Point((int)(itemFrame.Rect.Height * 0.25f), 0)
}, style: "OpenButton", scaleToFit: true);
itemFrame.Padding = new Vector4(folderIcon.Rect.Width * 1.5f, itemFrame.Padding.Y, itemFrame.Padding.Z, itemFrame.Padding.W);
}
IEnumerable<string> files = null;
foreach (string pattern in currentFileTypePattern.Split(','))
{
string patternTrimmed = pattern.Trim();
patternTrimmed = "*" + filterBox.Text + "*" + patternTrimmed;
if (files == null)
{
files = Directory.EnumerateFiles(currentDirectory, patternTrimmed);
}
else
{
files = files.Concat(Directory.EnumerateFiles(currentDirectory, patternTrimmed));
}
}
foreach (var file in files)
{
string txt = file;
if (txt.StartsWith(currentDirectory)) { txt = txt.Substring(currentDirectory.Length); }
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), txt)
{
UserData = (bool?)false
};
}
}
catch (Exception e)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), "Could not list items in directory: " + e.Message)
{
CanBeFocused = false
};
}
directoryBox.Text = currentDirectory;
fileBox.Text = "";
fileList.Deselect();
}
public static bool MoveToParentDirectory(GUIButton button, object userdata)
{
string dir = CurrentDirectory;
if (dir.EndsWith("/")) { dir = dir.Substring(0, dir.Length - 1); }
int index = dir.LastIndexOf("/");
if (index < 0) { return false; }
CurrentDirectory = CurrentDirectory.Substring(0, index+1);
return false;
}
public static void AddToGUIUpdateList()
{
if (!Open) { return; }
backgroundFrame?.AddToGUIUpdateList();
}
}
}
@@ -1,15 +1,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.CharacterEditor;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Barotrauma.Sounds;
using Barotrauma.Tutorials;
using EventInput;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -24,11 +28,23 @@ namespace Barotrauma
PickItemFail,
DropItem
}
public enum CursorState
{
Default, // Cursor
Hand, // Hand with a finger
Move, // arrows pointing to all directions
IBeam, // Text
Dragging,// Closed hand
Waiting, // Hourglass
WaitingBackground // Cursor + Hourglass
}
public static class GUI
{
public static GUICanvas Canvas => GUICanvas.Instance;
public static CursorState MouseCursor = CursorState.Default;
public static readonly SamplerState SamplerState = new SamplerState()
{
Filter = TextureFilter.Linear,
@@ -62,43 +78,44 @@ namespace Barotrauma
public static readonly string[] rectComponentLabels = { "X", "Y", "W", "H" };
public static readonly string[] colorComponentLabels = { "R", "G", "B", "A" };
public static float Scale
{
get { return (GameMain.GraphicsWidth / 1920.0f + GameMain.GraphicsHeight / 1080.0f) / 2.0f * GameSettings.HUDScale; }
}
public static Vector2 ReferenceResolution => new Vector2(1920f, 1080f);
public static float Scale => (GameMain.GraphicsWidth / ReferenceResolution.X + GameMain.GraphicsHeight / ReferenceResolution.Y) / 2.0f * GameSettings.HUDScale;
public static float xScale => GameMain.GraphicsWidth / ReferenceResolution.X * GameSettings.HUDScale;
public static float yScale => GameMain.GraphicsHeight / ReferenceResolution.Y * GameSettings.HUDScale;
public static float HorizontalAspectRatio => GameMain.GraphicsWidth / (float)GameMain.GraphicsHeight;
public static float VerticalAspectRatio => GameMain.GraphicsHeight / (float)GameMain.GraphicsWidth;
public static float RelativeHorizontalAspectRatio => HorizontalAspectRatio / (ReferenceResolution.X / ReferenceResolution.Y);
public static float RelativeVerticalAspectRatio => VerticalAspectRatio / (ReferenceResolution.Y / ReferenceResolution.X);
public static float xScale
public static float SlicedSpriteScale
{
get { return GameMain.GraphicsWidth / 1920.0f * GameSettings.HUDScale; }
}
public static float yScale
{
get { return GameMain.GraphicsHeight / 1080.0f * GameSettings.HUDScale; }
get
{
if (Math.Abs(1.0f - Scale) < 0.1f)
{
//don't scale if very close to the "reference resolution"
return 1.0f;
}
return Scale;
}
}
public static GUIStyle Style;
private static Texture2D t;
private static Sprite Cursor => Style.CursorSprite;
private static Sprite[] MouseCursorSprites => Style.CursorSprite;
private static bool debugDrawSounds, debugDrawEvents;
private static GraphicsDevice graphicsDevice;
public static GraphicsDevice GraphicsDevice
{
get
{
return graphicsDevice;
}
}
public static GraphicsDevice GraphicsDevice { get; private set; }
private static List<GUIMessage> messages = new List<GUIMessage>();
private static Sound[] sounds;
private static bool pauseMenuOpen, settingsMenuOpen;
public static GUIFrame PauseMenu { get; private set; }
private static Sprite arrow, lockIcon, checkmarkIcon, timerIcon;
private static Sprite arrow;
public static bool HideCursor;
public static KeyboardDispatcher KeyboardDispatcher { get; set; }
@@ -108,15 +125,20 @@ namespace Barotrauma
public static bool ScreenChanged;
public static ScalableFont Font => Style?.Font;
// Usable in CJK as a regular font
public static ScalableFont GlobalFont => Style?.GlobalFont;
public static ScalableFont UnscaledSmallFont => Style?.UnscaledSmallFont;
public static ScalableFont SmallFont => Style?.SmallFont;
public static ScalableFont LargeFont => Style?.LargeFont;
public static ScalableFont VideoTitleFont => Style?.VideoTitleFont;
public static ScalableFont ObjectiveTitleFont => Style?.ObjectiveTitleFont;
public static ScalableFont ObjectiveNameFont => Style?.ObjectiveNameFont;
public static ScalableFont SubHeadingFont => Style?.SubHeadingFont;
public static ScalableFont DigitalFont => Style?.DigitalFont;
public static ScalableFont HotkeyFont => Style?.HotkeyFont;
public static ScalableFont CJKFont { get; private set; }
public static UISprite UIGlow => Style.UIGlow;
public static UISprite UIGlowCircular => Style.UIGlowCircular;
public static Sprite SubmarineIcon
{
@@ -141,21 +163,6 @@ namespace Barotrauma
get { return arrow; }
}
public static Sprite CheckmarkIcon
{
get { return checkmarkIcon; }
}
public static Sprite LockIcon
{
get { return lockIcon; }
}
public static Sprite TimerIcon
{
get { return timerIcon; }
}
public static bool SettingsMenuOpen
{
get { return settingsMenuOpen; }
@@ -184,13 +191,13 @@ namespace Barotrauma
public static void Init(GameWindow window, IEnumerable<ContentPackage> selectedContentPackages, GraphicsDevice graphicsDevice)
{
GUI.graphicsDevice = graphicsDevice;
GraphicsDevice = graphicsDevice;
var files = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle);
XElement selectedStyle = null;
foreach (var file in files)
{
XDocument doc = XMLExtensions.TryLoadXml(file);
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc == null) { continue; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
@@ -198,7 +205,7 @@ namespace Barotrauma
mainElement = doc.Root.FirstElement();
if (selectedStyle != null)
{
DebugConsole.NewMessage($"Overriding the ui styles with '{file}'", Color.Yellow);
DebugConsole.NewMessage($"Overriding the ui styles with '{file.Path}'", Color.Yellow);
}
}
else if (selectedStyle != null)
@@ -247,13 +254,10 @@ namespace Barotrauma
t.SetData(new Color[] { Color.White });// fill the texture with white
});
SubmarineIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(452, 385, 182, 81), new Vector2(0.5f, 0.5f));
arrow = new Sprite("Content/UI/IconAtlas.png", new Rectangle(392, 393, 49, 45), new Vector2(0.5f, 0.5f));
SpeechBubbleIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(385, 449, 66, 60), new Vector2(0.5f, 0.5f));
BrokenIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(898, 386, 123, 123), new Vector2(0.5f, 0.5f));
lockIcon = new Sprite("Content/UI/UI_Atlas.png", new Rectangle(996, 677, 21, 25), new Vector2(0.5f, 0.5f));
checkmarkIcon = new Sprite("Content/UI/UI_Atlas.png", new Rectangle(932, 398, 33, 28), new Vector2(0.5f, 0.5f));
timerIcon = new Sprite("Content/UI/UI_Atlas.png", new Rectangle(997, 653, 18, 21), new Vector2(0.5f, 0.5f));
SubmarineIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(452, 385, 182, 81), new Vector2(0.5f, 0.5f));
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(392, 393, 49, 45), new Vector2(0.5f, 0.5f));
SpeechBubbleIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(385, 449, 66, 60), new Vector2(0.5f, 0.5f));
BrokenIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(898, 386, 123, 123), new Vector2(0.5f, 0.5f));
}
/// <summary>
@@ -279,12 +283,50 @@ namespace Barotrauma
ScreenOverlayColor, true);
}
#if UNSTABLE
string line1 = "Barotrauma Unstable v" + GameMain.Version;
string line2 = "(" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")";
Rectangle watermarkRect = new Rectangle(-50, GameMain.GraphicsHeight - 80, 50 + (int)(Math.Max(LargeFont.MeasureString(line1).X, Font.MeasureString(line2).X) * 1.2f), 100);
float alpha = 1.0f;
int yOffset = 0;
if (Screen.Selected == GameMain.GameScreen)
{
yOffset = -HUDLayoutSettings.ChatBoxArea.Height;
watermarkRect.Y += yOffset;
}
if (Screen.Selected == GameMain.GameScreen || Screen.Selected == GameMain.SubEditorScreen)
{
alpha = 0.2f;
}
Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw(
spriteBatch, watermarkRect, Color.Black * 0.8f * alpha);
LargeFont.DrawString(spriteBatch, line1,
new Vector2(10, GameMain.GraphicsHeight - 30 - LargeFont.MeasureString(line1).Y + yOffset), Color.White * 0.6f * alpha);
Font.DrawString(spriteBatch, line2,
new Vector2(10, GameMain.GraphicsHeight - 30 + yOffset), Color.White * 0.6f * alpha);
if (Screen.Selected != GameMain.GameScreen)
{
var buttonRect =
new Rectangle(20 + (int)Math.Max(LargeFont.MeasureString(line1).X, Font.MeasureString(line2).X), GameMain.GraphicsHeight - (int)(45 * Scale) + yOffset, (int)(150 * Scale), (int)(40 * Scale));
if (DrawButton(spriteBatch, buttonRect, "Report Bug", Style.GetComponentStyle("GUIBugButton").Color * 0.8f))
{
GameMain.Instance.ShowBugReporter();
}
}
#endif
if (DisableHUD) { return; }
if (GameMain.ShowFPS || GameMain.DebugDraw)
{
DrawString(spriteBatch, new Vector2(10, 10),
"FPS: " + (int)GameMain.PerformanceCounter.AverageFramesPerSecond,
"FPS: " + Math.Round(GameMain.PerformanceCounter.AverageFramesPerSecond),
Color.White, Color.Black * 0.5f, 0, SmallFont);
}
@@ -294,9 +336,9 @@ namespace Barotrauma
DrawString(spriteBatch, new Vector2(300, y),
"Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" +
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
Color.Green, Color.Black * 0.8f, font: SmallFont);
GUI.Style.Green, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.Green);
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, GUI.Style.Green);
y += 50;
DrawString(spriteBatch, new Vector2(300, y),
@@ -305,26 +347,26 @@ namespace Barotrauma
Color.LightBlue, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.LightBlue);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), 20, 0, Color.Red);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), 20, 0, GUI.Style.Red);
y += 50;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
{
float elapsedMillisecs = GameMain.PerformanceCounter.GetAverageElapsedMillisecs(key);
DrawString(spriteBatch, new Vector2(300, y),
key + ": " + elapsedMillisecs.ToString("0.00"),
Color.Lerp(Color.LightGreen, Color.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, SmallFont);
Color.Lerp(Color.LightGreen, GUI.Style.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, SmallFont);
y += 15;
}
if (FarseerPhysics.Settings.EnableDiagnostics)
if (Settings.EnableDiagnostics)
{
DrawString(spriteBatch, new Vector2(320, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.ContinuousPhysicsTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 15), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.ControllersUpdateTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 30), "AddRemoveTime: " + GameMain.World.AddRemoveTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.AddRemoveTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 45), "NewContactsTime: " + GameMain.World.NewContactsTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.NewContactsTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 60), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.ContactsUpdateTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 75), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime, Color.Lerp(Color.LightGreen, Color.Red, GameMain.World.SolveUpdateTime / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.ContinuousPhysicsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 15), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 30), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.AddRemoveTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 45), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.NewContactsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 60), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.ContactsUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(320, y + 75), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont);
}
}
@@ -335,7 +377,7 @@ namespace Barotrauma
Color.White, Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(10, 40),
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.FindAll(b => b.Awake && b.Enabled).Count} awake, {GameMain.World.BodyList.FindAll(b => b.Awake && b.BodyType == FarseerPhysics.Dynamics.BodyType.Dynamic && b.Enabled).Count} dynamic)",
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.FindAll(b => b.Awake && b.Enabled).Count} awake, {GameMain.World.BodyList.FindAll(b => b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled).Count} dynamic)",
Color.White, Color.Black * 0.5f, 0, SmallFont);
if (Screen.Selected.Cam != null)
@@ -354,7 +396,7 @@ namespace Barotrauma
DrawString(spriteBatch, new Vector2(10, 90),
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
Color.Lerp(Color.Green, Color.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, SmallFont);
Color.Lerp(GUI.Style.Green, GUI.Style.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(10, 115),
"Loaded sprites: " + Sprite.LoadedSprites.Count() + "\n(" + Sprite.LoadedSprites.Select(s => s.FilePath).Distinct().Count() + " unique textures)",
@@ -393,10 +435,10 @@ namespace Barotrauma
}
else
{
soundStr += System.IO.Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename);
soundStr += Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename);
#if DEBUG
if (PlayerInput.GetKeyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.G))
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.G))
{
if (PlayerInput.MousePosition.Y >= y && PlayerInput.MousePosition.Y <= y + 12)
{
@@ -437,10 +479,6 @@ namespace Barotrauma
"Ctrl+S to show sound debug info", Color.White, Color.Black * 0.5f, 0, SmallFont);
}
if (PlayerInput.KeyDown(Keys.LeftControl) && PlayerInput.KeyHit(Keys.S))
{
debugDrawSounds = !debugDrawSounds;
}
if (debugDrawEvents)
{
@@ -453,13 +491,12 @@ namespace Barotrauma
DrawString(spriteBatch, new Vector2(10, 300),
"Ctrl+E to show EventManager debug info", Color.White, Color.Black * 0.5f, 0, SmallFont);
}
if (PlayerInput.KeyDown(Keys.LeftControl) && PlayerInput.KeyHit(Keys.E))
{
debugDrawEvents = !debugDrawEvents;
}
if (MouseOn != null)
{
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 500, 20), $"Selected UI Element: {MouseOn.GetType().ToString()}", Color.LightGreen, Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 500, 20),
$"Selected UI Element: {MouseOn.GetType().Name} ({ (MouseOn.Style?.Element.Name.LocalName ?? "no style") }, {MouseOn.Rect})",
Color.LightGreen, Color.Black * 0.5f, 0, SmallFont);
}
}
@@ -482,17 +519,21 @@ namespace Barotrauma
MouseOn.DrawToolTip(spriteBatch);
}
if (GameMain.WindowActive)
if (GameMain.WindowActive && !HideCursor)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
Cursor.Draw(spriteBatch, PlayerInput.LatestMousePosition, 0, Scale / 2f);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
var sprite = MouseCursorSprites[(int) MouseCursor] ?? MouseCursorSprites[(int)CursorState.Default];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
HideCursor = false;
}
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, float blurAmount = 1.0f, float aberrationStrength = 1.0f)
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, float aberrationStrength = 1.0f)
{
double aberrationT = (Timing.TotalTime * 0.5f);
GameMain.GameScreen.PostProcessEffect.Parameters["blurDistance"].SetValue(0.001f * aberrationStrength);
@@ -522,15 +563,15 @@ namespace Barotrauma
}
#region Update list
private static List<GUIComponent> updateList = new List<GUIComponent>();
private static readonly List<GUIComponent> updateList = new List<GUIComponent>();
//essentially a copy of the update list, used as an optimization to quickly check if the component is present in the update list
private static HashSet<GUIComponent> updateListSet = new HashSet<GUIComponent>();
private static Queue<GUIComponent> removals = new Queue<GUIComponent>();
private static Queue<GUIComponent> additions = new Queue<GUIComponent>();
private static readonly HashSet<GUIComponent> updateListSet = new HashSet<GUIComponent>();
private static readonly Queue<GUIComponent> removals = new Queue<GUIComponent>();
private static readonly Queue<GUIComponent> additions = new Queue<GUIComponent>();
// A helpers list for all elements that have a draw order less than 0.
private static List<GUIComponent> first = new List<GUIComponent>();
private static readonly List<GUIComponent> first = new List<GUIComponent>();
// A helper list for all elements that have a draw order greater than 0.
private static List<GUIComponent> last = new List<GUIComponent>();
private static readonly List<GUIComponent> last = new List<GUIComponent>();
/// <summary>
/// Adds the component on the addition queue.
@@ -700,25 +741,244 @@ namespace Barotrauma
GUIComponent prevMouseOn = MouseOn;
MouseOn = null;
int inventoryIndex = -1;
if (Inventory.IsMouseOnInventory())
{
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
}
for (int i = updateList.Count - 1; i > inventoryIndex; i--)
if (!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked())
{
GUIComponent c = updateList[i];
if (!c.CanBeFocused) { continue; }
if (c.MouseRect.Contains(PlayerInput.MousePosition))
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
{
if ((!PlayerInput.LeftButtonHeld() && !PlayerInput.LeftButtonClicked()) || c == prevMouseOn)
var c = updateList[i];
if (!c.CanBeFocused) { continue; }
if (c.MouseRect.Contains(PlayerInput.MousePosition))
{
MouseOn = c;
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || c == prevMouseOn)
{
MouseOn = c;
}
break;
}
break;
}
}
else
{
MouseOn = prevMouseOn;
}
MouseCursor = UpdateMouseCursorState(MouseOn);
return MouseOn;
}
private static CursorState UpdateMouseCursorState(GUIComponent c)
{
// Waiting and drag cursor override everything else
if (MouseCursor == CursorState.Waiting) { return CursorState.Waiting; }
if (GUIScrollBar.DraggingBar != null) { return GUIScrollBar.DraggingBar.Bar.HoverCursor; }
// Wire cursors
if (Character.Controlled != null)
{
if (Character.Controlled.SelectedConstruction?.GetComponent<ConnectionPanel>() != null)
{
if (Connection.DraggingConnected != null)
{
return CursorState.Dragging;
}
else if (ConnectionPanel.HighlightedWire != null)
{
return CursorState.Hand;
}
}
if (Wire.DraggingWire != null) { return CursorState.Dragging; }
}
if (c == null || c is GUICustomComponent)
{
switch (Screen.Selected)
{
// Character editor limbs
case CharacterEditorScreen editor:
return editor.GetMouseCursorState();
// Portrait area during gameplay
case GameScreen _ when !(Character.Controlled?.ShouldLockHud() ?? true):
if (HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) ||
Rectangle.Union(HUDLayoutSettings.AfflictionAreaLeft, HUDLayoutSettings.HealthBarArea).Contains(PlayerInput.MousePosition))
{
return CursorState.Hand;
}
break;
// Sub editor drag and highlight
case SubEditorScreen editor:
{
// Portrait area
if ((editor.CharacterMode || editor.WiringMode) &&
HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition))
{
return CursorState.Hand;
}
foreach (var mapEntity in MapEntity.mapEntityList)
{
if (MapEntity.StartMovingPos != Vector2.Zero)
{
return CursorState.Dragging;
}
if (mapEntity.IsHighlighted)
{
return CursorState.Hand;
}
}
break;
}
// Campaign map highlighted location
case LobbyScreen lobby:
{
if (lobby.CampaignUI?.Campaign.Map.HighlightedLocation != null) { return CursorState.Hand; }
break;
}
case NetLobbyScreen lobby:
{
if (lobby.CampaignUI?.Campaign.Map.HighlightedLocation != null) { return CursorState.Hand; }
break;
}
}
}
if (c != null && c.Visible)
{
// When a button opens a submenu, it increases to the size of the entire screen.
// And this is of course picked up as clickable area.
// There has to be a better way of checking this but for now this works.
var monitorRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
var parent = FindInteractParent(c);
if (c.Enabled)
{
// Some parent elements take priority
// but not when the child is a GUIButton or GUITickBox
if (!(parent is GUIButton) && !(parent is GUIListBox) ||
(c is GUIButton) || (c is GUITickBox))
{
if (!c.Rect.Equals(monitorRect)) { return c.HoverCursor; }
}
}
// Children in list boxes can be interacted with despite not having
// a GUIButton inside of them so instead of hard coding we check if
// the children can be interacted with by checking their hover state
if (parent is GUIListBox listBox)
{
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
if (listBox.CanDragElements) { return CursorState.Move; }
var hoverParent = c;
while (true)
{
if (hoverParent == parent || hoverParent == null) { break; }
if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; }
hoverParent = hoverParent.Parent;
}
}
if (parent != null)
{
if (!parent.Rect.Equals(monitorRect)) { return parent.HoverCursor; }
}
}
if (Inventory.IsMouseOnInventory()) { return Inventory.GetInventoryMouseCursor(); }
var character = Character.Controlled;
// ReSharper disable once InvertIf
if (character != null)
{
// Health menus
if (character.CharacterHealth.MouseOnElement) { return CursorState.Hand; }
if (character.SelectedCharacter != null)
{
if (character.SelectedCharacter.CharacterHealth.MouseOnElement)
{
return CursorState.Hand;
}
}
// Character is hovering over an item placed in the world
if (character.FocusedItem != null) { return CursorState.Hand; }
}
return CursorState.Default;
static GUIComponent FindInteractParent(GUIComponent component)
{
while (true)
{
var parent = component.Parent;
if (parent == null) { return null; }
if (ContainsMouse(parent))
{
if (parent.Enabled)
{
switch (parent)
{
case GUIButton button:
return button;
case GUITextBox box:
return box;
case GUIListBox list:
return list;
case GUIScrollBar bar:
return bar;
}
}
component = parent;
}
else
{
return null;
}
}
}
static bool ContainsMouse(GUIComponent component)
{
// If component has a mouse rectangle then use that, if not use it's physical rect
return !component.MouseRect.Equals(Rectangle.Empty) ?
component.MouseRect.Contains(PlayerInput.MousePosition) :
component.Rect.Contains(PlayerInput.MousePosition);
}
}
/// <summary>
/// Set the cursor to an hourglass.
/// Will automatically revert after 10 seconds or when <see cref="ClearCursorWait"/> is called.
/// </summary>
public static void SetCursorWaiting()
{
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
static IEnumerable<object> WaitCursorCoroutine()
{
MouseCursor = CursorState.Waiting;
var timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
while (DateTime.Now < timeOut) { yield return CoroutineStatus.Running; }
if (MouseCursor == CursorState.Waiting) { MouseCursor = CursorState.Default; }
yield return CoroutineStatus.Success;
}
}
public static void ClearCursorWait()
{
CoroutineManager.StopCoroutines("WaitCursorTimeout");
MouseCursor = CursorState.Default;
}
public static bool HasSizeChanged(Point referenceResolution, float referenceUIScale, float referenceHUDScale)
{
@@ -728,10 +988,19 @@ namespace Barotrauma
public static void Update(float deltaTime)
{
if (PlayerInput.KeyDown(Keys.LeftControl) && PlayerInput.KeyHit(Keys.S))
{
debugDrawSounds = !debugDrawSounds;
}
if (PlayerInput.KeyDown(Keys.LeftControl) && PlayerInput.KeyHit(Keys.E))
{
debugDrawEvents = !debugDrawEvents;
}
HandlePersistingElements(deltaTime);
RefreshUpdateList();
UpdateMouseOn();
System.Diagnostics.Debug.Assert(updateList.Count == updateListSet.Count);
Debug.Assert(updateList.Count == updateListSet.Count);
updateList.ForEach(c => c.UpdateAuto(deltaTime));
UpdateMessages(deltaTime);
}
@@ -814,6 +1083,26 @@ namespace Barotrauma
DrawLine(sb, t, start, end, clr, depth, width);
}
public static void DrawLine(SpriteBatch sb, Sprite sprite, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, int width = 1)
{
Vector2 edge = end - start;
// calculate angle to rotate line
float angle = (float)Math.Atan2(edge.Y, edge.X);
sb.Draw(sprite.Texture,
new Rectangle(// rectangle defines shape of line and position of start of line
(int)start.X,
(int)start.Y,
(int)edge.Length(), //sb will strech the texture to fill this rectangle
width), //width of line, change this to make thicker line
sprite.SourceRect,
clr, //colour of line
angle, //angle of line (calulated above)
new Vector2(0, sprite.SourceRect.Height / 2), // point in line about which to rotate
SpriteEffects.None,
depth);
}
public static void DrawLine(SpriteBatch sb, Texture2D texture, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, int width = 1)
{
Vector2 edge = end - start;
@@ -846,6 +1135,18 @@ namespace Barotrauma
font.DrawString(sb, text, pos, color);
}
public static void DrawStringWithColors(SpriteBatch sb, Vector2 pos, string text, Color color, List<ColorData> colorData, Color? backgroundColor = null, int backgroundPadding = 0, ScalableFont font = null, float depth = 0.0f)
{
if (font == null) font = Font;
if (backgroundColor != null)
{
Vector2 textSize = font.MeasureString(text);
DrawRectangle(sb, pos - Vector2.One * backgroundPadding, textSize + Vector2.One * 2.0f * backgroundPadding, (Color)backgroundColor, true, depth, 5);
}
font.DrawStringWithColors(sb, text, pos, color, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, depth, colorData);
}
public static void DrawRectangle(SpriteBatch sb, Vector2 start, Vector2 size, Color clr, bool isFilled = false, float depth = 0.0f, int thickness = 1)
{
if (size.X < 0)
@@ -926,13 +1227,13 @@ namespace Barotrauma
if (rect.Contains(PlayerInput.MousePosition))
{
clicked = PlayerInput.LeftButtonHeld();
clicked = PlayerInput.PrimaryMouseButtonHeld();
color = clicked ?
new Color((int)(color.R * 0.8f), (int)(color.G * 0.8f), (int)(color.B * 0.8f), color.A) :
new Color((int)(color.R * 1.2f), (int)(color.G * 1.2f), (int)(color.B * 1.2f), color.A);
if (!isHoldable) clicked = PlayerInput.LeftButtonClicked();
if (!isHoldable) clicked = PlayerInput.PrimaryMouseButtonClicked();
}
DrawRectangle(sb, rect, color, true);
@@ -1017,7 +1318,7 @@ namespace Barotrauma
public static void DrawSineWithDots(SpriteBatch spriteBatch, Vector2 from, Vector2 dir, float amplitude, float length, float scale, int pointCount, Color color, int dotSize = 2)
{
Vector2 up = dir.Right();
//DrawLine(spriteBatch, from, from + dir, Color.Red);
//DrawLine(spriteBatch, from, from + dir, GUI.Style.Red);
//DrawLine(spriteBatch, from, from + up * dir.Length(), Color.Blue);
for (int i = 0; i < pointCount; i++)
{
@@ -1221,7 +1522,7 @@ namespace Barotrauma
{
font = font ?? SmallFont;
var frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, elementHeight), parent), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), name, font: font)
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), name, font: font)
{
ToolTip = toolTip
};
@@ -1242,7 +1543,7 @@ namespace Barotrauma
{
var frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, Math.Max(elementHeight, 26)), parent), color: Color.Transparent);
font = font ?? SmallFont;
var label = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform), name, font: font)
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform), name, font: font)
{
ToolTip = toolTip
};
@@ -1286,7 +1587,7 @@ namespace Barotrauma
public static GUIComponent CreatePointField(Point value, int elementHeight, string displayName, RectTransform parent, string toolTip = null)
{
var frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, Math.Max(elementHeight, 26)), parent), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: SmallFont)
new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: SmallFont)
{
ToolTip = toolTip
};
@@ -1317,7 +1618,7 @@ namespace Barotrauma
{
font = font ?? SmallFont;
var frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, Math.Max(elementHeight, 26)), parent), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), name, font: font)
new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), name, font: font)
{
ToolTip = toolTip
};
@@ -1474,20 +1775,30 @@ namespace Barotrauma
if (!rect1.Intersects(rect2)) continue;
intersections = true;
int rect1Area = rect1.Width * rect1.Height;
int rect2Area = rect2.Width * rect2.Height;
Point centerDiff = rect1.Center - rect2.Center;
//move the interfaces away from each other, in a random direction if they're at the same position
Vector2 moveAmount = centerDiff == Point.Zero ? Rand.Vector(1.0f) : Vector2.Normalize(centerDiff.ToVector2());
//if the horizontal move amount is much larger than vertical, only move horizontally
//(= attempt to place the elements side-by-side if they're more apart horizontally than vertically)
if (Math.Abs(moveAmount.X) > Math.Abs(moveAmount.Y) * 8.0f)
{
moveAmount.Y = 0.0f;
}
//same for the y-axis
else if (Math.Abs(moveAmount.Y) > Math.Abs(moveAmount.X) * 8.0f)
{
moveAmount.X = 0.0f;
}
//make sure we don't move the interfaces out of the screen
Vector2 moveAmount1 = ClampMoveAmount(rect1, area, moveAmount * 20.0f * rect1Area / (rect1Area + rect2Area));
Vector2 moveAmount2 = ClampMoveAmount(rect2, area, -moveAmount * 20.0f * rect1Area / (rect1Area + rect2Area));
Vector2 moveAmount1 = ClampMoveAmount(rect1, area, moveAmount * 10.0f);
Vector2 moveAmount2 = ClampMoveAmount(rect2, area, -moveAmount * 10.0f);
//move by 10 units in the desired direction and repeat until nothing overlaps
//(or after 100 iterations, in which case we'll just give up and let them overlap)
elements[i].RectTransform.ScreenSpaceOffset += (moveAmount1).ToPoint();
elements[j].RectTransform.ScreenSpaceOffset += (moveAmount2).ToPoint();
elements[i].RectTransform.ScreenSpaceOffset += moveAmount1.ToPoint();
elements[j].RectTransform.ScreenSpaceOffset += moveAmount2.ToPoint();
}
if (disallowedAreas == null) continue;
@@ -1552,15 +1863,15 @@ namespace Barotrauma
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas), style: null, color: Color.Black * 0.5f);
var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.35f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(200, 300) });
var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.3f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(250, 300) });
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.85f, 0.8f), pauseMenuInner.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.05f) })
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.6f), pauseMenuInner.RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.05f
};
var button = new GUIButton(new RectTransform(new Vector2(0.12f, 0.12f), buttonContainer.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(-0.05f, -0.13f) },
var button = new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
"", style: "GUIBugButton")
{
IgnoreLayoutGroups = true,
@@ -1568,12 +1879,12 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"), style: "GUIButtonLarge")
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"))
{
OnClicked = TogglePauseMenu
};
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"), style: "GUIButtonLarge")
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"))
{
OnClicked = (btn, userData) =>
{
@@ -1587,7 +1898,7 @@ namespace Barotrauma
{
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
{
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"), style: "GUIButtonLarge");
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"));
button.OnClicked += (btn, userData) =>
{
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuRetryVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
@@ -1611,13 +1922,44 @@ namespace Barotrauma
return true;
};
}
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("EndRound"))
{
OnClicked = (btn, userdata) =>
{
if (!GameMain.Client.HasPermission(ClientPermissions.ManageRound)) { return false; }
if (!Submarine.MainSub.AtStartPosition && !Submarine.MainSub.AtEndPosition)
{
var msgBox = new GUIMessageBox("", TextManager.Get("EndRoundSubNotAtLevelEnd"), new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, __) =>
{
TogglePauseMenu(btn, userdata);
GameMain.Client.RequestRoundEnd();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
else
{
TogglePauseMenu(btn, userdata);
GameMain.Client.RequestRoundEnd();
}
return true;
}
};
}
}
if (Screen.Selected == GameMain.LobbyScreen)
{
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
{
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"), style: "GUIButtonLarge")
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
{
UserData = "save"
};
@@ -1626,7 +1968,7 @@ namespace Barotrauma
}
}
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"), style: "GUIButtonLarge");
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"));
button.OnClicked += (btn, userData) =>
{
var quitButton = button;
@@ -1703,6 +2045,12 @@ namespace Barotrauma
sounds[soundIndex]?.Play(null, "ui");
}
public static bool IsFourByThree()
{
float aspectRatio = HorizontalAspectRatio;
return aspectRatio > 1.3f && aspectRatio < 1.4f;
}
#endregion
}
}
@@ -20,9 +20,7 @@ namespace Barotrauma
public OnButtonDownHandler OnButtonDown;
public bool CanBeSelected = true;
private Color? defaultTextColor;
public override bool Enabled
{
get
@@ -33,13 +31,7 @@ namespace Barotrauma
set
{
if (value == enabled) { return; }
enabled = value;
if (color.A == 0)
{
if (defaultTextColor == null) { defaultTextColor = TextBlock.TextColor; }
TextBlock.TextColor = enabled ? defaultTextColor.Value : defaultTextColor.Value * 0.5f;
}
frame.Color = enabled ? color : Color.Gray * 0.7f;
enabled = frame.Enabled = textBlock.Enabled = value;
}
}
@@ -105,6 +97,11 @@ namespace Barotrauma
set { textBlock.TextColor = value; }
}
public Color HoverTextColor
{
get { return textBlock.HoverTextColor; }
set { textBlock.HoverTextColor = value; }
}
public override float FlashTimer
{
@@ -115,12 +112,12 @@ namespace Barotrauma
{
get
{
return (textBlock==null) ? GUI.Font : textBlock.Font;
return (textBlock == null) ? GUI.Font : textBlock.Font;
}
set
{
base.Font = value;
if (textBlock != null) textBlock.Font = value;
if (textBlock != null) textBlock.Font = value;
}
}
@@ -144,35 +141,44 @@ namespace Barotrauma
}
set
{
textBlock.ToolTip = value;
base.ToolTip = value;
textBlock.ToolTip = value;
}
}
public bool Selected { get; set; }
public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : base(style, rectT)
{
CanBeFocused = true;
HoverCursor = CursorState.Hand;
frame = new GUIFrame(new RectTransform(Vector2.One, rectT), style) { CanBeFocused = false };
if (style != null) { GUI.Style.Apply(frame, style == "" ? "GUIButton" : style); }
if (color.HasValue)
{
this.color = color.Value;
this.color = frame.Color = color.Value;
}
frame = new GUIFrame(new RectTransform(Vector2.One, rectT), style) { CanBeFocused = false };
if (style != null) GUI.Style.Apply(frame, style == "" ? "GUIButton" : style);
textBlock = new GUITextBlock(new RectTransform(Vector2.One, rectT), text, textAlignment: textAlignment, style: null)
textBlock = new GUITextBlock(new RectTransform(Vector2.One, rectT, Anchor.Center), text, textAlignment: textAlignment, style: null)
{
TextColor = this.style == null ? Color.Black : this.style.textColor,
TextColor = this.style == null ? Color.Black : this.style.TextColor,
HoverTextColor = this.style == null ? Color.Black : this.style.HoverTextColor,
SelectedTextColor = this.style == null ? Color.Black : this.style.SelectedTextColor,
CanBeFocused = false
};
if (rectT.Rect.Height == 0 && !string.IsNullOrEmpty(text))
{
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(textBlock.Text).Y));
RectTransform.MinSize = textBlock.RectTransform.MinSize = new Point(0, Rect.Height);
RectTransform.MinSize = textBlock.RectTransform.MinSize = new Point(0, System.Math.Max(rectT.MinSize.Y, Rect.Height));
TextBlock.SetTextPos();
}
GUI.Style.Apply(textBlock, "", this);
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
//use the default CJK font as a fallback
if (TextManager.IsCJK(textBlock.Text) && !textBlock.Font.IsCJK)
{
textBlock.Font = GUI.CJKFont;
}
Enabled = true;
}
@@ -180,12 +186,12 @@ namespace Barotrauma
{
base.ApplyStyle(style);
if (frame != null) frame.ApplyStyle(style);
if (frame != null) { frame.ApplyStyle(style); }
}
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null)
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectInflate = null)
{
Frame.Flash(color, flashDuration, useRectangleFlash, flashRectInflate);
Frame.Flash(color, flashDuration, useRectangleFlash, useCircularFlash, flashRectInflate);
}
protected override void Draw(SpriteBatch spriteBatch)
@@ -199,52 +205,52 @@ namespace Barotrauma
base.Update(deltaTime);
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && CanBeFocused && Enabled && GUI.IsMouseOn(this))
{
state = ComponentState.Hover;
if (PlayerInput.LeftButtonDown())
State = Selected ?
ComponentState.HoverSelected :
ComponentState.Hover;
if (PlayerInput.PrimaryMouseButtonDown())
{
OnButtonDown?.Invoke();
}
if (PlayerInput.LeftButtonHeld())
if (PlayerInput.PrimaryMouseButtonHeld())
{
if (OnPressed != null)
{
if (OnPressed())
{
state = ComponentState.Pressed;
State = ComponentState.Pressed;
}
}
else
{
state = ComponentState.Pressed;
State = ComponentState.Pressed;
}
}
else if (PlayerInput.LeftButtonClicked())
else if (PlayerInput.PrimaryMouseButtonClicked())
{
GUI.PlayUISound(GUISoundType.Click);
if (OnClicked != null)
{
if (OnClicked(this, UserData) && CanBeSelected)
if (OnClicked(this, UserData))
{
state = ComponentState.Selected;
State = ComponentState.Selected;
}
}
else
{
Selected = !Selected;
// state = state == ComponentState.Selected ? ComponentState.None : ComponentState.Selected;
}
}
}
}
else
{
state = Selected ? ComponentState.Selected : ComponentState.None;
State = Selected ? ComponentState.Selected : ComponentState.None;
}
foreach (GUIComponent child in Children)
{
child.State = state;
child.State = State;
}
//frame.State = state;
}
}
}
@@ -15,9 +15,11 @@ namespace Barotrauma
{
#region Hierarchy
public GUIComponent Parent => RectTransform.Parent?.GUIComponent;
public CursorState HoverCursor = CursorState.Default;
public IEnumerable<GUIComponent> Children => RectTransform.Children.Select(c => c.GUIComponent);
public T GetChild<T>() where T : GUIComponent
{
return Children.FirstOrDefault(c => c is T) as T;
@@ -28,6 +30,19 @@ namespace Barotrauma
return GetAllChildren().FirstOrDefault(c => c is T) as T;
}
public IEnumerable<T> GetAllChildren<T>() where T : GUIComponent
{
return GetAllChildren().Where(c => c is T).Select(c => c as T);
}
/// <summary>
/// Returns all child elements in the hierarchy.
/// </summary>
public IEnumerable<GUIComponent> GetAllChildren()
{
return RectTransform.GetAllChildren().Select(c => c.GUIComponent);
}
public GUIComponent GetChild(int index)
{
if (index < 0 || index >= CountChildren) return null;
@@ -49,15 +64,6 @@ namespace Barotrauma
return null;
}
/// <summary>
/// Returns all child elements in the hierarchy.
/// If the component has RectTransform, it's more efficient to use RectTransform.GetChildren and access the GUIComponent property directly.
/// </summary>
public IEnumerable<GUIComponent> GetAllChildren()
{
return RectTransform.GetAllChildren().Select(c => c.GUIComponent);
}
public bool IsParentOf(GUIComponent component, bool recursive = true)
{
if (component == null) { return false; }
@@ -132,31 +138,30 @@ namespace Barotrauma
public int UpdateOrder { get; set; }
public Action<GUIComponent> OnAddedToGUIUpdateList;
/// <summary>
/// Launched at the beginning of the Draw method. Note: if the method is overridden, the event might not be called!
public enum ComponentState { None, Hover, Pressed, Selected };
public enum ComponentState { None, Hover, Pressed, Selected, HoverSelected };
protected Alignment alignment;
protected GUIComponentStyle style;
protected object userData;
public bool CanBeFocused;
protected Color color;
protected Color hoverColor;
protected Color selectedColor;
protected Color disabledColor;
protected Color pressedColor;
private CoroutineHandle pulsateCoroutine;
protected ComponentState state;
protected Color flashColor;
protected float flashDuration = 1.5f;
// TODO: We should use an enum for the flash modes, but it would require a bit of refactoring, because Flash method is use in so many places.
private bool useRectangleFlash;
private bool useCircularFlash;
public virtual float FlashTimer
{
get { return flashTimer; }
@@ -164,7 +169,20 @@ namespace Barotrauma
protected float flashTimer;
private Vector2 flashRectInflate;
public bool IgnoreLayoutGroups;
private bool ignoreLayoutGroups;
public bool IgnoreLayoutGroups
{
get { return ignoreLayoutGroups; }
set
{
if (ignoreLayoutGroups == value) { return; }
ignoreLayoutGroups = value;
if (Parent is GUILayoutGroup layoutGroup)
{
layoutGroup.NeedsToRecalculate = true;
}
}
}
public virtual ScalableFont Font
{
@@ -172,12 +190,25 @@ namespace Barotrauma
set;
}
// Use the rawtooltip when copying displayed tooltips so that any possible color-data related values are translated over as well
public string RawToolTip;
private string toolTip;
public virtual string ToolTip
{
get;
set;
get
{
return toolTip;
}
set
{
RawToolTip = value;
TooltipColorData = ColorData.GetColorData(value, out value);
toolTip = value;
}
}
public List<ColorData> TooltipColorData = null;
public GUIComponentStyle Style
{
get { return style; }
@@ -195,7 +226,7 @@ namespace Barotrauma
get { return enabled; }
set { enabled = value; }
}
private static GUITextBlock toolTipBlock;
public Vector2 Center
@@ -255,10 +286,31 @@ namespace Barotrauma
public virtual Color OutlineColor { get; set; }
public ComponentState State
protected ComponentState _state;
protected ComponentState _previousState;
protected bool selected;
public virtual bool Selected
{
get { return state; }
set { state = value; }
get { return selected; }
set
{
selected = value;
Children.ForEach(c => c.Selected = value);
}
}
public virtual ComponentState State
{
get { return _state; }
set
{
if (_state != value)
{
spriteFadeTimer = SpriteCrossFadeTime;
colorFadeTimer = ColorCrossFadeTime;
_previousState = _state;
}
_state = value;
}
}
public object UserData
@@ -289,6 +341,11 @@ namespace Barotrauma
get { return selectedColor; }
set { selectedColor = value; }
}
public virtual Color DisabledColor
{
get { return disabledColor; }
set { disabledColor = value; }
}
public virtual Color PressedColor
{
@@ -296,6 +353,14 @@ namespace Barotrauma
set { pressedColor = value; }
}
public TransitionMode ColorTransition { get; private set; }
public SpriteFallBackState FallBackState { get; private set; }
public float SpriteCrossFadeTime { get; private set; }
public float ColorCrossFadeTime { get; private set; }
private float spriteFadeTimer;
private float colorFadeTimer;
public bool ExternalHighlight = false;
private RectTransform rectTransform;
@@ -316,23 +381,26 @@ namespace Barotrauma
/// <summary>
/// This is the new constructor.
/// </summary>
protected GUIComponent(string style, RectTransform rectT) : this(style)
protected GUIComponent(string style, RectTransform rectT)
{
RectTransform = rectT;
Visible = true;
OutlineColor = Color.Transparent;
Font = GUI.Font;
CanBeFocused = true;
if (style != null) { GUI.Style.Apply(this, style); }
}
protected GUIComponent(string style)
{
Visible = true;
OutlineColor = Color.Transparent;
Font = GUI.Font;
CanBeFocused = true;
CanBeFocused = true; //TODO: change default to false?
if (style != null)
GUI.Style.Apply(this, style);
if (style != null) { GUI.Style.Apply(this, style); }
}
#region Updating
@@ -387,6 +455,14 @@ namespace Barotrauma
{
flashTimer -= deltaTime;
}
if (spriteFadeTimer > 0)
{
spriteFadeTimer -= deltaTime;
}
if (colorFadeTimer > 0)
{
colorFadeTimer -= deltaTime;
}
}
/// <summary>
@@ -433,34 +509,115 @@ namespace Barotrauma
RectTransform.Children.ForEach(c => c.GUIComponent.DrawManually(spriteBatch, recursive, recursive));
}
protected virtual Color GetCurrentColor(ComponentState state)
protected Color _currentColor;
protected virtual Color GetColor(ComponentState state)
{
switch (state)
if (!Enabled) { return DisabledColor; }
return state switch
{
case ComponentState.Hover:
return HoverColor;
case ComponentState.Pressed:
return PressedColor;
case ComponentState.Selected:
return SelectedColor;
default:
return Color;
}
ComponentState.Hover => HoverColor,
ComponentState.HoverSelected => HoverColor,
ComponentState.Pressed => PressedColor,
ComponentState.Selected => SelectedColor,
_ => Color,
};
}
private float GetEasing(TransitionMode easing, float t)
{
return easing switch
{
TransitionMode.Smooth => MathUtils.SmoothStep(t),
TransitionMode.Smoother => MathUtils.SmootherStep(t),
TransitionMode.EaseIn => MathUtils.EaseIn(t),
TransitionMode.EaseOut => MathUtils.EaseOut(t),
TransitionMode.Exponential => t * t,
TransitionMode.Linear => t,
_ => t,
};
}
protected Color GetBlendedColor(Color targetColor, ref Color blendedColor)
{
blendedColor = ColorCrossFadeTime > 0 ? Color.Lerp(blendedColor, targetColor, MathUtils.InverseLerp(ColorCrossFadeTime, 0, GetEasing(ColorTransition, colorFadeTimer))) : targetColor;
return blendedColor;
}
protected virtual void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
var rect = Rect;
Color currColor = GetCurrentColor(state);
if (currColor.A > 0.0f && (sprites == null || !sprites.Any())) GUI.DrawRectangle(spriteBatch, rect, currColor * (currColor.A / 255.0f), true);
if (sprites != null && sprites[state] != null && currColor.A > 0.0f)
GetBlendedColor(GetColor(State), ref _currentColor);
if (_currentColor.A > 0.0f && (sprites == null || !sprites.Any()))
{
foreach (UISprite uiSprite in sprites[state])
GUI.DrawRectangle(spriteBatch, rect, _currentColor * (_currentColor.A / 255.0f), true);
}
if (sprites != null && _currentColor.A > 0)
{
if (!sprites.TryGetValue(_previousState, out List<UISprite> previousSprites) || previousSprites.None())
{
uiSprite.Draw(spriteBatch, rect, currColor * (currColor.A / 255.0f), SpriteEffects);
switch (FallBackState)
{
case SpriteFallBackState.Toggle:
sprites.TryGetValue(Selected ? ComponentState.Selected : ComponentState.None, out previousSprites);
break;
default:
if (Enum.TryParse(FallBackState.ToString(), ignoreCase: true, out ComponentState fallBackState))
{
sprites.TryGetValue(fallBackState, out previousSprites);
}
break;
}
}
// Handle fallbacks when some of the sprites are not defined
if (!sprites.TryGetValue(State, out List<UISprite> currentSprites) || currentSprites.None())
{
switch (FallBackState)
{
case SpriteFallBackState.Toggle:
sprites.TryGetValue(Selected ? ComponentState.Selected : ComponentState.None, out currentSprites);
break;
default:
if (Enum.TryParse(FallBackState.ToString(), ignoreCase: true, out ComponentState fallBackState))
{
sprites.TryGetValue(fallBackState, out currentSprites);
}
break;
}
}
if (_previousState != State && currentSprites != previousSprites)
{
if (previousSprites != null && previousSprites.Any())
{
// Draw the previous sprites(s) only while cross fading out
Color previousColor = GetColor(_previousState);
foreach (UISprite uiSprite in previousSprites)
{
float alphaMultiplier = SpriteCrossFadeTime > 0 && (uiSprite.CrossFadeOut || currentSprites != null && currentSprites.Any(s => s.CrossFadeIn))
? MathUtils.InverseLerp(0, SpriteCrossFadeTime, GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : 0;
if (alphaMultiplier > 0)
{
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects);
}
}
}
}
if (currentSprites != null && currentSprites.Any())
{
// Draw the current sprite(s)
foreach (UISprite uiSprite in currentSprites)
{
float alphaMultiplier = SpriteCrossFadeTime > 0 && (uiSprite.CrossFadeIn || previousSprites != null && previousSprites.Any(s => s.CrossFadeOut))
? MathUtils.InverseLerp(SpriteCrossFadeTime, 0, GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : (_currentColor.A / 255.0f);
if (alphaMultiplier > 0)
{
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects);
}
}
}
}
@@ -475,15 +632,16 @@ namespace Barotrauma
//MathHelper.Pi * 0.8f -> the curve goes from 144 deg to 0,
//i.e. quickly bumps up from almost full brightness to full and then fades out
if (!useRectangleFlash)
if (useRectangleFlash)
{
GUI.UIGlow.Draw(spriteBatch,
flashRect,
flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
GUI.DrawRectangle(spriteBatch, flashRect, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), true);
}
else
{
GUI.DrawRectangle(spriteBatch, flashRect, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), true);
var glow = useCircularFlash ? GUI.UIGlowCircular : GUI.UIGlow;
glow.Draw(spriteBatch,
flashRect,
flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
}
}
}
@@ -494,24 +652,23 @@ namespace Barotrauma
public void DrawToolTip(SpriteBatch spriteBatch)
{
if (!Visible) return;
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect);
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect, TooltipColorData);
}
public static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle targetElement)
public static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle targetElement, List<ColorData> colorData = null)
{
if (Tutorials.Tutorial.ContentRunning) return;
if (Tutorials.Tutorial.ContentRunning) { return; }
int width = (int)(400 * GUI.Scale);
int height = (int)(18 * GUI.Scale);
Point padding = new Point((int)(20 * GUI.Scale), (int)(7 * GUI.Scale));
Point padding = new Point((int)(10 * GUI.Scale));
if (toolTipBlock == null || (string)toolTipBlock.userData != toolTip)
{
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, height), null), toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, height), null), colorData, toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
toolTipBlock.RectTransform.NonScaledSize = new Point(
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + padding.X),
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).Y + padding.Y));
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + padding.X + toolTipBlock.Padding.X + toolTipBlock.Padding.Z),
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).Y + padding.Y + toolTipBlock.Padding.Y + toolTipBlock.Padding.W));
toolTipBlock.userData = toolTip;
}
@@ -537,13 +694,14 @@ namespace Barotrauma
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
}
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null)
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectInflate = null)
{
flashTimer = flashDuration;
this.flashRectInflate = flashRectInflate ?? Vector2.Zero;
this.useRectangleFlash = useRectangleFlash;
this.useCircularFlash = useCircularFlash;
this.flashDuration = flashDuration;
flashColor = (color == null) ? Color.Red : (Color)color;
flashColor = (color == null) ? GUI.Style.Red : (Color)color;
}
public void FadeOut(float duration, bool removeAfter)
@@ -597,28 +755,53 @@ namespace Barotrauma
public virtual void ApplyStyle(GUIComponentStyle style)
{
if (style == null) return;
if (style == null) { return; }
color = style.Color;
_currentColor = color;
hoverColor = style.HoverColor;
selectedColor = style.SelectedColor;
pressedColor = style.PressedColor;
disabledColor = style.DisabledColor;
sprites = style.Sprites;
OutlineColor = style.OutlineColor;
SpriteCrossFadeTime = style.SpriteCrossFadeTime;
ColorCrossFadeTime = style.ColorCrossFadeTime;
ColorTransition = style.TransitionMode;
FallBackState = style.FallBackState;
if (rectTransform != null)
{
ApplySizeRestrictions(style);
}
this.style = style;
}
public void ApplySizeRestrictions(GUIComponentStyle style)
{
if (style.Width.HasValue)
{
RectTransform.MinSize = new Point(style.Width.Value, RectTransform.MinSize.Y);
RectTransform.MaxSize = new Point(style.Width.Value, RectTransform.MaxSize.Y);
if (rectTransform.IsFixedSize) { RectTransform.Resize(new Point(style.Width.Value, rectTransform.NonScaledSize.Y)); }
}
if (style.Height.HasValue)
{
RectTransform.MinSize = new Point(RectTransform.MinSize.X, style.Height.Value);
RectTransform.MaxSize = new Point(RectTransform.MaxSize.X, style.Height.Value);
if (rectTransform.IsFixedSize) { RectTransform.Resize(new Point(rectTransform.NonScaledSize.X, style.Height.Value)); }
}
}
public static GUIComponent FromXML(XElement element, RectTransform parent)
{
GUIComponent component = null;
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional" &&
!CheckConditional(subElement))
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase) && !CheckConditional(subElement))
{
return null;
}
@@ -667,7 +850,7 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional") { continue; }
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase)) { continue; }
FromXML(subElement, component is GUIListBox listBox ? listBox.Content.RectTransform : component.RectTransform);
}
@@ -765,14 +948,8 @@ namespace Barotrauma
case "largefont":
font = GUI.LargeFont;
break;
case "videotitlefont":
font = GUI.VideoTitleFont;
break;
case "objectivetitlefont":
font = GUI.ObjectiveTitleFont;
break;
case "objectivenamefont":
font = GUI.ObjectiveNameFont;
case "subheading":
font = GUI.SubHeadingFont;
break;
}
@@ -795,7 +972,11 @@ namespace Barotrauma
{
try
{
System.Diagnostics.Process.Start(url);
#if USE_STEAM
Steam.SteamManager.OverlayCustomURL(url);
#else
ToolBox.OpenFileWithShell(url);
#endif
}
catch (Exception e)
{
@@ -837,7 +1018,7 @@ namespace Barotrauma
private static GUIFrame LoadGUIFrame(XElement element, RectTransform parent)
{
string style = element.GetAttributeString("style", element.Name.ToString().ToLowerInvariant() == "spacing" ? null : "");
string style = element.GetAttributeString("style", element.Name.ToString().Equals("spacing", StringComparison.OrdinalIgnoreCase) ? null : "");
if (style == "null") { style = null; }
return new GUIFrame(RectTransform.Load(element, parent), style: style);
}
@@ -13,8 +13,9 @@ namespace Barotrauma
public OnSelectedHandler OnSelected;
public OnSelectedHandler OnDropped;
private GUIButton button;
private GUIListBox listBox;
private readonly GUIButton button;
private readonly GUIImage icon;
private readonly GUIListBox listBox;
private RectTransform currentHighestParent;
private List<RectTransform> parentHierarchy = new List<RectTransform>();
@@ -41,7 +42,11 @@ namespace Barotrauma
public bool ButtonEnabled
{
get { return button.Enabled; }
set { button.Enabled = value; }
set
{
button.Enabled = value;
if (icon != null) { icon.Enabled = value; }
}
}
public GUIComponent SelectedComponent
@@ -49,6 +54,7 @@ namespace Barotrauma
get { return listBox.SelectedComponent; }
}
// TODO: fix implicit hiding
public bool Selected
{
get
@@ -83,6 +89,12 @@ namespace Barotrauma
}
}
public Color ButtonTextColor
{
get { return button.TextColor; }
set { button.TextColor = value; }
}
public void ReceiveTextInput(char inputChar)
{
GUI.KeyboardDispatcher.Subscriber = null;
@@ -139,8 +151,9 @@ namespace Barotrauma
}
}
public GUIDropDown(RectTransform rectT, string text = "", int elementCount = 4, string style = "", bool selectMultiple = false) : base(style, rectT)
public GUIDropDown(RectTransform rectT, string text = "", int elementCount = 4, string style = "", bool selectMultiple = false, bool dropAbove = false) : base(style, rectT)
{
HoverCursor = CursorState.Hand;
CanBeFocused = true;
this.selectMultiple = selectMultiple;
@@ -150,14 +163,25 @@ namespace Barotrauma
OnClicked = OnClicked
};
GUI.Style.Apply(button, "", this);
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, Anchor.BottomCenter, Pivot.TopCenter)
button.TextBlock.SetTextPos();
Anchor listAnchor = dropAbove ? Anchor.TopCenter : Anchor.BottomCenter;
Pivot listPivot = dropAbove ? Pivot.BottomCenter : Pivot.TopCenter;
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, listAnchor, listPivot)
{ IsFixedSize = false }, style: null)
{
Enabled = !selectMultiple,
OnSelected = SelectItem
};
GUI.Style.Apply(listBox.Content, "GUIListBox", this);
GUI.Style.Apply(listBox, "GUIListBox", this);
GUI.Style.Apply(listBox.ContentBackground, "GUIListBox", this);
if (button.Style.ChildStyles.ContainsKey("dropdownicon"))
{
icon = new GUIImage(new RectTransform(new Vector2(0.6f, 0.6f), button.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5, 0) }, null, scaleToFit: true);
icon.ApplyStyle(button.Style.ChildStyles["dropdownicon"]);
}
currentHighestParent = FindHighestParent();
currentHighestParent.GUIComponent.OnAddedToGUIUpdateList += AddListBoxToGUIUpdateList;
@@ -243,6 +267,7 @@ namespace Barotrauma
i++;
}
button.Text = string.Join(", ", texts);
// TODO: The callback is called at least twice, remove this?
OnSelected?.Invoke(tb.Parent, tb.Parent.UserData);
return true;
}
@@ -290,6 +315,7 @@ namespace Barotrauma
button.Text = textBlock.Text;
}
Dropped = false;
// TODO: OnSelected can be called multiple times and when it shouldn't be called -> turn into an event so that nobody else can call it.
OnSelected?.Invoke(component, component.UserData);
return true;
}
@@ -390,7 +416,7 @@ namespace Barotrauma
if (!Visible) return;
wasOpened = false;
base.Update(deltaTime);
if (Dropped && PlayerInput.LeftButtonClicked())
if (Dropped && PlayerInput.PrimaryMouseButtonClicked())
{
Rectangle listBoxRect = listBox.Rect;
if (!listBoxRect.Contains(PlayerInput.MousePosition) && !button.Rect.Contains(PlayerInput.MousePosition))
@@ -8,6 +8,7 @@ namespace Barotrauma
{
public GUIFrame(RectTransform rectT, string style = "", Color? color = null) : base(style, rectT)
{
Enabled = true;
if (color.HasValue)
{
this.color = color.Value;
@@ -18,7 +19,7 @@ namespace Barotrauma
{
if (!Visible) return;
Color currColor = GetCurrentColor(state);
Color currColor = GetColor(State);
if (sprites == null || !sprites.Any(s => s.Value.Any())) GUI.DrawRectangle(spriteBatch, Rect, currColor * (currColor.A/255.0f), true);
base.Draw(spriteBatch);
@@ -87,7 +87,7 @@ namespace Barotrauma
}
if (style == null)
{
color = hoverColor = selectedColor = pressedColor = Color.White;
color = hoverColor = selectedColor = pressedColor = disabledColor = Color.White;
}
if (!scaleToFit)
{
@@ -97,15 +97,17 @@ namespace Barotrauma
{
rectT.SizeChanged += RecalculateScale;
}
Enabled = true;
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
if (Parent != null) { state = Parent.State; }
if (OverrideState != null) { state = OverrideState.Value; }
Color currColor = GetCurrentColor(state);
if (Parent != null) { State = Parent.State; }
if (OverrideState != null) { State = OverrideState.Value; }
Color currentColor = GetColor(State);
if (BlendState != null)
{
@@ -115,23 +117,23 @@ namespace Barotrauma
if (style != null)
{
foreach (UISprite uiSprite in style.Sprites[state])
foreach (UISprite uiSprite in style.Sprites[State])
{
if (Math.Abs(Rotation) > float.Epsilon)
{
float scale = Math.Min(Rect.Width / uiSprite.Sprite.size.X, Rect.Height / uiSprite.Sprite.size.Y);
spriteBatch.Draw(uiSprite.Sprite.Texture, Rect.Center.ToVector2(), uiSprite.Sprite.SourceRect, currColor * (currColor.A / 255.0f), Rotation, uiSprite.Sprite.size / 2,
spriteBatch.Draw(uiSprite.Sprite.Texture, Rect.Center.ToVector2(), uiSprite.Sprite.SourceRect, currentColor * (currentColor.A / 255.0f), Rotation, uiSprite.Sprite.size / 2,
Scale * scale, SpriteEffects, 0.0f);
}
else
{
uiSprite.Draw(spriteBatch, Rect, currColor * (currColor.A / 255.0f), SpriteEffects);
uiSprite.Draw(spriteBatch, Rect, currentColor * (currentColor.A / 255.0f), SpriteEffects);
}
}
}
else if (sprite?.Texture != null)
{
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currColor * (currColor.A / 255.0f), Rotation, sprite.size / 2,
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, sprite.size / 2,
Scale, SpriteEffects, 0.0f);
}
@@ -68,6 +68,10 @@ namespace Barotrauma
public bool NeedsToRecalculate
{
get { return needsToRecalculate; }
set
{
if (value) { needsToRecalculate = true; }
}
}
public GUILayoutGroup(RectTransform rectT, bool isHorizontal = false, Anchor childAnchor = Anchor.TopLeft) : base(null, rectT)
@@ -86,20 +90,49 @@ namespace Barotrauma
float stretchFactor = 1.0f;
if (stretch && RectTransform.Children.Count() > 0)
{
foreach (RectTransform child in RectTransform.Children)
{
if (child.GUIComponent.IgnoreLayoutGroups) { continue; }
if (child.ScaleBasis == ScaleBasis.BothHeight) { child.MinSize = new Point(child.Rect.Height, child.MinSize.Y); }
if (child.ScaleBasis == ScaleBasis.BothWidth) { child.MinSize = new Point(child.MinSize.X, child.Rect.Width); }
if (child.ScaleBasis == ScaleBasis.Smallest)
{
if (Rect.Width < Rect.Height)
{
child.MinSize = new Point(child.MinSize.X, child.Rect.Width);
}
else
{
child.MinSize = new Point(child.Rect.Height, child.MinSize.Y);
}
}
if (child.ScaleBasis == ScaleBasis.Largest)
{
if (Rect.Width > Rect.Height)
{
child.MinSize = new Point(child.MinSize.X, child.Rect.Width);
}
else
{
child.MinSize = new Point(child.Rect.Height, child.MinSize.Y);
}
}
}
float minSize = RectTransform.Children
.Where(c => !c.GUIComponent.IgnoreLayoutGroups)
.Sum(c => isHorizontal ? c.MinSize.X : c.MinSize.Y);
.Sum(c => isHorizontal ? (c.IsFixedSize ? c.NonScaledSize.X : c.MinSize.X) : (c.IsFixedSize ? c.NonScaledSize.Y : c.MinSize.Y));
float totalSize = RectTransform.Children
.Where(c => !c.GUIComponent.IgnoreLayoutGroups)
.Sum(c => isHorizontal ?
MathHelper.Clamp(c.Rect.Width, c.MinSize.X, c.MaxSize.X) :
MathHelper.Clamp(c.Rect.Height, c.MinSize.Y, c.MaxSize.Y));
.Sum(c => isHorizontal ?
(c.IsFixedSize ? c.Rect.Width : MathHelper.Clamp(c.Rect.Width, c.MinSize.X, c.MaxSize.X)) :
(c.IsFixedSize ? c.Rect.Height : MathHelper.Clamp(c.Rect.Height, c.MinSize.Y, c.MaxSize.Y)));
float thisSize = (isHorizontal ? Rect.Width : Rect.Height);
totalSize +=
(RectTransform.Children.Count() - 1) *
totalSize +=
(RectTransform.Children.Count(c => !c.GUIComponent.IgnoreLayoutGroups) - 1) *
(absoluteSpacing + relativeSpacing * thisSize);
stretchFactor = totalSize <= 0.0f || minSize >= thisSize ?
@@ -117,20 +150,34 @@ namespace Barotrauma
{
child.RelativeOffset = new Vector2(relPos, child.RelativeOffset.Y);
child.AbsoluteOffset = new Point(absPos, child.AbsoluteOffset.Y);
absPos += (int)Math.Max((child.Rect.Width + absoluteSpacing) * stretchFactor, child.MinSize.X);
if (stretch)
if (child.IsFixedSize)
{
child.RelativeSize = new Vector2(child.RelativeSize.X * stretchFactor, child.RelativeSize.Y);
absPos += child.NonScaledSize.X + absoluteSpacing;
}
else
{
absPos += (int)(MathHelper.Clamp(child.Rect.Width * stretchFactor, child.MinSize.X, child.MaxSize.X) + (absoluteSpacing * stretchFactor));
if (stretch)
{
child.RelativeSize = new Vector2(child.RelativeSize.X * stretchFactor, child.RelativeSize.Y);
}
}
}
else
{
child.RelativeOffset = new Vector2(child.RelativeOffset.X, relPos);
child.AbsoluteOffset = new Point(child.AbsoluteOffset.X, absPos);
absPos += (int)Math.Max((child.Rect.Height + absoluteSpacing) * stretchFactor, child.MinSize.Y);
if (stretch)
if (child.IsFixedSize)
{
child.RelativeSize = new Vector2(child.RelativeSize.X, child.RelativeSize.Y * stretchFactor);
absPos += child.NonScaledSize.Y + absoluteSpacing;
}
else
{
absPos += (int)(MathHelper.Clamp(child.Rect.Height * stretchFactor, child.MinSize.Y, child.MaxSize.Y) + (absoluteSpacing * stretchFactor));
if (stretch)
{
child.RelativeSize = new Vector2(child.RelativeSize.X, child.RelativeSize.Y * stretchFactor);
}
}
}
relPos += relativeSpacing * stretchFactor;
@@ -19,14 +19,39 @@ namespace Barotrauma
public delegate object CheckSelectedHandler();
public CheckSelectedHandler CheckSelected;
public GUIScrollBar ScrollBar { get; private set; }
public delegate void OnRearrangedHandler(GUIListBox listBox, object obj);
public OnRearrangedHandler OnRearranged;
/// <summary>
/// A frame drawn behind the content of the listbox
/// </summary>
public GUIFrame ContentBackground { get; private set; }
/// <summary>
/// A frame that contains the contents of the listbox. The frame itself is not rendered.
/// </summary>
public GUIFrame Content { get; private set; }
public GUIScrollBar ScrollBar { get; private set; }
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
private int totalSize;
private bool childrenNeedsRecalculation;
private bool scrollBarNeedsRecalculation;
private bool dimensionsNeedsRecalculation;
// TODO: Define in styles?
private int ScrollBarSize
{
get
{
//use the average of the "desired" size and the scaled size
//scaling the bar linearly with the resolution tends to make them too large on large resolutions
float desiredSize = 25.0f;
float scaledSize = desiredSize * GUI.Scale;
return (int)((desiredSize + scaledSize) / 2.0f);
}
}
public bool SelectMultiple;
@@ -46,6 +71,18 @@ namespace Barotrauma
}
}
private Vector4? overridePadding;
public Vector4 Padding
{
get
{
if (overridePadding.HasValue) { return overridePadding.Value; }
if (Style == null) { return Vector4.Zero; }
return Style.Padding;
}
set { overridePadding = value; }
}
public GUIComponent SelectedComponent
{
get
@@ -54,6 +91,7 @@ namespace Barotrauma
}
}
// TODO: fix implicit hiding
public bool Selected { get; set; }
public List<GUIComponent> AllSelected
@@ -114,6 +152,7 @@ namespace Barotrauma
/// Disables the scroll bar without hiding it.
/// </summary>
public bool ScrollBarEnabled { get; set; } = true;
public bool KeepSpaceForScrollBar { get; set; }
public bool ScrollBarVisible
{
@@ -123,8 +162,9 @@ namespace Barotrauma
}
set
{
if (ScrollBar.Visible == value) { return; }
ScrollBar.Visible = value;
AutoHideScrollBar = false;
dimensionsNeedsRecalculation = true;
}
}
@@ -132,70 +172,94 @@ namespace Barotrauma
/// Automatically hides the scroll bar when the content fits in.
/// </summary>
public bool AutoHideScrollBar { get; set; } = true;
private bool IsScrollBarOnDefaultSide { get; set; }
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "") : base(style, rectT)
public bool CanDragElements { get; set; } = false;
private GUIComponent draggedElement;
private Rectangle draggedReferenceRectangle;
private Point draggedReferenceOffset;
public GUIComponent DraggedElement => draggedElement;
/// <param name="isScrollBarOnDefaultSide">For horizontal listbox, default side is on the bottom. For vertical, it's on the right.</param>
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true) : base(style, rectT)
{
CanBeFocused = true;
selected = new List<GUIComponent>();
Point frameSize = isHorizontal ?
new Point(rectT.NonScaledSize.X, rectT.NonScaledSize.Y - 20) :
new Point(rectT.NonScaledSize.X - 20, rectT.NonScaledSize.Y);
Content = new GUIFrame(new RectTransform(frameSize, rectT), style)
ContentBackground = new GUIFrame(new RectTransform(Vector2.One, rectT), style)
{
CanBeFocused = false
};
Content = new GUIFrame(new RectTransform(Vector2.One, ContentBackground.RectTransform), style: null)
{
CanBeFocused = false
};
Content.RectTransform.ChildrenChanged += (_) =>
{
scrollBarNeedsRecalculation = true;
childrenNeedsRecalculation = true;
};
if (style != null) GUI.Style.Apply(Content, "", this);
if (style != null)
{
GUI.Style.Apply(ContentBackground, "", this);
}
if (color.HasValue)
{
this.color = color.Value;
}
IsScrollBarOnDefaultSide = isScrollBarOnDefaultSide;
Point size;
Anchor anchor;
if (isHorizontal)
{
ScrollBar = new GUIScrollBar(new RectTransform(new Point(Rect.Width, 20), rectT, Anchor.BottomLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, 20) }, isHorizontal: isHorizontal);
size = new Point((int)(Rect.Width - Padding.X - Padding.Z), (int)(ScrollBarSize * GUI.Scale));
anchor = isScrollBarOnDefaultSide ? Anchor.BottomCenter : Anchor.TopCenter;
}
else
{
ScrollBar = new GUIScrollBar(new RectTransform(new Point(20, Rect.Height), rectT, Anchor.TopRight, Pivot.TopLeft) { AbsoluteOffset = new Point(20, 0) }, isHorizontal: isHorizontal);
// TODO: Should this be multiplied by the GUI.Scale as well?
size = new Point(ScrollBarSize, (int)(Rect.Height - Padding.Y - Padding.W));
anchor = isScrollBarOnDefaultSide ? Anchor.CenterRight : Anchor.CenterLeft;
}
ScrollBar = new GUIScrollBar(
new RectTransform(size, rectT, anchor)
{
AbsoluteOffset = isHorizontal ?
new Point(0, IsScrollBarOnDefaultSide ? (int)Padding.W : (int)Padding.Y) :
new Point(IsScrollBarOnDefaultSide ? (int)Padding.Z : (int)Padding.X, 0)
},
isHorizontal: isHorizontal);
UpdateScrollBarSize();
Enabled = true;
ScrollBar.BarScroll = 0.0f;
RectTransform.ScaleChanged += UpdateDimensions;
RectTransform.SizeChanged += UpdateDimensions;
RectTransform.ScaleChanged += () => dimensionsNeedsRecalculation = true;
RectTransform.SizeChanged += () => dimensionsNeedsRecalculation = true;
UpdateDimensions();
}
private void UpdateDimensions()
{
if (!ScrollBar.Visible)
{
Content.RectTransform.NonScaledSize = Rect.Size;
}
else
{
Point frameSize = ScrollBar.IsHorizontal ?
new Point(Rect.Width, Rect.Height - 20) :
new Point(Rect.Width - 20, Rect.Height);
Content.RectTransform.NonScaledSize = frameSize;
}
ScrollBar.RectTransform.NonScaledSize = ScrollBar.IsHorizontal ? new Point(Rect.Width, 20) : new Point(20, Rect.Height);
dimensionsNeedsRecalculation = false;
ContentBackground.RectTransform.Resize(Rect.Size);
bool reduceScrollbarSize = KeepSpaceForScrollBar ? ScrollBarEnabled : ScrollBarVisible;
Point contentSize = reduceScrollbarSize ? CalculateFrameSize(ScrollBar.IsHorizontal, ScrollBarSize) : Rect.Size;
Content.RectTransform.Resize(new Point((int)(contentSize.X - Padding.X - Padding.Z), (int)(contentSize.Y - Padding.Y - Padding.W)));
if (!IsScrollBarOnDefaultSide) { Content.RectTransform.SetPosition(Anchor.BottomRight); }
Content.RectTransform.AbsoluteOffset = new Point(
IsScrollBarOnDefaultSide ? (int)Padding.X : (int)Padding.Z,
IsScrollBarOnDefaultSide ? (int)Padding.Y : (int)Padding.W);
ScrollBar.RectTransform.Resize(ScrollBar.IsHorizontal ?
new Point((int)(Rect.Width - Padding.X - Padding.Z), ScrollBarSize) :
new Point(ScrollBarSize, (int)(Rect.Height - Padding.Y - Padding.W)));
ScrollBar.RectTransform.AbsoluteOffset = ScrollBar.IsHorizontal ?
new Point(0, (int)Padding.W) :
new Point((int)Padding.Z, 0);
UpdateScrollBarSize();
}
public void Select(object userData, bool force = false, bool autoScroll = true)
{
var children = Content.Children;
int i = 0;
foreach (GUIComponent child in children)
{
@@ -209,9 +273,11 @@ namespace Barotrauma
}
}
private Point CalculateFrameSize(bool isHorizontal, int scrollBarSize)
=> isHorizontal ? new Point(Rect.Width, Rect.Height - scrollBarSize) : new Point(Rect.Width - scrollBarSize, Rect.Height);
private void RepositionChildren()
{
var children = Content.Children;
int x = 0, y = 0;
if (ScrollBar.BarSize < 1.0f)
{
@@ -231,7 +297,7 @@ namespace Barotrauma
if (!child.Visible) { continue; }
if (RectTransform != null)
{
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
@@ -245,7 +311,7 @@ namespace Barotrauma
{
y = 0;
x += child.Rect.Width + Spacing;
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
@@ -255,7 +321,6 @@ namespace Barotrauma
{
y += child.Rect.Height + Spacing;
}
}
else
{
@@ -263,7 +328,7 @@ namespace Barotrauma
{
x = 0;
y += child.Rect.Height + Spacing;
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
@@ -291,6 +356,44 @@ namespace Barotrauma
private void UpdateChildrenRect()
{
//dragging
if (CanDragElements && draggedElement != null)
{
if (!PlayerInput.LeftButtonHeld())
{
OnRearranged?.Invoke(this, draggedElement.UserData);
draggedElement = null;
RepositionChildren();
}
else
{
draggedElement.RectTransform.AbsoluteOffset = draggedReferenceOffset + new Point(0, (int)PlayerInput.MousePosition.Y - draggedReferenceRectangle.Center.Y);
int index = Content.RectTransform.GetChildIndex(draggedElement.RectTransform);
int currIndex = index;
while (currIndex > 0 && PlayerInput.MousePosition.Y < draggedReferenceRectangle.Top)
{
currIndex--;
draggedReferenceRectangle.Y -= draggedReferenceRectangle.Height;
draggedReferenceOffset.Y -= draggedReferenceRectangle.Height;
}
while (currIndex < Content.CountChildren - 1 && PlayerInput.MousePosition.Y > draggedReferenceRectangle.Bottom)
{
currIndex++;
draggedReferenceRectangle.Y += draggedReferenceRectangle.Height;
draggedReferenceOffset.Y += draggedReferenceRectangle.Height;
}
if (currIndex != index)
{
draggedElement.RectTransform.RepositionChildInHierarchy(currIndex);
}
return;
}
}
for (int i = 0; i < Content.CountChildren; i++)
{
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
@@ -300,10 +403,17 @@ namespace Barotrauma
if (Enabled && CanBeFocused && child.CanBeFocused && (GUI.IsMouseOn(child)) && child.Rect.Contains(PlayerInput.MousePosition))
{
child.State = ComponentState.Hover;
if (PlayerInput.LeftButtonClicked())
if (PlayerInput.PrimaryMouseButtonClicked())
{
Select(i, autoScroll: false);
}
if (CanDragElements && PlayerInput.LeftButtonDown() && GUI.MouseOn == child)
{
draggedElement = child;
draggedReferenceRectangle = child.Rect;
draggedReferenceOffset = child.RectTransform.AbsoluteOffset;
}
}
else if (selected.Contains(child))
{
@@ -329,7 +439,7 @@ namespace Barotrauma
{
foreach (GUIComponent child in Children)
{
if (child == Content || child == ScrollBar) { continue; }
if (child == Content || child == ScrollBar || child == ContentBackground) { continue; }
child.AddToGUIUpdateList(ignoreChildren, order);
}
}
@@ -360,7 +470,7 @@ namespace Barotrauma
OnAddedToGUIUpdateList?.Invoke(this);
return;
}
Content.AddToGUIUpdateList(true, order);
int lastVisible = 0;
for (int i = 0; i < Content.CountChildren; i++)
{
@@ -396,7 +506,7 @@ namespace Barotrauma
child.ClampMouseRectToParent = true;
//no need to go through grandchildren if the child is a GUIListBox, it handles this by itself
if (child is GUIListBox) return;
if (child is GUIListBox) { return; }
foreach (GUIComponent grandChild in child.Children)
{
@@ -406,7 +516,7 @@ namespace Barotrauma
protected override void Update(float deltaTime)
{
if (!Visible) return;
if (!Visible) { return; }
UpdateChildrenRect();
RepositionChildren();
@@ -414,23 +524,20 @@ namespace Barotrauma
if (scrollBarNeedsRecalculation)
{
UpdateScrollBarSize();
scrollBarNeedsRecalculation = false;
}
bool prevScrollBarVisible = ScrollBar.Visible;
ScrollBar.Enabled = ScrollBarEnabled && ScrollBar.BarSize < 1.0f;
if (AutoHideScrollBar)
{
ScrollBar.Visible = ScrollBar.BarSize < 1.0f;
}
if (ScrollBar.Visible != prevScrollBarVisible) { UpdateDimensions(); }
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && PlayerInput.ScrollWheelSpeed != 0)
{
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
}
ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
if (AutoHideScrollBar)
{
ScrollBarVisible = ScrollBar.Enabled;
}
if (dimensionsNeedsRecalculation)
{
UpdateDimensions();
}
}
public void SelectNext(bool force = false, bool autoScroll = true)
@@ -463,14 +570,18 @@ namespace Barotrauma
public void Select(int childIndex, bool force = false, bool autoScroll = true)
{
if (childIndex >= Content.CountChildren || childIndex < 0) return;
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
GUIComponent child = Content.GetChild(childIndex);
bool wasSelected = true;
if (OnSelected != null) wasSelected = force || OnSelected(child, child.UserData);
if (!wasSelected) return;
if (OnSelected != null)
{
// TODO: The callback is called twice, fix this!
wasSelected = force || OnSelected(child, child.UserData);
}
if (!wasSelected) { return; }
if (SelectMultiple)
{
@@ -541,7 +652,8 @@ namespace Barotrauma
public void UpdateScrollBarSize()
{
if (Content == null) return;
scrollBarNeedsRecalculation = false;
if (Content == null) { return; }
totalSize = 0;
var children = Content.Children.Where(c => c.Visible);
@@ -589,10 +701,10 @@ namespace Barotrauma
totalSize += Content.CountChildren * Spacing;
}
float minScrollBarSize = 20.0f;
ScrollBar.BarSize = ScrollBar.IsHorizontal ?
Math.Max(Math.Min(Content.Rect.Width / (float)totalSize, 1.0f), 5.0f / Content.Rect.Width) :
Math.Max(Math.Min(Content.Rect.Height / (float)totalSize, 1.0f), 5.0f / Content.Rect.Height);
Math.Max(Math.Min(Content.Rect.Width / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Width) :
Math.Max(Math.Min(Content.Rect.Height / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Height);
}
public override void ClearChildren()
@@ -603,7 +715,7 @@ namespace Barotrauma
public override void RemoveChild(GUIComponent child)
{
if (child == null) return;
if (child == null) { return; }
child.RectTransform.Parent = null;
if (selected.Contains(child)) selected.Remove(child);
UpdateScrollBarSize();
@@ -617,10 +729,10 @@ namespace Barotrauma
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
if (!Visible) { return; }
ContentBackground.DrawManually(spriteBatch, alsoChildren: false);
Content.DrawManually(spriteBatch, alsoChildren: false);
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
if (HideChildrenOutsideFrame)
@@ -654,22 +766,25 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState);
}
if (ScrollBar.Visible) ScrollBar.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
if (ScrollBarVisible)
{
ScrollBar.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
}
}
private bool IsChildInsideFrame(GUIComponent child)
{
if (child == null) return false;
if (child == null) { return false; }
if (ScrollBar.IsHorizontal)
{
if (child.Rect.Right < Content.Rect.X) return false;
if (child.Rect.X > Content.Rect.Right) return false;
if (child.Rect.Right < Content.Rect.X) { return false; }
if (child.Rect.X > Content.Rect.Right) { return false; }
}
else
{
if (child.Rect.Bottom < Content.Rect.Y) return false;
if (child.Rect.Y > Content.Rect.Bottom) return false;
if (child.Rect.Bottom < Content.Rect.Y) { return false; }
if (child.Rect.Y > Content.Rect.Bottom) { return false; }
}
return true;
@@ -14,6 +14,9 @@ namespace Barotrauma
get { return Math.Max(400, 400 * (GameMain.GraphicsWidth / 1920)); }
}
private float inGameCloseTimer = 0.0f;
private const float inGameCloseTime = 15f;
public enum Type
{
Default,
@@ -87,7 +90,7 @@ namespace Barotrauma
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
headerText, textAlignment: Alignment.Center, wrap: true);
headerText, font: GUI.SubHeadingFont, textAlignment: Alignment.Center, wrap: true);
GUI.Style.Apply(Header, "", this);
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
@@ -100,21 +103,28 @@ namespace Barotrauma
Text.RectTransform.IsFixedSize = true;
}
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter, maxSize: new Point(1000, 50)),
isHorizontal: true, childAnchor: buttons.Length > 1 ? Anchor.BottomLeft : Anchor.Center)
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter), childAnchor: Anchor.TopCenter)
{
AbsoluteSpacing = 5,
IgnoreLayoutGroups = true
};
int buttonSize = 35;
var buttonStyle = GUI.Style.GetComponentStyle("GUIButton");
if (buttonStyle != null && buttonStyle.Height.HasValue)
{
buttonSize = buttonStyle.Height.Value;
}
buttonContainer.RectTransform.NonScaledSize = buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.MaxSize =
new Point(buttonContainer.Rect.Width, (int)(30 * GUI.Scale));
new Point(buttonContainer.Rect.Width, (int)((buttonSize + 5) * buttons.Length));
buttonContainer.RectTransform.IsFixedSize = true;
if (height == 0)
{
height += Header.Rect.Height + Content.AbsoluteSpacing;
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
height += buttonContainer.Rect.Height;
height += buttonContainer.Rect.Height + 20;
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
InnerFrame.RectTransform.NonScaledSize =
@@ -126,7 +136,7 @@ namespace Barotrauma
Buttons = new List<GUIButton>(buttons.Length);
for (int i = 0; i < buttons.Length; i++)
{
var button = new GUIButton(new RectTransform(new Vector2(Math.Min(0.9f / buttons.Length, 0.5f), 1.0f), buttonContainer.RectTransform), buttons[i], style: "GUIButtonLarge");
var button = new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f / buttons.Length), buttonContainer.RectTransform), buttons[i]);
Buttons.Add(button);
}
}
@@ -154,7 +164,7 @@ namespace Barotrauma
Buttons = new List<GUIButton>(1)
{
new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
style: GUI.Style.GetComponentStyle("GUIButtonSolidHorizontalArrow") != null ? "GUIButtonSolidHorizontalArrow" : "GUIButtonHorizontalArrow")
style: "GUIButtonHorizontalArrow")
{
OnClicked = Close
}
@@ -168,10 +178,10 @@ namespace Barotrauma
{
Text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), text, textAlignment: textAlignment, wrap: true);
GUI.Style.Apply(Text, "", this);
/*Content.Recalculate();
Content.Recalculate();
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
new Point(Text.Rect.Width, Text.Rect.Height);
Text.RectTransform.IsFixedSize = true;*/
Text.RectTransform.IsFixedSize = true;
}
if (height == 0)
@@ -238,6 +248,13 @@ namespace Barotrauma
{
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
inGameCloseTimer += deltaTime;
if (inGameCloseTimer >= inGameCloseTime)
{
Close();
}
}
else
{
@@ -16,8 +16,8 @@ namespace Barotrauma
public OnValueChangedHandler OnValueChanged;
public GUITextBox TextBox { get; private set; }
public GUIButton PlusButton { get; private set; }
public GUIButton MinusButton { get; private set; }
private GUIButton plusButton, minusButton;
private NumberType inputType;
public NumberType InputType
@@ -25,10 +25,17 @@ namespace Barotrauma
get { return inputType; }
set
{
if (inputType == value) { return; }
inputType = value;
PlusButton.Visible = inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
MinusButton.Visible = PlusButton.Visible;
if (inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue))
{
ShowPlusMinusButtons();
}
else
{
HidePlusMinusButtons();
}
}
}
@@ -40,9 +47,15 @@ namespace Barotrauma
{
minValueFloat = value;
ClampFloatValue();
PlusButton.Visible = inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
MinusButton.Visible = PlusButton.Visible;
if (inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue))
{
ShowPlusMinusButtons();
}
else
{
HidePlusMinusButtons();
}
}
}
public float? MaxValueFloat
@@ -52,9 +65,15 @@ namespace Barotrauma
{
maxValueFloat = value;
ClampFloatValue();
PlusButton.Visible = inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
MinusButton.Visible = PlusButton.Visible;
if (inputType == NumberType.Int ||
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue))
{
ShowPlusMinusButtons();
}
else
{
HidePlusMinusButtons();
}
}
}
@@ -64,7 +83,7 @@ namespace Barotrauma
get { return floatValue; }
set
{
if (value == floatValue) return;
if (MathUtils.NearlyEqual(value, floatValue)) return;
floatValue = value;
ClampFloatValue();
float newValue = floatValue;
@@ -115,7 +134,23 @@ namespace Barotrauma
if (value == intValue) return;
intValue = value;
UpdateText();
OnValueChanged?.Invoke(this);
}
}
public override bool Enabled
{
get => base.Enabled;
set
{
plusButton.Enabled = true;
minusButton.Enabled = true;
if (InputType == NumberType.Int) { ClampIntValue(); } else { ClampFloatValue(); }
TextBox.Enabled = value;
if (!value)
{
plusButton.Enabled = false;
minusButton.Enabled = false;
}
}
}
@@ -146,37 +181,31 @@ namespace Barotrauma
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null) : base(style, rectT)
{
LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true) { Stretch = true };
LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
float _relativeButtonAreaWidth = relativeButtonAreaWidth ?? MathHelper.Clamp(Rect.Height / (float)Rect.Width, 0.1f, 0.5f);
float _relativeButtonAreaWidth = relativeButtonAreaWidth ?? MathHelper.Clamp(Rect.Height / (float)Rect.Width, 0.1f, 0.25f);
TextBox = new GUITextBox(new RectTransform(new Vector2(1.0f - _relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform), textAlignment: textAlignment, style: style)
TextBox = new GUITextBox(new RectTransform(new Vector2(1.0f - _relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform), textAlignment: textAlignment, style: "GUITextBoxNoIcon")
{
ClampText = false,
// For some reason the caret in the number inputs is dimmer than it should.
// It should not be rendered behind anything, as I first suspected.
// Therefore this hack.
CaretColor = Color.White
ClampText = false
};
TextBox.CaretColor = TextBox.TextColor;
TextBox.OnTextChanged += TextChanged;
var buttonArea = new GUIFrame(new RectTransform(new Vector2(_relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight), style: null);
/*if (!relativeButtonAreaWidth.HasValue)
{
// Not sure what's the point of this
buttonArea.RectTransform.MinSize = new Point(Rect.Height, 0);
}*/
PlusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), "+");
PlusButton.OnButtonDown += () =>
plusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), style: null);
GUI.Style.Apply(plusButton, "PlusButton", this);
plusButton.OnButtonDown += () =>
{
pressedTimer = pressedDelay;
return true;
};
PlusButton.OnClicked += (button, data) =>
plusButton.OnClicked += (button, data) =>
{
IncreaseValue();
return true;
};
PlusButton.OnPressed += () =>
plusButton.OnPressed += () =>
{
if (!IsPressedTimerRunning)
{
@@ -184,20 +213,20 @@ namespace Barotrauma
}
return true;
};
PlusButton.Visible = inputType == NumberType.Int;
MinusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), "-");
MinusButton.OnButtonDown += () =>
minusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), style: null);
GUI.Style.Apply(minusButton, "MinusButton", this);
minusButton.OnButtonDown += () =>
{
pressedTimer = pressedDelay;
return true;
};
MinusButton.OnClicked += (button, data) =>
minusButton.OnClicked += (button, data) =>
{
ReduceValue();
return true;
};
MinusButton.OnPressed += () =>
minusButton.OnPressed += () =>
{
if (!IsPressedTimerRunning)
{
@@ -205,7 +234,11 @@ namespace Barotrauma
}
return true;
};
MinusButton.Visible = inputType == NumberType.Int;
if (inputType != NumberType.Int)
{
HidePlusMinusButtons();
}
if (inputType == NumberType.Int)
{
@@ -240,6 +273,23 @@ namespace Barotrauma
break;
}
RectTransform.MinSize = TextBox.RectTransform.MinSize;
LayoutGroup.Recalculate();
}
private void HidePlusMinusButtons()
{
plusButton.Parent.Visible = false;
plusButton.Parent.IgnoreLayoutGroups = true;
TextBox.RectTransform.RelativeSize = Vector2.One;
LayoutGroup.Recalculate();
}
private void ShowPlusMinusButtons()
{
plusButton.Parent.Visible = true;
plusButton.Parent.IgnoreLayoutGroups = false;
TextBox.RectTransform.RelativeSize = new Vector2(1.0f - plusButton.Parent.RectTransform.RelativeSize.X, 1.0f);
LayoutGroup.Recalculate();
}
@@ -319,12 +369,12 @@ namespace Barotrauma
if (MinValueFloat != null)
{
floatValue = Math.Max(floatValue, MinValueFloat.Value);
MinusButton.Enabled = floatValue > MinValueFloat;
minusButton.Enabled = floatValue > MinValueFloat;
}
if (MaxValueFloat != null)
{
floatValue = Math.Min(floatValue, MaxValueFloat.Value);
PlusButton.Enabled = floatValue < MaxValueFloat;
plusButton.Enabled = floatValue < MaxValueFloat;
}
}
@@ -333,12 +383,12 @@ namespace Barotrauma
if (MinValueInt != null)
{
intValue = Math.Max(intValue, MinValueInt.Value);
MinusButton.Enabled = intValue > MinValueInt;
minusButton.Enabled = intValue > MinValueInt;
}
if (MaxValueInt != null)
{
intValue = Math.Min(intValue, MaxValueInt.Value);
PlusButton.Enabled = intValue < MaxValueInt;
plusButton.Enabled = intValue < MaxValueInt;
}
}
@@ -1,15 +1,16 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
{
public class GUIProgressBar : GUIComponent
{
private bool isHorizontal;
private GUIFrame frame, slider;
private readonly GUIFrame frame, slider;
private float barSize;
private readonly bool showFrame;
public delegate float ProgressGetterHandler();
public ProgressGetterHandler ProgressGetter;
@@ -38,7 +39,7 @@ namespace Barotrauma
}
}
public GUIProgressBar(RectTransform rectT, float barSize, Color? color = null, string style = "") : base(style, rectT)
public GUIProgressBar(RectTransform rectT, float barSize, Color? color = null, string style = "", bool showFrame = true) : base(style, rectT)
{
if (color.HasValue)
{
@@ -49,12 +50,53 @@ namespace Barotrauma
GUI.Style.Apply(frame, "", this);
slider = new GUIFrame(new RectTransform(Vector2.One, rectT));
GUI.Style.Apply(slider, "Slider", this);
this.showFrame = showFrame;
this.barSize = barSize;
Enabled = true;
}
/// <summary>
/// Get the area the slider should be drawn inside
/// </summary>
/// <param name="fillAmount">0 = empty, 1 = full</param>
public Rectangle GetSliderRect(float fillAmount)
{
Rectangle sliderArea = new Rectangle(
frame.Rect.X + (int)style.Padding.X,
frame.Rect.Y + (int)style.Padding.Y,
(int)(frame.Rect.Width - style.Padding.X - style.Padding.Z),
(int)(frame.Rect.Height - style.Padding.Y - style.Padding.W));
Vector4 sliceBorderSizes = Vector4.Zero;
if (slider.sprites.ContainsKey(slider.State) && (slider.sprites[slider.State].First()?.Slice ?? false))
{
var slices = slider.sprites[slider.State].First().Slices;
sliceBorderSizes = new Vector4(slices[0].Width, slices[0].Height, slices[8].Width, slices[8].Height);
sliceBorderSizes *= slider.sprites[slider.State].First().GetSliceBorderScale(sliderArea.Size);
}
Rectangle sliderRect = IsHorizontal ?
new Rectangle(
sliderArea.X + (int)sliceBorderSizes.X,
sliderArea.Y,
(int)((sliderArea.Width - sliceBorderSizes.X - sliceBorderSizes.Z) * fillAmount),
sliderArea.Height)
:
new Rectangle(
sliderArea.X,
(int)(sliderArea.Bottom - (sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount - sliceBorderSizes.W),
sliderArea.Width,
(int)((sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount));
sliderRect.Width = Math.Max(sliderRect.Width, 1);
sliderRect.Height = Math.Max(sliderRect.Height, 1);
return sliderRect;
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
if (!Visible) { return; }
if (ProgressGetter != null)
{
@@ -72,21 +114,25 @@ namespace Barotrauma
}
}
Rectangle sliderRect = new Rectangle(
frame.Rect.X,
(int)(frame.Rect.Y + (isHorizontal ? 0 : frame.Rect.Height * (1.0f - barSize))),
isHorizontal ? (int)((frame.Rect.Width) * barSize) : frame.Rect.Width,
isHorizontal ? (int)(frame.Rect.Height) : (int)(frame.Rect.Height * barSize));
frame.Visible = true;
var sliderRect = GetSliderRect(barSize);
slider.RectTransform.AbsoluteOffset = new Point((int)style.Padding.X, (int)style.Padding.Y);
slider.RectTransform.MaxSize = new Point(
(int)(Rect.Width - style.Padding.X + style.Padding.Z),
(int)(Rect.Height - style.Padding.Y + style.Padding.W));
frame.Visible = showFrame;
slider.Visible = true;
if (AutoDraw)
if (showFrame)
{
frame.DrawAuto(spriteBatch);
}
else
{
frame.DrawManually(spriteBatch);
if (AutoDraw)
{
frame.DrawAuto(spriteBatch);
}
else
{
frame.DrawManually(spriteBatch);
}
}
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
@@ -97,7 +143,7 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
Color currColor = GetCurrentColor(state);
Color currColor = GetColor(State);
slider.Color = currColor;
if (AutoDraw)
@@ -54,8 +54,9 @@ namespace Barotrauma
}
}
private int? selected;
public int? Selected
// intentional hiding?
private new int? selected;
public new int? Selected
{
get
{
@@ -64,7 +65,7 @@ namespace Barotrauma
set
{
OnSelect?.Invoke(this, value);
if (selected != null && selected.Equals(value)) return;
if (selected != null && selected.Equals(value)) { return; }
selected = value;
foreach (KeyValuePair<int, GUITickBox> radioButton in radioButtons)
{
@@ -72,7 +73,10 @@ namespace Barotrauma
{
radioButton.Value.Selected = true;
}
else if (radioButton.Value.Selected) radioButton.Value.Selected = false;
else if (radioButton.Value.Selected)
{
radioButton.Value.Selected = false;
}
}
}
}
@@ -7,7 +7,10 @@ namespace Barotrauma
{
public class GUIScrollBar : GUIComponent
{
public static GUIScrollBar draggingBar;
public static GUIScrollBar DraggingBar
{
get; private set;
}
private bool isHorizontal;
@@ -19,11 +22,11 @@ namespace Barotrauma
private float step;
private Vector2? dragStartPos;
public delegate bool OnMovedHandler(GUIScrollBar scrollBar, float barScroll);
public OnMovedHandler OnMoved;
public OnMovedHandler OnReleased;
public bool IsBooleanSwitch;
public override string ToolTip
@@ -77,7 +80,11 @@ namespace Barotrauma
{
enabled = value;
Bar.Enabled = value;
if (!enabled) Bar.Selected = false;
Children.ForEach(c => c.Enabled = value);
if (!enabled)
{
Bar.Selected = false;
}
}
}
@@ -113,12 +120,12 @@ namespace Barotrauma
{
get
{
if (ScrollToValue==null) return (BarScroll * (Range.Y - Range.X)) + Range.X;
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);
if (ValueToScroll == null) BarScroll = (value - Range.X) / (Range.Y - Range.X);
else BarScroll = ValueToScroll(this, value);
}
}
@@ -179,22 +186,39 @@ namespace Barotrauma
public float BarSize
{
get { return barSize; }
set
set
{
barSize = Math.Min(Math.Max(value, 0.0f), 1.0f);
UpdateRect();
}
}
public GUIScrollBar(RectTransform rectT, float barSize = 1, Color? color = null, string style = "", bool? isHorizontal = null) : base(style, rectT)
{
CanBeFocused = true;
this.isHorizontal = isHorizontal ?? (Rect.Width > Rect.Height);
Frame = new GUIFrame(new RectTransform(Vector2.One, rectT));
GUI.Style.Apply(Frame, IsHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this);
this.barSize = barSize;
Bar = new GUIButton(new RectTransform(Vector2.One, rectT, IsHorizontal ? Anchor.CenterLeft : Anchor.TopCenter), color: color);
Bar = new GUIButton(new RectTransform(Vector2.One, rectT, IsHorizontal ? Anchor.CenterLeft : Anchor.TopCenter), color: color, style: null);
switch (style)
{
case "":
HoverCursor = CursorState.Default;
Bar.HoverCursor = CursorState.Default;
break;
case "GUISlider":
HoverCursor = CursorState.Default;
Bar.HoverCursor = CursorState.Hand;
break;
default:
HoverCursor = CursorState.Hand;
Bar.HoverCursor = CursorState.Hand;
break;
}
GUI.Style.Apply(Bar, IsHorizontal ? "GUIButtonHorizontal" : "GUIButtonVertical", this);
Bar.OnPressed = SelectBar;
enabled = true;
@@ -219,12 +243,16 @@ namespace Barotrauma
{
if (!Visible) { return; }
base.Update(deltaTime);
if (!enabled) { return; }
Frame.State = GUI.MouseOn == Frame ? ComponentState.Hover : ComponentState.None;
if (Frame.State == ComponentState.Hover && PlayerInput.PrimaryMouseButtonHeld())
{
Frame.State = ComponentState.Pressed;
}
if (IsBooleanSwitch &&
(!PlayerInput.LeftButtonHeld() || (GUI.MouseOn != this && !IsParentOf(GUI.MouseOn))))
(!PlayerInput.PrimaryMouseButtonHeld() || (GUI.MouseOn != this && !IsParentOf(GUI.MouseOn))))
{
int dir = Math.Sign(barScroll - (minValue + maxValue) / 2.0f);
if (dir == 0) dir = 1;
@@ -235,11 +263,12 @@ namespace Barotrauma
}
}
if (draggingBar == this)
if (DraggingBar == this)
{
GUI.ForceMouseOn(this);
if (dragStartPos == null) { dragStartPos = PlayerInput.MousePosition; }
if (!PlayerInput.LeftButtonHeld())
if (!PlayerInput.PrimaryMouseButtonHeld())
{
if (IsBooleanSwitch && GUI.MouseOn == Bar && Vector2.Distance(dragStartPos.Value, PlayerInput.MousePosition) < 5)
{
@@ -247,7 +276,7 @@ namespace Barotrauma
OnMoved?.Invoke(this, BarScroll);
}
OnReleased?.Invoke(this, BarScroll);
draggingBar = null;
DraggingBar = null;
dragStartPos = null;
}
@@ -259,9 +288,9 @@ namespace Barotrauma
}
else if (GUI.MouseOn == Frame)
{
if (PlayerInput.LeftButtonClicked())
if (PlayerInput.PrimaryMouseButtonClicked())
{
draggingBar?.OnReleased?.Invoke(draggingBar, draggingBar.BarScroll);
DraggingBar?.OnReleased?.Invoke(DraggingBar, DraggingBar.BarScroll);
if (IsBooleanSwitch)
{
MoveButton(new Vector2(
@@ -280,10 +309,10 @@ namespace Barotrauma
private bool SelectBar()
{
if (!enabled || !PlayerInput.LeftButtonDown()) { return false; }
if (!enabled || !PlayerInput.PrimaryMouseButtonDown()) { return false; }
if (barSize >= 1.0f) { return false; }
draggingBar = this;
DraggingBar = this;
return true;
}
@@ -0,0 +1,431 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma
{
public class GUIStyle
{
private Dictionary<string, GUIComponentStyle> componentStyles;
private XElement configElement;
private GraphicsDevice graphicsDevice;
private ScalableFont defaultFont;
public ScalableFont Font { get; private set; }
public ScalableFont GlobalFont { get; private set; }
public ScalableFont UnscaledSmallFont { get; private set; }
public ScalableFont SmallFont { get; private set; }
public ScalableFont LargeFont { get; private set; }
public ScalableFont SubHeadingFont { get; private set; }
public ScalableFont DigitalFont { get; private set; }
public ScalableFont HotkeyFont { get; private set; }
public Dictionary<ScalableFont, bool> ForceFontUpperCase
{
get;
private set;
} = new Dictionary<ScalableFont, bool>();
public readonly Sprite[] CursorSprite = new Sprite[7];
public UISprite UIGlow { get; private set; }
public UISprite UIGlowCircular { get; private set; }
public SpriteSheet FocusIndicator { get; private set; }
/// <summary>
/// General green color used for elements whose colors are set from code
/// </summary>
public Color Green { get; private set; } = Color.LightGreen;
/// <summary>
/// General red color used for elements whose colors are set from code
/// </summary>
public Color Orange { get; private set; } = Color.Orange;
/// <summary>
/// General red color used for elements whose colors are set from code
/// </summary>
public Color Red { get; private set; } = Color.Red;
/// <summary>
/// General blue color used for elements whose colors are set from code
/// </summary>
public Color Blue { get; private set; } = Color.Blue;
public Color ColorInventoryEmpty { get; private set; } = Color.Red;
public Color ColorInventoryHalf { get; private set; } = Color.Orange;
public Color ColorInventoryFull { get; private set; } = Color.LightGreen;
public Color ColorInventoryBackground { get; private set; } = Color.Gray;
public Color TextColor { get; private set; } = Color.White * 0.8f;
public Color TextColorBright { get; private set; } = Color.White * 0.9f;
public Color TextColorDark { get; private set; } = Color.Black * 0.9f;
public Color TextColorDim { get; private set; } = Color.White * 0.6f;
// Inventory
public Color EquipmentSlotIconColor { get; private set; } = new Color(99, 70, 64);
// Health HUD
public Color BuffColorLow { get; private set; } = Color.LightGreen;
public Color BuffColorMedium { get; private set; } = Color.Green;
public Color BuffColorHigh { get; private set; } = Color.DarkGreen;
public Color DebuffColorLow { get; private set; } = Color.DarkSalmon;
public Color DebuffColorMedium { get; private set; } = Color.Red;
public Color DebuffColorHigh { get; private set; } = Color.DarkRed;
public Color HealthBarColorLow { get; private set; } = Color.Red;
public Color HealthBarColorMedium { get; private set; } = Color.Orange;
public Color HealthBarColorHigh { get; private set; } = new Color(78, 114, 88);
public Color EquipmentIndicatorNotEquipped { get; private set; } = Color.Gray;
public Color EquipmentIndicatorEquipped { get; private set; } = new Color(105, 202, 125);
public Color EquipmentIndicatorRunningOut { get; private set; } = new Color(202, 105, 105);
public static Point ItemFrameMargin => new Point(50, 56).Multiply(GUI.SlicedSpriteScale);
public static Point ItemFrameOffset => new Point(0, 3).Multiply(GUI.SlicedSpriteScale);
public GUIStyle(XElement element, GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
componentStyles = new Dictionary<string, GUIComponentStyle>();
configElement = element;
foreach (XElement subElement in configElement.Elements())
{
var name = subElement.Name.ToString().ToLowerInvariant();
switch (name)
{
case "cursor":
if (subElement.HasElements)
{
foreach (var children in subElement.Descendants())
{
var index = children.GetAttributeInt("state", (int)CursorState.Default);
CursorSprite[index] = new Sprite(children);
}
}
else
{
CursorSprite[(int)CursorState.Default] = new Sprite(subElement);
}
break;
case "green":
Green = subElement.GetAttributeColor("color", Green);
break;
case "orange":
Orange = subElement.GetAttributeColor("color", Orange);
break;
case "red":
Red = subElement.GetAttributeColor("color", Red);
break;
case "blue":
Blue = subElement.GetAttributeColor("color", Blue);
break;
case "colorinventoryempty":
ColorInventoryEmpty = subElement.GetAttributeColor("color", ColorInventoryEmpty);
break;
case "colorinventoryhalf":
ColorInventoryHalf = subElement.GetAttributeColor("color", ColorInventoryHalf);
break;
case "colorinventoryfull":
ColorInventoryFull = subElement.GetAttributeColor("color", ColorInventoryFull);
break;
case "colorinventorybackground":
ColorInventoryBackground = subElement.GetAttributeColor("color", ColorInventoryBackground);
break;
case "textcolordark":
TextColorDark = subElement.GetAttributeColor("color", TextColorDark);
break;
case "textcolorbright":
TextColorBright = subElement.GetAttributeColor("color", TextColorBright);
break;
case "textcolordim":
TextColorDim = subElement.GetAttributeColor("color", TextColorDim);
break;
case "textcolornormal":
case "textcolor":
TextColor = subElement.GetAttributeColor("color", TextColor);
break;
case "equipmentsloticoncolor":
EquipmentSlotIconColor = subElement.GetAttributeColor("color", EquipmentSlotIconColor);
break;
case "buffcolorlow":
BuffColorLow = subElement.GetAttributeColor("color", BuffColorLow);
break;
case "buffcolormedium":
BuffColorMedium = subElement.GetAttributeColor("color", BuffColorMedium);
break;
case "buffcolorhigh":
BuffColorHigh = subElement.GetAttributeColor("color", BuffColorHigh);
break;
case "debuffcolorlow":
DebuffColorLow = subElement.GetAttributeColor("color", DebuffColorLow);
break;
case "debuffcolormedium":
DebuffColorMedium = subElement.GetAttributeColor("color", DebuffColorMedium);
break;
case "debuffcolorhigh":
DebuffColorHigh = subElement.GetAttributeColor("color", DebuffColorHigh);
break;
case "healthbarcolorlow":
HealthBarColorLow = subElement.GetAttributeColor("color", HealthBarColorLow);
break;
case "healthbarcolormedium":
HealthBarColorMedium = subElement.GetAttributeColor("color", HealthBarColorMedium);
break;
case "healthbarcolorhigh":
HealthBarColorHigh = subElement.GetAttributeColor("color", HealthBarColorHigh);
break;
case "equipmentindicatornotequipped":
EquipmentIndicatorNotEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorNotEquipped);
break;
case "equipmentindicatorequipped":
EquipmentIndicatorEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorEquipped);
break;
case "equipmentindicatorrunningout":
EquipmentIndicatorRunningOut = subElement.GetAttributeColor("color", EquipmentIndicatorRunningOut);
break;
case "uiglow":
UIGlow = new UISprite(subElement);
break;
case "uiglowcircular":
UIGlowCircular = new UISprite(subElement);
break;
case "focusindicator":
FocusIndicator = new SpriteSheet(subElement);
break;
case "font":
Font = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[Font] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "globalfont":
GlobalFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[GlobalFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "unscaledsmallfont":
UnscaledSmallFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[UnscaledSmallFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "smallfont":
SmallFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[SmallFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "largefont":
LargeFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[LargeFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "digitalfont":
DigitalFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[DigitalFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "hotkeyfont":
HotkeyFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[HotkeyFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
case "objectivetitle":
case "subheading":
SubHeadingFont = LoadFont(subElement, graphicsDevice);
ForceFontUpperCase[SubHeadingFont] = subElement.GetAttributeBool("forceuppercase", false);
break;
default:
GUIComponentStyle componentStyle = new GUIComponentStyle(subElement, this);
componentStyles.Add(subElement.Name.ToString().ToLowerInvariant(), componentStyle);
break;
}
}
if (GlobalFont == null)
{
GlobalFont = Font;
DebugConsole.NewMessage("Global font not defined in the current UI style file. The global font is used to render western symbols when using Chinese/Japanese/Korean localization. Using default font instead...", Color.Orange);
}
GameMain.Instance.OnResolutionChanged += () => { RescaleElements(); };
}
/// <summary>
/// Returns the default font of the currently selected language
/// </summary>
public ScalableFont LoadCurrentDefaultFont()
{
defaultFont?.Dispose();
defaultFont = null;
foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "font":
defaultFont = LoadFont(subElement, graphicsDevice);
break;
}
}
return defaultFont;
}
private void RescaleElements()
{
if (configElement == null) { return; }
if (configElement.Elements() == null) { return; }
foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "font":
if (Font == null) { continue; }
Font.Size = GetFontSize(subElement);
break;
case "smallfont":
if (SmallFont == null) { continue; }
SmallFont.Size = GetFontSize(subElement);
break;
case "largefont":
if (LargeFont == null) { continue; }
LargeFont.Size = GetFontSize(subElement);
break;
case "hotkeyfont":
if (HotkeyFont == null) { continue; }
HotkeyFont.Size = GetFontSize(subElement);
break;
case "objectivetitle":
case "subheading":
if (SubHeadingFont == null) { continue; }
SubHeadingFont.Size = GetFontSize(subElement);
break;
}
}
foreach (var componentStyle in componentStyles.Values)
{
componentStyle.GetSize(componentStyle.Element);
foreach (var childStyle in componentStyle.ChildStyles.Values)
{
childStyle.GetSize(childStyle.Element);
}
}
}
private ScalableFont LoadFont(XElement element, GraphicsDevice graphicsDevice)
{
string file = GetFontFilePath(element);
uint size = GetFontSize(element);
bool dynamicLoading = GetFontDynamicLoading(element);
bool isCJK = GetIsCJK(element);
return new ScalableFont(file, size, graphicsDevice, dynamicLoading, isCJK);
}
private uint GetFontSize(XElement element, uint defaultSize = 14)
{
//check if any of the language override fonts want to override the font size as well
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
uint overrideFontSize = GetFontSize(subElement, 0);
if (overrideFontSize > 0) { return overrideFontSize; }
}
}
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{
return (uint)subElement.GetAttributeInt("size", 14);
}
}
return defaultSize;
}
private string GetFontFilePath(XElement element)
{
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeString("file", "");
}
}
return element.GetAttributeString("file", "");
}
private bool GetFontDynamicLoading(XElement element)
{
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeBool("dynamicloading", false);
}
}
return element.GetAttributeBool("dynamicloading", false);
}
private bool GetIsCJK(XElement element)
{
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeBool("iscjk", false);
}
}
return element.GetAttributeBool("iscjk", false);
}
public GUIComponentStyle GetComponentStyle(string name)
{
componentStyles.TryGetValue(name.ToLowerInvariant(), out GUIComponentStyle style);
return style;
}
public void Apply(GUIComponent targetComponent, string styleName = "", GUIComponent parent = null)
{
GUIComponentStyle componentStyle = null;
if (parent != null)
{
GUIComponentStyle parentStyle = parent.Style;
if (parent.Style == null)
{
string parentStyleName = parent.GetType().Name.ToLowerInvariant();
if (!componentStyles.TryGetValue(parentStyleName, out parentStyle))
{
DebugConsole.ThrowError("Couldn't find a GUI style \""+ parentStyleName + "\"");
return;
}
}
string childStyleName = string.IsNullOrEmpty(styleName) ? targetComponent.GetType().Name : styleName;
parentStyle.ChildStyles.TryGetValue(childStyleName.ToLowerInvariant(), out componentStyle);
}
else
{
if (string.IsNullOrEmpty(styleName))
{
styleName = targetComponent.GetType().Name;
}
if (!componentStyles.TryGetValue(styleName.ToLowerInvariant(), out componentStyle))
{
DebugConsole.ThrowError("Couldn't find a GUI style \""+ styleName+"\"");
return;
}
}
targetComponent.ApplyStyle(componentStyle);
}
}
}
@@ -16,8 +16,8 @@ namespace Barotrauma
protected Vector2 textPos;
protected Vector2 origin;
protected Color textColor;
protected Color textColor, disabledTextColor, selectedTextColor;
private string wrappedText;
private string censoredText;
@@ -63,8 +63,12 @@ namespace Barotrauma
}
set
{
if (base.Font == value) return;
if (base.Font == value) { return; }
base.Font = originalFont = value;
if (text != null && GUI.Style.ForceFontUpperCase.ContainsKey(Font) && GUI.Style.ForceFontUpperCase[Font])
{
Text = text.ToUpper();
}
SetTextPos();
}
}
@@ -74,13 +78,14 @@ namespace Barotrauma
get { return text; }
set
{
string newText = forceUpperCase ? value?.ToUpper() : value;
string newText = forceUpperCase || (GUI.Style.ForceFontUpperCase.ContainsKey(Font) && GUI.Style.ForceFontUpperCase[Font]) || (style != null && style.ForceUpperCase) ?
value?.ToUpper() :
value;
if (Text == newText) { return; }
//reset scale, it gets recalculated in SetTextPos
if (autoScale) { textScale = 1.0f; }
if (autoScaleHorizontal || autoScaleVertical) { textScale = 1.0f; }
text = newText;
wrappedText = newText;
@@ -127,19 +132,36 @@ namespace Barotrauma
}
}
private bool autoScale;
private bool autoScaleHorizontal, autoScaleVertical;
/// <summary>
/// When enabled, the text is automatically scaled down to fit the textblock.
/// When enabled, the text is automatically scaled down to fit the textblock horizontally.
/// </summary>
public bool AutoScale
public bool AutoScaleHorizontal
{
get { return autoScale; }
get { return autoScaleHorizontal; }
set
{
if (autoScale == value) return;
autoScale = value;
if (autoScale)
if (autoScaleHorizontal == value) { return; }
autoScaleHorizontal = value;
if (autoScaleHorizontal)
{
SetTextPos();
}
}
}
/// <summary>
/// When enabled, the text is automatically scaled down to fit the textblock vertically.
/// </summary>
public bool AutoScaleVertical
{
get { return autoScaleVertical; }
set
{
if (autoScaleVertical == value) { return; }
autoScaleVertical = value;
if (autoScaleVertical)
{
SetTextPos();
}
@@ -155,7 +177,9 @@ namespace Barotrauma
if (forceUpperCase == value) { return; }
forceUpperCase = value;
if (forceUpperCase)
if (forceUpperCase ||
(style != null && style.ForceUpperCase) ||
(GUI.Style.ForceFontUpperCase.ContainsKey(Font) && GUI.Style.ForceFontUpperCase[Font]))
{
Text = text?.ToUpper();
}
@@ -179,6 +203,19 @@ namespace Barotrauma
set { textColor = value; }
}
private Color? hoverTextColor;
public Color HoverTextColor
{
get { return hoverTextColor ?? textColor; }
set { hoverTextColor = value; }
}
public Color SelectedTextColor
{
get { return selectedTextColor; }
set { selectedTextColor = value; }
}
public Alignment TextAlignment
{
get { return textAlignment; }
@@ -200,6 +237,9 @@ namespace Barotrauma
{
get { return censoredText; }
}
private List<ColorData> colorData = null;
private bool hasColorHighlight = false;
/// <summary>
/// This is the new constructor.
@@ -215,7 +255,7 @@ namespace Barotrauma
}
if (textColor.HasValue)
{
this.textColor = textColor.Value;
OverrideTextColor(textColor.Value);
}
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
@@ -239,8 +279,15 @@ namespace Barotrauma
RectTransform.ScaleChanged += SetTextPos;
RectTransform.SizeChanged += SetTextPos;
Enabled = true;
Censor = false;
}
public GUITextBlock(RectTransform rectT, List<ColorData> colorData, string text, Color? textColor = null, ScalableFont font = null, Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool playerInput = false)
: this(rectT, text, textColor, font, textAlignment, wrap, style, color, playerInput)
{
this.colorData = colorData;
hasColorHighlight = colorData != null;
}
public void CalculateHeightFromText(int padding = 0)
{
@@ -248,24 +295,40 @@ namespace Barotrauma
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText).Y + padding));
}
public override void ApplyStyle(GUIComponentStyle style)
public override void ApplyStyle(GUIComponentStyle componentStyle)
{
if (style == null) return;
base.ApplyStyle(style);
padding = style.Padding;
if (componentStyle == null) { return; }
base.ApplyStyle(componentStyle);
padding = componentStyle.Padding;
textColor = style.textColor;
textColor = componentStyle.TextColor;
hoverTextColor = componentStyle.HoverTextColor;
disabledTextColor = componentStyle.DisabledTextColor;
selectedTextColor = componentStyle.SelectedTextColor;
switch (componentStyle.Font)
{
case "font":
Font = componentStyle.Style.Font;
break;
case "smallfont":
Font = componentStyle.Style.SmallFont;
break;
case "largefont":
Font = componentStyle.Style.LargeFont;
break;
case "objectivetitle":
case "subheading":
Font = componentStyle.Style.SubHeadingFont;
break;
}
}
public void SetTextPos()
{
if (text == null) return;
if (text == null) { return; }
censoredText = "";
for (int i = 0; i < text.Length; i++)
{
censoredText += "\u2022";
}
censoredText = string.IsNullOrEmpty(text) ? "" : new string('\u2022', text.Length);
var rect = Rect;
@@ -284,12 +347,16 @@ namespace Barotrauma
overflowClipActive = TextSize.X > rect.Width - padding.X - padding.Z;
}
if (autoScale && textScale > 0.1f &&
(TextSize.X * textScale > rect.Width - padding.X - padding.Z || TextSize.Y * textScale > rect.Height - padding.Y - padding.W))
Vector2 minSize = new Vector2(
Math.Max(rect.Width - padding.X - padding.Z, 5.0f),
Math.Max(rect.Height - padding.Y - padding.W, 5.0f));
if (!autoScaleHorizontal) { minSize.X = float.MaxValue; }
if (!Wrap && !autoScaleVertical) { minSize.Y = float.MaxValue; }
if ((autoScaleHorizontal || autoScaleVertical) && textScale > 0.1f &&
(TextSize.X * textScale > minSize.X || TextSize.Y * textScale > minSize.Y))
{
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;
TextScale = Math.Max(0.1f, Math.Min(minSize.X / TextSize.X, minSize.Y / TextSize.Y)) - 0.01f;
return;
}
@@ -349,17 +416,28 @@ namespace Barotrauma
textColor = new Color(textColor.R, textColor.G, textColor.B, a);
}
/// <summary>
/// Overrides the color for all the states.
/// </summary>
public void OverrideTextColor(Color color)
{
textColor = color;
hoverTextColor = color;
selectedTextColor = color;
disabledTextColor = color;
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
if (!Visible) { return; }
Color currColor = GetCurrentColor(state);
Color currColor = GetColor(State);
var rect = Rect;
base.Draw(spriteBatch);
if (TextGetter != null) Text = TextGetter();
if (TextGetter != null) { Text = TextGetter(); }
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
if (overflowClipActive)
@@ -379,12 +457,30 @@ namespace Barotrauma
pos.Y = (int)pos.Y;
}
Font.DrawString(spriteBatch,
Censor ? censoredText : (Wrap ? wrappedText : text),
pos,
textColor * (textColor.A / 255.0f),
0.0f, origin, TextScale,
SpriteEffects.None, textDepth);
Color currentTextColor = State == ComponentState.Hover || State == ComponentState.HoverSelected ? HoverTextColor : TextColor;
if (!enabled)
{
currentTextColor = disabledTextColor;
}
else if (State == ComponentState.Selected)
{
currentTextColor = selectedTextColor;
}
if (!hasColorHighlight)
{
Font.DrawString(spriteBatch,
Censor ? censoredText : (Wrap ? wrappedText : text),
pos,
currentTextColor * (currentTextColor.A / 255.0f),
0.0f, origin, TextScale,
SpriteEffects.None, textDepth);
}
else
{
Font.DrawStringWithColors(spriteBatch, Censor ? censoredText : (Wrap ? wrappedText : text), pos,
currentTextColor * (currentTextColor.A / 255.0f), 0.0f, origin, TextScale, SpriteEffects.None, textDepth, colorData);
}
}
if (overflowClipActive)
@@ -408,19 +504,30 @@ namespace Barotrauma
/// <summary>
/// Set the text scale of the GUITextBlocks so that they all use the same scale and can fit the text within the block.
/// </summary>
public static void AutoScaleAndNormalize(IEnumerable<GUITextBlock> textBlocks)
public static void AutoScaleAndNormalize(bool scaleHorizontal = true, bool scaleVertical = false, params GUITextBlock[] textBlocks)
{
AutoScaleAndNormalize(textBlocks.AsEnumerable<GUITextBlock>(), scaleHorizontal, scaleVertical);
}
/// <summary>
/// Set the text scale of the GUITextBlocks so that they all use the same scale and can fit the text within the block.
/// </summary>
public static void AutoScaleAndNormalize(IEnumerable<GUITextBlock> textBlocks, bool scaleHorizontal = true, bool scaleVertical = false, float? defaultScale = null)
{
if (!textBlocks.Any()) { return; }
float minScale = Math.Max(textBlocks.First().TextScale, 1.0f);
foreach (GUITextBlock textBlock in textBlocks)
{
textBlock.AutoScale = true;
if (defaultScale.HasValue) { textBlock.TextScale = defaultScale.Value; }
textBlock.AutoScaleHorizontal = scaleHorizontal;
textBlock.AutoScaleVertical = scaleVertical;
minScale = Math.Min(textBlock.TextScale, minScale);
}
foreach (GUITextBlock textBlock in textBlocks)
{
textBlock.AutoScale = false;
textBlock.AutoScaleHorizontal = false;
textBlock.AutoScaleVertical = false;
textBlock.TextScale = minScale;
}
}
@@ -19,8 +19,9 @@ namespace Barotrauma
bool caretVisible;
float caretTimer;
private GUIFrame frame;
private GUITextBlock textBlock;
private readonly GUIFrame frame;
private readonly GUITextBlock textBlock;
private readonly GUIImage icon;
public Func<string, string> textFilterFunction;
@@ -48,7 +49,6 @@ namespace Barotrauma
get { return _caretIndex; }
set
{
previousCaretIndex = _caretIndex;
_caretIndex = value;
caretPosDirty = true;
}
@@ -63,7 +63,6 @@ namespace Barotrauma
private int selectionStartIndex;
private int selectionEndIndex;
private bool IsLeftToRight => selectionStartIndex <= selectionEndIndex;
private int previousCaretIndex;
private Vector2 selectionStartPos;
private Vector2 selectionEndPos;
private Vector2 selectionRectSize;
@@ -76,8 +75,8 @@ namespace Barotrauma
set { textBlock.TextGetter = value; }
}
private bool selected;
public bool Selected
private new bool selected;
public new bool Selected
{
get
{
@@ -105,6 +104,11 @@ namespace Barotrauma
}
}
public GUITextBlock TextBlock
{
get { return textBlock; }
}
//should the text be limited to the size of the box
//ignored when MaxTextLength is set or text wrapping is enabled
public bool ClampText
@@ -134,7 +138,8 @@ namespace Barotrauma
get { return enabled; }
set
{
enabled = value;
enabled = frame.Enabled = textBlock.Enabled = value;
if (icon != null) { icon.Enabled = value; }
if (!enabled && Selected)
{
Deselect();
@@ -228,26 +233,62 @@ namespace Barotrauma
{
get { return textBlock.WrappedText; }
}
public bool Readonly { get; set; }
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, ScalableFont font = null,
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false)
: base(style, rectT)
{
HoverCursor = CursorState.IBeam;
CanBeFocused = true;
Enabled = true;
this.color = color ?? Color.White;
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
GUI.Style.Apply(frame, style == "" ? "GUITextBox" : style);
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.Center), text, textColor, font, textAlignment, wrap, playerInput: true);
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text, textColor, font, textAlignment, wrap, playerInput: true);
GUI.Style.Apply(textBlock, "", this);
CaretEnabled = true;
caretPosDirty = true;
new GUICustomComponent(new RectTransform(Vector2.One, frame.RectTransform), onDraw: DrawCaretAndSelection);
int clearButtonWidth = 0;
if (createClearButton)
{
var clearButton = new GUIButton(new RectTransform(new Vector2(0.6f, 0.6f), frame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5, 0) }, style: "GUICancelButton")
{
OnClicked = (bt, userdata) =>
{
Text = "";
frame.Flash(Color.White);
return true;
}
};
textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - clearButton.Rect.Height - clearButton.RectTransform.AbsoluteOffset.X * 2, int.MaxValue);
clearButtonWidth = (int)(clearButton.Rect.Width * 1.2f);
}
if (this.style != null && this.style.ChildStyles.ContainsKey("textboxicon"))
{
icon = new GUIImage(new RectTransform(new Vector2(0.6f, 0.6f), frame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5 + clearButtonWidth, 0) }, null, scaleToFit: true);
icon.ApplyStyle(this.style.ChildStyles["textboxicon"]);
textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - clearButtonWidth - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue);
}
Font = textBlock.Font;
rectT.SizeChanged += () => { caretPosDirty = true; };
rectT.ScaleChanged += () => { caretPosDirty = true; };
Enabled = true;
rectT.SizeChanged += () =>
{
if (icon != null) { textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue); }
caretPosDirty = true;
};
rectT.ScaleChanged += () =>
{
if (icon != null) { textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue); }
caretPosDirty = true;
};
}
private bool SetText(string text, bool store = true)
@@ -417,13 +458,13 @@ namespace Barotrauma
return currPosition != null ? currPosition.Item2 : textBlock.Text.Length;
}
public void Select()
public void Select(int forcedCaretIndex = -1)
{
if (memento.Current == null)
{
memento.Store(Text);
}
CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
CaretIndex = forcedCaretIndex == - 1 ? GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
ClearSelection();
selected = true;
GUI.KeyboardDispatcher.Subscriber = this;
@@ -442,9 +483,9 @@ namespace Barotrauma
OnDeselected?.Invoke(this, Keys.None);
}
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectOffset = null)
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectOffset = null)
{
textBlock.Flash(color, flashDuration, useRectangleFlash, flashRectOffset);
frame.Flash(color, flashDuration, useRectangleFlash, useCircularFlash, flashRectOffset);
}
protected override void Update(float deltaTime)
@@ -452,17 +493,17 @@ namespace Barotrauma
if (!Visible) return;
if (flashTimer > 0.0f) flashTimer -= deltaTime;
if (!Enabled) return;
if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || GUI.IsMouseOn(this)))
if (!Enabled) { return; }
if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || (!(GUI.MouseOn is GUIButton) && GUI.IsMouseOn(this))))
{
state = ComponentState.Hover;
if (PlayerInput.LeftButtonDown())
State = ComponentState.Hover;
if (PlayerInput.PrimaryMouseButtonDown())
{
Select();
}
else
{
isSelecting = PlayerInput.LeftButtonHeld();
isSelecting = PlayerInput.PrimaryMouseButtonHeld();
}
if (PlayerInput.DoubleClicked())
{
@@ -482,7 +523,7 @@ namespace Barotrauma
{
if ((PlayerInput.LeftButtonClicked() || PlayerInput.RightButtonClicked()) && selected) Deselect();
isSelecting = false;
state = ComponentState.None;
State = ComponentState.None;
}
if (!isSelecting)
{
@@ -493,14 +534,14 @@ namespace Barotrauma
{
if (textBlock.OverflowClipActive)
{
if (CaretScreenPos.X < Rect.X + textBlock.Padding.X)
if (CaretScreenPos.X < textBlock.Rect.X + textBlock.Padding.X)
{
textBlock.TextPos = new Vector2(textBlock.TextPos.X + ((Rect.X + textBlock.Padding.X) - CaretScreenPos.X), textBlock.TextPos.Y);
textBlock.TextPos = new Vector2(textBlock.TextPos.X + ((textBlock.Rect.X + textBlock.Padding.X) - CaretScreenPos.X), textBlock.TextPos.Y);
CalculateCaretPos();
}
else if (CaretScreenPos.X > Rect.Right - textBlock.Padding.Z)
else if (CaretScreenPos.X > textBlock.Rect.Right - textBlock.Padding.Z)
{
textBlock.TextPos = new Vector2(textBlock.TextPos.X - (CaretScreenPos.X - (Rect.Right - textBlock.Padding.Z)), textBlock.TextPos.Y);
textBlock.TextPos = new Vector2(textBlock.TextPos.X - (CaretScreenPos.X - (textBlock.Rect.Right - textBlock.Padding.Z)), textBlock.TextPos.Y);
CalculateCaretPos();
}
}
@@ -514,7 +555,7 @@ namespace Barotrauma
if (GUI.KeyboardDispatcher.Subscriber == this)
{
state = ComponentState.Selected;
State = ComponentState.Selected;
Character.DisableControls = true;
if (OnEnterPressed != null && PlayerInput.KeyHit(Keys.Enter))
{
@@ -526,16 +567,12 @@ namespace Barotrauma
Deselect();
}
textBlock.State = state;
textBlock.State = State;
}
protected override void Draw(SpriteBatch spriteBatch)
private void DrawCaretAndSelection(SpriteBatch spriteBatch, GUICustomComponent customComponent)
{
if (!Visible) return;
base.Draw(spriteBatch);
// Frame is not used in the old system.
frame?.DrawManually(spriteBatch);
textBlock.DrawManually(spriteBatch);
if (!Visible) { return; }
if (Selected)
{
if (caretVisible )
@@ -553,9 +590,9 @@ namespace Barotrauma
//GUI.DrawString(spriteBatch, new Vector2(100, 20), selectionStartIndex.ToString(), Color.White, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(140, 20), selectionEndIndex.ToString(), Color.White, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 40), selectedText.ToString(), Color.Yellow, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 60), $"caret index: {CaretIndex.ToString()}", Color.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 80), $"caret pos: {caretPos.ToString()}", Color.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 100), $"caret screen pos: {CaretScreenPos.ToString()}", Color.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 60), $"caret index: {CaretIndex.ToString()}", GUI.Style.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 80), $"caret pos: {caretPos.ToString()}", GUI.Style.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 100), $"caret screen pos: {CaretScreenPos.ToString()}", GUI.Style.Red, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 120), $"text start pos: {(textBlock.TextPos - textBlock.Origin).ToString()}", Color.White, Color.Black);
//GUI.DrawString(spriteBatch, new Vector2(100, 140), $"cursor pos: {PlayerInput.MousePosition.ToString()}", Color.White, Color.Black);
}
@@ -635,6 +672,7 @@ namespace Barotrauma
public void ReceiveTextInput(string input)
{
if (Readonly) { return; }
if (selectedCharacters > 0)
{
RemoveSelectedText();
@@ -658,7 +696,7 @@ namespace Barotrauma
switch (command)
{
case '\b': //backspace
case '\b' when !Readonly: //backspace
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
{
SetText(string.Empty, false);
@@ -680,7 +718,7 @@ namespace Barotrauma
case (char)0x3: // ctrl-c
CopySelectedText();
break;
case (char)0x16: // ctrl-v
case (char)0x16 when !Readonly: // ctrl-v
string text = GetCopiedText();
RemoveSelectedText();
if (SetText(Text.Insert(CaretIndex, text)))
@@ -691,12 +729,15 @@ namespace Barotrauma
break;
case (char)0x18: // ctrl-x
CopySelectedText();
RemoveSelectedText();
if (!Readonly)
{
RemoveSelectedText();
}
break;
case (char)0x1: // ctrl-a
SelectAll();
break;
case (char)0x1A: // ctrl-z
case (char)0x1A when !Readonly: // ctrl-z
text = memento.Undo();
if (text != Text)
{
@@ -706,7 +747,7 @@ namespace Barotrauma
OnTextChanged?.Invoke(this, Text);
}
break;
case (char)0x12: // ctrl-r
case (char)0x12 when !Readonly: // ctrl-r
text = memento.Redo();
if (text != Text)
{
@@ -763,7 +804,7 @@ namespace Barotrauma
caretTimer = 0;
HandleSelection();
break;
case Keys.Delete:
case Keys.Delete when !Readonly:
if (selectedCharacters > 0)
{
RemoveSelectedText();
@@ -806,7 +847,7 @@ namespace Barotrauma
}
}
}
IEnumerable<GUITextBox> GetAndSortTextBoxes(GUIComponent parent) => parent.GetAllChildren().Select(c => c as GUITextBox).Where(t => t != null).OrderBy(t => t.Rect.Y).ThenBy(t => t.Rect.X);
IEnumerable<GUITextBox> GetAndSortTextBoxes(GUIComponent parent) => parent.GetAllChildren<GUITextBox>().OrderBy(t => t.Rect.Y).ThenBy(t => t.Rect.X);
GUITextBox SelectNextTextBox(GUIListBox listBox)
{
var textBoxes = GetAndSortTextBoxes(listBox.SelectedComponent);
@@ -18,14 +18,12 @@ namespace Barotrauma
private GUIRadioButtonGroup radioButtonGroup;
private bool selected;
public bool Selected
public override bool Selected
{
get { return selected; }
set
{
if (value == selected) return;
{
if (value == selected) { return; }
if (radioButtonGroup != null && radioButtonGroup.SelectedRadioButton == this)
{
selected = true;
@@ -33,8 +31,7 @@ namespace Barotrauma
}
selected = value;
state = (selected) ? ComponentState.Selected : ComponentState.None;
box.State = state;
State = selected ? ComponentState.Selected : ComponentState.None;
if (value && radioButtonGroup != null)
{
radioButtonGroup.SelectRadioButton(this);
@@ -44,7 +41,18 @@ namespace Barotrauma
}
}
private Color? defaultTextColor;
public override ComponentState State
{
get
{
return base.State;
}
set
{
base.State = value;
box.State = TextBlock.State = value;
}
}
public override bool Enabled
{
@@ -56,12 +64,7 @@ namespace Barotrauma
set
{
if (value == enabled) { return; }
enabled = value;
if (color.A == 0)
{
if (defaultTextColor == null) { defaultTextColor = TextBlock.TextColor; }
TextBlock.TextColor = enabled ? defaultTextColor.Value : defaultTextColor.Value * 0.5f;
}
enabled = box.Enabled = TextBlock.Enabled = value;
}
}
@@ -126,20 +129,16 @@ namespace Barotrauma
set { text.Text = value; }
}
public Color? DefaultTextColor
{
get { return defaultTextColor; }
}
public GUITickBox(RectTransform rectT, string label, ScalableFont font = null, string style = "") : base(null, rectT)
{
CanBeFocused = true;
HoverCursor = CursorState.Hand;
layoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), true);
box = new GUIFrame(new RectTransform(Vector2.One, layoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight)
box = new GUIFrame(new RectTransform(Vector2.One, layoutGroup.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.BothHeight)
{
IsFixedSize = false
IsFixedSize = true
}, string.Empty, Color.DarkGray)
{
HoverColor = Color.Gray,
@@ -147,12 +146,20 @@ namespace Barotrauma
CanBeFocused = false
};
GUI.Style.Apply(box, style == "" ? "GUITickBox" : style);
if (box.RectTransform.MinSize.Y > 0)
{
RectTransform.MinSize = box.RectTransform.MinSize;
RectTransform.MaxSize = box.RectTransform.MaxSize;
RectTransform.Resize(new Point(RectTransform.NonScaledSize.X, RectTransform.MinSize.Y));
box.RectTransform.MinSize = new Point(box.RectTransform.MinSize.Y);
box.RectTransform.Resize(box.RectTransform.MinSize);
}
Vector2 textBlockScale = new Vector2((float)(Rect.Width - Rect.Height) / (float)Math.Max(Rect.Width, 1.0), 1.0f);
text = new GUITextBlock(new RectTransform(textBlockScale, layoutGroup.RectTransform), label, font: font, textAlignment: Alignment.CenterLeft)
text = new GUITextBlock(new RectTransform(textBlockScale, layoutGroup.RectTransform, Anchor.CenterLeft), label, font: font, textAlignment: Alignment.CenterLeft)
{
CanBeFocused = false
};
GUI.Style.Apply(text, "GUIButtonHorizontal", this);
GUI.Style.Apply(text, "GUITextBlock", this);
Enabled = true;
ResizeBox();
@@ -170,23 +177,29 @@ namespace Barotrauma
{
Vector2 textBlockScale = new Vector2(Math.Max(Rect.Width - box.Rect.Width, 0.0f) / Math.Max(Rect.Width, 1.0f), 1.0f);
text.RectTransform.RelativeSize = textBlockScale;
box.RectTransform.MinSize = new Point(Rect.Height);
box.RectTransform.Resize(box.RectTransform.MinSize);
text.SetTextPos();
}
protected override void Update(float deltaTime)
{
if (!Visible) return;
if (!Visible) { return; }
base.Update(deltaTime);
if (GUI.MouseOn == this && Enabled)
{
box.State = ComponentState.Hover;
State = Selected ?
ComponentState.HoverSelected :
ComponentState.Hover;
if (PlayerInput.LeftButtonHeld())
if (PlayerInput.PrimaryMouseButtonHeld())
{
box.State = ComponentState.Selected;
State = ComponentState.Selected;
}
if (PlayerInput.LeftButtonClicked())
if (PlayerInput.PrimaryMouseButtonClicked())
{
if (radioButtonGroup == null)
{
@@ -198,14 +211,13 @@ namespace Barotrauma
}
}
}
else if (selected)
{
State = ComponentState.Selected;
}
else
{
box.State = ComponentState.None;
}
if (selected)
{
box.State = ComponentState.Selected;
State = ComponentState.None;
}
}
}
@@ -0,0 +1,190 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Barotrauma
{
static class HUDLayoutSettings
{
public static bool DebugDraw;
private static int inventoryTopY;
public static int InventoryTopY
{
get { return inventoryTopY; }
set
{
if (value == inventoryTopY) return;
inventoryTopY = value;
CreateAreas();
}
}
public static Rectangle ButtonAreaTop
{
get; private set;
}
public static Rectangle MessageAreaTop
{
get; private set;
}
public static Rectangle CrewArea
{
get; private set;
}
public static Rectangle ChatBoxArea
{
get; private set;
}
public static Rectangle ObjectiveAnchor
{
get; private set;
}
public static Rectangle InventoryAreaLower
{
get; private set;
}
/*public static Rectangle HealthBarAreaRight
{
get; private set;
}*/
public static Rectangle HealthBarArea
{
get; private set;
}
public static Rectangle BottomRightInfoArea
{
get; private set;
}
public static Rectangle AfflictionAreaLeft
{
get; private set;
}
public static Rectangle HealthWindowAreaLeft
{
get; private set;
}
public static Rectangle PortraitArea
{
get; private set;
}
public static int Padding
{
get; private set;
}
static HUDLayoutSettings()
{
if (GameMain.Instance != null)
{
GameMain.Instance.OnResolutionChanged += CreateAreas;
GameMain.Config.OnHUDScaleChanged += CreateAreas;
CreateAreas();
CharacterInfo.Init();
}
}
public static RectTransform ToRectTransform(Rectangle rect, RectTransform parent)
{
return new RectTransform(new Vector2(rect.Width / (float)GameMain.GraphicsWidth, rect.Height / (float)GameMain.GraphicsHeight), parent)
{
RelativeOffset = new Vector2(rect.X / (float)GameMain.GraphicsWidth, rect.Y / (float)GameMain.GraphicsHeight)
};
}
public static void CreateAreas()
{
Padding = (int)(11 * GUI.Scale);
if (inventoryTopY == 0) { inventoryTopY = GameMain.GraphicsHeight - 30; }
//slice from the top of the screen for misc buttons (info, end round, server controls)
ButtonAreaTop = new Rectangle(Padding, Padding, GameMain.GraphicsWidth - Padding * 2, (int)(50 * GUI.Scale));
int infoAreaWidth = (int)(142 * GUI.Scale);
int infoAreaHeight = (int)(98 * GUI.Scale);
int portraitSize = (int)(infoAreaHeight * 0.95f);
BottomRightInfoArea = new Rectangle(GameMain.GraphicsWidth - Padding * 2 - infoAreaWidth, GameMain.GraphicsHeight - Padding * 2 - infoAreaHeight, infoAreaWidth, infoAreaHeight);
PortraitArea = new Rectangle(GameMain.GraphicsWidth - portraitSize, BottomRightInfoArea.Bottom - portraitSize + Padding / 2, portraitSize, portraitSize);
//horizontal slices at the corners of the screen for health bar and affliction icons
int afflictionAreaHeight = (int)(50 * GUI.Scale);
int healthBarWidth = BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing * 2 + CharacterInventory.HideButtonWidth;
int healthBarHeight = (int)(50f * GUI.Scale);
HealthBarArea = new Rectangle(BottomRightInfoArea.X - (healthBarWidth - BottomRightInfoArea.Width) + (int)(2 * GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + (int)(10 * GUI.Scale), healthBarWidth, healthBarHeight);
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
//HealthBarAreaRight = new Rectangle(Padding, GameMain.GraphicsHeight - healthBarHeight - Padding, healthBarWidth, healthBarHeight);
/*if (HealthBarAreaRight.Y + healthBarHeight * 0.75f < PortraitArea.Y)
{
HealthBarAreaRight = new Rectangle(GameMain.GraphicsWidth - Padding - healthBarWidth, HealthBarAreaRight.Y, HealthBarAreaRight.Width, HealthBarAreaRight.Height);
}*/
//AfflictionAreaRight = new Rectangle(HealthBarAreaRight.X, HealthBarAreaRight.Y + healthBarHeight + Padding, healthBarWidth, afflictionAreaHeight);
int messageAreaWidth = GameMain.GraphicsWidth / 3;
MessageAreaTop = new Rectangle((GameMain.GraphicsWidth - messageAreaWidth) / 2, ButtonAreaTop.Bottom, messageAreaWidth, ButtonAreaTop.Height);
bool isFourByThree = GUI.IsFourByThree();
int chatBoxWidth = !isFourByThree ? (int)(475 * GUI.Scale) : (int)(375 * GUI.Scale);
int chatBoxHeight = (int)Math.Max(GameMain.GraphicsHeight * 0.25f, 150);
ChatBoxArea = new Rectangle(Padding, GameMain.GraphicsHeight - Padding - chatBoxHeight, chatBoxWidth, chatBoxHeight);
int objectiveAnchorWidth = (int)(250 * GUI.Scale);
int objectiveAnchorOffsetY = (int)(150 * GUI.Scale);
ObjectiveAnchor = new Rectangle(Padding, ChatBoxArea.Y - objectiveAnchorOffsetY, objectiveAnchorWidth, 0);
CrewArea = new Rectangle(Padding, Padding, (int)Math.Max(400 * GUI.Scale, 220), ObjectiveAnchor.Top - Padding * 2);
InventoryAreaLower = new Rectangle(Padding, inventoryTopY, GameMain.GraphicsWidth - Padding * 2, GameMain.GraphicsHeight - inventoryTopY);
int healthWindowWidth = (int)(GameMain.GraphicsWidth * 0.5f);
int healthWindowHeight = (int)(GameMain.GraphicsWidth * 0.5f * 0.65f);
int healthWindowX = GameMain.GraphicsWidth / 2 - healthWindowWidth / 2;
int healthWindowY = GameMain.GraphicsHeight / 2 - healthWindowHeight / 2;
HealthWindowAreaLeft = new Rectangle(healthWindowX, healthWindowY, healthWindowWidth, healthWindowHeight);
}
public static void Draw(SpriteBatch spriteBatch)
{
GUI.DrawRectangle(spriteBatch, ButtonAreaTop, Color.White * 0.5f);
GUI.DrawRectangle(spriteBatch, MessageAreaTop, GUI.Style.Orange * 0.5f);
GUI.DrawRectangle(spriteBatch, CrewArea, Color.Blue * 0.5f);
GUI.DrawRectangle(spriteBatch, ChatBoxArea, Color.Cyan * 0.5f);
GUI.DrawRectangle(spriteBatch, HealthBarArea, Color.Red * 0.5f);
GUI.DrawRectangle(spriteBatch, AfflictionAreaLeft, Color.Red * 0.5f);
GUI.DrawRectangle(spriteBatch, InventoryAreaLower, Color.Yellow * 0.5f);
GUI.DrawRectangle(spriteBatch, HealthWindowAreaLeft, Color.Red * 0.5f);
GUI.DrawRectangle(spriteBatch, BottomRightInfoArea, Color.Green * 0.5f);
}
}
public static class HUD
{
public static bool CloseHUD(Rectangle rect)
{
// Always close when hitting escape
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) { return true; }
//don't close when the cursor is on a UI element
if (GUI.MouseOn != null) { return false; }
//don't close when hovering over an inventory element
if (Inventory.IsMouseOnInventory()) { return false; }
bool input = PlayerInput.PrimaryMouseButtonDown() || PlayerInput.SecondaryMouseButtonClicked();
return input && !rect.Contains(PlayerInput.MousePosition);
}
}
}
@@ -6,14 +6,18 @@ using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Media;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
class LoadingScreen
{
private Texture2D backgroundTexture;
private readonly Texture2D defaultBackgroundTexture, overlay;
private readonly SpriteSheet decorativeGraph, decorativeMap;
private Texture2D currentBackgroundTexture;
private Sprite noiseSprite;
private RenderTarget2D renderTarget;
private string randText = "";
private Sprite languageSelectionCursor;
private ScalableFont languageSelectionFont, languageSelectionFontCJK;
@@ -21,11 +25,22 @@ namespace Barotrauma
private Video currSplashScreen;
private DateTime videoStartTime;
private Queue<Triplet<string, Point, float>> pendingSplashScreens = new Queue<Triplet<string, Point, float>>();
public struct PendingSplashScreen
{
public string Filename;
public float Gain;
public PendingSplashScreen(string filename, float gain)
{
Filename = filename;
Gain = gain;
}
}
private Queue<PendingSplashScreen> pendingSplashScreens = new Queue<PendingSplashScreen>();
/// <summary>
/// Triplet.first = filepath, Triplet.second = resolution, Triplet.third = audio gain
/// </summary>
public Queue<Triplet<string, Point, float>> PendingSplashScreens
public Queue<PendingSplashScreen> PendingSplashScreens
{
get
{
@@ -54,15 +69,9 @@ namespace Barotrauma
}
}
private float state;
private string selectedTip;
public Vector2 BackgroundPosition;
public Vector2 TitlePosition;
private object loadMutex = new object();
private readonly object loadMutex = new object();
private float? loadState;
public float? LoadState
@@ -98,15 +107,13 @@ namespace Barotrauma
public LoadingScreen(GraphicsDevice graphics)
{
backgroundTexture = TextureLoader.FromFile("Content/UI/titleBackground.png");
defaultBackgroundTexture = TextureLoader.FromFile("Content/Map/LocationPortraits/AlienRuins.png");
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
GameMain.Instance.OnResolutionChanged += () =>
{
renderTarget?.Dispose();
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
};
decorativeMap = new SpriteSheet("Content/Map/MapHUD.png", 6, 5, Vector2.Zero, sourceRect: new Rectangle(0, 0, 2048, 640));
decorativeGraph = new SpriteSheet("Content/Map/MapHUD.png", 4, 10, Vector2.Zero, sourceRect: new Rectangle(1025, 1259, 1024, 732));
overlay = TextureLoader.FromFile("Content/UI/LoadingScreenOverlay.png");
noiseSprite = new Sprite("Content/UI/noise.png", Vector2.Zero);
DrawLoadingText = true;
selectedTip = TextManager.Get("LoadingScreenTip", true);
}
@@ -136,41 +143,35 @@ namespace Barotrauma
drawn = true;
graphics.SetRenderTarget(renderTarget);
currentBackgroundTexture ??= defaultBackgroundTexture;
float backgroundScale = GameMain.GraphicsHeight / 1500.0f;
float titleScale = MathHelper.SmoothStep(0.8f, 1.0f, state / 10.0f) * GameMain.GraphicsHeight / 1000.0f;
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, samplerState: GUI.SamplerState);
state += deltaTime;
float scale = (GameMain.GraphicsWidth / (float)currentBackgroundTexture.Width) * 1.2f;
float paddingX = currentBackgroundTexture.Width * scale - GameMain.GraphicsWidth;
float paddingY = currentBackgroundTexture.Height * scale - GameMain.GraphicsHeight;
if (DrawLoadingText)
{
BackgroundPosition = new Vector2(GameMain.GraphicsWidth * 0.3f, GameMain.GraphicsHeight * 0.45f);
TitlePosition = new Vector2(GameMain.GraphicsWidth * 0.5f, GameMain.GraphicsHeight * 0.45f);
}
double noiseT = (Timing.TotalTime * 0.02f);
Vector2 pos = new Vector2((float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0.5f) - 0.5f);
pos = new Vector2(pos.X * paddingX, pos.Y * paddingY);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, samplerState: GUI.SamplerState);
graphics.Clear(Color.Black);
spriteBatch.Draw(currentBackgroundTexture,
new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2 + pos,
null, Color.White, 0.0f, new Vector2(currentBackgroundTexture.Width / 2, currentBackgroundTexture.Height / 2),
scale, SpriteEffects.None, 0.0f);
spriteBatch.Draw(backgroundTexture, BackgroundPosition, null, Color.White * Math.Min(state / 5.0f, 1.0f), 0.0f,
new Vector2(backgroundTexture.Width / 2.0f, backgroundTexture.Height / 2.0f),
backgroundScale * 1.5f, SpriteEffects.None, 0.2f);
titleSprite?.Draw(spriteBatch, TitlePosition, Color.White * Math.Min((state - 1.0f) / 5.0f, 1.0f), scale: titleScale);
spriteBatch.End();
spriteBatch.Draw(overlay, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
graphics.SetRenderTarget(null);
float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0);
float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f;
noiseSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight),
startOffset: new Point(Rand.Range(0, noiseSprite.SourceRect.Width), Rand.Range(0, noiseSprite.SourceRect.Height)),
color: Color.White * noiseStrength * 0.1f,
textureScale: Vector2.One * noiseScale);
if (WaterRenderer.Instance != null)
{
WaterRenderer.Instance.ScrollWater(Vector2.One * 10.0f, deltaTime);
WaterRenderer.Instance.RenderWater(spriteBatch, renderTarget, null);
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, samplerState: GUI.SamplerState);
titleSprite?.Draw(spriteBatch, TitlePosition, Color.White * Math.Min((state - 1.0f) / 5.0f, 1.0f), scale: titleScale);
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
scale: GameMain.GraphicsHeight / 2000.0f);
if (WaitForLanguageSelection)
{
@@ -183,7 +184,18 @@ namespace Barotrauma
string loadText;
if (LoadState == 100.0f)
{
loadText = TextManager.Get("PressAnyKey");
#if DEBUG
if (GameMain.Config.AutomaticQuickStartEnabled && GameMain.FirstLoad)
{
loadText = "QUICKSTARTING ...";
}
else
{
#endif
loadText = TextManager.Get("PressAnyKey");
#if DEBUG
}
#endif
}
else
{
@@ -196,7 +208,7 @@ namespace Barotrauma
if (GUI.LargeFont != null)
{
GUI.LargeFont.DrawString(spriteBatch, loadText.ToUpper(),
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText).X / 2.0f, GameMain.GraphicsHeight * 0.7f),
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText.ToUpper()).X / 2.0f, GameMain.GraphicsHeight * 0.75f),
Color.White);
}
}
@@ -210,12 +222,49 @@ namespace Barotrauma
for (int i = 0; i < lines.Length; i++)
{
GUI.Font.DrawString(spriteBatch, lines[i],
new Vector2((int)(GameMain.GraphicsWidth / 2.0f - GUI.Font.MeasureString(lines[i]).X / 2.0f), (int)(GameMain.GraphicsHeight * 0.78f + i * lineHeight)), Color.White);
new Vector2((int)(GameMain.GraphicsWidth / 2.0f - GUI.Font.MeasureString(lines[i]).X / 2.0f), (int)(GameMain.GraphicsHeight * 0.8f + i * lineHeight)), Color.White);
}
}
}
spriteBatch.End();
spriteBatch.Begin(blendState: BlendState.Additive);
Vector2 decorativeScale = new Vector2(GameMain.GraphicsHeight / 1080.0f);
float noiseVal = (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.25f, Timing.TotalTime * 0.5f, 0);
decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal),
new Vector2(GameMain.GraphicsWidth * 0.001f, GameMain.GraphicsHeight * 0.24f),
Color.White, Vector2.Zero, 0.0f, decorativeScale, SpriteEffects.FlipVertically);
decorativeMap.Draw(spriteBatch, (int)(decorativeMap.FrameCount * noiseVal),
new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.66f),
Color.White, decorativeMap.FrameSize.ToVector2(), 0.0f, decorativeScale);
if (noiseVal < 0.2f)
{
//SCP-CB reference
randText = (new string[] { "NIL", "black white gray", "Sometimes we would have had time to scream", "e8m106]af", "NO" }).GetRandom();
}
else if (noiseVal < 0.3f)
{
randText = ToolBox.RandomSeed(9);
}
else if (noiseVal < 0.5f)
{
randText =
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
Rand.Int(100).ToString().PadLeft(2, '0');
}
GUI.LargeFont?.DrawString(spriteBatch, randText,
new Vector2(GameMain.GraphicsWidth - decorativeMap.FrameSize.X * decorativeScale.X * 0.8f, GameMain.GraphicsHeight * 0.57f),
Color.White * (1.0f - noiseVal));
spriteBatch.End();
}
private void DrawLanguageSelectionPrompt(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
@@ -249,7 +298,7 @@ namespace Barotrauma
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
hover ? Color.White : Color.White * 0.6f);
if (hover && PlayerInput.LeftButtonClicked())
if (hover && PlayerInput.PrimaryMouseButtonClicked())
{
GameMain.Config.Language = language;
//reload tip in the selected language
@@ -275,12 +324,11 @@ namespace Barotrauma
if (currSplashScreen == null)
{
var newSplashScreen = PendingSplashScreens.Dequeue();
string fileName = newSplashScreen.First;
Point resolution = newSplashScreen.Second;
string fileName = newSplashScreen.Filename;
try
{
currSplashScreen = new Video(graphics, GameMain.SoundManager, fileName, (uint)resolution.X, (uint)resolution.Y);
currSplashScreen.AudioGain = newSplashScreen.Third;
currSplashScreen = Video.Load(graphics, GameMain.SoundManager, fileName);
currSplashScreen.AudioGain = newSplashScreen.Gain;
videoStartTime = DateTime.Now;
}
catch (Exception e)
@@ -298,12 +346,12 @@ namespace Barotrauma
spriteBatch.Draw(currSplashScreen.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.End();
if (GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.LeftButtonDown()))
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
{
currSplashScreen.Dispose(); currSplashScreen = null;
}
}
else if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500))
else if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 1500))
{
currSplashScreen.Dispose(); currSplashScreen = null;
}
@@ -315,6 +363,7 @@ namespace Barotrauma
drawn = false;
LoadState = null;
selectedTip = TextManager.Get("LoadingScreenTip", true);
currentBackgroundTexture = LocationType.List.GetRandom()?.GetPortrait(Rand.Int(int.MaxValue))?.Texture;
while (!drawn)
{
@@ -35,7 +35,9 @@ namespace Barotrauma
Parent = new GUIFrame(rectT, null, Color);
EditorBox = new GUIListBox(new RectTransform(Vector2.One * 0.98f, rectT, Anchor.Center), color: Color.Black, style: null)
{
Spacing = 10
Spacing = 10,
AutoHideScrollBar = true,
KeepSpaceForScrollBar = true
};
return EditorBox;
}
@@ -23,7 +23,9 @@ namespace Barotrauma
public enum ScaleBasis
{
Normal, BothWidth, BothHeight
Normal,
BothWidth, BothHeight,
Smallest, Largest
}
public class RectTransform
@@ -50,13 +52,13 @@ namespace Barotrauma
{
parent.children.Add(this);
RecalculateAll(false, true, true);
ParentChanged?.Invoke(parent);
Parent.ChildrenChanged?.Invoke(this);
}
ParentChanged?.Invoke(parent);
}
}
private List<RectTransform> children = new List<RectTransform>();
private readonly List<RectTransform> children = new List<RectTransform>();
public IEnumerable<RectTransform> Children => children;
public int CountChildren => children.Count;
@@ -291,7 +293,16 @@ namespace Barotrauma
}
}
private ScaleBasis scaleBasis;
private ScaleBasis _scaleBasis;
public ScaleBasis ScaleBasis
{
get { return _scaleBasis; }
set
{
_scaleBasis = value;
RecalculateAbsoluteSize();
}
}
public bool IsLastChild
{
@@ -330,7 +341,7 @@ namespace Barotrauma
public RectTransform(Vector2 relativeSize, RectTransform parent, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null, ScaleBasis scaleBasis = ScaleBasis.Normal)
{
Init(parent, anchor, pivot);
this.scaleBasis = scaleBasis;
_scaleBasis = scaleBasis;
this.relativeSize = relativeSize;
this.minSize = minSize;
this.maxSize = maxSize;
@@ -342,19 +353,23 @@ namespace Barotrauma
}
/// <summary>
/// By default, elements defined with an absolute size (in pixels), will be treated as fixed sized.
/// This can be changed by setting IsFixedSize to false.
/// By default, elements defined with an absolute size (in pixels) will scale with the parent.
/// This can be changed by setting IsFixedSize to true.
/// </summary>
public RectTransform(Point absoluteSize, RectTransform parent = null, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null)
public RectTransform(Point absoluteSize, RectTransform parent = null, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, ScaleBasis scaleBasis = ScaleBasis.Normal, bool isFixedSize = false)
{
Init(parent, anchor, pivot);
this.scaleBasis = ScaleBasis.Normal;
_scaleBasis = scaleBasis;
this.nonScaledSize = absoluteSize;
RecalculateScale();
RecalculateRelativeSize();
RecalculateRelativeSize();
if (scaleBasis != ScaleBasis.Normal)
{
RecalculateAbsoluteSize();
}
RecalculateAnchorPoint();
RecalculatePivotOffset();
IsFixedSize = true;
IsFixedSize = isFixedSize;
parent?.ChildrenChanged?.Invoke(this);
}
@@ -364,13 +379,24 @@ namespace Barotrauma
Enum.TryParse(element.GetAttributeString("pivot", anchor.ToString()), out Pivot pivot);
Point? minSize = null, maxSize = null;
if (element.Attribute("minsize") != null) minSize = element.GetAttributePoint("minsize", Point.Zero);
//if (element.Attribute("maxsize") != null) maxSize = element.GetAttributePoint("maxsize", new Point(1000, 1000));
ScaleBasis scaleBasis = ScaleBasis.Normal;
if (element.Attribute("minsize") != null)
{
minSize = element.GetAttributePoint("minsize", Point.Zero);
}
if (element.Attribute("maxsize") != null)
{
maxSize = element.GetAttributePoint("maxsize", new Point(1000, 1000));
}
string sb = element.GetAttributeString("scalebasis", null);
if (sb != null)
{
Enum.TryParse(sb, ignoreCase: true, out scaleBasis);
}
RectTransform rectTransform;
if (element.Attribute("absolutesize") != null)
{
rectTransform = new RectTransform(element.GetAttributePoint("absolutesize", new Point(1000, 1000)), parent, anchor, pivot)
rectTransform = new RectTransform(element.GetAttributePoint("absolutesize", new Point(1000, 1000)), parent, anchor, pivot, scaleBasis)
{
minSize = minSize,
maxSize = maxSize
@@ -378,7 +404,7 @@ namespace Barotrauma
}
else
{
rectTransform = new RectTransform(element.GetAttributeVector2("relativesize", Vector2.One), parent, anchor, pivot, minSize, maxSize);
rectTransform = new RectTransform(element.GetAttributeVector2("relativesize", Vector2.One), parent, anchor, pivot, minSize, maxSize, scaleBasis);
}
rectTransform.RelativeOffset = element.GetAttributeVector2("relativeoffset", Vector2.Zero);
rectTransform.AbsoluteOffset = element.GetAttributePoint("absoluteoffset", Point.Zero);
@@ -426,15 +452,37 @@ namespace Barotrauma
protected void RecalculateAbsoluteSize()
{
Point size = NonScaledParentRect.Size;
if (scaleBasis == ScaleBasis.BothWidth)
switch (ScaleBasis)
{
size.Y = size.X;
case ScaleBasis.BothWidth:
size.Y = size.X;
break;
case ScaleBasis.BothHeight:
size.X = size.Y;
break;
case ScaleBasis.Smallest:
if (size.X < size.Y)
{
size.Y = size.X;
}
else
{
size.X = size.Y;
}
break;
case ScaleBasis.Largest:
if (size.X > size.Y)
{
size.Y = size.X;
}
else
{
size.X = size.Y;
}
break;
}
else if (scaleBasis == ScaleBasis.BothHeight)
{
size.X = size.Y;
}
nonScaledSize = size.Multiply(RelativeSize).Clamp(MinSize, MaxSize);
size = size.Multiply(RelativeSize);
nonScaledSize = size.Clamp(MinSize, MaxSize);
recalculateRect = true;
SizeChanged?.Invoke();
}
@@ -464,7 +512,7 @@ namespace Barotrauma
}
}
private bool RemoveFromHierarchy(bool displayErrors = true, bool recalculate = true)
private bool RemoveFromHierarchy(bool displayErrors = true)
{
if (Parent == null)
{
@@ -506,7 +554,7 @@ namespace Barotrauma
public void Resize(Point absoluteSize, bool resizeChildren = true)
{
nonScaledSize = absoluteSize;
nonScaledSize = absoluteSize.Clamp(MinSize, MaxSize);
RecalculateRelativeSize();
RecalculateAll(resize: false, scale: false, withChildren: false);
RecalculateChildren(resizeChildren, false);
@@ -573,7 +621,7 @@ namespace Barotrauma
/// </summary>
public IEnumerable<RectTransform> GetAllChildren()
{
return children.SelectManyRecursive(c => c.children);
return children.Concat(children.SelectManyRecursive(c => c.children));
}
public int GetChildIndex(RectTransform rectT)
@@ -599,7 +647,7 @@ namespace Barotrauma
public void SortChildren(Comparison<RectTransform> comparison)
{
children.Sort(comparison);
RecalculateAll(false, true, true);
RecalculateAll(false, false, true);
Parent.ChildrenChanged?.Invoke(this);
}
@@ -650,6 +698,53 @@ namespace Barotrauma
children[i].GUIComponent.AddToGUIUpdateList(ignoreChildren, order);
}
}
public void MatchPivotToAnchor() => MatchPivotToAnchor(Anchor);
private Point? animTargetPos;
public Point AnimTargetPos
{
get { return animTargetPos ?? AbsoluteOffset; }
}
public void MoveOverTime(Point targetPos, float duration)
{
animTargetPos = targetPos;
CoroutineManager.StartCoroutine(DoMoveAnimation(targetPos, duration));
}
public void ScaleOverTime(Point targetSize, float duration)
{
CoroutineManager.StartCoroutine(DoScaleAnimation(targetSize, duration));
}
private IEnumerable<object> DoMoveAnimation(Point targetPos, float duration)
{
Vector2 startPos = AbsoluteOffset.ToVector2();
float t = 0.0f;
while (t < duration && duration > 0.0f)
{
t += CoroutineManager.DeltaTime;
AbsoluteOffset = Vector2.SmoothStep(startPos, targetPos.ToVector2(), t / duration).ToPoint();
yield return CoroutineStatus.Running;
}
AbsoluteOffset = targetPos;
animTargetPos = null;
yield return CoroutineStatus.Success;
}
private IEnumerable<object> DoScaleAnimation(Point targetSize, float duration)
{
Vector2 startSize = NonScaledSize.ToVector2();
float t = 0.0f;
while (t < duration && duration > 0.0f)
{
t += CoroutineManager.DeltaTime;
NonScaledSize = Vector2.SmoothStep(startSize, targetSize.ToVector2(), t / duration).ToPoint();
yield return CoroutineStatus.Running;
}
NonScaledSize = targetSize;
yield return CoroutineStatus.Success;
}
#endregion
#region Static methods
@@ -37,15 +37,36 @@ namespace Barotrauma
private set;
}
/// <summary>
/// How much the borders of a sliced sprite are allowed to scale
/// You may for example want to prevent a 1-pixel border from scaling down (and disappearing) on small resolutions
/// </summary>
private readonly float minBorderScale = 0.1f, maxBorderScale = 10.0f;
public bool CrossFadeIn { get; private set; } = true;
public bool CrossFadeOut { get; private set; } = true;
public TransitionMode TransitionMode { get; private set; }
public UISprite(XElement element)
{
Sprite = new Sprite(element);
MaintainAspectRatio = element.GetAttributeBool("maintainaspectratio", false);
Tile = element.GetAttributeBool("tile", true);
CrossFadeIn = element.GetAttributeBool("crossfadein", CrossFadeIn);
CrossFadeOut = element.GetAttributeBool("crossfadeout", CrossFadeOut);
string transitionMode = element.GetAttributeString("transition", string.Empty);
if (Enum.TryParse(transitionMode, ignoreCase: true, out TransitionMode transition))
{
TransitionMode = transition;
}
Vector4 sliceVec = element.GetAttributeVector4("slice", Vector4.Zero);
if (sliceVec != Vector4.Zero)
{
minBorderScale = element.GetAttributeFloat("minborderscale", 0.1f);
maxBorderScale = element.GetAttributeFloat("minborderscale", 10.0f);
Rectangle slice = new Rectangle((int)sliceVec.X, (int)sliceVec.Y, (int)(sliceVec.Z - sliceVec.X), (int)(sliceVec.W - sliceVec.Y));
Slice = true;
@@ -74,6 +95,19 @@ namespace Barotrauma
}
}
/// <summary>
/// Get the scale of the sliced sprite's borders when it's draw inside an area of a specific size
/// </summary>
public float GetSliceBorderScale(Point drawSize)
{
if (!Slice) { return 1.0f; }
Vector2 scale = new Vector2(
MathHelper.Clamp((float)drawSize.X / (Slices[0].Height + Slices[6].Height), 0, 1),
MathHelper.Clamp((float)drawSize.Y / (Slices[0].Width + Slices[2].Width), 0, 1));
return MathHelper.Clamp(Math.Min(Math.Min(scale.X, scale.Y), GUI.SlicedSpriteScale), minBorderScale, maxBorderScale);
}
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None)
{
if (Sprite.Texture == null)
@@ -86,43 +120,24 @@ namespace Barotrauma
{
Vector2 pos = new Vector2(rect.X, rect.Y);
int centerWidth = Math.Max(rect.Width - Slices[0].Width - Slices[2].Width, 0);
int centerHeight = Math.Max(rect.Height - Slices[0].Height - Slices[8].Height, 0);
Vector2 scale = Vector2.One;
if (centerHeight == 0)
{
scale.Y = MathHelper.Clamp((float)rect.Height / (Slices[0].Height + Slices[3].Height + Slices[6].Height), 0, 1);
centerHeight = rect.Height - (int)((Slices[0].Height + Slices[6].Height) * scale.Y);
}
else
{
scale.Y = MathHelper.Clamp((float)rect.Height / (Slices[0].Height + Slices[6].Height), 0, 1);
centerHeight = (int)(centerHeight * scale.Y);
}
if (centerWidth == 0)
{
scale.X = MathHelper.Clamp((float)rect.Height / (Slices[0].Width + Slices[1].Width + Slices[2].Width), 0, 1);
centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale.X);
}
else
{
scale.X = MathHelper.Clamp((float)rect.Width / (Slices[0].Width + Slices[2].Width), 0, 1);
centerWidth = (int)(centerWidth * scale.X);
}
float scale = GetSliceBorderScale(rect.Size);
int centerHeight = rect.Height - (int)((Slices[0].Height + Slices[6].Height) * scale);
int centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale);
for (int x = 0; x < 3; x++)
{
float width = (x == 1 ? centerWidth : Slices[x].Width * scale.X);
int width = (int)(x == 1 ? centerWidth : Slices[x].Width * scale);
if (width <= 0) { continue; }
for (int y = 0; y < 3; y++)
{
float height = (y == 1 ? centerHeight : Slices[x + y * 3].Height * scale.Y);
int height = (int)(y == 1 ? centerHeight : Slices[x + y * 3].Height * scale);
if (height <= 0) { continue; }
spriteBatch.Draw(Sprite.Texture,
new Rectangle((int)pos.X, (int)pos.Y, (int)width, (int)height),
new Rectangle((int)pos.X, (int)pos.Y, width, height),
Slices[x + y * 3],
color);
pos.Y += height;
}
pos.X += width;
@@ -20,7 +20,7 @@ namespace Barotrauma
private GUICustomComponent videoView;
private GUIButton okButton;
private Color backgroundColor = new Color(0f, 0f, 0f, 1f);
private Color backgroundColor = new Color(0f, 0f, 0f, 0.8f);
private Action callbackOnStop;
private Point scaledVideoResolution;
@@ -62,8 +62,8 @@ namespace Barotrauma
int width = scaledVideoResolution.X;
int height = scaledVideoResolution.Y;
background = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor);
videoFrame = new GUIFrame(new RectTransform(Point.Zero, background.RectTransform, Anchor.Center, Pivot.Center), "SonarFrame");
background = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas, Anchor.Center), style: null, color: backgroundColor);
videoFrame = new GUIFrame(new RectTransform(Point.Zero, background.RectTransform, Anchor.Center, Pivot.Center), style: "InnerFrame");
if (useTextOnRightSide)
{
@@ -75,13 +75,13 @@ namespace Barotrauma
}
videoView = new GUICustomComponent(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.Center), (spriteBatch, guiCustomComponent) => { DrawVideo(spriteBatch, guiCustomComponent.Rect); });
title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.VideoTitleFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left);
title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.LargeFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left);
textContent = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.Font, textAlignment: Alignment.TopLeft);
objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight, textColor: Color.White);
objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterRight, textColor: Color.White);
objectiveTitle.Text = TextManager.Get("Tutorial.NewObjective");
objectiveText = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveNameFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight);
objectiveText = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.SubHeadingFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight);
objectiveTitle.Visible = objectiveText.Visible = false;
}
@@ -111,9 +111,7 @@ namespace Barotrauma
if (currentVideo == null) return;
if (currentVideo.IsPlaying) return;
currentVideo.Dispose();
currentVideo = null;
currentVideo = CreateVideo(scaledVideoResolution);
currentVideo.Play();
}
public void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
@@ -140,7 +138,7 @@ namespace Barotrauma
currentVideo = null;
}
currentVideo = CreateVideo(scaledVideoResolution);
currentVideo = CreateVideo();
title.Text = textSettings != null ? TextManager.Get(contentId) : string.Empty;
textContent.Text = textSettings != null ? textSettings.Text : string.Empty;
objectiveText.Text = objective;
@@ -178,10 +176,10 @@ namespace Barotrauma
background.RectTransform.NonScaledSize = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
videoFrame.RectTransform.NonScaledSize += scaledVideoResolution + new Point(scaledBorderSize, scaledBorderSize);
videoView.RectTransform.NonScaledSize += scaledVideoResolution;
videoFrame.RectTransform.NonScaledSize = scaledVideoResolution + new Point(scaledBorderSize, scaledBorderSize);
videoView.RectTransform.NonScaledSize = scaledVideoResolution;
title.RectTransform.NonScaledSize += new Point(scaledTextWidth, scaledTitleHeight);
title.RectTransform.NonScaledSize = new Point(scaledTextWidth, scaledTitleHeight);
title.RectTransform.AbsoluteOffset = new Point((int)(5 * GUI.Scale), (int)(10 * GUI.Scale));
if (textSettings != null && !string.IsNullOrEmpty(textSettings.Text))
@@ -189,7 +187,7 @@ namespace Barotrauma
textSettings.Text = ToolBox.WrapText(textSettings.Text, scaledTextWidth, GUI.Font);
int wrappedHeight = textSettings.Text.Split('\n').Length * scaledTextHeight;
textFrame.RectTransform.NonScaledSize += new Point(scaledTextWidth + scaledBorderSize, wrappedHeight + scaledBorderSize + scaledButtonSize.Y + scaledTitleHeight);
textFrame.RectTransform.NonScaledSize = new Point(scaledTextWidth + scaledBorderSize, wrappedHeight + scaledBorderSize + scaledButtonSize.Y + scaledTitleHeight);
if (useTextOnRightSide)
{
@@ -200,7 +198,7 @@ namespace Barotrauma
textFrame.RectTransform.AbsoluteOffset = new Point(0, scaledVideoResolution.Y + scaledBorderSize * 2);
}
textContent.RectTransform.NonScaledSize += new Point(scaledTextWidth, wrappedHeight);
textContent.RectTransform.NonScaledSize = new Point(scaledTextWidth, wrappedHeight);
textContent.RectTransform.AbsoluteOffset = new Point(0, scaledBorderSize + scaledTitleHeight);
}
@@ -212,7 +210,7 @@ namespace Barotrauma
objectiveText.RectTransform.AbsoluteOffset = new Point(scaledXOffset, textContent.RectTransform.Rect.Height + objectiveTitle.Rect.Height + (int)(scaledTextHeight * 2.25f));
textFrame.RectTransform.NonScaledSize += new Point(0, scaledObjectiveFrameHeight);
objectiveText.RectTransform.NonScaledSize += new Point(textFrame.Rect.Width, scaledTextHeight);
objectiveText.RectTransform.NonScaledSize = new Point(textFrame.Rect.Width, scaledTextHeight);
objectiveTitle.Visible = objectiveText.Visible = true;
}
else
@@ -258,13 +256,13 @@ namespace Barotrauma
}
}
private Video CreateVideo(Point resolution)
private Video CreateVideo()
{
Video video = null;
try
{
video = new Video(GameMain.Instance.GraphicsDevice, GameMain.SoundManager, filePath, (uint)resolution.X, (uint)resolution.Y);
video = Video.Load(GameMain.Instance.GraphicsDevice, GameMain.SoundManager, filePath);
}
catch (Exception e)
{
@@ -41,7 +41,7 @@ namespace Barotrauma
/// </summary>
public bool isFilled;
public int inputAreaMargin;
public Color color = Color.Red;
public Color color = GUI.Style.Red;
public Color? secondaryColor;
public Color textColor = Color.White;
public Color textBackgroundColor = Color.Black * 0.5f;
@@ -65,7 +65,7 @@ namespace Barotrauma
public object data;
public bool IsSelected => enabled && selectedWidgets.Contains(this);
public bool IsControlled => IsSelected && PlayerInput.LeftButtonHeld();
public bool IsControlled => IsSelected && PlayerInput.PrimaryMouseButtonHeld();
public bool IsMouseOver => GUI.MouseOn == null && InputRect.Contains(PlayerInput.MousePosition);
private bool enabled = true;
public bool Enabled
@@ -111,10 +111,10 @@ namespace Barotrauma
{
PreUpdate?.Invoke(deltaTime);
if (!enabled) { return; }
if (IsMouseOver || (!RequireMouseOn && selectedWidgets.Contains(this) && PlayerInput.LeftButtonHeld()))
if (IsMouseOver || (!RequireMouseOn && selectedWidgets.Contains(this) && PlayerInput.PrimaryMouseButtonHeld()))
{
Hovered?.Invoke();
if (RequireMouseOn || PlayerInput.LeftButtonDown())
if (RequireMouseOn || PlayerInput.PrimaryMouseButtonDown())
{
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())
{
@@ -130,15 +130,15 @@ namespace Barotrauma
}
if (IsSelected)
{
if (PlayerInput.LeftButtonDown())
if (PlayerInput.PrimaryMouseButtonDown())
{
MouseDown?.Invoke();
}
if (PlayerInput.LeftButtonHeld())
if (PlayerInput.PrimaryMouseButtonHeld())
{
MouseHeld?.Invoke(deltaTime);
}
if (PlayerInput.LeftButtonClicked())
if (PlayerInput.PrimaryMouseButtonClicked())
{
MouseUp?.Invoke();
}
@@ -66,7 +66,7 @@ namespace Barotrauma
if (vanillaContent == null)
{
// TODO: Dynamic method for defining and finding the vanilla content package.
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
}
return vanillaContent;
}
@@ -153,8 +153,6 @@ namespace Barotrauma
get { return Client; }
}
public static Process ServerChildProcess;
public static RasterizerState ScissorTestEnable
{
get;
@@ -166,8 +164,17 @@ namespace Barotrauma
get { return loadingScreenOpen; }
}
public bool Paused
{
get; private set;
}
private const GraphicsProfile GfxProfile = GraphicsProfile.Reach;
#if DEBUG
public static bool FirstLoad = true;
#endif
public GameMain(string[] args)
{
Content.RootDirectory = "Content";
@@ -184,13 +191,25 @@ namespace Barotrauma
Config = new GameSettings();
Md5Hash.LoadCache();
ConsoleArguments = args;
ConnectName = null;
ConnectEndpoint = null;
ConnectLobby = 0;
ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby);
try
{
ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby);
}
catch (IndexOutOfRangeException e)
{
DebugConsole.ThrowError($"Failed to parse console arguments ({string.Join(' ', ConsoleArguments)})", e);
ConnectName = null;
ConnectEndpoint = null;
ConnectLobby = 0;
}
GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window);
@@ -378,19 +397,15 @@ namespace Barotrauma
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0);
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 20.0f, 0);
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume, 0);
if (ConsoleArguments.Contains("-skipintro")) {
Config.EnableSplashScreen = false;
}
if (Config.EnableSplashScreen)
if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro"))
{
var pendingSplashScreens = TitleScreen.PendingSplashScreens;
float baseVolume = MathHelper.Clamp(Config.SoundVolume * 2.0f, 0.0f, 1.0f);
pendingSplashScreens?.Enqueue(new Triplet<string, Point, float>("Content/Splash_UTG.mp4", new Point(1280, 720), baseVolume * 0.5f));
pendingSplashScreens?.Enqueue(new Triplet<string, Point, float>("Content/Splash_FF.mp4", new Point(1280, 720), baseVolume));
pendingSplashScreens?.Enqueue(new Triplet<string, Point, float>("Content/Splash_Daedalic.mp4", new Point(1920, 1080), baseVolume * 0.15f));
pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_UTG.webm", baseVolume * 0.5f));
pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_FF.webm", baseVolume));
pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_Daedalic.webm", baseVolume * 0.1f));
}
//if not loading in a separate thread, wait for the splash screens to finish before continuing the loading
@@ -406,17 +421,27 @@ namespace Barotrauma
GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
DebugConsole.Init();
CrossThread.RequestExecutionOnMainThread(() =>
if (Config.AutoUpdateWorkshopItems)
{
if (Config.AutoUpdateWorkshopItems)
bool waitingForWorkshopUpdates = true;
bool result = false;
TaskPool.Add(SteamManager.AutoUpdateWorkshopItems(), (task) =>
{
if (SteamManager.AutoUpdateWorkshopItems())
result = task.Result;
waitingForWorkshopUpdates = false;
});
while (waitingForWorkshopUpdates) { yield return CoroutineStatus.Running; }
if (result)
{
CrossThread.RequestExecutionOnMainThread(() =>
{
ContentPackage.LoadAll();
Config.ReloadContentPackages();
}
});
}
});
}
if (SelectedPackages.None())
@@ -466,7 +491,7 @@ namespace Barotrauma
yield return CoroutineStatus.Running;
Character.LoadAllConfigFiles();
CharacterPrefab.LoadAll();
MissionPrefab.Init();
TraitorMissionPrefab.Init();
MapEntityPrefab.Init();
@@ -475,6 +500,7 @@ namespace Barotrauma
LevelGenerationParams.LoadPresets();
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
TitleScreen.LoadState = 50.0f;
yield return CoroutineStatus.Running;
@@ -513,15 +539,15 @@ namespace Barotrauma
TitleScreen.LoadState = 70.0f;
yield return CoroutineStatus.Running;
if (SteamManager.USE_STEAM)
#if USE_STEAM
SteamWorkshopScreen = new SteamWorkshopScreen();
if (SteamManager.IsInitialized)
{
SteamWorkshopScreen = new SteamWorkshopScreen();
if (SteamManager.IsInitialized)
{
SteamManager.Instance.Friends.OnInvitedToGame += OnInvitedToGame;
SteamManager.Instance.Lobby.OnLobbyJoinRequested += OnLobbyJoinRequested;
}
Steamworks.SteamFriends.OnGameRichPresenceJoinRequested += OnInvitedToGame;
Steamworks.SteamFriends.OnGameLobbyJoinRequested += OnLobbyJoinRequested;
}
#endif
SubEditorScreen = new SubEditorScreen();
TitleScreen.LoadState = 75.0f;
@@ -581,7 +607,7 @@ namespace Barotrauma
msgBox.Buttons[0].OnClicked += (_, userdata) =>
{
string fullPath = Path.GetFullPath(exePaths.First());
Process.Start(fullPath);
ToolBox.OpenFileWithShell(fullPath);
Exit();
return true;
};
@@ -601,6 +627,7 @@ namespace Barotrauma
Video.Close();
VoipCapture.Instance?.Dispose();
SoundManager?.Dispose();
MainThread = null;
}
/// <summary>
@@ -608,7 +635,7 @@ namespace Barotrauma
/// </summary>
/// <param name="type"></param>
/// <param name="searchAllContentPackages">If true, also returns files in content packages that are installed but not currently selected.</param>
public IEnumerable<string> GetFilesOfType(ContentType type, bool searchAllContentPackages = false)
public IEnumerable<ContentFile> GetFilesOfType(ContentType type, bool searchAllContentPackages = false)
{
if (searchAllContentPackages)
{
@@ -620,16 +647,30 @@ namespace Barotrauma
}
}
public void OnInvitedToGame(Facepunch.Steamworks.SteamFriend friend, string connectCommand)
{
ToolBox.ParseConnectCommand(connectCommand.Split(' '), out ConnectName, out ConnectEndpoint, out ConnectLobby);
public void OnInvitedToGame(Steamworks.Friend friend, string connectCommand) => OnInvitedToGame(connectCommand);
DebugConsole.NewMessage(ConnectName+", "+ConnectEndpoint,Color.Yellow);
public void OnInvitedToGame(string connectCommand)
{
try
{
ToolBox.ParseConnectCommand(ToolBox.SplitCommand(connectCommand), out ConnectName, out ConnectEndpoint, out ConnectLobby);
}
catch (IndexOutOfRangeException e)
{
#if DEBUG
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect invitation command ({connectCommand})", e);
#endif
ConnectName = null;
ConnectEndpoint = null;
ConnectLobby = 0;
}
DebugConsole.NewMessage(ConnectName + ", " + ConnectEndpoint, Color.Yellow);
}
public void OnLobbyJoinRequested(UInt64 lobbyId)
{
SteamManager.JoinLobby(lobbyId, true);
public void OnLobbyJoinRequested(Steamworks.Data.Lobby lobby, Steamworks.SteamId friendId)
{
SteamManager.JoinLobby(lobby.Id, true);
}
/// <summary>
@@ -639,7 +680,6 @@ namespace Barotrauma
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
Timing.TotalTime = gameTime.TotalGameTime.TotalSeconds;
Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds;
int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step);
if (Timing.Accumulator > Timing.Step * 6.0)
@@ -654,8 +694,6 @@ namespace Barotrauma
PlayerInput.UpdateVariable();
bool paused = true;
if (SoundManager != null)
{
if (WindowActive || !Config.MuteOnFocusLost)
@@ -670,6 +708,8 @@ namespace Barotrauma
while (Timing.Accumulator >= Timing.Step)
{
Timing.TotalTime += Timing.Step;
Stopwatch sw = new Stopwatch();
sw.Start();
@@ -695,11 +735,20 @@ namespace Barotrauma
}
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen &&
(!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.LeftButtonClicked()) && WindowActive)))
(!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.PrimaryMouseButtonClicked()) && WindowActive)))
{
loadingScreenOpen = false;
}
#if DEBUG
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && Config.AutomaticQuickStartEnabled && FirstLoad)
{
loadingScreenOpen = false;
FirstLoad = false;
MainMenuScreen.QuickStart();
}
#endif
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
{
string errMsg = "Loading was interrupted due to an error";
@@ -774,14 +823,22 @@ namespace Barotrauma
GUI.TogglePauseMenu();
}
//open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC
else if (Character.Controlled == null ||
((Character.Controlled.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
else if ((Character.Controlled == null || !itemHudActive())
//TODO: do we need to check Inventory.SelectedSlot?
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null))
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null
&& !CrewManager.IsCommandInterfaceOpen)
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
}
bool itemHudActive()
{
if (Character.Controlled?.SelectedConstruction == null) { return false; }
return
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
((Character.Controlled.ViewTarget as Item)?.Prefab?.FocusOnSelected ?? false);
}
}
#if DEBUG
@@ -794,15 +851,15 @@ namespace Barotrauma
}
#endif
GUI.ClearUpdateList();
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning || DebugConsole.Paused) &&
GUI.ClearUpdateList();
Paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning || DebugConsole.Paused) &&
(NetworkMember == null || !NetworkMember.GameStarted);
#if !DEBUG
if (NetworkMember == null && !WindowActive && !paused && true && Screen.Selected != MainMenuScreen && Config.PauseOnFocusLost)
if (NetworkMember == null && !WindowActive && !Paused && true && Screen.Selected != MainMenuScreen && Config.PauseOnFocusLost)
{
GUI.TogglePauseMenu();
paused = true;
Paused = true;
}
#endif
@@ -813,12 +870,14 @@ namespace Barotrauma
Client.AddToGUIUpdateList();
}
FileSelection.AddToGUIUpdateList();
DebugConsole.AddToGUIUpdateList();
DebugConsole.Update((float)Timing.Step);
paused = paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted));
Paused = Paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted));
if (!paused)
if (!Paused)
{
Screen.Selected.Update(Timing.Step);
}
@@ -846,7 +905,7 @@ namespace Barotrauma
GUI.Update((float)Timing.Step);
}
CoroutineManager.Update((float)Timing.Step, paused ? 0.0f : (float)Timing.Step);
CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step);
SteamManager.Update((float)Timing.Step);
@@ -862,7 +921,7 @@ namespace Barotrauma
PerformanceCounter.UpdateIterationsGraph.Update(updateIterations);
}
if (!paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
if (!Paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
}
public static void ResetFrameTime()
@@ -880,7 +939,13 @@ namespace Barotrauma
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds;
PerformanceCounter.Update(deltaTime);
double step = 1.0 / Timing.FrameLimit;
while (!Config.VSyncEnabled && sw.Elapsed.TotalSeconds + deltaTime < step)
{
Thread.Sleep(1);
}
PerformanceCounter.Update(sw.Elapsed.TotalSeconds + deltaTime);
if (loadingScreenOpen)
{
@@ -1015,25 +1080,39 @@ namespace Barotrauma
public void ShowBugReporter()
{
if (GUIMessageBox.VisibleBox != null && GUIMessageBox.VisibleBox.UserData as string == "bugreporter")
{
return;
}
var msgBox = new GUIMessageBox(TextManager.Get("bugreportbutton"), "");
msgBox.UserData = "bugreporter";
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), msgBox.Content.RectTransform)) { Stretch = true, RelativeSpacing = 0.025f };
linkHolder.RectTransform.MaxSize = new Point(int.MaxValue, linkHolder.Rect.Height);
#if !UNSTABLE
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportfeedbackform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
UserData = "https://steamcommunity.com/app/602960/discussions/1/",
OnClicked = (btn, userdata) =>
{
SteamManager.OverlayCustomURL(userdata as string);
if (!SteamManager.OverlayCustomURL(userdata as string))
{
ShowOpenUrlInWebBrowserPrompt(userdata as string);
}
msgBox.Close();
return true;
}
};
#endif
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportgithubform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
#if UNSTABLE
UserData = "https://barotraumagame.com/unstable-3rf3w5t4ter/",
#else
UserData = "https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md",
#endif
OnClicked = (btn, userdata) =>
{
ShowOpenUrlInWebBrowserPrompt(userdata as string);
@@ -1087,7 +1166,7 @@ namespace Barotrauma
};
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
{
Process.Start(url);
ToolBox.OpenFileWithShell(url);
msgBox.Close();
return true;
};
File diff suppressed because it is too large Load Diff
@@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -36,34 +35,39 @@ namespace Barotrauma
CanBeFocused = false
};
var newCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
var loadCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, null, saveFiles);
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("NewCampaign"), style: "GUITabButton")
{
OnClicked = (btn, obj) =>
{
newCampaignContainer.Visible = true;
loadCampaignContainer.Visible = false;
return true;
}
Selected = true
};
var loadCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.00f), buttonContainer.RectTransform),
TextManager.Get("LoadCampaign"), style: "GUITabButton")
{
OnClicked = (btn, obj) =>
{
newCampaignContainer.Visible = false;
loadCampaignContainer.Visible = true;
return true;
}
};
TextManager.Get("LoadCampaign"), style: "GUITabButton");
newCampaignButton.OnClicked = (btn, obj) =>
{
newCampaignButton.Selected = true;
loadCampaignButton.Selected = false;
newCampaignContainer.Visible = true;
loadCampaignContainer.Visible = false;
return true;
};
loadCampaignButton.OnClicked = (btn, obj) =>
{
newCampaignButton.Selected = false;
loadCampaignButton.Selected = true;
newCampaignContainer.Visible = false;
loadCampaignContainer.Visible = true;
return true;
};
loadCampaignContainer.Visible = false;
GUITextBlock.AutoScaleAndNormalize(newCampaignButton.TextBlock, loadCampaignButton.TextBlock);
campaignSetupUI.StartNewGame = GameMain.Client.SetupNewCampaign;
campaignSetupUI.LoadGame = GameMain.Client.SetupLoadCampaign;
@@ -129,7 +133,7 @@ namespace Barotrauma
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write((UInt16)MapEntityPrefab.List.IndexOf(pi.ItemPrefab));
msg.Write(pi.ItemPrefab.Identifier);
msg.Write((UInt16)pi.Quantity);
}
}
@@ -157,16 +161,16 @@ namespace Barotrauma
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
for (int i = 0; i < purchasedItemCount; i++)
{
UInt16 itemPrefabIndex = msg.ReadUInt16();
string itemPrefabIdentifier = msg.ReadString();
UInt16 itemQuantity = msg.ReadUInt16();
purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
}
bool hasCharacterData = msg.ReadBoolean();
CharacterInfo myCharacterInfo = null;
if (hasCharacterData)
{
myCharacterInfo = CharacterInfo.ClientRead(Character.HumanSpeciesName, msg);
myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
}
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
@@ -32,11 +32,12 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { TryEndRound(GetLeavingSub()); return true; }
};
foreach (JobPrefab jobPrefab in JobPrefab.List.Values)
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
{
for (int i = 0; i < jobPrefab.InitialCount; i++)
{
CrewManager.AddCharacterInfo(new CharacterInfo(Character.HumanSpeciesName, "", jobPrefab));
var variant = Rand.Range(0, jobPrefab.Variants);
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant));
}
}
}
@@ -90,7 +91,7 @@ namespace Barotrauma
if (Character.Controlled.Submarine != outpost) { return null; }
//if there's a sub docked to the outpost, we can leave the level
if (outpost.DockedTo.Count > 0)
if (outpost.DockedTo.Any())
{
var dockedSub = outpost.DockedTo.FirstOrDefault();
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
@@ -292,7 +293,7 @@ namespace Barotrauma
summaryScreen.RemoveChild(summaryScreen.Children.FirstOrDefault(c => c is GUIButton));
var okButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform),
var okButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
TextManager.Get("LoadGameButton"))
{
OnClicked = (GUIButton button, object obj) =>
@@ -304,7 +305,7 @@ namespace Barotrauma
}
};
var quitButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform),
var quitButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
TextManager.Get("QuitButton"));
quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu;
quitButton.OnClicked += (GUIButton button, object obj) =>
@@ -401,14 +402,17 @@ namespace Barotrauma
campaign.Money = element.GetAttributeInt("money", 0);
campaign.CheatsEnabled = element.GetAttributeBool("cheatsenabled", false);
campaign.InitialSuppliesSpawned = element.GetAttributeBool("initialsuppliesspawned", false);
if (campaign.CheatsEnabled)
{
DebugConsole.CheatsEnabled = true;
if (Steam.SteamManager.USE_STEAM && !SteamAchievementManager.CheatsEnabled)
#if USE_STEAM
if (!SteamAchievementManager.CheatsEnabled)
{
SteamAchievementManager.CheatsEnabled = true;
new GUIMessageBox("Cheats enabled", "Cheat commands have been enabled on the campaign. You will not receive Steam Achievements until you restart the game.");
}
#endif
}
//backwards compatibility with older save files
@@ -429,7 +433,8 @@ namespace Barotrauma
XElement modeElement = new XElement("SinglePlayerCampaign",
// Refunds the money when save & quitting from the map if there are items selected in the store
new XAttribute("money", Money + (CargoManager != null ? CargoManager.GetTotalItemCost() : 0)),
new XAttribute("cheatsenabled", CheatsEnabled));
new XAttribute("cheatsenabled", CheatsEnabled),
new XAttribute("initialsuppliesspawned", InitialSuppliesSpawned));
CrewManager.Save(modeElement);
Map.Save(modeElement);
element.Add(modeElement);
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
@@ -56,17 +57,30 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman");
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
var revolver = captain.Inventory.FindItemByIdentifier("revolver");
var revolver = FindOrGiveItem(captain, "revolver");
revolver.Unequip(captain);
captain.Inventory.RemoveItem(revolver);
var captainscap = captain.Inventory.FindItemByIdentifier("captainscap");
captainscap.Unequip(captain);
captain.Inventory.RemoveItem(captainscap);
var captainscap =
captain.Inventory.FindItemByIdentifier("captainscap1") ??
captain.Inventory.FindItemByIdentifier("captainscap2") ??
captain.Inventory.FindItemByIdentifier("captainscap3");
var captainsuniform = captain.Inventory.FindItemByIdentifier("captainsuniform");
captainsuniform.Unequip(captain);
captain.Inventory.RemoveItem(captainsuniform);
if (captainscap != null)
{
captainscap.Unequip(captain);
captain.Inventory.RemoveItem(captainscap);
}
var captainsuniform =
captain.Inventory.FindItemByIdentifier("captainsuniform1") ??
captain.Inventory.FindItemByIdentifier("captainsuniform2") ??
captain.Inventory.FindItemByIdentifier("captainsuniform3");
if (captainsuniform != null)
{
captainsuniform.Unequip(captain);
captain.Inventory.RemoveItem(captainsuniform);
}
var steerOrder = Order.GetPrefab("steer");
captain_steerIcon = steerOrder.SymbolSprite;
@@ -85,7 +99,7 @@ namespace Barotrauma.Tutorials
captain_medicSpawnPos = Item.ItemList.Find(i => i.HasTag("captain_medicspawnpos")).WorldPosition;
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
var medicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("medicaldoctor"));
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("medicaldoctor"));
captain_medic = Character.Create(medicInfo, captain_medicSpawnPos, "medicaldoctor");
captain_medic.GiveJobItems(null);
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
@@ -107,15 +121,15 @@ namespace Barotrauma.Tutorials
SetDoorAccess(tutorial_lockedDoor_1, null, false);
SetDoorAccess(tutorial_lockedDoor_2, null, false);
var mechanicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("mechanic"));
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("mechanic"));
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "mechanic");
captain_mechanic.GiveJobItems();
var securityInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("securityofficer"));
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("securityofficer"));
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "securityofficer");
captain_security.GiveJobItems();
var engineerInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer"));
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "engineer");
captain_engineer.GiveJobItems();
@@ -143,13 +157,14 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!captain_medicObjectiveSensor.MotionDetected);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(captain_medic.Info.DisplayName, TextManager.Get("Captain.Radio.Medic"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(2f, false);
GameMain.GameSession.CrewManager.ToggleCrewAreaOpen = true;
GameMain.GameSession.CrewManager.ToggleCrewListOpen = true;
GameMain.GameSession.CrewManager.AddCharacter(captain_medic);
TriggerTutorialSegment(0);
TriggerTutorialSegment(0, GameMain.Config.KeyBindText(InputType.Command));
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_medic, "follow", highlightColor, new Vector2(5, 5));
// TODO: Rework order highlighting for new command UI
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_medic, "follow", highlightColor, new Vector2(5, 5));
}
while (!HasOrder(captain_medic, "follow"));
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
@@ -159,34 +174,37 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!captain_enteredSubmarineSensor.MotionDetected);
yield return new WaitForSeconds(3f, false);
captain_mechanic.AIController.Enabled = captain_security.AIController.Enabled = captain_engineer.AIController.Enabled = true;
TriggerTutorialSegment(1);
TriggerTutorialSegment(1, GameMain.Config.KeyBindText(InputType.Command));
GameMain.GameSession.CrewManager.AddCharacter(captain_mechanic);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
// TODO: Rework order highlighting for new command UI
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
//HighlightOrderOption("jobspecific");
}
while (!HasOrder(captain_mechanic, "repairsystems"));
RemoveCompletedObjective(segments[1]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(2);
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Command));
GameMain.GameSession.CrewManager.AddCharacter(captain_security);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_security, "operateweapons", highlightColor, new Vector2(5, 5));
// TODO: Rework order highlighting for new command UI
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_security, "operateweapons", highlightColor, new Vector2(5, 5));
HighlightOrderOption("fireatwill");
}
while (!HasOrder(captain_security, "operateweapons", "fireatwill"));
RemoveCompletedObjective(segments[2]);
yield return new WaitForSeconds(4f, false);
TriggerTutorialSegment(3);
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Command));
GameMain.GameSession.CrewManager.AddCharacter(captain_engineer);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_engineer, "operatereactor", highlightColor, new Vector2(5, 5));
// TODO: Rework order highlighting for new command UI
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_engineer, "operatereactor", highlightColor, new Vector2(5, 5));
HighlightOrderOption("powerup");
}
while (!HasOrder(captain_engineer, "operatereactor", "powerup"));
@@ -204,7 +222,7 @@ namespace Barotrauma.Tutorials
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f, false);
} while (Submarine.MainSub.DockedTo.Count > 0);
} while (Submarine.MainSub.DockedTo.Any());
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(5); // Navigate to destination
@@ -212,10 +230,9 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(captain_navConsole.Item))
{
if (captain_sonar.ActiveTickBox.Box.FlashTimer <= 0)
if (captain_sonar.SonarModeSwitch.Frame.FlashTimer <= 0)
{
captain_sonar.ActiveTickBox.Box.Flash(highlightColor, 1.5f, false, new Vector2(2.5f, 2.5f));
//captain_sonar.ActiveTickBox.Box.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.5f);
captain_sonar.SonarModeSwitch.Frame.Flash(highlightColor, 1.5f, false, false, new Vector2(2.5f, 2.5f));
}
}
yield return null;
@@ -229,7 +246,7 @@ namespace Barotrauma.Tutorials
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f, false);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Any());
RemoveCompletedObjective(segments[6]);
yield return new WaitForSeconds(3f, false);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.GetWithVariable("Captain.Radio.Complete", "[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);
@@ -22,7 +22,6 @@ namespace Barotrauma.Tutorials
private ItemContainer doctor_medBayCabinet;
private Character patient1, patient2;
private List<Character> subPatients;
private Hull startRoom;
private Hull medBay;
private Door doctor_firstDoor;
@@ -56,6 +55,22 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
doctor = Character.Controlled;
var bandages = FindOrGiveItem(doctor, "antibleeding1");
bandages.Unequip(doctor);
doctor.Inventory.RemoveItem(bandages);
var syringegun = FindOrGiveItem(doctor, "syringegun");
syringegun.Unequip(doctor);
doctor.Inventory.RemoveItem(syringegun);
var antibiotics = FindOrGiveItem(doctor, "antibiotics");
antibiotics.Unequip(doctor);
doctor.Inventory.RemoveItem(antibiotics);
var morphine = FindOrGiveItem(doctor, "antidama1");
morphine.Unequip(doctor);
doctor.Inventory.RemoveItem(morphine);
doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>();
doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>();
@@ -63,30 +78,30 @@ namespace Barotrauma.Tutorials
var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
var assistantInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("assistant"));
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("assistant"));
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
patient1.GiveJobItems(null);
patient1.CanSpeak = false;
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 45.0f) }, stun: 0, playSound: false);
patient1.AIController.Enabled = false;
assistantInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("assistant"));
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("assistant"));
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
patient2.GiveJobItems(null);
patient2.CanSpeak = false;
patient2.AIController.Enabled = false;
var mechanicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient1);
var securityInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("securityofficer"));
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("securityofficer"));
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient2);
var engineerInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient3.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient3);
@@ -176,7 +191,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(2.0f);
}*/
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Deselect)); // Medical supplies objective
TriggerTutorialSegment(0, GameMain.Config.KeyBindText(InputType.Select), GameMain.Config.KeyBindText(InputType.Deselect), GameMain.Config.KeyBindText(InputType.ToggleInventory)); // Medical supplies objective
do
{
@@ -205,7 +220,7 @@ namespace Barotrauma.Tutorials
// 2nd tutorial segment, treat self -------------------------------------------------------------------------
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Health)); // Open health interface
TriggerTutorialSegment(1, GameMain.Config.KeyBindText(InputType.Health)); // Open health interface
while (CharacterHealth.OpenHealthWindow == null)
{
doctor.CharacterHealth.HealthBarPulsateTimer = 1.0f;
@@ -255,17 +270,18 @@ namespace Barotrauma.Tutorials
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
GameMain.GameSession.CrewManager.AddCharacter(doctor);
GameMain.GameSession.CrewManager.AddCharacter(patient1);
GameMain.GameSession.CrewManager.ToggleCrewAreaOpen = true;
GameMain.GameSession.CrewManager.ToggleCrewListOpen = true;
patient1.CharacterHealth.UseHealthWindow = false;
yield return new WaitForSeconds(3.0f, false);
patient1.AIController.Enabled = true;
doctor.RemoveActiveObjectiveEntity(patient1);
TriggerTutorialSegment(3); // Get the patient to medbay
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Command)); // Get the patient to medbay
while (patient1.CurrentOrder == null || patient1.CurrentOrder.Identifier != "follow")
{
GameMain.GameSession.CrewManager.HighlightOrderButton(patient1, "follow", highlightColor, new Vector2(5, 5));
// TODO: Rework order highlighting for new command UI
// GameMain.GameSession.CrewManager.HighlightOrderButton(patient1, "follow", highlightColor, new Vector2(5, 5));
yield return null;
}
@@ -282,7 +298,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(2.0f, false);
TriggerTutorialSegment(4, GameMain.Config.KeyBind(InputType.Health)); // treat burns
TriggerTutorialSegment(4, GameMain.Config.KeyBindText(InputType.Health)); // treat burns
do
{
@@ -344,14 +360,18 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!tutorial_upperFinalDoor.IsOpen);
yield return new WaitForSeconds(2.0f, false);
TriggerTutorialSegment(5, GameMain.Config.KeyBind(InputType.Health)); // perform CPR
TriggerTutorialSegment(5, GameMain.Config.KeyBindText(InputType.Health)); // perform CPR
SetHighlight(patient2, true);
while (patient2.IsUnconscious)
{
if (CharacterHealth.OpenHealthWindow != null && doctor.AnimController.Anim != AnimController.Animation.CPR)
{
CharacterHealth.OpenHealthWindow.CPRButton.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f);
CharacterHealth.OpenHealthWindow.CPRButton.Flash();
//Disabled pulse until it's replaced by a better effect
//CharacterHealth.OpenHealthWindow.CPRButton.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f);
if (CharacterHealth.OpenHealthWindow.CPRButton.FlashTimer <= 0.0f)
{
CharacterHealth.OpenHealthWindow.CPRButton.Flash(highlightColor);
}
}
yield return null;
}
@@ -374,7 +394,7 @@ namespace Barotrauma.Tutorials
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.EnteredSub"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(3.0f, false);
TriggerTutorialSegment(6, GameMain.Config.KeyBind(InputType.Health)); // give treatment to anyone in need
TriggerTutorialSegment(6, GameMain.Config.KeyBindText(InputType.Health)); // give treatment to anyone in need
foreach (var patient in subPatients)
{
@@ -87,7 +87,7 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
engineer = Character.Controlled;
var toolbox = engineer.Inventory.FindItemByIdentifier("toolbox");
var toolbox = FindOrGiveItem(engineer, "toolbox");
toolbox.Unequip(engineer);
engineer.Inventory.RemoveItem(toolbox);
@@ -127,7 +127,7 @@ namespace Barotrauma.Tutorials
engineer_reactor = Item.ItemList.Find(i => i.HasTag("engineer_reactor")).GetComponent<Reactor>();
engineer_reactor.FireDelay = engineer_reactor.MeltdownDelay = float.PositiveInfinity;
engineer_reactor.FuelConsumptionRate = 0.0f;
engineer_reactor.OnOffSwitch.BarScroll = 1f;
engineer_reactor.PowerOn = true;
reactorOperatedProperly = false;
engineer_secondDoor = Item.ItemList.Find(i => i.HasTag("engineer_seconddoor")).GetComponent<Door>(); ;
@@ -195,7 +195,7 @@ namespace Barotrauma.Tutorials
engineer_submarineJunctionBox_2 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_2"));
engineer_submarineJunctionBox_3 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_3"));
engineer_submarineReactor = Item.ItemList.Find(i => i.HasTag("engineer_submarinereactor")).GetComponent<Reactor>();
engineer_submarineReactor.OnOffSwitch.BarScrollValue = .25f;
engineer_submarineReactor.PowerOn = true;
engineer_submarineReactor.IsActive = engineer_submarineReactor.AutoTemp = false;
engineer_submarineJunctionBox_1.Indestructible = false;
@@ -235,7 +235,7 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!engineer_equipmentObjectiveSensor.MotionDetected);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Equipment"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(0.5f, false);
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Deselect)); // Retrieve equipment
TriggerTutorialSegment(0, GameMain.Config.KeyBindText(InputType.Select), GameMain.Config.KeyBindText(InputType.Deselect), GameMain.Config.KeyBindText(InputType.ToggleInventory)); // Retrieve equipment
bool firstSlotRemoved = false;
bool secondSlotRemoved = false;
bool thirdSlotRemoved = false;
@@ -289,19 +289,19 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(engineer_reactor.Item))
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
if (engineer_reactor.OnOffSwitch.FlashTimer <= 0)
engineer_reactor.AutoTemp = false;
if (engineer_reactor.PowerButton.FlashTimer <= 0)
{
engineer_reactor.OnOffSwitch.Flash(highlightColor, 1.5f, false);
engineer_reactor.PowerButton.Flash(highlightColor, 1.5f, false);
}
}
yield return null;
} while (engineer_reactor.OnOffSwitch.BarScroll > 0.45f);
} while (!engineer_reactor.PowerOn);
do
{
if (IsSelectedItem(engineer_reactor.Item) && engineer_reactor.Item.OwnInventory.slots != null)
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
engineer_reactor.AutoTemp = false;
HighlightInventorySlot(engineer.Inventory, "fuelrod", highlightColor, 0.5f, 0.5f, 0f);
for (int i = 0; i < engineer_reactor.Item.OwnInventory.slots.Length; i++)
@@ -316,7 +316,7 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(engineer_reactor.Item))
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
engineer_reactor.AutoTemp = false;
if (engineer_reactor.FissionRateScrollBar.FlashTimer <= 0)
{
engineer_reactor.FissionRateScrollBar.Flash(highlightColor, 1.5f);
@@ -335,9 +335,9 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(engineer_reactor.Item))
{
if (engineer_reactor.AutoTempSlider.FlashTimer <= 0)
if (engineer_reactor.AutoTempSwitch.FlashTimer <= 0)
{
engineer_reactor.AutoTempSlider.Flash(highlightColor, 1.5f, false, new Vector2(10, 10));
engineer_reactor.AutoTempSwitch.Flash(highlightColor, 1.5f, false, false, new Vector2(10, 10));
}
}
yield return null;
@@ -348,7 +348,7 @@ namespace Barotrauma.Tutorials
{
yield return new WaitForSeconds(0.1f, false);
wait -= 0.1f;
engineer_reactor.AutoTempSlider.BarScrollValue = 0.0f;
engineer_reactor.AutoTemp = true;
} while (wait > 0.0f);
engineer.SelectedConstruction = null;
engineer_reactor.CanBeSelected = false;
@@ -361,7 +361,7 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!engineer_secondDoor.IsOpen);
yield return new WaitForSeconds(1f, false);
Repairable repairableJunctionBoxComponent = engineer_brokenJunctionBox.GetComponent<Repairable>();
TriggerTutorialSegment(2, GameMain.Config.KeyBind(InputType.Select)); // Repair the junction box
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Select)); // Repair the junction box
do
{
if (!engineer.HasEquippedItem("screwdriver"))
@@ -389,7 +389,7 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (!engineer_thirdDoor.IsOpen);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.FaultyWiring"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(3, GameMain.Config.KeyBind(InputType.Use), GameMain.Config.KeyBind(InputType.Deselect)); // Connect the junction boxes
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Use), GameMain.Config.KeyBindText(InputType.Deselect)); // Connect the junction boxes
do { CheckGhostWires(); HandleJunctionBoxWiringHighlights(); yield return null; } while (engineer_workingPump.Voltage < engineer_workingPump.MinVoltage); // Wait until connected all the way to the pump
CheckGhostWires();
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
@@ -87,18 +87,18 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
mechanic = Character.Controlled;
var toolbox = mechanic.Inventory.FindItemByIdentifier("toolbox");
var toolbox = FindOrGiveItem(mechanic, "toolbox");
toolbox.Unequip(mechanic);
mechanic.Inventory.RemoveItem(toolbox);
var crowbar = mechanic.Inventory.FindItemByIdentifier("crowbar");
var crowbar = FindOrGiveItem(mechanic, "crowbar");
crowbar.Unequip(mechanic);
mechanic.Inventory.RemoveItem(crowbar);
var repairOrder = Order.GetPrefab("repairsystems");
mechanic_repairIcon = repairOrder.SymbolSprite;
mechanic_repairIconColor = repairOrder.Color;
mechanic_weldIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(1, 256, 127, 127), new Vector2(0.5f, 0.5f));
mechanic_weldIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(1, 256, 127, 127), new Vector2(0.5f, 0.5f));
// Other tutorial items
tutorial_securityFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoorlight")).GetComponent<LightComponent>();
@@ -241,7 +241,7 @@ namespace Barotrauma.Tutorials
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.WakeUp"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(2.5f, false);
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Up), GameMain.Config.KeyBind(InputType.Left), GameMain.Config.KeyBind(InputType.Down), GameMain.Config.KeyBind(InputType.Right), GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Select)); // Open door objective
TriggerTutorialSegment(0, GameMain.Config.KeyBindText(InputType.Up), GameMain.Config.KeyBindText(InputType.Left), GameMain.Config.KeyBindText(InputType.Down), GameMain.Config.KeyBindText(InputType.Right), GameMain.Config.KeyBindText(InputType.Select), GameMain.Config.KeyBindText(InputType.Select)); // Open door objective
yield return new WaitForSeconds(0.0f, false);
SetDoorAccess(mechanic_firstDoor, mechanic_firstDoorLight, true);
SetHighlight(mechanic_firstDoor.Item, true);
@@ -254,7 +254,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(0.0f, false);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Deselect)); // Equipment & inventory objective
TriggerTutorialSegment(1, GameMain.Config.KeyBindText(InputType.Select), GameMain.Config.KeyBindText(InputType.Deselect), GameMain.Config.KeyBindText(InputType.ToggleInventory)); // Equipment & inventory objective
SetHighlight(mechanic_equipmentCabinet.Item, true);
bool firstSlotRemoved = false;
bool secondSlotRemoved = false;
@@ -296,7 +296,7 @@ namespace Barotrauma.Tutorials
// Room 3
do { yield return null; } while (!mechanic_weldingObjectiveSensor.MotionDetected);
TriggerTutorialSegment(2, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Welding objective
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Aim), GameMain.Config.KeyBindText(InputType.Shoot), GameMain.Config.KeyBindText(InputType.ToggleInventory)); // Welding objective
do
{
if (!mechanic.HasEquippedItem("divingmask"))
@@ -316,16 +316,16 @@ namespace Barotrauma.Tutorials
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_1);
RemoveCompletedObjective(segments[2]);
yield return new WaitForSeconds(1f, false);
TriggerTutorialSegment(3, GameMain.Config.KeyBind(InputType.Select)); // Pump objective
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Select)); // Pump objective
SetHighlight(mechanic_workingPump.Item, true);
do
{
yield return null;
if (IsSelectedItem(mechanic_workingPump.Item))
{
if (mechanic_workingPump.IsActiveSlider.FlashTimer <= 0)
if (mechanic_workingPump.PowerButton.FlashTimer <= 0)
{
mechanic_workingPump.IsActiveSlider.Flash(uiHighlightColor, 1.5f, true);
mechanic_workingPump.PowerButton.Flash(uiHighlightColor, 1.5f, true);
}
}
} while (mechanic_workingPump.FlowPercentage >= 0 || !mechanic_workingPump.IsActive); // Highlight until draining
@@ -348,6 +348,9 @@ namespace Barotrauma.Tutorials
TriggerTutorialSegment(4); // Deconstruct
SetHighlight(mechanic_craftingCabinet.Item, true);
bool gotOxygenTank = false;
bool gotSodium = false;
do
{
if (mechanic.SelectedConstruction == mechanic_craftingCabinet.Item)
@@ -381,8 +384,18 @@ namespace Barotrauma.Tutorials
}
}
}
if (!gotOxygenTank && mechanic.Inventory.FindItemByIdentifier("oxygentank") != null)
{
gotOxygenTank = true;
}
if (!gotSodium && mechanic.Inventory.FindItemByIdentifier("sodium") != null)
{
gotSodium = true;
}
yield return null;
} while ((mechanic.Inventory.FindItemByIdentifier("oxygentank") == null && mechanic.Inventory.FindItemByIdentifier("aluminium") == null) || mechanic.Inventory.FindItemByIdentifier("sodium") == null); // Wait until looted
} while (!gotOxygenTank || !gotSodium); // Wait until looted
yield return new WaitForSeconds(1.0f, false);
SetHighlight(mechanic_craftingCabinet.Item, false);
SetHighlight(mechanic_deconstructor.Item, true);
@@ -424,7 +437,9 @@ namespace Barotrauma.Tutorials
}
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("aluminium") == null); // Wait until deconstructed
} while (
mechanic.Inventory.FindItemByIdentifier("aluminium") == null &&
mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("aluminium") == null); // Wait until aluminium obtained
SetHighlight(mechanic_deconstructor.Item, false);
RemoveCompletedObjective(segments[4]);
@@ -482,7 +497,7 @@ namespace Barotrauma.Tutorials
// Room 5
do { yield return null; } while (!mechanic_fireSensor.MotionDetected);
TriggerTutorialSegment(6, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Using the extinguisher
TriggerTutorialSegment(6, GameMain.Config.KeyBindText(InputType.Aim), GameMain.Config.KeyBindText(InputType.Shoot)); // Using the extinguisher
do { yield return null; } while (!mechanic_fire.Removed); // Wait until extinguished
yield return new WaitForSeconds(3f, false);
RemoveCompletedObjective(segments[6]);
@@ -528,7 +543,7 @@ namespace Barotrauma.Tutorials
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Use)); // Repairing machinery (pump)
TriggerTutorialSegment(9, GameMain.Config.KeyBindText(InputType.Use)); // Repairing machinery (pump)
SetHighlight(mechanic_brokenPump.Item, true);
mechanic_brokenPump.CanBeSelected = true;
Repairable repairablePumpComponent = mechanic_brokenPump.Item.GetComponent<Repairable>();
@@ -554,9 +569,9 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(mechanic_brokenPump.Item))
{
if (mechanic_brokenPump.IsActiveSlider.FlashTimer <= 0)
if (mechanic_brokenPump.PowerButton.FlashTimer <= 0)
{
mechanic_brokenPump.IsActiveSlider.Flash(uiHighlightColor, 1.5f, true);
mechanic_brokenPump.PowerButton.Flash(uiHighlightColor, 1.5f, true);
}
}
}
@@ -89,19 +89,34 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
officer = Character.Controlled;
var handcuffs = officer.Inventory.FindItemByIdentifier("handcuffs");
var handcuffs = FindOrGiveItem(officer, "handcuffs");
handcuffs.Unequip(officer);
officer.Inventory.RemoveItem(handcuffs);
var stunbaton = officer.Inventory.FindItemByIdentifier("stunbaton");
var stunbaton = FindOrGiveItem(officer, "stunbaton");
stunbaton.Unequip(officer);
officer.Inventory.RemoveItem(stunbaton);
var ballistichelmet = officer.Inventory.FindItemByIdentifier("ballistichelmet");
var smg = FindOrGiveItem(officer, "smg");
smg.Unequip(officer);
officer.Inventory.RemoveItem(smg);
var divingknife = FindOrGiveItem(officer, "divingknife");
divingknife.Unequip(officer);
officer.Inventory.RemoveItem(divingknife);
var steroids = FindOrGiveItem(officer, "steroids");
steroids.Unequip(officer);
officer.Inventory.RemoveItem(steroids);
var ballistichelmet =
officer.Inventory.FindItemByIdentifier("ballistichelmet1") ??
officer.Inventory.FindItemByIdentifier("ballistichelmet2") ??
FindOrGiveItem(officer, "ballistichelmet3");
ballistichelmet.Unequip(officer);
officer.Inventory.RemoveItem(ballistichelmet);
var bodyarmor = officer.Inventory.FindItemByIdentifier("bodyarmor");
var bodyarmor = FindOrGiveItem(officer, "bodyarmor");
bodyarmor.Unequip(officer);
officer.Inventory.RemoveItem(bodyarmor);
@@ -109,6 +124,11 @@ namespace Barotrauma.Tutorials
officer_gunIcon = gunOrder.SymbolSprite;
officer_gunIconColor = gunOrder.Color;
var bandage = FindOrGiveItem(officer, "antibleeding1");
bandage.Unequip(officer);
officer.Inventory.RemoveItem(bandage);
FindOrGiveItem(officer, "antibleeding1");
// Other tutorial items
tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent<LightComponent>();
tutorial_submarineSteering = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
@@ -185,6 +205,8 @@ namespace Barotrauma.Tutorials
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
yield return new WaitForSeconds(0.01f);
// Room 1
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
while (shakeTimer > 0.0f) // Wake up, shake
@@ -238,7 +260,7 @@ namespace Barotrauma.Tutorials
//RemoveCompletedObjective(segments[0]);
SetHighlight(officer_equipmentCabinet.Item, false);
do { yield return null; } while (IsSelectedItem(officer_equipmentCabinet.Item));
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Equip melee weapon & armor
TriggerTutorialSegment(1, GameMain.Config.KeyBindText(InputType.Aim), GameMain.Config.KeyBindText(InputType.Shoot)); // Equip melee weapon & armor
do
{
if (!officer.HasEquippedItem("stunbaton"))
@@ -249,12 +271,12 @@ namespace Barotrauma.Tutorials
{
HighlightInventorySlot(officer.Inventory, "bodyarmor", highlightColor, .5f, .5f, 0f);
}
if (!officer.HasEquippedItem("ballistichelmet"))
if (!officer.HasEquippedItem("ballistichelmet1"))
{
HighlightInventorySlot(officer.Inventory, "ballistichelmet", highlightColor, .5f, .5f, 0f);
HighlightInventorySlot(officer.Inventory, "ballistichelmet1", highlightColor, .5f, .5f, 0f);
}
yield return new WaitForSeconds(1f, false);
} while (!officer.HasEquippedItem("stunbaton") || !officer.HasEquippedItem("bodyarmor") || !officer.HasEquippedItem("ballistichelmet"));
} while (!officer.HasEquippedItem("stunbaton") || !officer.HasEquippedItem("bodyarmor") || !officer.HasEquippedItem("ballistichelmet1"));
RemoveCompletedObjective(segments[1]);
SetDoorAccess(officer_firstDoor, officer_firstDoorLight, true);
@@ -291,7 +313,7 @@ namespace Barotrauma.Tutorials
SetHighlight(officer_ammoShelf_2.Item, false);
RemoveCompletedObjective(segments[3]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(4, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Shoot), GameMain.Config.KeyBind(InputType.Deselect)); // Kill hammerhead
TriggerTutorialSegment(4, GameMain.Config.KeyBindText(InputType.Select), GameMain.Config.KeyBindText(InputType.Shoot), GameMain.Config.KeyBindText(InputType.Deselect)); // Kill hammerhead
officer_hammerhead = SpawnMonster("hammerhead", officer_hammerheadSpawnPos);
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
SetHighlight(officer_coilgunPeriscope, true);
@@ -325,7 +347,7 @@ namespace Barotrauma.Tutorials
//do { yield return null; } while (!officer_rangedWeaponSensor.MotionDetected);
do { yield return null; } while (!officer_thirdDoor.IsOpen);
yield return new WaitForSeconds(3f, false);
TriggerTutorialSegment(5, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Ranged weapons
TriggerTutorialSegment(5, GameMain.Config.KeyBindText(InputType.Aim), GameMain.Config.KeyBindText(InputType.Shoot)); // Ranged weapons
SetHighlight(officer_rangedWeaponHolder.Item, true);
do { yield return null; } while (!officer_rangedWeaponHolder.Inventory.IsEmpty()); // Wait until looted
SetHighlight(officer_rangedWeaponHolder.Item, false);
@@ -31,8 +31,8 @@ namespace Barotrauma.Tutorials
protected Color highlightColor = Color.OrangeRed;
protected Color uiHighlightColor = new Color(150, 50, 0);
protected Color buttonHighlightColor = new Color(255, 100, 0);
protected Color inaccessibleColor = Color.Red;
protected Color accessibleColor = Color.Green;
protected Color inaccessibleColor = GUI.Style.Red;
protected Color accessibleColor = GUI.Style.Green;
public ScenarioTutorial(XElement element) : base(element)
{
@@ -88,7 +88,7 @@ namespace Barotrauma.Tutorials
GameMain.GameSession.StartRound(levelSeed);
}
GameMain.GameSession.EventManager.Events.Clear();
GameMain.GameSession.EventManager.ActiveEvents.Clear();
GameMain.GameSession.EventManager.Enabled = false;
GameMain.GameScreen.Select();
@@ -102,7 +102,7 @@ namespace Barotrauma.Tutorials
Submarine.MainSub.GodMode = true;
CharacterInfo charInfo = configElement.Element("Character") == null ?
new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer")) :
new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer")) :
new CharacterInfo(configElement.Element("Character"));
WayPoint wayPoint = GetSpawnPoint(charInfo);
@@ -298,5 +298,16 @@ namespace Barotrauma.Tutorials
character.Bloodloss = 0.0f;
character.SetStun(0.0f, true);
}
protected Item FindOrGiveItem(Character character, string identifier)
{
var item = character.Inventory.FindItemByIdentifier(identifier);
if (item != null && !item.Removed) { return item; }
ItemPrefab itemPrefab = MapEntityPrefab.Find(name: null, identifier: identifier) as ItemPrefab;
item = new Item(itemPrefab, Vector2.Zero, submarine: null);
character.Inventory.TryPutItem(item, character, item.AllowedSlots);
return item;
}
}
}
@@ -99,9 +99,9 @@ namespace Barotrauma.Tutorials
public static void Init()
{
Tutorials = new List<Tutorial>();
foreach (string file in GameMain.Instance.GetFilesOfType(ContentType.Tutorials))
foreach (ContentFile file in GameMain.Instance.GetFilesOfType(ContentType.Tutorials))
{
XDocument doc = XMLExtensions.TryLoadXml(file);
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc?.Root == null) continue;
foreach (XElement element in doc.Root.Elements())
@@ -372,9 +372,10 @@ namespace Barotrauma.Tutorials
private void CreateObjectiveGUI(TutorialSegment segment, int index, TutorialContentTypes type)
{
Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f));
string objectiveText = TextManager.ParseInputTypes(segment.Objective);
Point replayButtonSize = new Point((int)(GUI.LargeFont.MeasureString(objectiveText).X), (int)(GUI.LargeFont.MeasureString(objectiveText).Y * 1.45f));
segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) =>
{
if (type == TutorialContentTypes.Video)
@@ -389,13 +390,15 @@ namespace Barotrauma.Tutorials
};
string objectiveTitleText = TextManager.ParseInputTypes(objectiveTranslated);
int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveTitleText).Y / 2f + 5));
segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point((int)GUI.ObjectiveTitleFont.MeasureString(objectiveTitleText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterRight, Pivot.BottomRight) /*{ AbsoluteOffset = new Point((int)(-10 * GUI.Scale), 0) }*/,
objectiveTitleText, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight);
int yOffset = (int)((GUI.SubHeadingFont.MeasureString(objectiveTitleText).Y + 5));
segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point((int)GUI.SubHeadingFont.MeasureString(objectiveTitleText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterLeft, Pivot.BottomLeft) /*{ AbsoluteOffset = new Point((int)(-10 * GUI.Scale), 0) }*/,
objectiveTitleText, textColor: Color.White, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft)
{
ForceUpperCase = true
};
string objectiveText = TextManager.ParseInputTypes(segment.Objective);
segment.LinkedText = new GUITextBlock(new RectTransform(new Point((int)GUI.ObjectiveNameFont.MeasureString(objectiveText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterRight, Pivot.TopRight) /*{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }*/,
objectiveText, textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight);
segment.LinkedText = new GUITextBlock(new RectTransform(new Point((int)GUI.LargeFont.MeasureString(objectiveText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterLeft, Pivot.TopLeft) /*{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }*/,
objectiveText, textColor: new Color(4, 180, 108), font: GUI.LargeFont, textAlignment: Alignment.CenterLeft);
segment.LinkedTitle.Color = segment.LinkedTitle.HoverColor = segment.LinkedTitle.PressedColor = segment.LinkedTitle.SelectedColor = Color.Transparent;
segment.LinkedText.Color = segment.LinkedText.HoverColor = segment.LinkedText.PressedColor = segment.LinkedText.SelectedColor = Color.Transparent;
@@ -449,19 +452,19 @@ namespace Barotrauma.Tutorials
RectTransform rectTA;
if (objectiveTextWidth > objectiveTitleWidth)
{
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(10 * GUI.Scale), 0);
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomRight, Pivot.BottomRight);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(25 * GUI.Scale), 0);
}
else
{
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(10 * GUI.Scale) - (objectiveTitleWidth - objectiveTextWidth), 0);
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomRight, Pivot.BottomRight);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(25 * GUI.Scale) - (objectiveTitleWidth - objectiveTextWidth), 0);
}
GUIImage checkmark = new GUIImage(rectTA, "CheckMark");
checkmark.Color = checkmark.SelectedColor = checkmark.HoverColor = checkmark.PressedColor = color;
RectTransform rectTB = new RectTransform(new Vector2(1.1f, .8f), segment.LinkedText.RectTransform, Anchor.Center, Pivot.Center);
RectTransform rectTB = new RectTransform(new Vector2(1.0f, .8f), segment.LinkedText.RectTransform, Anchor.Center, Pivot.Center);
GUIImage stroke = new GUIImage(rectTB, "Stroke");
stroke.Color = stroke.SelectedColor = stroke.HoverColor = stroke.PressedColor = color;
@@ -493,14 +496,6 @@ namespace Barotrauma.Tutorials
protected GUIComponent CreateInfoFrame(string title, string text, int width = 300, int height = 80, string anchorStr = "", bool hasButton = false, Action callback = null, Action showVideo = null)
{
if (hasButton) height += 60;
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
height += (int)(GUI.Font.MeasureString(wrappedText).Y + 50);
if (title.Length > 0)
{
height += 35;
}
Anchor anchor = Anchor.TopRight;
@@ -509,12 +504,23 @@ namespace Barotrauma.Tutorials
Enum.TryParse(anchorStr, out anchor);
}
var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", new Color(0, 0, 0, 1f));
width = (int)(width * GUI.Scale);
height = (int)(height * GUI.Scale);
var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), background.RectTransform, anchor) { AbsoluteOffset = new Point(20) });
infoBlock.Flash(Color.Green);
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
height += (int)GUI.Font.MeasureString(wrappedText).Y;
var infoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), infoBlock.RectTransform, Anchor.Center))
if (title.Length > 0)
{
height += (int)GUI.Font.MeasureString(title).Y + (int)(150 * GUI.Scale);
}
var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), style: null, Color.Black * 0.5f);
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), background.RectTransform, anchor));
infoBlock.Flash(GUI.Style.Green);
var infoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), infoBlock.RectTransform, Anchor.Center))
{
Stretch = true,
AbsoluteSpacing = 5
@@ -523,26 +529,35 @@ namespace Barotrauma.Tutorials
if (title.Length > 0)
{
var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform),
title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0));
title, font: GUI.LargeFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0));
titleBlock.RectTransform.IsFixedSize = true;
}
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), " " + text, wrap: true);
textBlock.RectTransform.IsFixedSize = true;
List<ColorData> colorData = ColorData.GetColorData(text, out text);
GUITextBlock textBlock;
if (colorData == null)
{
textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), " " + text, wrap: true);
}
else
{
textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), colorData, " " + text, wrap: true);
}
textBlock.RectTransform.IsFixedSize = true;
infoBoxClosedCallback = callback;
if (hasButton)
{
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), infoContent.RectTransform) { MinSize = new Point(0, 30), MaxSize = new Point((int) infoContent.Rect.X, 60) }, isHorizontal: true)
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), infoContent.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.1f
};
buttonContainer.RectTransform.IsFixedSize = true;
if (showVideo != null)
{
buttonContainer.Stretch = true;
var videoButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("Video"), style: "GUIButtonLarge")
{
@@ -553,8 +568,13 @@ namespace Barotrauma.Tutorials
}
};
}
else
{
buttonContainer.Stretch = false;
buttonContainer.ChildAnchor = Anchor.Center;
}
var okButton = new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform),
var okButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("OK"), style: "GUIButtonLarge")
{
OnClicked = CloseInfoFrame
@@ -1,21 +1,20 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
namespace Barotrauma
{
partial class GameSession
{
private InfoFrameTab selectedTab;
private GUIButton infoFrame;
private GUIFrame infoFrame;
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
private GUIFrame infoFrameContent;
public RoundSummary RoundSummary { get; private set; }
public static bool IsInfoFrameOpen => GameMain.GameSession?.infoFrame != null;
private RoundSummary roundSummary;
public RoundSummary RoundSummary
{
get { return roundSummary; }
}
private bool ToggleInfoFrame()
{
if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
@@ -40,7 +39,9 @@ namespace Barotrauma
{
int width = 600, height = 400;
infoFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
tabButtons.Clear();
infoFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.35f), infoFrame.RectTransform, Anchor.Center) { MinSize = new Point(width, height), RelativeOffset = new Vector2(0.0f, 0.033f) });
@@ -56,12 +57,14 @@ namespace Barotrauma
UserData = InfoFrameTab.Crew,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(crewButton);
var missionButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("Mission"), style: "GUITabButton")
{
UserData = InfoFrameTab.Mission,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(missionButton);
if (GameMain.NetworkMember != null)
{
@@ -70,6 +73,7 @@ namespace Barotrauma
UserData = InfoFrameTab.MyCharacter,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(myCharacterButton);
}
/*TODO: fix
@@ -89,6 +93,7 @@ namespace Barotrauma
selectedTab = (InfoFrameTab)userData;
CreateInfoFrame();
tabButtons.ForEach(tb => tb.Selected = (InfoFrameTab)tb.UserData == selectedTab);
switch (selectedTab)
{
@@ -178,14 +183,14 @@ namespace Barotrauma
{
if (GameMain.NetLobbyScreen?.HeadSelectionList != null)
{
if (PlayerInput.LeftButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.HeadSelectionList))
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.HeadSelectionList))
{
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
}
}
if (GameMain.NetLobbyScreen?.JobSelectionFrame != null)
{
if (PlayerInput.LeftButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
{
GameMain.NetLobbyScreen.JobList.Deselect();
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
@@ -30,17 +30,21 @@ namespace Barotrauma
TakeFromCharacter,
PutToContainer,
PutToCharacter,
UseTreatment
PutToEquippedItem,
UseTreatment,
}
private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
private Point screenResolution;
public Vector2[] SlotPositions;
public static Point SlotSize;
public static int Spacing;
public static int HideButtonWidth;
private Layout layout;
public Layout CurrentLayout
{
@@ -68,22 +72,44 @@ namespace Barotrauma
{
get { return personalSlotArea; }
}
private GUIImage[] indicators = new GUIImage[5];
private int[] indicatorIndexes = new int[5];
private Vector2 indicatorSpriteSize;
private GUILayoutGroup indicatorGroup;
partial void InitProjSpecific(XElement element)
{
Hidden = true;
hideButton = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), (int)(60 * GUI.Scale)), GUI.Canvas)
hideButton = new GUIButton(new RectTransform(new Point((int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f)), HUDLayoutSettings.BottomRightInfoArea.Height), GUI.Canvas)
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
"", style: "UIToggleButton");
hideButton.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
"", style: "EquipmentToggleButton");
indicatorGroup = new GUILayoutGroup(new RectTransform(Point.Zero, hideButton.RectTransform)) { IsHorizontal = false };
indicatorGroup.ChildAnchor = Anchor.TopCenter;
indicatorSpriteSize = GUI.Style.GetComponentStyle("EquipmentIndicatorDivingSuit").Sprites[GUIComponent.ComponentState.None][0].Sprite.size;
indicators[0] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorDivingSuit");
indicators[1] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorID");
indicators[2] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorOutfit");
indicators[3] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadwear");
indicators[4] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadphones");
indicatorIndexes[0] = FindLimbSlot(InvSlotType.OuterClothes);
indicatorIndexes[1] = FindLimbSlot(InvSlotType.Card);
indicatorIndexes[2] = FindLimbSlot(InvSlotType.InnerClothes);
indicatorIndexes[3] = FindLimbSlot(InvSlotType.Head);
indicatorIndexes[4] = FindLimbSlot(InvSlotType.Headset);
for (int i = 0; i < indicators.Length; i++)
{
indicators[i].CanBeFocused = false;
}
hideButton.OnClicked += (GUIButton btn, object userdata) =>
{
hidePersonalSlots = !hidePersonalSlots;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = hidePersonalSlots ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
}
return true;
};
@@ -94,13 +120,14 @@ namespace Barotrauma
limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
int margin = 2;
limbSlotIcons.Add(InvSlotType.Headset, new Sprite("Content/UI/IconAtlas.png", new Rectangle(384 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.InnerClothes, new Sprite("Content/UI/IconAtlas.png", new Rectangle(512 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.Card, new Sprite("Content/UI/IconAtlas.png", new Rectangle(640 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/IconAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(640 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 896 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.Headset, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(384 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.InnerClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(512 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.Card, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(640 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
}
SlotPositions = new Vector2[SlotTypes.Length];
CurrentLayout = Layout.Default;
@@ -140,16 +167,18 @@ namespace Barotrauma
public override void CreateSlots()
{
if (slots == null) { slots = new InventorySlot[capacity]; }
float multiplier = !GUI.IsFourByThree() ? UIScale : UIScale * 0.925f;
for (int i = 0; i < capacity; i++)
{
InventorySlot prevSlot = slots[i];
Sprite slotSprite = slotSpriteSmall;
Sprite slotSprite = SlotSpriteSmall;
Rectangle slotRect = new Rectangle(
(int)(SlotPositions[i].X),
(int)(SlotPositions[i].Y),
(int)(slotSprite.size.X * UIScale), (int)(slotSprite.size.Y * UIScale));
(int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));
if (Items[i] != null)
{
@@ -163,7 +192,7 @@ namespace Barotrauma
slots[i] = new InventorySlot(slotRect)
{
SubInventoryDir = Math.Sign(HUDLayoutSettings.InventoryAreaUpper.Bottom - slotRect.Center.Y),
SubInventoryDir = Math.Sign(GameMain.GraphicsHeight / 2 - slotRect.Center.Y),
Disabled = false,
SlotSprite = slotSprite,
Color = SlotTypes[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f
@@ -239,13 +268,44 @@ namespace Barotrauma
return false;
}
private void SetIndicatorSizes()
{
indicatorGroup.RectTransform.AbsoluteOffset = new Point((int)Math.Round(4 * GUI.Scale), (int)Math.Round(7 * GUI.Scale));
indicatorGroup.RectTransform.NonScaledSize = new Point(hideButton.Rect.Width - indicatorGroup.RectTransform.AbsoluteOffset.X * 2, hideButton.Rect.Height - indicatorGroup.RectTransform.AbsoluteOffset.Y * 2);
indicatorGroup.AbsoluteSpacing = (int)Math.Ceiling(2 * GUI.Scale);
int indicatorHeight = (indicatorGroup.RectTransform.NonScaledSize.Y - indicatorGroup.AbsoluteSpacing * (indicators.Length - 1)) / indicators.Length;
int indicatorWidth = (int)(indicatorSpriteSize.X / (indicatorSpriteSize.Y / indicatorHeight));
if (HideButtonWidth % 2 != indicatorWidth % 2) indicatorWidth++;
Point indicatorSize = new Point(indicatorWidth, indicatorHeight);
for (int i = 0; i < indicators.Length; i++)
{
indicators[i].RectTransform.NonScaledSize = indicatorSize;
}
}
private void SetSlotPositions(Layout layout)
{
int spacing = (int)(10 * UIScale);
Point slotSize = (slotSpriteSmall.size * UIScale).ToPoint();
int bottomOffset = slotSize.Y + spacing * 2 + ContainedIndicatorHeight;
bool isFourByThree = GUI.IsFourByThree();
if (isFourByThree)
{
Spacing = (int)(5 * UIScale);
}
else
{
Spacing = (int)(8 * UIScale);
}
if (slots == null) CreateSlots();
HideButtonWidth = (int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f));
SlotSize = !isFourByThree ? (SlotSpriteSmall.size * UIScale).ToPoint() : (SlotSpriteSmall.size * UIScale * .925f).ToPoint();
int bottomOffset = SlotSize.Y + Spacing * 2 + ContainedIndicatorHeight;
if (slots == null) { CreateSlots(); }
hideButton.Visible = false;
@@ -256,11 +316,11 @@ namespace Barotrauma
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (slotSize.X + spacing) / 2;
int upperX = HUDLayoutSettings.PortraitArea.X - slotSize.X * 2;
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
//make sure the rightmost normal slot doesn't overlap with the personal slots
x -= Math.Max((x + normalSlotCount * (slotSize.X + spacing)) - (upperX - personalSlotCount * (slotSize.X + spacing)), 0);
x -= Math.Max((x + normalSlotCount * (SlotSize.X + Spacing)) - (upperX - personalSlotCount * (SlotSize.X + Spacing)), 0);
int hideButtonSlotIndex = -1;
for (int i = 0; i < SlotPositions.Length; i++)
@@ -268,27 +328,29 @@ namespace Barotrauma
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset);
upperX -= slotSize.X + spacing;
upperX -= SlotSize.X + Spacing;
personalSlotArea = (hideButtonSlotIndex == -1) ?
new Rectangle(SlotPositions[i].ToPoint(), slotSize) :
Rectangle.Union(personalSlotArea, new Rectangle(SlotPositions[i].ToPoint(), slotSize));
new Rectangle(SlotPositions[i].ToPoint(), SlotSize) :
Rectangle.Union(personalSlotArea, new Rectangle(SlotPositions[i].ToPoint(), SlotSize));
hideButtonSlotIndex = i;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slotSize.X + spacing;
x += SlotSize.X + Spacing;
}
}
if (hideButtonSlotIndex > -1)
{
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
hideButton.RectTransform.NonScaledSize = new Point(slotSize.X / 2, slotSize.Y + slots[hideButtonSlotIndex].EquipButtonRect.Height);
hideButton.RectTransform.NonScaledSize = new Point(HideButtonWidth, HUDLayoutSettings.BottomRightInfoArea.Height);
hideButton.RectTransform.AbsoluteOffset = new Point(
personalSlotArea.Right + spacing,
personalSlotArea.Y - slots[hideButtonSlotIndex].EquipButtonRect.Height);
personalSlotArea.Right + Spacing * 2,
HUDLayoutSettings.BottomRightInfoArea.Y);
hideButton.Visible = true;
SetIndicatorSizes();
}
}
break;
@@ -296,7 +358,7 @@ namespace Barotrauma
{
int extraOffset = 0;
int x = HUDLayoutSettings.InventoryAreaLower.Right;
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - slotSize.X - spacing;
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
for (int i = 0; i < slots.Length; i++)
{
if (HideSlot(i)) continue;
@@ -306,7 +368,7 @@ namespace Barotrauma
}
else
{
x -= slotSize.X + spacing;
x -= SlotSize.X + Spacing;
}
}
@@ -316,13 +378,13 @@ namespace Barotrauma
if (HideSlot(i)) continue;
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - spacing * 2);
personalSlotX -= slots[i].Rect.Width + spacing;
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - Spacing * 2);
personalSlotX -= slots[i].Rect.Width + Spacing;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
x += slots[i].Rect.Width + spacing;
x += slots[i].Rect.Width + Spacing;
}
}
@@ -330,7 +392,7 @@ namespace Barotrauma
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
x -= slots[i].Rect.Width + spacing;
x -= slots[i].Rect.Width + Spacing;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
}
}
@@ -344,28 +406,28 @@ namespace Barotrauma
if (HideSlot(i)) continue;
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - spacing * 2);
personalSlotX += slots[i].Rect.Width + spacing;
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2);
personalSlotX += slots[i].Rect.Width + Spacing;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + spacing;
x += slots[i].Rect.Width + Spacing;
}
}
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + spacing;
x += slots[i].Rect.Width + Spacing;
}
}
break;
case Layout.Center:
{
int columns = 5;
int startX = (GameMain.GraphicsWidth / 2) - (slotSize.X * columns + spacing * (columns - 1)) / 2;
int startY = GameMain.GraphicsHeight / 2 - (slotSize.Y * 2);
int startX = (GameMain.GraphicsWidth / 2) - (SlotSize.X * columns + Spacing * (columns - 1)) / 2;
int startY = GameMain.GraphicsHeight / 2 - (SlotSize.Y * 2);
int x = startX, y = startY;
for (int i = 0; i < SlotPositions.Length; i++)
{
@@ -373,10 +435,10 @@ namespace Barotrauma
if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
x += slots[i].Rect.Width + spacing;
x += slots[i].Rect.Width + Spacing;
}
}
y += slots[0].Rect.Height + spacing + ContainedIndicatorHeight + slots[0].EquipButtonRect.Height;
y += slots[0].Rect.Height + Spacing + ContainedIndicatorHeight + slots[0].EquipButtonRect.Height;
x = startX;
int n = 0;
for (int i = 0; i < SlotPositions.Length; i++)
@@ -385,12 +447,12 @@ namespace Barotrauma
if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
x += slots[i].Rect.Width + spacing;
x += slots[i].Rect.Width + Spacing;
n++;
if (n >= columns)
{
x = startX;
y += slots[i].Rect.Height + spacing + ContainedIndicatorHeight + slots[i].EquipButtonRect.Height;
y += slots[i].Rect.Height + Spacing + ContainedIndicatorHeight + slots[i].EquipButtonRect.Height;
n = 0;
}
}
@@ -431,34 +493,39 @@ namespace Barotrauma
((selectedSlot != null && selectedSlot.IsSubSlot) || (draggingItem != null && (draggingSlot == null || !draggingSlot.MouseOn())));
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
if (layout == Layout.Default && hideButton.Visible)
if (layout == Layout.Default)
{
hideButton.AddToGUIUpdateList();
hideButton.UpdateManually(deltaTime, alsoChildren: true);
hidePersonalSlotsState = hidePersonalSlots ?
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
for (int i = 0; i < slots.Length; i++)
if (hideButton.Visible)
{
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
if (HidePersonalSlots)
hideButton.AddToGUIUpdateList();
hideButton.UpdateManually(deltaTime, alsoChildren: true);
hidePersonalSlotsState = hidePersonalSlots ?
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
bool personalSlotsMoving = hidePersonalSlotsState > 0 && hidePersonalSlotsState < 1f;
for (int i = 0; i < slots.Length; i++)
{
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
if (HidePersonalSlots)
{
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
}
slots[i].IsMoving = personalSlotsMoving;
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
}
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
}
}
if (hoverOnInventory) HideTimer = 0.5f;
if (HideTimer > 0.0f) HideTimer -= deltaTime;
if (hoverOnInventory) { HideTimer = 0.5f; }
if (HideTimer > 0.0f) { HideTimer -= deltaTime; }
for (int i = 0; i < capacity; i++)
{
if (Items[i] != null && Items[i] != draggingItem && Character.Controlled?.Inventory == this &&
GUI.KeyboardDispatcher.Subscriber == null &&
GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen &&
slots[i].QuickUseKey != Keys.None && PlayerInput.KeyHit(slots[i].QuickUseKey))
{
QuickUseItem(Items[i], true, false, true);
@@ -530,8 +597,10 @@ namespace Barotrauma
}
}
if (character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
if (character == Character.Controlled && character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
{
UpdateEquipmentIndicators();
//remove the highlighted slots of other characters' inventories when not grabbing anyone
highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory != this && s.ParentInventory?.Owner is Character);
@@ -620,36 +689,48 @@ namespace Barotrauma
}
var quickUseAction = GetQuickUseAction(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
"" : TextManager.Get("QuickUseAction." + quickUseAction.ToString());
//equipped item that can't be put in the inventory, use delayed dropping
if (quickUseAction == QuickUseAction.Drop)
if (quickUseAction != QuickUseAction.Drop)
{
slot.QuickUseButtonToolTip =
TextManager.Get("QuickUseAction.HoldToUnequip", returnNull: true) ??
(GameMain.Config.Language == "English" ? "Hold to unequip" : TextManager.Get("QuickUseAction.Unequip"));
if (PlayerInput.LeftButtonHeld())
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.SelectedItems.FirstOrDefault(i => i != null)?.Name);
if (PlayerInput.PrimaryMouseButtonDown()) slot.EquipButtonState = GUIComponent.ComponentState.Pressed;
if (PlayerInput.PrimaryMouseButtonClicked())
{
slot.QuickUseTimer = Math.Max(0.1f, slot.QuickUseTimer + deltaTime);
if (slot.QuickUseTimer >= 1.0f)
QuickUseItem(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
}
}
}
private void UpdateEquipmentIndicators()
{
for (int i = 0; i < indicators.Length; i++)
{
Item item = Items[indicatorIndexes[i]];
if (item != null)
{
Wearable wearable = item.GetComponent<Wearable>();
if (wearable != null && wearable.DisplayContainedStatus)
{
item.Drop(Character.Controlled);
GUI.PlayUISound(GUISoundType.DropItem);
float conditionPercentage = item.GetContainedItemConditionPercentage();
if (conditionPercentage != -1)
{
indicators[i].Color = ToolBox.GradientLerp(conditionPercentage, GUI.Style.EquipmentIndicatorRunningOut, GUI.Style.EquipmentIndicatorEquipped);
}
else
{
indicators[i].Color = GUI.Style.EquipmentIndicatorRunningOut;
}
}
else
{
indicators[i].Color = GUI.Style.EquipmentIndicatorEquipped;
}
}
else
{
slot.QuickUseTimer = Math.Max(0.0f, slot.QuickUseTimer - deltaTime * 5.0f);
}
}
else
{
if (PlayerInput.LeftButtonDown()) slot.EquipButtonState = GUIComponent.ComponentState.Pressed;
if (PlayerInput.LeftButtonClicked())
{
QuickUseItem(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
indicators[i].Color = GUI.Style.EquipmentIndicatorNotEquipped;
}
}
}
@@ -773,6 +854,10 @@ namespace Barotrauma
{
return QuickUseAction.TakeFromCharacter;
}
else if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)))
{
return QuickUseAction.PutToEquippedItem;
}
else if (allowEquip) //doubleclicked and no other inventory is selected
{
//not equipped -> attempt to equip
@@ -879,14 +964,29 @@ namespace Barotrauma
{
success = TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
}
break;
break;
case QuickUseAction.PutToEquippedItem:
for (int i = 0; i < character.SelectedItems.Length; i++)
{
if (character.SelectedItems[i]?.OwnInventory != null &&
character.SelectedItems[i].OwnInventory.TryPutItem(item, Character.Controlled))
{
success = true;
for (int j = 0; j < capacity; j++)
{
if (Items[j] == character.SelectedItems[i]) slots[j].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f);
}
break;
}
}
break;
}
if (success)
{
for (int i = 0; i < capacity; i++)
{
if (Items[i] == item) slots[i].ShowBorderHighlight(Color.Green, 0.1f, 0.4f);
if (Items[i] == item) slots[i].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f);
}
}
@@ -917,8 +1017,18 @@ namespace Barotrauma
character.Name, Color.White * 0.9f);
}
base.Draw(spriteBatch);
for (int i = 0; i < capacity; i++)
{
if (HideSlot(i)) continue;
Rectangle interactRect = slots[i].InteractRect;
interactRect.Location += slots[i].DrawOffset.ToPoint();
//don't draw the item if it's being dragged out of the slot
bool drawItem = draggingItem == null || draggingItem != Items[i] || interactRect.Contains(PlayerInput.MousePosition);
DrawSlot(spriteBatch, this, slots[i], Items[i], i, drawItem, SlotTypes[i]);
}
if (hideButton != null && hideButton.Visible && !Locked)
{
hideButton.DrawManually(spriteBatch, alsoChildren: true);
@@ -937,7 +1047,7 @@ namespace Barotrauma
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
{
var icon = limbSlotIcons[SlotTypes[i]];
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, Color.White * 0.3f, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUI.Style.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
}
continue;
}
@@ -955,35 +1065,56 @@ namespace Barotrauma
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.Right, slots[i].Rect.Bottom) + slots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
}
Color color = slots[i].EquipButtonState == GUIComponent.ComponentState.Pressed ? Color.Gray : Color.White * 0.8f;
if (slots[i].EquipButtonState == GUIComponent.ComponentState.Hover)
{
color = Color.White;
GUIComponent.ComponentState state = slots[i].EquipButtonState;
if (state == GUIComponent.ComponentState.Hover)
{
highlightedQuickUseSlot = slots[i];
}
if (Locked) { color *= 0.3f; }
var quickUseIndicator = Items[i].AllowedSlots.Any(a => a == InvSlotType.Any) ?
EquipIndicator : DropIndicator;
var quickUseHighlight = Items[i].AllowedSlots.Any(a => a == InvSlotType.Any) ?
EquipIndicatorHighlight : DropIndicatorHighlight;
quickUseIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, quickUseIndicator.Origin, 0, UIScale);
slots[i].QuickUseTimer = Math.Min(slots[i].QuickUseTimer, 1.0f);
if (slots[i].QuickUseTimer > 0.0f)
if (!Items[i].AllowedSlots.Any(a => a == InvSlotType.Any))
{
float indicatorFillAmount = character.HasEquippedItem(Items[i]) ? 1.0f - slots[i].QuickUseTimer : slots[i].QuickUseTimer;
quickUseHighlight.DrawTiled(spriteBatch,
slots[i].EquipButtonRect.Center.ToVector2() - quickUseHighlight.Origin * UIScale * 0.85f,
new Vector2(quickUseIndicator.SourceRect.Width * indicatorFillAmount, quickUseIndicator.SourceRect.Height) * UIScale * 0.85f,
null,
color * 0.9f,
null,
Vector2.One * UIScale * 0.85f);
continue;
}
else if (character.HasEquippedItem(Items[i]))
Color color = Color.White;
if (Locked)
{
color *= 0.5f;
}
if (character.HasEquippedItem(Items[i]))
{
quickUseHighlight.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color * 0.9f, quickUseHighlight.Origin, 0, UIScale * 0.85f);
switch (state)
{
case GUIComponent.ComponentState.None:
EquippedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Hover:
EquippedHoverIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Pressed:
case GUIComponent.ComponentState.Selected:
case GUIComponent.ComponentState.HoverSelected:
EquippedClickedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
}
}
else
{
switch (state)
{
case GUIComponent.ComponentState.None:
UnequippedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Hover:
UnequippedHoverIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Pressed:
case GUIComponent.ComponentState.Selected:
case GUIComponent.ComponentState.HoverSelected:
UnequippedClickedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
}
}
}
@@ -12,6 +12,10 @@ namespace Barotrauma.Items.Components
private ConvexHull convexHull;
private ConvexHull convexHull2;
private float shake;
private float shakeTimer;
private Vector2 shakePos;
//openState when the vertices of the convex hull were last calculated
private float lastConvexHullState;
@@ -71,7 +75,7 @@ namespace Barotrauma.Items.Components
if (convexHull2 != null)
{
Rectangle rect2 = doorRect;
rect2.Y = rect2.Y + (int)((Window.Y * item.Scale - Window.Height * item.Scale));
rect2.Y += (int)(Window.Y * item.Scale - Window.Height * item.Scale);
rect2.Y += (int)(doorRect.Height * openState);
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
@@ -101,7 +105,23 @@ namespace Barotrauma.Items.Components
convexHull.SetVertices(GetConvexHullCorners(rect));
}
}
partial void UpdateProjSpecific(float deltaTime)
{
if (shakeTimer > 0.0f)
{
shakeTimer -= deltaTime;
Vector2 noisePos = new Vector2((float)PerlinNoise.CalculatePerlin(shakeTimer * 10.0f, shakeTimer * 10.0f, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(shakeTimer * 10.0f, shakeTimer * 10.0f, 0.5f) - 0.5f);
shakePos = noisePos * shake * 2.0f;
shake = Math.Min(shake, shakeTimer * 10.0f);
}
else
{
shakePos = Vector2.Zero;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
Color color = item.SpriteColor;
@@ -114,7 +134,7 @@ namespace Barotrauma.Items.Components
if (stuck > 0.0f && weldedSprite != null)
{
Vector2 weldSpritePos = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2.0f);
Vector2 weldSpritePos = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2.0f) + shakePos;
if (item.Submarine != null) weldSpritePos += item.Submarine.DrawPosition;
weldSpritePos.Y = -weldSpritePos.Y;
@@ -122,15 +142,14 @@ namespace Barotrauma.Items.Components
weldSpritePos, item.SpriteColor * (stuck / 100.0f), scale: item.Scale);
}
if (openState == 1.0f)
if (openState >= 1.0f)
{
Body.Enabled = false;
return;
}
if (IsHorizontal)
{
Vector2 pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2);
Vector2 pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2) + shakePos;
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
pos.Y = -pos.Y;
@@ -156,7 +175,7 @@ namespace Barotrauma.Items.Components
}
else
{
Vector2 pos = new Vector2(item.Rect.Center.X, item.Rect.Y);
Vector2 pos = new Vector2(item.Rect.Center.X, item.Rect.Y) + shakePos;
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
pos.Y = -pos.Y;
@@ -181,6 +200,15 @@ namespace Barotrauma.Items.Components
}
}
partial void OnFailedToOpen()
{
if (shakeTimer <= 0.0f)
{
PlaySound(ActionType.OnFailure);
shake = 5.0f;
shakeTimer = 1.0f;
}
}
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage, bool forcedOpen)
{
@@ -200,7 +228,7 @@ namespace Barotrauma.Items.Components
//sent by the server, or reverting it back to its old state if no msg from server was received
PredictedState = open;
resetPredictionTimer = CorrectionDelay;
if (stateChanged) PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse, item.WorldPosition);
if (stateChanged) PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse);
}
else
{
@@ -208,7 +236,7 @@ namespace Barotrauma.Items.Components
if (!isNetworkMessage || open != PredictedState)
{
StopPicking(null);
PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse, item.WorldPosition);
PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse);
}
}
}
@@ -221,6 +249,14 @@ namespace Barotrauma.Items.Components
bool forcedOpen = msg.ReadBoolean();
SetState(open, isNetworkMessage: true, sendNetworkMessage: false, forcedOpen: forcedOpen);
Stuck = msg.ReadRangedSingle(0.0f, 100.0f, 8);
UInt16 lastUserID = msg.ReadUInt16();
Character user = lastUserID == 0 ? null : Entity.FindEntityByID(lastUserID) as Character;
if (user != lastUser)
{
lastUser = user;
toggleCooldownTimer = ToggleCoolDown;
}
if (isStuck) { OpenState = 0.0f; }
PredictedState = null;
}
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
partial void DischargeProjSpecific()
{
PlaySound(ActionType.OnUse, item.WorldPosition);
PlaySound(ActionType.OnUse);
foreach (Node node in nodes)
{
GameMain.ParticleManager.CreateParticle("swirlysmoke", node.WorldPosition, Vector2.Zero);
@@ -0,0 +1,108 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Barotrauma.Items.Components
{
partial class Holdable : IDrawableComponent
{
public Vector2 DrawSize
{
get { return item.Rect.Size.ToVector2(); }
}
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (!IsActive || picker == null || !CanBeAttached() || !picker.IsKeyDown(InputType.Aim) || picker != Character.Controlled) { return; }
Vector2 gridPos = picker.Position;
Vector2 roundedGridPos = new Vector2(
MathUtils.RoundTowardsClosest(picker.Position.X, Submarine.GridSize.X),
MathUtils.RoundTowardsClosest(picker.Position.Y, Submarine.GridSize.Y));
Vector2 attachPos = GetAttachPosition(picker);
if (item.Submarine == null)
{
Structure attachTarget = Structure.GetAttachTarget(item.WorldPosition);
if (attachTarget != null)
{
if (attachTarget.Submarine != null)
{
//set to submarine-relative position
gridPos += attachTarget.Submarine.Position;
roundedGridPos += attachTarget.Submarine.Position;
attachPos += attachTarget.Submarine.Position;
}
}
}
else
{
gridPos += item.Submarine.Position;
roundedGridPos += item.Submarine.Position;
attachPos += item.Submarine.Position;
}
Submarine.DrawGrid(spriteBatch, 14, gridPos, roundedGridPos, alpha: 0.7f);
item.Sprite.Draw(
spriteBatch,
new Vector2(attachPos.X, -attachPos.Y),
item.SpriteColor * 0.5f,
0.0f, item.Scale, SpriteEffects.None, 0.0f);
GUI.DrawRectangle(spriteBatch, new Vector2(attachPos.X - 2, -attachPos.Y - 2), Vector2.One * 5, GUI.Style.Red, thickness: 3);
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
if (!attachable || body == null) { return; }
Vector2 attachPos = (Vector2)extraData[2];
msg.Write(attachPos.X);
msg.Write(attachPos.Y);
}
public override void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
base.ClientRead(type, msg, sendingTime);
bool shouldBeAttached = msg.ReadBoolean();
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
if (!attachable)
{
DebugConsole.ThrowError("Received an attachment event for an item that's not attachable.");
return;
}
if (shouldBeAttached)
{
if (!attached)
{
Drop(false, null);
item.SetTransform(simPosition, 0.0f);
AttachToWall();
}
}
else
{
if (attached)
{
DropConnectedWires(null);
if (body != null)
{
item.body = body;
item.body.Enabled = true;
}
IsActive = false;
DeattachFromWall();
}
}
}
}
}
@@ -0,0 +1,123 @@
using Barotrauma.Particles;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class RangedWeapon : ItemComponent
{
private Sprite crosshairSprite, crosshairPointerSprite;
private Vector2 crosshairPos, crosshairPointerPos;
private float currentCrossHairScale, currentCrossHairPointerScale;
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
[Serialize(1.0f, false, description: "The scale of the crosshair sprite (if there is one).")]
public float CrossHairScale
{
get;
private set;
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "crosshair":
{
string texturePath = subElement.GetAttributeString("texture", "");
crosshairSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.FilePath));
}
break;
case "crosshairpointer":
{
string texturePath = subElement.GetAttributeString("texture", "");
crosshairPointerSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.FilePath));
}
break;
case "particleemitter":
particleEmitters.Add(new ParticleEmitter(subElement));
break;
}
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
currentCrossHairScale = currentCrossHairPointerScale = cam == null ? 1.0f : cam.Zoom;
if (crosshairSprite != null)
{
Vector2 aimRefWorldPos = character.AimRefPosition;
if (character.Submarine != null) { aimRefWorldPos += character.Submarine.Position; }
Vector2 itemPos = cam.WorldToScreen(aimRefWorldPos);
float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
Vector2 barrelDir = new Vector2((float)Math.Cos(rotation), -(float)Math.Sin(rotation));
Vector2 mouseDiff = itemPos - PlayerInput.MousePosition;
crosshairPos = new Vector2(
MathHelper.Clamp(itemPos.X + barrelDir.X * mouseDiff.Length(), 0, GameMain.GraphicsWidth),
MathHelper.Clamp(itemPos.Y + barrelDir.Y * mouseDiff.Length(), 0, GameMain.GraphicsHeight));
float spread = GetSpread(character);
Projectile projectile = FindProjectile();
if (projectile != null)
{
spread += MathHelper.ToRadians(projectile.Spread);
}
float crossHairDist = Vector2.Distance(item.WorldPosition, cam.ScreenToWorld(crosshairPos));
float spreadDist = (float)Math.Sin(spread) * crossHairDist;
currentCrossHairPointerScale = MathHelper.Clamp(spreadDist / Math.Min(crosshairSprite.size.X, crosshairSprite.size.Y), 0.1f, 10.0f);
}
currentCrossHairScale *= CrossHairScale;
crosshairPointerPos = PlayerInput.MousePosition;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (crosshairSprite == null) { return; }
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
//camera focused on some other item/device, don't draw the crosshair
if (character.ViewTarget != null && (character.ViewTarget is Item item) && item.Prefab.FocusOnSelected) { return; }
GUI.HideCursor = (crosshairSprite != null || crosshairPointerSprite != null) &&
GUI.MouseOn == null && !Inventory.IsMouseOnInventory() && !GameMain.Instance.Paused;
if (GUI.HideCursor)
{
crosshairSprite?.Draw(spriteBatch, crosshairPos, Color.White, 0, currentCrossHairScale);
crosshairPointerSprite?.Draw(spriteBatch, crosshairPointerPos, 0, currentCrossHairPointerScale);
}
}
partial void LaunchProjSpecific()
{
Vector2 particlePos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
float rotation = -item.body.Rotation;
if (item.body.Dir < 0.0f) { rotation += MathHelper.Pi; }
foreach (ParticleEmitter emitter in particleEmitters)
{
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: rotation, particleRotation: rotation);
}
}
protected override void RemoveComponentSpecific()
{
crosshairSprite?.Remove();
crosshairSprite = null;
crosshairPointerSprite?.Remove();
crosshairSprite = null;
}
}
}
@@ -47,6 +47,11 @@ namespace Barotrauma.Items.Components
partial class ItemComponent : ISerializableEntity
{
public bool HasSounds
{
get { return sounds.Count > 0; }
}
private bool[] hasSoundsOfType;
private Dictionary<ActionType, List<ItemSound>> sounds;
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
@@ -177,18 +182,56 @@ namespace Barotrauma.Items.Components
}
}
private bool shouldMuffleLooping;
private float lastMuffleCheckTime;
private ItemSound loopingSound;
private SoundChannel loopingSoundChannel;
public void PlaySound(ActionType type, Vector2 position, Character user = null)
private List<SoundChannel> playingOneshotSoundChannels = new List<SoundChannel>();
public void UpdateSounds()
{
if (!isActive || item.Condition <= 0.0f)
{
StopSounds(ActionType.OnActive);
}
if (loopingSound != null && loopingSoundChannel != null && loopingSoundChannel.IsPlaying)
{
if (Timing.TotalTime > lastMuffleCheckTime + 0.2f)
{
shouldMuffleLooping = SoundPlayer.ShouldMuffleSound(Character.Controlled, item.WorldPosition, loopingSound.Range, Character.Controlled?.CurrentHull);
lastMuffleCheckTime = (float)Timing.TotalTime;
}
loopingSoundChannel.Muffled = shouldMuffleLooping;
float targetGain = GetSoundVolume(loopingSound);
float gainDiff = targetGain - loopingSoundChannel.Gain;
loopingSoundChannel.Gain += Math.Abs(gainDiff) < 0.1f ? gainDiff : Math.Sign(gainDiff) * 0.1f;
loopingSoundChannel.Position = new Vector3(item.WorldPosition, 0.0f);
}
for (int i = 0; i < playingOneshotSoundChannels.Count; i++)
{
if (!playingOneshotSoundChannels[i].IsPlaying)
{
playingOneshotSoundChannels[i].Dispose();
playingOneshotSoundChannels[i] = null;
}
}
playingOneshotSoundChannels.RemoveAll(ch => ch == null);
foreach (SoundChannel channel in playingOneshotSoundChannels)
{
channel.Position = new Vector3(item.WorldPosition, 0.0f);
}
}
public void PlaySound(ActionType type, Character user = null)
{
if (!hasSoundsOfType[(int)type]) { return; }
if (loopingSound != null)
{
float targetGain = 0.0f;
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range ||
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(item.WorldPosition, 0.0f)) > loopingSound.Range * loopingSound.Range ||
(targetGain = GetSoundVolume(loopingSound)) <= 0.0001f)
{
if (loopingSoundChannel != null)
@@ -205,26 +248,14 @@ namespace Barotrauma.Items.Components
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
new Vector3(position.X, position.Y, 0.0f),
new Vector3(item.WorldPosition, 0.0f),
0.01f,
SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull));
SoundPlayer.ShouldMuffleSound(Character.Controlled, item.WorldPosition, loopingSound.Range, Character.Controlled?.CurrentHull));
loopingSoundChannel.Looping = true;
//TODO: tweak
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
loopingSoundChannel.Far = loopingSound.Range;
}
if (loopingSoundChannel != null)
{
if (Timing.TotalTime > lastMuffleCheckTime + 0.2f)
{
shouldMuffleLooping = SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull);
lastMuffleCheckTime = (float)Timing.TotalTime;
}
loopingSoundChannel.Muffled = shouldMuffleLooping;
float gainDiff = targetGain - loopingSoundChannel.Gain;
loopingSoundChannel.Gain += Math.Abs(gainDiff) < 0.1f ? gainDiff : Math.Sign(gainDiff) * 0.1f;
loopingSoundChannel.Position = new Vector3(position.X, position.Y, 0.0f);
}
return;
}
@@ -246,7 +277,7 @@ namespace Barotrauma.Items.Components
{
foreach (ItemSound sound in matchingSounds)
{
PlaySound(sound, position, user);
PlaySound(sound, item.WorldPosition, user);
}
return;
}
@@ -256,7 +287,7 @@ namespace Barotrauma.Items.Components
}
itemSound = matchingSounds[index];
PlaySound(matchingSounds[index], position, user);
PlaySound(matchingSounds[index], item.WorldPosition, user);
}
}
@@ -293,7 +324,8 @@ namespace Barotrauma.Items.Components
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0001f) { return; }
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
if (channel != null) { playingOneshotSoundChannels.Add(channel); }
}
}
@@ -420,7 +452,7 @@ namespace Barotrauma.Items.Components
if (!filePath.Contains("/") && !filePath.Contains("\\") && !filePath.Contains(Path.DirectorySeparatorChar))
{
filePath = Path.Combine(Path.GetDirectoryName(item.Prefab.ConfigFile), filePath);
filePath = Path.Combine(Path.GetDirectoryName(item.Prefab.FilePath), filePath);
}
ActionType type;
@@ -13,6 +13,8 @@ namespace Barotrauma.Items.Components
private GUICustomComponent guiCustomComponent;
private Point prevResolution;
public Sprite InventoryTopSprite
{
get { return inventoryTopSprite; }
@@ -52,15 +54,6 @@ namespace Barotrauma.Items.Components
[Serialize(-1.0f, false, description: "Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.")]
public float ContainedSpriteDepth { get; set; }
private float itemRotation;
[Serialize(0.0f, false, description: "The rotation in which the contained sprites are drawn (in degrees).")]
public float ItemRotation
{
get { return MathHelper.ToDegrees(itemRotation); }
set { itemRotation = MathHelper.ToRadians(value); }
}
[Serialize(null, false, description: "An optional text displayed above the item's inventory.")]
public string UILabel { get; set; }
@@ -126,19 +119,64 @@ namespace Barotrauma.Items.Components
else
{
//if a GUIFrame has been defined, draw the inventory inside it
guiCustomComponent = new GUICustomComponent(new RectTransform(new Vector2(0.9f), GuiFrame.RectTransform, Anchor.Center),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
Inventory.RectTransform = guiCustomComponent.RectTransform;
CreateGUI();
prevResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
}
}
private void CreateGUI()
{
var content = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset },
style: null)
{
CanBeFocused = false
};
string labelText = GetUILabel();
GUITextBlock label = null;
if (!string.IsNullOrEmpty(labelText))
{
label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform, Anchor.TopCenter),
labelText, font: GUI.SubHeadingFont, textAlignment: Alignment.Center, wrap: true);
}
float minInventoryAreaSize = 0.5f;
guiCustomComponent = new GUICustomComponent(
new RectTransform(new Vector2(1.0f, label == null ? 1.0f : Math.Max(1.0f - label.RectTransform.RelativeSize.Y, minInventoryAreaSize)), content.RectTransform, Anchor.BottomCenter),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
Inventory.RectTransform = guiCustomComponent.RectTransform;
}
public string GetUILabel()
{
if (UILabel == string.Empty) { return string.Empty; }
if (UILabel != null)
{
return TextManager.Get("UILabel." + UILabel);
}
else
{
return item?.Name;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
if ((prevResolution.X > 0 && prevResolution.Y > 0) &&
(prevResolution.X != GameMain.GraphicsWidth || prevResolution.Y != GameMain.GraphicsHeight))
{
GuiFrame.ClearChildren();
CreateGUI();
prevResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
}
DrawContainedItems(spriteBatch, itemDepth);
}
@@ -146,7 +184,6 @@ namespace Barotrauma.Items.Components
{
Vector2 transformedItemPos = ItemPos * item.Scale;
Vector2 transformedItemInterval = ItemInterval * item.Scale;
float currentRotation = itemRotation;
if (item.body == null)
{
@@ -177,8 +214,6 @@ namespace Barotrauma.Items.Components
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
transformedItemPos += item.DrawPosition;
currentRotation += item.body.Rotation;
}
Vector2 currentItemPos = transformedItemPos;
@@ -198,12 +233,6 @@ namespace Barotrauma.Items.Components
item.IsHighlighted = false;
}
if (containedItem.body != null &&
Math.Abs(containedItem.body.FarseerBody.Rotation - currentRotation) > 0.001f)
{
containedItem.body.SetTransformIgnoreContacts(containedItem.body.SimPosition, currentRotation);
}
Vector2 origin = containedItem.Sprite.Origin;
if (item.FlippedX) { origin.X = containedItem.Sprite.SourceRect.Width - origin.X; }
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
@@ -216,7 +245,7 @@ namespace Barotrauma.Items.Components
new Vector2(currentItemPos.X, -currentItemPos.Y),
containedItem.GetSpriteColor(),
origin,
- currentRotation,
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation),
containedItem.Scale,
spriteEffects,
depth: containedSpriteDepth);

Some files were not shown because too many files have changed in this diff Show More