38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -9,6 +9,11 @@ build/
|
|||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
[Dd]ebug*/
|
||||||
|
[Rr]elease*/
|
||||||
|
|
||||||
|
# Barotrauma content folder
|
||||||
|
Content/
|
||||||
|
|
||||||
*.v12.suo
|
*.v12.suo
|
||||||
*.suo
|
*.suo
|
||||||
@@ -17,3 +22,6 @@ bld/
|
|||||||
*.vsp
|
*.vsp
|
||||||
*.psess
|
*.psess
|
||||||
.vs/
|
.vs/
|
||||||
|
|
||||||
|
# Mac
|
||||||
|
*.DS_Store
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
<ReleaseVersion>0.7.0.1</ReleaseVersion>
|
||||||
<PublishUrl>publish\</PublishUrl>
|
<PublishUrl>publish\</PublishUrl>
|
||||||
<Install>true</Install>
|
<Install>true</Install>
|
||||||
<InstallFrom>Disk</InstallFrom>
|
<InstallFrom>Disk</InstallFrom>
|
||||||
@@ -26,50 +29,66 @@
|
|||||||
<ApplicationVersion>0.1.0.%2a</ApplicationVersion>
|
<ApplicationVersion>0.1.0.%2a</ApplicationVersion>
|
||||||
<UseApplicationTrust>false</UseApplicationTrust>
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
<ReleaseVersion>0.7.0.1</ReleaseVersion>
|
|
||||||
<NuGetPackageImportStamp>
|
|
||||||
</NuGetPackageImportStamp>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseLinux|x86' ">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseLinux|x64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>..\bin\ReleaseLinux\</OutputPath>
|
<OutputPath>..\bin\ReleaseLinux\</OutputPath>
|
||||||
<DefineConstants>TRACE;LINUX;CLIENT</DefineConstants>
|
<DefineConstants>TRACE;LINUX;CLIENT</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<Optimize>true</Optimize>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugLinux|x86' ">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugLinux|x64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>..\bin\DebugLinux\</OutputPath>
|
<OutputPath>..\bin\DebugLinux\</OutputPath>
|
||||||
<DefineConstants>TRACE;LINUX;CLIENT;DEBUG</DefineConstants>
|
<DefineConstants>TRACE;LINUX;CLIENT;DEBUG</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<DebugType>full</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseWindows|x86' ">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseMac|x64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>pdbonly</DebugType>
|
<OutputPath>..\bin\ReleaseMac\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;OSX;CLIENT</DefineConstants>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugMac|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>..\bin\DebugMac\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;OSX;CLIENT;DEBUG</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseWindows|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<OutputPath>..\bin\ReleaseWindows\</OutputPath>
|
<OutputPath>..\bin\ReleaseWindows\</OutputPath>
|
||||||
<DefineConstants>TRACE;WINDOWS;CLIENT</DefineConstants>
|
<DefineConstants>TRACE;WINDOWS;CLIENT</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<Optimize>true</Optimize>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugWindows|x86' ">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugWindows|x64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>..\bin\DebugWindows\</OutputPath>
|
<OutputPath>..\bin\DebugWindows\</OutputPath>
|
||||||
<DefineConstants>TRACE;WINDOWS;CLIENT;DEBUG</DefineConstants>
|
<DefineConstants>TRACE;WINDOWS;CLIENT;DEBUG</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<DebugType>full</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
@@ -77,23 +96,47 @@
|
|||||||
<Compile Include="Source\Characters\AICharacter.cs" />
|
<Compile Include="Source\Characters\AICharacter.cs" />
|
||||||
<Compile Include="Source\Characters\AI\AIController.cs" />
|
<Compile Include="Source\Characters\AI\AIController.cs" />
|
||||||
<Compile Include="Source\Characters\AI\AITarget.cs" />
|
<Compile Include="Source\Characters\AI\AITarget.cs" />
|
||||||
<Compile Include="Source\Characters\AI\CrewCommander.cs" />
|
|
||||||
<Compile Include="Source\Characters\AI\EnemyAIController.cs" />
|
<Compile Include="Source\Characters\AI\EnemyAIController.cs" />
|
||||||
<Compile Include="Source\Characters\AI\HumanAIController.cs" />
|
<Compile Include="Source\Characters\AI\HumanAIController.cs" />
|
||||||
<Compile Include="Source\Characters\Animation\Ragdoll.cs" />
|
<Compile Include="Source\Characters\Animation\Ragdoll.cs" />
|
||||||
<Compile Include="Source\Characters\Attack.cs" />
|
<Compile Include="Source\Characters\Attack.cs" />
|
||||||
|
<Compile Include="Source\Characters\Health\AfflictionPsychosis.cs" />
|
||||||
|
<Compile Include="Source\Events\EventManager.cs" />
|
||||||
|
<Compile Include="Source\GameSession\GameModes\Tutorials\ContextualTutorial.cs" />
|
||||||
|
<Compile Include="Source\GameSession\GameModes\Tutorials\ScenarioTutorial.cs" />
|
||||||
|
<Compile Include="Source\GUI\ChatBox.cs" />
|
||||||
|
<Compile Include="Source\GUI\ParamsEditor.cs" />
|
||||||
|
<Compile Include="Source\GUI\ShapeExtensions.cs" />
|
||||||
|
<Compile Include="Source\GUI\Graph.cs" />
|
||||||
|
<Compile Include="Source\Characters\CharacterHealth.cs" />
|
||||||
<Compile Include="Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
|
<Compile Include="Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
|
||||||
|
<Compile Include="Source\GUI\GUICanvas.cs" />
|
||||||
|
<Compile Include="Source\GUI\GUICustomComponent.cs" />
|
||||||
|
<Compile Include="Source\GUI\GUILayoutGroup.cs" />
|
||||||
|
<Compile Include="Source\GUI\HUDLayoutSettings.cs" />
|
||||||
|
<Compile Include="Source\GUI\RectTransform.cs" />
|
||||||
|
<Compile Include="Source\GUI\SpriteSheetPlayer.cs" />
|
||||||
|
<Compile Include="Source\GUI\UISprite.cs" />
|
||||||
|
<Compile Include="Source\GUI\Widget.cs" />
|
||||||
|
<Compile Include="Source\Items\Components\ElectricalDischarger.cs" />
|
||||||
|
<Compile Include="Source\Items\Components\LevelResource.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\Controller.cs" />
|
<Compile Include="Source\Items\Components\Machines\Controller.cs" />
|
||||||
<Compile Include="Source\Map\Levels\BackgroundSprite\BackgroundCreature.cs" />
|
<Compile Include="Source\Items\Components\Repairable.cs" />
|
||||||
<Compile Include="Source\Map\Levels\BackgroundSprite\BackgroundCreatureManager.cs" />
|
<Compile Include="Source\Items\Components\RepairTool.cs" />
|
||||||
<Compile Include="Source\Map\Levels\BackgroundSprite\BackgroundCreaturePrefab.cs" />
|
<Compile Include="Source\Items\Components\Signal\CustomInterface.cs" />
|
||||||
|
<Compile Include="Source\Items\Components\Signal\MotionSensor.cs" />
|
||||||
|
<Compile Include="Source\Items\Components\Signal\WifiComponent.cs" />
|
||||||
|
<Compile Include="Source\Items\ItemInventory.cs" />
|
||||||
|
<Compile Include="Source\Map\ItemAssemblyPrefab.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\BackgroundCreatures\BackgroundCreature.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\BackgroundCreatures\BackgroundCreatureManager.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\BackgroundCreatures\BackgroundCreaturePrefab.cs" />
|
||||||
<Compile Include="Source\Characters\Character.cs" />
|
<Compile Include="Source\Characters\Character.cs" />
|
||||||
<Compile Include="Source\Characters\CharacterHUD.cs" />
|
<Compile Include="Source\Characters\CharacterHUD.cs" />
|
||||||
<Compile Include="Source\Characters\CharacterInfo.cs" />
|
<Compile Include="Source\Characters\CharacterInfo.cs" />
|
||||||
<Compile Include="Source\Characters\CharacterNetworking.cs" />
|
<Compile Include="Source\Characters\CharacterNetworking.cs" />
|
||||||
<Compile Include="Source\Characters\CharacterSound.cs" />
|
<Compile Include="Source\Characters\CharacterSound.cs" />
|
||||||
<Compile Include="Source\Characters\HUDProgressBar.cs" />
|
<Compile Include="Source\Characters\HUDProgressBar.cs" />
|
||||||
<Compile Include="Source\Characters\HuskInfection.cs" />
|
|
||||||
<Compile Include="Source\Characters\Jobs\JobPrefab.cs" />
|
<Compile Include="Source\Characters\Jobs\JobPrefab.cs" />
|
||||||
<Compile Include="Source\Characters\Limb.cs" />
|
<Compile Include="Source\Characters\Limb.cs" />
|
||||||
<Compile Include="Source\DebugConsole.cs" />
|
<Compile Include="Source\DebugConsole.cs" />
|
||||||
@@ -109,7 +152,7 @@
|
|||||||
<Compile Include="Source\GameSession\GameModes\Tutorials\BasicTutorial.cs" />
|
<Compile Include="Source\GameSession\GameModes\Tutorials\BasicTutorial.cs" />
|
||||||
<Compile Include="Source\GameSession\GameModes\Tutorials\EditorTutorial.cs" />
|
<Compile Include="Source\GameSession\GameModes\Tutorials\EditorTutorial.cs" />
|
||||||
<Compile Include="Source\GameSession\GameModes\Tutorials\TutorialMode.cs" />
|
<Compile Include="Source\GameSession\GameModes\Tutorials\TutorialMode.cs" />
|
||||||
<Compile Include="Source\GameSession\GameModes\Tutorials\TutorialType.cs" />
|
<Compile Include="Source\GameSession\GameModes\Tutorials\Tutorial.cs" />
|
||||||
<Compile Include="Source\GameSession\GameSession.cs" />
|
<Compile Include="Source\GameSession\GameSession.cs" />
|
||||||
<Compile Include="Source\GameSession\HireManager.cs" />
|
<Compile Include="Source\GameSession\HireManager.cs" />
|
||||||
<Compile Include="Source\GameSession\RoundSummary.cs" />
|
<Compile Include="Source\GameSession\RoundSummary.cs" />
|
||||||
@@ -143,7 +186,7 @@
|
|||||||
<Compile Include="Source\Items\Components\Machines\Fabricator.cs" />
|
<Compile Include="Source\Items\Components\Machines\Fabricator.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\MiniMap.cs" />
|
<Compile Include="Source\Items\Components\Machines\MiniMap.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\Pump.cs" />
|
<Compile Include="Source\Items\Components\Machines\Pump.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\Radar.cs" />
|
<Compile Include="Source\Items\Components\Machines\Sonar.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\Reactor.cs" />
|
<Compile Include="Source\Items\Components\Machines\Reactor.cs" />
|
||||||
<Compile Include="Source\Items\Components\Machines\Steering.cs" />
|
<Compile Include="Source\Items\Components\Machines\Steering.cs" />
|
||||||
<Compile Include="Source\Items\Components\Power\PowerContainer.cs" />
|
<Compile Include="Source\Items\Components\Power\PowerContainer.cs" />
|
||||||
@@ -155,7 +198,6 @@
|
|||||||
<Compile Include="Source\Items\Components\StatusHUD.cs" />
|
<Compile Include="Source\Items\Components\StatusHUD.cs" />
|
||||||
<Compile Include="Source\Items\Components\Turret.cs" />
|
<Compile Include="Source\Items\Components\Turret.cs" />
|
||||||
<Compile Include="Source\Items\DockingPort.cs" />
|
<Compile Include="Source\Items\DockingPort.cs" />
|
||||||
<Compile Include="Source\Items\FixRequirement.cs" />
|
|
||||||
<Compile Include="Source\Items\Inventory.cs" />
|
<Compile Include="Source\Items\Inventory.cs" />
|
||||||
<Compile Include="Source\Items\Item.cs" />
|
<Compile Include="Source\Items\Item.cs" />
|
||||||
<Compile Include="Source\Items\ItemPrefab.cs" />
|
<Compile Include="Source\Items\ItemPrefab.cs" />
|
||||||
@@ -164,10 +206,12 @@
|
|||||||
<Compile Include="Source\Map\FireSource.cs" />
|
<Compile Include="Source\Map\FireSource.cs" />
|
||||||
<Compile Include="Source\Map\Gap.cs" />
|
<Compile Include="Source\Map\Gap.cs" />
|
||||||
<Compile Include="Source\Map\Hull.cs" />
|
<Compile Include="Source\Map\Hull.cs" />
|
||||||
<Compile Include="Source\Map\Levels\BackgroundSprite\BackgroundSpriteManager.cs" />
|
<Compile Include="Source\Map\Levels\LevelObjects\LevelObject.cs" />
|
||||||
<Compile Include="Source\Map\Levels\BackgroundSprite\BackgroundSpritePrefab.cs" />
|
<Compile Include="Source\Map\Levels\LevelObjects\LevelObjectManager.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\LevelObjects\LevelObjectPrefab.cs" />
|
||||||
<Compile Include="Source\Map\Levels\CaveGenerator.cs" />
|
<Compile Include="Source\Map\Levels\CaveGenerator.cs" />
|
||||||
<Compile Include="Source\Map\Levels\Level.cs" />
|
<Compile Include="Source\Map\Levels\Level.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\LevelObjects\LevelTrigger.cs" />
|
||||||
<Compile Include="Source\Map\Levels\LevelRenderer.cs" />
|
<Compile Include="Source\Map\Levels\LevelRenderer.cs" />
|
||||||
<Compile Include="Source\Map\Levels\Ruins\RuinGenerator.cs" />
|
<Compile Include="Source\Map\Levels\Ruins\RuinGenerator.cs" />
|
||||||
<Compile Include="Source\Map\Levels\WaterRenderer.cs" />
|
<Compile Include="Source\Map\Levels\WaterRenderer.cs" />
|
||||||
@@ -195,6 +239,8 @@
|
|||||||
<Compile Include="Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
|
<Compile Include="Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
|
||||||
<Compile Include="Source\Networking\NetStats.cs" />
|
<Compile Include="Source\Networking\NetStats.cs" />
|
||||||
<Compile Include="Source\Networking\NetworkMember.cs" />
|
<Compile Include="Source\Networking\NetworkMember.cs" />
|
||||||
|
<Compile Include="Source\Networking\OrderChatMessage.cs" />
|
||||||
|
<Compile Include="Source\Networking\ServerInfo.cs" />
|
||||||
<Compile Include="Source\Networking\ServerLog.cs" />
|
<Compile Include="Source\Networking\ServerLog.cs" />
|
||||||
<Compile Include="Source\Networking\Voting.cs" />
|
<Compile Include="Source\Networking\Voting.cs" />
|
||||||
<Compile Include="Source\Networking\WhiteList.cs" />
|
<Compile Include="Source\Networking\WhiteList.cs" />
|
||||||
@@ -208,10 +254,14 @@
|
|||||||
<Compile Include="Source\Physics\PhysicsBody.cs" />
|
<Compile Include="Source\Physics\PhysicsBody.cs" />
|
||||||
<Compile Include="Source\PlayerInput.cs" />
|
<Compile Include="Source\PlayerInput.cs" />
|
||||||
<Compile Include="Source\Program.cs" />
|
<Compile Include="Source\Program.cs" />
|
||||||
|
<Compile Include="Source\Screens\CharacterEditorScreen.cs" />
|
||||||
<Compile Include="Source\Screens\BlurEffect.cs" />
|
<Compile Include="Source\Screens\BlurEffect.cs" />
|
||||||
<Compile Include="Source\Screens\CampaignSetupUI.cs" />
|
<Compile Include="Source\Screens\CampaignSetupUI.cs" />
|
||||||
<Compile Include="Source\Screens\CampaignUI.cs" />
|
<Compile Include="Source\Screens\CampaignUI.cs" />
|
||||||
<Compile Include="Source\Screens\CharacterEditorScreen.cs" />
|
<Compile Include="Source\Screens\LevelEditorScreen.cs" />
|
||||||
|
<Compile Include="Source\Screens\OldCharacterEditorScreen.cs" />
|
||||||
|
<Compile Include="Source\Screens\SpriteEditorScreen.cs" />
|
||||||
|
<Compile Include="Source\Screens\SteamWorkshopScreen.cs" />
|
||||||
<Compile Include="Source\Screens\SubEditorScreen.cs" />
|
<Compile Include="Source\Screens\SubEditorScreen.cs" />
|
||||||
<Compile Include="Source\Screens\GameScreen.cs" />
|
<Compile Include="Source\Screens\GameScreen.cs" />
|
||||||
<Compile Include="Source\Screens\LobbyScreen.cs" />
|
<Compile Include="Source\Screens\LobbyScreen.cs" />
|
||||||
@@ -222,10 +272,17 @@
|
|||||||
<Compile Include="Source\Screens\ServerListScreen.cs" />
|
<Compile Include="Source\Screens\ServerListScreen.cs" />
|
||||||
<Compile Include="Source\Serialization\SerializableEntityEditor.cs" />
|
<Compile Include="Source\Serialization\SerializableEntityEditor.cs" />
|
||||||
<Compile Include="Source\Sounds\OggSound.cs" />
|
<Compile Include="Source\Sounds\OggSound.cs" />
|
||||||
<Compile Include="Source\Sounds\OggStream.cs" />
|
|
||||||
<Compile Include="Source\Sounds\Sound.cs" />
|
<Compile Include="Source\Sounds\Sound.cs" />
|
||||||
|
<Compile Include="Source\Sounds\SoundChannel.cs" />
|
||||||
<Compile Include="Source\Sounds\SoundManager.cs" />
|
<Compile Include="Source\Sounds\SoundManager.cs" />
|
||||||
<Compile Include="Source\Sounds\SoundPlayer.cs" />
|
<Compile Include="Source\Sounds\SoundPlayer.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformableSprite.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\CustomDeformation.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\Inflate.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\NoiseDeformation.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\PositionalDeformation.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\JointBendDeformation.cs" />
|
||||||
|
<Compile Include="Source\Sprite\DeformAnimations\SpriteDeformation.cs" />
|
||||||
<Compile Include="Source\Sprite\Sprite.cs" />
|
<Compile Include="Source\Sprite\Sprite.cs" />
|
||||||
<Compile Include="Source\Sprite\SpriteSheet.cs" />
|
<Compile Include="Source\Sprite\SpriteSheet.cs" />
|
||||||
<Compile Include="Source\Utils\MathUtils.cs" />
|
<Compile Include="Source\Utils\MathUtils.cs" />
|
||||||
@@ -244,7 +301,6 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="PresentationCore" />
|
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="PresentationCore" />
|
||||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="SharpDX">
|
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="SharpDX">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\SharpDX.dll</HintPath>
|
<HintPath>..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\SharpDX.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="NVorbis">
|
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="NVorbis">
|
||||||
@@ -262,18 +318,18 @@
|
|||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Condition="$(DefineConstants.Contains('LINUX')) OR $(DefineConstants.Contains('OSX'))" Include="MonoGame.Framework.DesktopGL">
|
||||||
|
<HintPath>..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.6.0.1625\lib\net40\MonoGame.Framework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="RestSharp">
|
<Reference Include="RestSharp">
|
||||||
<HintPath>..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
<HintPath>..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Condition="$(DefineConstants.Contains('LINUX'))" Include="MonoGame.Framework.DesktopGL">
|
|
||||||
<HintPath>..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.6.0.1625\lib\net40\MonoGame.Framework.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="freetype6.dll">
|
<Content Include="freetype6.dll">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="OpenAL32.dll">
|
<Content Include="oalinst.exe">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="wrap_oal.dll">
|
<Content Include="wrap_oal.dll">
|
||||||
@@ -312,6 +368,10 @@
|
|||||||
</BootstrapperPackage>
|
</BootstrapperPackage>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
|
||||||
|
<Project>{3af0347c-5a9b-4421-868c-8ee3dbfaebc6}</Project>
|
||||||
|
<Name>Facepunch.Steamworks</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.csproj">
|
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.csproj">
|
||||||
<Project>{3b8f9edb-6e5e-450c-abc2-ec49075d0b50}</Project>
|
<Project>{3b8f9edb-6e5e-450c-abc2-ec49075d0b50}</Project>
|
||||||
<Name>Hyper.ComponentModel</Name>
|
<Name>Hyper.ComponentModel</Name>
|
||||||
|
|||||||
Binary file not shown.
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.8.2.3")]
|
[assembly: AssemblyVersion("0.8.9.1")]
|
||||||
[assembly: AssemblyFileVersion("0.8.2.3")]
|
[assembly: AssemblyFileVersion("0.8.9.1")]
|
||||||
|
|||||||
@@ -8,9 +8,39 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
public static bool FollowSub = true;
|
public static bool FollowSub = true;
|
||||||
|
|
||||||
const float DefaultZoom = 1.0f;
|
private float defaultZoom = 1.3f;
|
||||||
const float ZoomSmoothness = 8.0f;
|
public float DefaultZoom
|
||||||
const float MoveSmoothness = 8.0f;
|
{
|
||||||
|
get { return defaultZoom; }
|
||||||
|
set { defaultZoom = MathHelper.Clamp(value, 0.5f, 2.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float zoomSmoothness = 8.0f;
|
||||||
|
public float ZoomSmoothness
|
||||||
|
{
|
||||||
|
get { return zoomSmoothness; }
|
||||||
|
set { zoomSmoothness = Math.Max(value, 0.01f); }
|
||||||
|
}
|
||||||
|
private float moveSmoothness = 8.0f;
|
||||||
|
public float MoveSmoothness
|
||||||
|
{
|
||||||
|
get { return moveSmoothness; }
|
||||||
|
set { moveSmoothness = Math.Max(value, 0.01f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float minZoom = 0.1f;
|
||||||
|
public float MinZoom
|
||||||
|
{
|
||||||
|
get { return minZoom;}
|
||||||
|
set { minZoom = MathHelper.Clamp(value, 0.01f, 10.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float maxZoom = 2.0f;
|
||||||
|
public float MaxZoom
|
||||||
|
{
|
||||||
|
get { return maxZoom; }
|
||||||
|
set { maxZoom = MathHelper.Clamp(value, 1.0f, 10.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
private float zoom;
|
private float zoom;
|
||||||
|
|
||||||
@@ -20,26 +50,36 @@ namespace Barotrauma
|
|||||||
private Vector2 position;
|
private Vector2 position;
|
||||||
private float rotation;
|
private float rotation;
|
||||||
|
|
||||||
|
private float angularVelocity;
|
||||||
|
private float angularDamping;
|
||||||
|
private float angularSpring;
|
||||||
|
|
||||||
private Vector2 prevPosition;
|
private Vector2 prevPosition;
|
||||||
private float prevZoom;
|
private float prevZoom;
|
||||||
|
|
||||||
public float Shake;
|
public float Shake;
|
||||||
private Vector2 shakePosition;
|
private Vector2 shakePosition;
|
||||||
private Vector2 shakeTargetPosition;
|
private float shakeTimer;
|
||||||
|
|
||||||
//the area of the world inside the camera view
|
//the area of the world inside the camera view
|
||||||
private Rectangle worldView;
|
private Rectangle worldView;
|
||||||
|
|
||||||
|
private float globalZoomScale = 1.0f;
|
||||||
|
|
||||||
private Point resolution;
|
private Point resolution;
|
||||||
|
|
||||||
private Vector2 targetPos;
|
private Vector2 targetPos;
|
||||||
|
|
||||||
|
//used to smooth out the movement when in freecam
|
||||||
|
private float targetZoom;
|
||||||
|
private Vector2 velocity;
|
||||||
|
|
||||||
public float Zoom
|
public float Zoom
|
||||||
{
|
{
|
||||||
get { return zoom; }
|
get { return zoom; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
zoom = Math.Max(value, GameMain.DebugDraw ? 0.01f : 0.1f);
|
zoom = MathHelper.Clamp(value, GameMain.DebugDraw ? 0.01f : MinZoom, MaxZoom);
|
||||||
|
|
||||||
Vector2 center = WorldViewCenter;
|
Vector2 center = WorldViewCenter;
|
||||||
float newWidth = resolution.X / zoom;
|
float newWidth = resolution.X / zoom;
|
||||||
@@ -58,7 +98,21 @@ namespace Barotrauma
|
|||||||
public float Rotation
|
public float Rotation
|
||||||
{
|
{
|
||||||
get { return rotation; }
|
get { return rotation; }
|
||||||
set { rotation = value; }
|
set
|
||||||
|
{
|
||||||
|
if (!MathUtils.IsValid(value)) return;
|
||||||
|
rotation = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AngularVelocity
|
||||||
|
{
|
||||||
|
get { return angularVelocity; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!MathUtils.IsValid(value)) return;
|
||||||
|
angularVelocity = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float OffsetAmount
|
public float OffsetAmount
|
||||||
@@ -99,18 +153,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public Camera()
|
public Camera()
|
||||||
{
|
{
|
||||||
zoom = prevZoom = 1.0f;
|
zoom = prevZoom = targetZoom = 1.0f;
|
||||||
rotation = 0.0f;
|
rotation = 0.0f;
|
||||||
position = Vector2.Zero;
|
position = Vector2.Zero;
|
||||||
|
|
||||||
worldView = new Rectangle(0,0,
|
CreateMatrices();
|
||||||
GameMain.GraphicsWidth,
|
GameMain.Instance.OnResolutionChanged += () => { CreateMatrices(); };
|
||||||
GameMain.GraphicsHeight);
|
|
||||||
|
|
||||||
resolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
|
||||||
|
|
||||||
viewMatrix =
|
|
||||||
Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0));
|
|
||||||
|
|
||||||
UpdateTransform(false);
|
UpdateTransform(false);
|
||||||
}
|
}
|
||||||
@@ -125,7 +173,15 @@ namespace Barotrauma
|
|||||||
public void Translate(Vector2 amount)
|
public void Translate(Vector2 amount)
|
||||||
{
|
{
|
||||||
position += amount;
|
position += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateMatrices()
|
||||||
|
{
|
||||||
|
resolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
worldView = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
viewMatrix = Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0));
|
||||||
|
|
||||||
|
globalZoomScale = new Vector2(resolution.X, resolution.Y).Length() / new Vector2(1920, 1080).Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTransform(bool interpolate = true)
|
public void UpdateTransform(bool interpolate = true)
|
||||||
@@ -140,16 +196,25 @@ namespace Barotrauma
|
|||||||
transform = Matrix.CreateTranslation(
|
transform = Matrix.CreateTranslation(
|
||||||
new Vector3(-interpolatedPosition.X, interpolatedPosition.Y, 0)) *
|
new Vector3(-interpolatedPosition.X, interpolatedPosition.Y, 0)) *
|
||||||
Matrix.CreateScale(new Vector3(interpolatedZoom, interpolatedZoom, 1)) *
|
Matrix.CreateScale(new Vector3(interpolatedZoom, interpolatedZoom, 1)) *
|
||||||
viewMatrix;
|
Matrix.CreateRotationZ(rotation) * viewMatrix;
|
||||||
|
|
||||||
shaderTransform = Matrix.CreateTranslation(
|
shaderTransform = Matrix.CreateTranslation(
|
||||||
new Vector3(
|
new Vector3(
|
||||||
-interpolatedPosition.X - resolution.X / interpolatedZoom / 2.0f,
|
-interpolatedPosition.X - resolution.X / interpolatedZoom / 2.0f,
|
||||||
-interpolatedPosition.Y - resolution.Y / interpolatedZoom / 2.0f, 0)) *
|
-interpolatedPosition.Y - resolution.Y / interpolatedZoom / 2.0f, 0)) *
|
||||||
Matrix.CreateScale(new Vector3(interpolatedZoom, interpolatedZoom, 1)) *
|
Matrix.CreateScale(new Vector3(interpolatedZoom, interpolatedZoom, 1)) *
|
||||||
viewMatrix;
|
|
||||||
|
viewMatrix * Matrix.CreateRotationZ(-rotation);
|
||||||
|
|
||||||
|
if (Character.Controlled == null)
|
||||||
|
{
|
||||||
|
GameMain.SoundManager.ListenerPosition = new Vector3(WorldViewCenter.X, WorldViewCenter.Y, -(100.0f / zoom));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMain.SoundManager.ListenerPosition = new Vector3(Character.Controlled.WorldPosition.X, Character.Controlled.WorldPosition.Y, -(100.0f / zoom));
|
||||||
|
}
|
||||||
|
|
||||||
Sound.CameraPos = new Vector3(WorldViewCenter.X, WorldViewCenter.Y, 0.0f);
|
|
||||||
|
|
||||||
if (!interpolate)
|
if (!interpolate)
|
||||||
{
|
{
|
||||||
@@ -158,27 +223,38 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2 previousOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets to false each time the MoveCamera method is called.
|
||||||
|
/// </summary>
|
||||||
|
public bool Freeze { get; set; }
|
||||||
|
|
||||||
public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true)
|
public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true)
|
||||||
{
|
{
|
||||||
prevPosition = position;
|
prevPosition = position;
|
||||||
prevZoom = zoom;
|
prevZoom = zoom;
|
||||||
|
|
||||||
float moveSpeed = 20.0f/zoom;
|
float moveSpeed = 20.0f / zoom;
|
||||||
|
|
||||||
Vector2 moveCam = Vector2.Zero;
|
Vector2 moveCam = Vector2.Zero;
|
||||||
if (targetPos == Vector2.Zero)
|
if (targetPos == Vector2.Zero)
|
||||||
{
|
{
|
||||||
if (allowMove && GUIComponent.KeyboardDispatcher.Subscriber == null)
|
Vector2 moveInput = Vector2.Zero;
|
||||||
|
if (allowMove && GUI.KeyboardDispatcher.Subscriber == null)
|
||||||
{
|
{
|
||||||
if (PlayerInput.KeyDown(Keys.LeftShift)) moveSpeed *= 2.0f;
|
if (PlayerInput.KeyDown(Keys.LeftShift)) moveSpeed *= 2.0f;
|
||||||
if (PlayerInput.KeyDown(Keys.LeftControl)) moveSpeed *= 0.5f;
|
if (PlayerInput.KeyDown(Keys.LeftControl)) moveSpeed *= 0.5f;
|
||||||
|
|
||||||
if (GameMain.Config.KeyBind(InputType.Left).IsDown()) moveCam.X -= moveSpeed;
|
if (GameMain.Config.KeyBind(InputType.Left).IsDown()) moveInput.X -= 1.0f;
|
||||||
if (GameMain.Config.KeyBind(InputType.Right).IsDown()) moveCam.X += moveSpeed;
|
if (GameMain.Config.KeyBind(InputType.Right).IsDown()) moveInput.X += 1.0f;
|
||||||
if (GameMain.Config.KeyBind(InputType.Down).IsDown()) moveCam.Y -= moveSpeed;
|
if (GameMain.Config.KeyBind(InputType.Down).IsDown()) moveInput.Y -= 1.0f;
|
||||||
if (GameMain.Config.KeyBind(InputType.Up).IsDown()) moveCam.Y += moveSpeed;
|
if (GameMain.Config.KeyBind(InputType.Up).IsDown()) moveInput.Y += 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f);
|
||||||
|
moveCam = velocity * moveSpeed * deltaTime * 60.0f;
|
||||||
|
|
||||||
if (Screen.Selected == GameMain.GameScreen && FollowSub)
|
if (Screen.Selected == GameMain.GameScreen && FollowSub)
|
||||||
{
|
{
|
||||||
var closestSub = Submarine.FindClosest(WorldViewCenter);
|
var closestSub = Submarine.FindClosest(WorldViewCenter);
|
||||||
@@ -188,45 +264,102 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveCam = moveCam * deltaTime * 60.0f;
|
|
||||||
|
|
||||||
if (allowZoom)
|
if (allowZoom)
|
||||||
{
|
{
|
||||||
Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition);
|
Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition);
|
||||||
Vector2 diffViewCenter;
|
Vector2 diffViewCenter;
|
||||||
diffViewCenter = ((mouseInWorld - Position) * Zoom);
|
diffViewCenter = ((mouseInWorld - Position) * Zoom);
|
||||||
Zoom = MathHelper.Clamp(zoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom, GameMain.DebugDraw ? 0.01f : 0.1f, 2.0f);
|
targetZoom = MathHelper.Clamp(
|
||||||
|
targetZoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom,
|
||||||
|
GameMain.DebugDraw ? MinZoom * 0.1f : MinZoom,
|
||||||
|
MaxZoom);
|
||||||
|
|
||||||
|
Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f);
|
||||||
if (!PlayerInput.KeyDown(Keys.F)) Position = mouseInWorld - (diffViewCenter / Zoom);
|
if (!PlayerInput.KeyDown(Keys.F)) Position = mouseInWorld - (diffViewCenter / Zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (allowMove)
|
||||||
{
|
{
|
||||||
Vector2 mousePos = PlayerInput.MousePosition;
|
Vector2 mousePos = PlayerInput.MousePosition;
|
||||||
|
Vector2 offset = mousePos - resolution.ToVector2() / 2;
|
||||||
Vector2 offset = mousePos - new Vector2(resolution.X / 2.0f, resolution.Y / 2.0f);
|
|
||||||
|
|
||||||
offset.X = offset.X / (resolution.X * 0.4f);
|
offset.X = offset.X / (resolution.X * 0.4f);
|
||||||
offset.Y = -offset.Y / (resolution.Y * 0.3f);
|
offset.Y = -offset.Y / (resolution.Y * 0.3f);
|
||||||
|
if (offset.LengthSquared() > 1.0f) offset.Normalize();
|
||||||
|
offset *= offsetAmount;
|
||||||
|
// Freeze the camera movement by default, when the cursor is on top of an ui element.
|
||||||
|
// Setting a positive value to the OffsetAmount, will override this behaviour.
|
||||||
|
if (GUI.MouseOn != null && offsetAmount > 0)
|
||||||
|
{
|
||||||
|
Freeze = true;
|
||||||
|
}
|
||||||
|
if (CharacterHealth.OpenHealthWindow != null)
|
||||||
|
{
|
||||||
|
offset *= 0;
|
||||||
|
Freeze = false;
|
||||||
|
}
|
||||||
|
if (Freeze)
|
||||||
|
{
|
||||||
|
offset = previousOffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
//how much to zoom out (zoom completely out when offset is 1000)
|
||||||
|
float zoomOutAmount = Math.Min(offset.Length() / 1000.0f, 1.0f);
|
||||||
|
//zoom amount when resolution is not taken into account
|
||||||
|
float unscaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount);
|
||||||
|
//zoom with resolution taken into account (zoom further out on smaller resolutions)
|
||||||
|
float scaledZoom = unscaledZoom * globalZoomScale;
|
||||||
|
|
||||||
if (offset.Length() > 1.0f) offset.Normalize();
|
//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));
|
||||||
|
|
||||||
offset = offset * offsetAmount;
|
|
||||||
|
|
||||||
float newZoom = Math.Min(DefaultZoom - Math.Min(offset.Length() / resolution.Y, 1.0f),1.0f);
|
|
||||||
Zoom += (newZoom - zoom) / ZoomSmoothness;
|
Zoom += (newZoom - zoom) / ZoomSmoothness;
|
||||||
|
|
||||||
|
//force targetzoom to the current zoom value, so the camera stays at the same zoom when switching to freecam
|
||||||
|
targetZoom = Zoom;
|
||||||
|
|
||||||
Vector2 diff = (targetPos + offset) - position;
|
Vector2 diff = (targetPos + offset) - position;
|
||||||
|
|
||||||
moveCam = diff / MoveSmoothness;
|
moveCam = diff / MoveSmoothness;
|
||||||
}
|
}
|
||||||
|
rotation += angularVelocity * deltaTime;
|
||||||
|
angularVelocity *= (1.0f - angularDamping);
|
||||||
|
angularVelocity += -rotation * angularSpring;
|
||||||
|
|
||||||
shakeTargetPosition = Rand.Vector(Shake);
|
angularDamping = 0.05f;
|
||||||
shakePosition = Vector2.Lerp(shakePosition, shakeTargetPosition, 0.5f);
|
angularSpring = 0.2f;
|
||||||
Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f);
|
|
||||||
|
if (Shake < 0.01f)
|
||||||
|
{
|
||||||
|
shakePosition = Vector2.Zero;
|
||||||
|
shakeTimer = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shakeTimer += deltaTime * 5.0f;
|
||||||
|
Vector2 noisePos = new Vector2((float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0.5f) - 0.5f);
|
||||||
|
|
||||||
|
shakePosition = noisePos * Shake * 2.0f;
|
||||||
|
Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
Translate(moveCam + shakePosition);
|
Translate(moveCam + shakePosition);
|
||||||
|
Freeze = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StopMovement()
|
||||||
|
{
|
||||||
|
targetZoom = zoom;
|
||||||
|
velocity = Vector2.Zero;
|
||||||
|
angularVelocity = 0.0f;
|
||||||
|
rotation = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
public Vector2 Position
|
public Vector2 Position
|
||||||
{
|
{
|
||||||
get { return position; }
|
get { return position; }
|
||||||
@@ -239,7 +372,7 @@ namespace Barotrauma
|
|||||||
position = value;
|
position = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 ScreenToWorld(Vector2 coords)
|
public Vector2 ScreenToWorld(Vector2 coords)
|
||||||
{
|
{
|
||||||
Vector2 worldCoords = Vector2.Transform(coords, Matrix.Invert(transform));
|
Vector2 worldCoords = Vector2.Transform(coords, Matrix.Invert(transform));
|
||||||
|
|||||||
@@ -14,16 +14,28 @@ namespace Barotrauma
|
|||||||
var rangeSprite = GUI.SubmarineIcon;
|
var rangeSprite = GUI.SubmarineIcon;
|
||||||
|
|
||||||
if (soundRange > 0.0f)
|
if (soundRange > 0.0f)
|
||||||
|
{
|
||||||
rangeSprite.Draw(spriteBatch,
|
rangeSprite.Draw(spriteBatch,
|
||||||
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
||||||
Color.Cyan * 0.1f, rangeSprite.Origin,
|
Color.Cyan * 0.1f, rangeSprite.Origin,
|
||||||
0.0f, soundRange / rangeSprite.size.X);
|
0.0f, soundRange / rangeSprite.size.X);
|
||||||
|
rangeSprite.Draw(spriteBatch,
|
||||||
|
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
||||||
|
Color.Cyan, rangeSprite.Origin,
|
||||||
|
0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
if (sightRange > 0.0f)
|
if (sightRange > 0.0f)
|
||||||
|
{
|
||||||
rangeSprite.Draw(spriteBatch,
|
rangeSprite.Draw(spriteBatch,
|
||||||
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
||||||
Color.Orange * 0.1f, rangeSprite.Origin,
|
Color.Orange * 0.1f, rangeSprite.Origin,
|
||||||
0.0f, sightRange / rangeSprite.size.X);
|
0.0f, sightRange / rangeSprite.size.X);
|
||||||
|
rangeSprite.Draw(spriteBatch,
|
||||||
|
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
||||||
|
Color.Orange, rangeSprite.Origin,
|
||||||
|
0.0f, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,304 +0,0 @@
|
|||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
|
||||||
{
|
|
||||||
class CrewCommander
|
|
||||||
{
|
|
||||||
private CrewManager crewManager;
|
|
||||||
|
|
||||||
private GUIFrame frame;
|
|
||||||
//GUIListBox characterList;
|
|
||||||
|
|
||||||
private bool infoTextShown;
|
|
||||||
|
|
||||||
private int characterFrameBottom;
|
|
||||||
|
|
||||||
public GUIFrame Frame
|
|
||||||
{
|
|
||||||
get { return IsOpen ? frame : null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsOpen
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CrewCommander(CrewManager crewManager)
|
|
||||||
{
|
|
||||||
this.crewManager = crewManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleGUIFrame()
|
|
||||||
{
|
|
||||||
IsOpen = !IsOpen;
|
|
||||||
|
|
||||||
if (IsOpen)
|
|
||||||
{
|
|
||||||
if (!infoTextShown)
|
|
||||||
{
|
|
||||||
GUI.AddMessage("Press " + GameMain.Config.KeyBind(InputType.CrewOrders) + " to open/close the command menu", Color.Cyan, 5.0f);
|
|
||||||
infoTextShown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame == null) CreateGUIFrame();
|
|
||||||
UpdateCharacters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateGUIFrame()
|
|
||||||
{
|
|
||||||
frame = new GUIFrame(Rectangle.Empty, Color.Black * 0.6f, null);
|
|
||||||
frame.Padding = new Vector4(200.0f, 100.0f, 200.0f, 100.0f);
|
|
||||||
|
|
||||||
GUIButton closeButton = new GUIButton(new Rectangle(0, 50, 100, 20), TextManager.Get("Close"), Alignment.BottomCenter, "", frame);
|
|
||||||
closeButton.OnClicked = (GUIButton button, object userData) =>
|
|
||||||
{
|
|
||||||
ToggleGUIFrame();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
int buttonWidth = 130;
|
|
||||||
int spacing = 20;
|
|
||||||
|
|
||||||
int y = 50;
|
|
||||||
|
|
||||||
for (int n = 0; n<2; n++)
|
|
||||||
{
|
|
||||||
List<Order> orders = (n==0) ?
|
|
||||||
Order.PrefabList.FindAll(o => o.ItemComponentType == null && string.IsNullOrEmpty(o.ItemName)) :
|
|
||||||
Order.PrefabList.FindAll(o => o.ItemComponentType != null || !string.IsNullOrEmpty(o.ItemName));
|
|
||||||
|
|
||||||
int startX = -(buttonWidth * orders.Count + spacing * (orders.Count - 1)) / 2;
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
foreach (Order order in orders)
|
|
||||||
{
|
|
||||||
int x = startX + (buttonWidth + spacing) * (i % orders.Count);
|
|
||||||
|
|
||||||
if (order.ItemComponentType!=null || !string.IsNullOrEmpty(order.ItemName))
|
|
||||||
{
|
|
||||||
List<Item> matchingItems = !string.IsNullOrEmpty(order.ItemName) ?
|
|
||||||
Item.ItemList.FindAll(it => it.Name == order.ItemName) :
|
|
||||||
Item.ItemList.FindAll(it => it.components.Any(ic => ic.GetType() == order.ItemComponentType));
|
|
||||||
|
|
||||||
int y2 = y;
|
|
||||||
foreach (Item it in matchingItems)
|
|
||||||
{
|
|
||||||
var newOrder = new Order(order, it.components.Find(ic => ic.GetType() == order.ItemComponentType));
|
|
||||||
|
|
||||||
CreateOrderButton(new Rectangle(x + buttonWidth / 2, y2, buttonWidth, 20), newOrder, y2==y);
|
|
||||||
y2 += 25;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CreateOrderButton(new Rectangle(x + buttonWidth / 2, y, buttonWidth, 20), order);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
y += 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GUIButton CreateOrderButton(Rectangle rect, Order order, bool createSymbol = true)
|
|
||||||
{
|
|
||||||
var orderButton = new GUIButton(rect, order.Name, null, Alignment.TopCenter, Alignment.Center, "GUITextBox", frame);
|
|
||||||
orderButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
|
||||||
orderButton.UserData = order;
|
|
||||||
orderButton.OnClicked = SetOrder;
|
|
||||||
|
|
||||||
if (createSymbol)
|
|
||||||
{
|
|
||||||
var symbol = new GUIImage(new Rectangle(0,-60,64,64), order.SymbolSprite, Alignment.TopCenter, orderButton);
|
|
||||||
symbol.Color = order.Color;
|
|
||||||
|
|
||||||
orderButton.children.Insert(0, symbol);
|
|
||||||
orderButton.children.RemoveAt(orderButton.children.Count-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateCharacters()
|
|
||||||
{
|
|
||||||
CreateGUIFrame();
|
|
||||||
|
|
||||||
List<GUIComponent> prevCharacterFrames = new List<GUIComponent>();
|
|
||||||
foreach (GUIComponent child in frame.children)
|
|
||||||
{
|
|
||||||
if (!(child.UserData is Character)) continue;
|
|
||||||
|
|
||||||
prevCharacterFrames.Add(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (GUIComponent child in prevCharacterFrames)
|
|
||||||
{
|
|
||||||
frame.RemoveChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Character> aliveCharacters = crewManager.GetCharacters().FindAll(c => !c.IsDead && c.AIController is HumanAIController);
|
|
||||||
|
|
||||||
characterFrameBottom = 0;
|
|
||||||
|
|
||||||
int charactersPerRow = 4;
|
|
||||||
|
|
||||||
int spacing = 5;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (Character character in aliveCharacters)
|
|
||||||
{
|
|
||||||
int rowCharacterCount = Math.Min(charactersPerRow, aliveCharacters.Count);
|
|
||||||
|
|
||||||
int startX = -(150 * rowCharacterCount + spacing * (rowCharacterCount - 1)) / 2;
|
|
||||||
int x = startX + (150 + spacing) * (i % Math.Min(charactersPerRow, aliveCharacters.Count));
|
|
||||||
int y = (105 + spacing)*((int)Math.Floor((double)i / charactersPerRow));
|
|
||||||
|
|
||||||
GUIFrame characterFrame = new GUIFrame(new Rectangle(x + 75, y, 150, 100), null, Alignment.TopCenter, null, frame);
|
|
||||||
characterFrame.UserData = character;
|
|
||||||
|
|
||||||
GUIButton characterButton = new GUIButton(new Rectangle(0, 0, 0, 40), "", null, Alignment.TopCenter, "GUITextBox", characterFrame);
|
|
||||||
characterButton.UserData = character;
|
|
||||||
characterButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
|
||||||
characterButton.Color = Character.Controlled == character ? Color.Gold : Color.White;
|
|
||||||
|
|
||||||
characterFrameBottom = Math.Max(characterFrameBottom, characterButton.Rect.Bottom);
|
|
||||||
|
|
||||||
string name = character.Info.Name;
|
|
||||||
if (character.Info.Job != null) name += '\n' + "(" + character.Info.Job.Name + ")";
|
|
||||||
|
|
||||||
GUITextBlock textBlock = new GUITextBlock(
|
|
||||||
new Rectangle(40, 0, 0, 25),
|
|
||||||
name,
|
|
||||||
Color.Transparent, null,
|
|
||||||
Alignment.Left, Alignment.Left,
|
|
||||||
"", characterButton, false);
|
|
||||||
textBlock.Font = GUI.SmallFont;
|
|
||||||
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
|
|
||||||
|
|
||||||
new GUIImage(new Rectangle(-5, -5, 0, 0), character.AnimController.Limbs[0].sprite, Alignment.Left, characterButton);
|
|
||||||
|
|
||||||
var humanAi = character.AIController as HumanAIController;
|
|
||||||
if (humanAi != null && humanAi.CurrentOrder != null)
|
|
||||||
{
|
|
||||||
CreateCharacterOrderFrame(characterFrame, humanAi.CurrentOrder, humanAi.CurrentOrderOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (GUIComponent child in frame.children)
|
|
||||||
{
|
|
||||||
if (!(child.UserData is Order)) continue;
|
|
||||||
|
|
||||||
Rectangle rect = child.Rect;
|
|
||||||
rect.Y += characterFrameBottom;
|
|
||||||
|
|
||||||
child.Rect = rect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectCharacter(Character character)
|
|
||||||
{
|
|
||||||
var characterButton = frame.FindChild(character) as GUIButton;
|
|
||||||
|
|
||||||
if (characterButton == null) return;
|
|
||||||
|
|
||||||
characterButton.Selected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SetOrder(GUIButton button, object userData)
|
|
||||||
{
|
|
||||||
Order order = userData as Order;
|
|
||||||
|
|
||||||
foreach (GUIComponent child in frame.children)
|
|
||||||
{
|
|
||||||
Character character = child.UserData as Character;
|
|
||||||
if (character == null) continue;
|
|
||||||
|
|
||||||
var characterButton = child.GetChild<GUIButton>();
|
|
||||||
characterButton.State = GUIComponent.ComponentState.None;
|
|
||||||
|
|
||||||
if (!characterButton.Selected) continue;
|
|
||||||
characterButton.Selected = false;
|
|
||||||
|
|
||||||
CreateCharacterOrderFrame(characterButton.Parent, order, "");
|
|
||||||
|
|
||||||
var humanAi = character.AIController as HumanAIController;
|
|
||||||
|
|
||||||
humanAi.SetOrder(order, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
//characterList.Deselect();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateCharacterOrderFrame(GUIComponent characterFrame, Order order, string selectedOption)
|
|
||||||
{
|
|
||||||
var character = characterFrame.UserData as Character;
|
|
||||||
if (character == null) return;
|
|
||||||
|
|
||||||
var humanAi = character.AIController as HumanAIController;
|
|
||||||
if (humanAi == null) return;
|
|
||||||
|
|
||||||
var existingOrder = characterFrame.children.Find(c => c.UserData is Order);
|
|
||||||
if (existingOrder != null) characterFrame.RemoveChild(existingOrder);
|
|
||||||
|
|
||||||
var orderFrame = new GUIFrame(new Rectangle(-5, 40, characterFrame.Rect.Width, 30 + order.Options.Length * 15), "InnerFrame", characterFrame);
|
|
||||||
/*orderFrame.OutlineColor = Color.LightGray * 0.5f;*/
|
|
||||||
orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
|
||||||
orderFrame.UserData = order;
|
|
||||||
|
|
||||||
var img = new GUIImage(new Rectangle(0, 0, 20, 20), order.SymbolSprite, Alignment.TopLeft, orderFrame);
|
|
||||||
img.Scale = 20.0f / img.SourceRect.Width;
|
|
||||||
img.Color = order.Color;
|
|
||||||
img.CanBeFocused = false;
|
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(img.Rect.Width, 0, 0, 20), order.DoingText, "", Alignment.TopLeft, Alignment.CenterLeft, orderFrame);
|
|
||||||
|
|
||||||
var optionList = new GUIListBox(new Rectangle(0, 20, 0, 80), Color.Transparent, null, orderFrame);
|
|
||||||
optionList.UserData = order;
|
|
||||||
|
|
||||||
for (int i = 0; i < order.Options.Length; i++ )
|
|
||||||
{
|
|
||||||
var optionBox = new GUITextBlock(new Rectangle(0, 0, 0, 15), order.Options[i], "", Alignment.TopLeft, Alignment.CenterLeft, optionList);
|
|
||||||
optionBox.Font = GUI.SmallFont;
|
|
||||||
optionBox.UserData = order.Options[i];
|
|
||||||
|
|
||||||
if (selectedOption == order.Options[i])
|
|
||||||
{
|
|
||||||
optionList.Select(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
optionList.OnSelected = SelectOrderOption;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SelectOrderOption(GUIComponent component, object userData)
|
|
||||||
{
|
|
||||||
string option = userData.ToString();
|
|
||||||
Order order = component.Parent.UserData as Order;
|
|
||||||
Character character = component.Parent.Parent.Parent.UserData as Character;
|
|
||||||
|
|
||||||
var humanAi = character.AIController as HumanAIController;
|
|
||||||
if (humanAi == null) return false;
|
|
||||||
|
|
||||||
humanAi.SetOrder(order, option);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!IsOpen) return;
|
|
||||||
|
|
||||||
frame.Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
|
using FarseerPhysics.Dynamics.Joints;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
@@ -15,21 +16,58 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (selectedAiTarget?.Entity != null)
|
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), Color.Red * 0.3f, 0, 5);
|
||||||
|
|
||||||
if (wallAttackPos != Vector2.Zero)
|
if (wallTarget != null)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch, ConvertUnits.ToDisplayUnits(new Vector2(wallAttackPos.X, -wallAttackPos.Y)) - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
|
Vector2 wallTargetPos = wallTarget.Position;
|
||||||
|
if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
|
||||||
|
wallTargetPos.Y = -wallTargetPos.Y;
|
||||||
|
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
|
||||||
|
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red);
|
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
|
/*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, "updatetargets: " + updateTargetsTimer, pos - Vector2.UnitY * 100.0f, Color.Red);
|
Color stateColor = Color.White;
|
||||||
GUI.Font.DrawString(spriteBatch, "cooldown: " + coolDownTimer, pos - Vector2.UnitY * 120.0f, Color.Red);
|
switch (State)
|
||||||
|
{
|
||||||
|
case AIState.Attack:
|
||||||
|
stateColor = IsCoolDownRunning ? Color.Orange : Color.Red;
|
||||||
|
break;
|
||||||
|
case AIState.Escape:
|
||||||
|
stateColor = Color.LightBlue;
|
||||||
|
break;
|
||||||
|
case AIState.Eat:
|
||||||
|
stateColor = Color.Brown;
|
||||||
|
break;
|
||||||
|
case AIState.GoTo:
|
||||||
|
stateColor = Color.Magenta;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
|
||||||
|
|
||||||
|
if (latchOntoAI != null)
|
||||||
|
{
|
||||||
|
foreach (Joint attachJoint in latchOntoAI.AttachJoints)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
|
||||||
|
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Orange * 0.6f, 0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latchOntoAI.WallAttachPos.HasValue)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, pos,
|
||||||
|
ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Orange * 0.6f, 0, 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
||||||
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
|
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
|
||||||
@@ -37,15 +75,14 @@ namespace Barotrauma
|
|||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
||||||
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
||||||
Color.LightGreen);
|
Color.Orange * 0.6f, 0, 3);
|
||||||
|
|
||||||
|
|
||||||
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
||||||
{
|
{
|
||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
||||||
Color.LightGreen);
|
Color.Orange * 0.6f, 0, 3);
|
||||||
|
|
||||||
GUI.SmallFont.DrawString(spriteBatch,
|
GUI.SmallFont.DrawString(spriteBatch,
|
||||||
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial void InitProjSpecific()
|
partial void InitProjSpecific()
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
|
/*if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
|
||||||
{
|
{
|
||||||
CurrentOrder = Order.PrefabList.Find(o => o.Name.ToLowerInvariant() == "dismissed");
|
CurrentOrder = Order.PrefabList.Find(o => o.AITag == "dismissed");
|
||||||
objectiveManager.SetOrder(CurrentOrder, "");
|
objectiveManager.SetOrder(CurrentOrder, "", null);
|
||||||
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder);
|
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder, null, null);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void SetOrderProjSpecific(Order order)
|
partial void SetOrderProjSpecific(Order order)
|
||||||
{
|
{
|
||||||
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, order);
|
GameMain.GameSession.CrewManager.DisplayCharacterOrder(Character, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
|||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
||||||
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
||||||
Color.LightGreen);
|
Color.LightGreen * 0.5f, 0, 3);
|
||||||
|
|
||||||
|
|
||||||
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
||||||
@@ -42,7 +42,7 @@ namespace Barotrauma
|
|||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
||||||
Color.LightGreen);
|
Color.LightGreen * 0.5f, 0, 3);
|
||||||
|
|
||||||
GUI.SmallFont.DrawString(spriteBatch,
|
GUI.SmallFont.DrawString(spriteBatch,
|
||||||
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
|
using Barotrauma.SpriteDeformations;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using FarseerPhysics.Dynamics;
|
using FarseerPhysics.Dynamics;
|
||||||
using FarseerPhysics.Dynamics.Joints;
|
using FarseerPhysics.Dynamics.Joints;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Barotrauma.Particles;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class Ragdoll
|
abstract partial class Ragdoll
|
||||||
{
|
{
|
||||||
|
public HashSet<SpriteDeformation> SpriteDeformations { get; protected set; } = new HashSet<SpriteDeformation>();
|
||||||
|
|
||||||
partial void ImpactProjSpecific(float impact, Body body)
|
partial void ImpactProjSpecific(float impact, Body body)
|
||||||
{
|
{
|
||||||
float volume = Math.Min(impact - 3.0f, 1.0f);
|
float volume = Math.Min(impact - 3.0f, 1.0f);
|
||||||
@@ -17,19 +24,18 @@ namespace Barotrauma
|
|||||||
if (body.UserData is Limb && character.Stun <= 0f)
|
if (body.UserData is Limb && character.Stun <= 0f)
|
||||||
{
|
{
|
||||||
Limb limb = (Limb)body.UserData;
|
Limb limb = (Limb)body.UserData;
|
||||||
|
if (impact > 3.0f && limb.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
|
||||||
if (impact > 3.0f && limb.SoundTimer <= 0.0f)
|
|
||||||
{
|
{
|
||||||
limb.SoundTimer = Limb.SoundInterval;
|
limb.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||||
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
|
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
|
||||||
{
|
{
|
||||||
SoundPlayer.PlaySound(limb.HitSoundTag, volume, impact * 100.0f, limb.WorldPosition);
|
SoundPlayer.PlaySound(limb.HitSoundTag, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
|
||||||
}
|
}
|
||||||
foreach (WearableSprite wearable in limb.WearingItems)
|
foreach (WearableSprite wearable in limb.WearingItems)
|
||||||
{
|
{
|
||||||
if (limb.type == wearable.Limb && !string.IsNullOrWhiteSpace(wearable.Sound))
|
if (limb.type == wearable.Limb && !string.IsNullOrWhiteSpace(wearable.Sound))
|
||||||
{
|
{
|
||||||
SoundPlayer.PlaySound(wearable.Sound, volume, impact * 100.0f, limb.WorldPosition);
|
SoundPlayer.PlaySound(wearable.Sound, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,21 +49,31 @@ namespace Barotrauma
|
|||||||
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
|
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (Character.Controlled == character) GameMain.GameScreen.Cam.Shake = Math.Min(strongestImpact, 3.0f);
|
if (Character.Controlled == character)
|
||||||
|
{
|
||||||
|
GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void Splash(Limb limb, Hull limbHull)
|
partial void Splash(Limb limb, Hull limbHull)
|
||||||
{
|
{
|
||||||
//create a splash particle
|
//create a splash particle
|
||||||
GameMain.ParticleManager.CreateParticle("watersplash",
|
for (int i = 0; i < MathHelper.Clamp(Math.Abs(limb.LinearVelocity.Y), 1.0f, 5.0f); i++)
|
||||||
new Vector2(limb.Position.X, limbHull.Surface) + limbHull.Submarine.Position,
|
{
|
||||||
new Vector2(0.0f, Math.Abs(-limb.LinearVelocity.Y * 20.0f)),
|
var splash = GameMain.ParticleManager.CreateParticle("watersplash",
|
||||||
0.0f, limbHull);
|
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
|
||||||
|
new Vector2(0.0f, Math.Abs(-limb.LinearVelocity.Y * 20.0f)) + Rand.Vector(Math.Abs(limb.LinearVelocity.Y * 10)),
|
||||||
|
Rand.Range(0.0f, MathHelper.TwoPi), limbHull);
|
||||||
|
|
||||||
|
if (splash != null)
|
||||||
|
{
|
||||||
|
splash.Size *= MathHelper.Clamp(Math.Abs(limb.LinearVelocity.Y) * 0.1f, 1.0f, 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameMain.ParticleManager.CreateParticle("bubbles",
|
GameMain.ParticleManager.CreateParticle("bubbles",
|
||||||
new Vector2(limb.Position.X, limbHull.Surface) + limbHull.Submarine.Position,
|
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
|
||||||
limb.LinearVelocity * 0.001f,
|
limb.LinearVelocity * 0.001f,
|
||||||
0.0f, limbHull);
|
0.0f, limbHull);
|
||||||
|
|
||||||
@@ -69,10 +85,90 @@ namespace Barotrauma
|
|||||||
SoundPlayer.PlaySplashSound(limb.WorldPosition, Math.Abs(limb.LinearVelocity.Y) + Rand.Range(-5.0f, 0.0f));
|
SoundPlayer.PlaySplashSound(limb.WorldPosition, Math.Abs(limb.LinearVelocity.Y) + Rand.Range(-5.0f, 0.0f));
|
||||||
splashSoundTimer = 0.5f;
|
splashSoundTimer = 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//+ some extra bubbles to follow the character underwater
|
||||||
|
GameMain.ParticleManager.CreateParticle("bubbles",
|
||||||
|
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
|
||||||
|
limb.LinearVelocity * 10.0f,
|
||||||
|
0.0f, limbHull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Draw(SpriteBatch spriteBatch)
|
partial void SetupDrawOrder()
|
||||||
|
{
|
||||||
|
//make sure every character gets drawn at a distinct "layer"
|
||||||
|
//(instead of having some of the limbs appear behind and some in front of other characters)
|
||||||
|
float startDepth = 0.1f;
|
||||||
|
float increment = 0.001f;
|
||||||
|
foreach (Character otherCharacter in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (otherCharacter == character) continue;
|
||||||
|
startDepth += increment;
|
||||||
|
}
|
||||||
|
//make sure each limb has a distinct depth value
|
||||||
|
List<Limb> depthSortedLimbs = Limbs.OrderBy(l => l.ActiveSprite == null ? 0.0f : l.ActiveSprite.Depth).ToList();
|
||||||
|
foreach (Limb limb in Limbs)
|
||||||
|
{
|
||||||
|
if (limb.ActiveSprite != null)
|
||||||
|
limb.ActiveSprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
|
||||||
|
}
|
||||||
|
depthSortedLimbs.Reverse();
|
||||||
|
inversedLimbDrawOrder = depthSortedLimbs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
|
{
|
||||||
|
LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime));
|
||||||
|
foreach (var deformation in SpriteDeformations)
|
||||||
|
{
|
||||||
|
if (deformation.DeformationParams.UseMovementSine)
|
||||||
|
{
|
||||||
|
if (this is AnimController animator)
|
||||||
|
{
|
||||||
|
//deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos + MathHelper.Pi);
|
||||||
|
deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.DeformationParams.Frequency + MathHelper.Pi * deformation.DeformationParams.SineOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deformation.Update(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void FlipProjSpecific()
|
||||||
|
{
|
||||||
|
foreach (Limb limb in Limbs)
|
||||||
|
{
|
||||||
|
if (limb == null || limb.IsSevered || limb.ActiveSprite == null) continue;
|
||||||
|
|
||||||
|
Vector2 spriteOrigin = limb.ActiveSprite.Origin;
|
||||||
|
spriteOrigin.X = limb.ActiveSprite.SourceRect.Width - spriteOrigin.X;
|
||||||
|
limb.ActiveSprite.Origin = spriteOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint)
|
||||||
|
{
|
||||||
|
foreach (Limb limb in new Limb[] { limbJoint.LimbA, limbJoint.LimbB })
|
||||||
|
{
|
||||||
|
float gibParticleAmount = MathHelper.Clamp(limb.Mass / character.AnimController.Mass, 0.1f, 1.0f);
|
||||||
|
foreach (ParticleEmitter emitter in character.GibEmitters)
|
||||||
|
{
|
||||||
|
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
|
||||||
|
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
|
||||||
|
|
||||||
|
emitter.Emit(1.0f, limb.WorldPosition, character.CurrentHull, amountMultiplier: gibParticleAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(character.BloodDecalName))
|
||||||
|
{
|
||||||
|
character.CurrentHull?.AddDecal(character.BloodDecalName, limb.WorldPosition, MathHelper.Clamp(limb.Mass, 0.5f, 2.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||||
{
|
{
|
||||||
if (simplePhysicsEnabled) return;
|
if (simplePhysicsEnabled) return;
|
||||||
|
|
||||||
@@ -87,10 +183,16 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Limb limb in Limbs)
|
//foreach (Limb limb in Limbs)
|
||||||
|
//{
|
||||||
|
// limb.Draw(spriteBatch, cam);
|
||||||
|
//}
|
||||||
|
|
||||||
|
for (int i = 0; i < limbs.Length; i++)
|
||||||
{
|
{
|
||||||
limb.Draw(spriteBatch);
|
inversedLimbDrawOrder[i].Draw(spriteBatch, cam);
|
||||||
}
|
}
|
||||||
|
LimbJoints.ForEach(j => j.Draw(spriteBatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DebugDraw(SpriteBatch spriteBatch)
|
public void DebugDraw(SpriteBatch spriteBatch)
|
||||||
@@ -103,7 +205,7 @@ namespace Barotrauma
|
|||||||
if (limb.PullJointEnabled)
|
if (limb.PullJointEnabled)
|
||||||
{
|
{
|
||||||
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
|
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
|
||||||
if (currentHull != null) pos += currentHull.Submarine.DrawPosition;
|
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
|
||||||
pos.Y = -pos.Y;
|
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), Color.Red, true, 0.01f);
|
||||||
}
|
}
|
||||||
@@ -128,7 +230,7 @@ namespace Barotrauma
|
|||||||
if (limb.body.TargetPosition != null)
|
if (limb.body.TargetPosition != null)
|
||||||
{
|
{
|
||||||
Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition);
|
Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition);
|
||||||
if (currentHull != null) pos += currentHull.Submarine.DrawPosition;
|
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
|
||||||
pos.Y = -pos.Y;
|
pos.Y = -pos.Y;
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 10, (int)pos.Y - 10, 20, 20), Color.Cyan, false, 0.01f);
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 10, (int)pos.Y - 10, 20, 20), Color.Cyan, false, 0.01f);
|
||||||
@@ -136,7 +238,15 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outsideCollisionBlocker.Enabled && currentHull.Submarine != null)
|
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);
|
||||||
|
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;
|
var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape;
|
||||||
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + currentHull.Submarine.Position;
|
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + currentHull.Submarine.Position;
|
||||||
@@ -149,13 +259,13 @@ namespace Barotrauma
|
|||||||
if (character.MemState.Count > 1)
|
if (character.MemState.Count > 1)
|
||||||
{
|
{
|
||||||
Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position);
|
Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position);
|
||||||
if (currentHull != null) prevPos += currentHull.Submarine.DrawPosition;
|
if (currentHull?.Submarine != null) prevPos += currentHull.Submarine.DrawPosition;
|
||||||
prevPos.Y = -prevPos.Y;
|
prevPos.Y = -prevPos.Y;
|
||||||
|
|
||||||
for (int i = 1; i < character.MemState.Count; i++)
|
for (int i = 1; i < character.MemState.Count; i++)
|
||||||
{
|
{
|
||||||
Vector2 currPos = ConvertUnits.ToDisplayUnits(character.MemState[i].Position);
|
Vector2 currPos = ConvertUnits.ToDisplayUnits(character.MemState[i].Position);
|
||||||
if (currentHull != null) currPos += currentHull.Submarine.DrawPosition;
|
if (currentHull?.Submarine != null) currPos += currentHull.Submarine.DrawPosition;
|
||||||
currPos.Y = -currPos.Y;
|
currPos.Y = -currPos.Y;
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 3, (int)currPos.Y - 3, 6, 6), Color.Cyan * 0.6f, true, 0.01f);
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 3, (int)currPos.Y - 3, 6, 6), Color.Cyan * 0.6f, true, 0.01f);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Particles;
|
using Barotrauma.Sounds;
|
||||||
|
using Barotrauma.Particles;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
@@ -6,17 +7,24 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class Attack
|
partial class Attack
|
||||||
{
|
{
|
||||||
private Sound sound;
|
public string StructureSoundType
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoundSound sound;
|
||||||
|
|
||||||
private ParticleEmitter particleEmitter;
|
private ParticleEmitter particleEmitter;
|
||||||
|
|
||||||
partial void InitProjSpecific(XElement element)
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
string soundPath = element.GetAttributeString("sound", "");
|
if (element.Attribute("sound") != null)
|
||||||
if (!string.IsNullOrWhiteSpace(soundPath))
|
|
||||||
{
|
{
|
||||||
sound = Sound.Load(soundPath);
|
DebugConsole.ThrowError("Error in attack ("+element+") - sounds should be defined as child elements, not as attributes.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StructureSoundType = element.GetAttributeString("structuresoundtype", "StructureBlunt");
|
||||||
|
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
@@ -25,6 +33,9 @@ namespace Barotrauma
|
|||||||
case "particleemitter":
|
case "particleemitter":
|
||||||
particleEmitter = new ParticleEmitter(subElement);
|
particleEmitter = new ParticleEmitter(subElement);
|
||||||
break;
|
break;
|
||||||
|
case "sound":
|
||||||
|
sound = Submarine.LoadRoundSound(subElement);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -39,7 +50,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (sound != null)
|
if (sound != null)
|
||||||
{
|
{
|
||||||
sound.Play(1.0f, 500.0f, worldPosition);
|
SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, worldPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class Character : Entity, IDamageable, ISerializableEntity, IClientSerializable, IServerSerializable
|
partial class Character : Entity, IDamageable, ISerializableEntity, IClientSerializable, IServerSerializable
|
||||||
{
|
{
|
||||||
|
public static bool DisableControls;
|
||||||
|
|
||||||
|
public static bool DebugDrawInteract;
|
||||||
|
|
||||||
protected float soundTimer;
|
protected float soundTimer;
|
||||||
protected float soundInterval;
|
protected float soundInterval;
|
||||||
protected float hudInfoTimer;
|
protected float hudInfoTimer;
|
||||||
protected bool hudInfoVisible;
|
protected bool hudInfoVisible;
|
||||||
|
|
||||||
float hudInfoHeight;
|
protected float lastRecvPositionUpdateTime;
|
||||||
|
|
||||||
|
private float hudInfoHeight;
|
||||||
|
|
||||||
private List<CharacterSound> sounds;
|
private List<CharacterSound> sounds;
|
||||||
|
|
||||||
@@ -32,12 +38,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (controlled == value) return;
|
if (controlled == value) return;
|
||||||
controlled = value;
|
controlled = value;
|
||||||
CharacterHUD.Reset();
|
if (controlled != null) controlled.Enabled = true;
|
||||||
|
GameMain.GameSession?.CrewManager?.SetCharacterSelected(controlled);
|
||||||
if (controlled != null)
|
CharacterHealth.OpenHealthWindow = null;
|
||||||
{
|
|
||||||
controlled.Enabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +52,58 @@ namespace Barotrauma
|
|||||||
get { return hudProgressBars; }
|
get { return hudProgressBars; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float blurStrength;
|
||||||
|
public float BlurStrength
|
||||||
|
{
|
||||||
|
get { return blurStrength; }
|
||||||
|
set { blurStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float distortStrength;
|
||||||
|
public float DistortStrength
|
||||||
|
{
|
||||||
|
get { return distortStrength; }
|
||||||
|
set { distortStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float radialDistortStrength;
|
||||||
|
public float RadialDistortStrength
|
||||||
|
{
|
||||||
|
get { return radialDistortStrength; }
|
||||||
|
set { radialDistortStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float chromaticAberrationStrength;
|
||||||
|
public float ChromaticAberrationStrength
|
||||||
|
{
|
||||||
|
get { return chromaticAberrationStrength; }
|
||||||
|
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BloodDecalName
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
|
||||||
|
public IEnumerable<ParticleEmitter> BloodEmitters
|
||||||
|
{
|
||||||
|
get { return bloodEmitters; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ParticleEmitter> damageEmitters = new List<ParticleEmitter>();
|
||||||
|
public IEnumerable<ParticleEmitter> DamageEmitters
|
||||||
|
{
|
||||||
|
get { return damageEmitters; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ParticleEmitter> gibEmitters = new List<ParticleEmitter>();
|
||||||
|
public IEnumerable<ParticleEmitter> GibEmitters
|
||||||
|
{
|
||||||
|
get { return gibEmitters; }
|
||||||
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific(XDocument doc)
|
partial void InitProjSpecific(XDocument doc)
|
||||||
{
|
{
|
||||||
soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f);
|
soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f);
|
||||||
@@ -56,15 +112,29 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int i = 0; i < Enum.GetNames(typeof(InputType)).Length; i++)
|
for (int i = 0; i < Enum.GetNames(typeof(InputType)).Length; i++)
|
||||||
{
|
{
|
||||||
keys[i] = new Key(GameMain.Config.KeyBind((InputType)i));
|
keys[i] = new Key((InputType)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var soundElements = doc.Root.Elements("sound").ToList();
|
BloodDecalName = doc.Root.GetAttributeString("blooddecal", "");
|
||||||
|
|
||||||
sounds = new List<CharacterSound>();
|
sounds = new List<CharacterSound>();
|
||||||
foreach (XElement soundElement in soundElements)
|
foreach (XElement subElement in doc.Root.Elements())
|
||||||
{
|
{
|
||||||
sounds.Add(new CharacterSound(soundElement));
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "sound":
|
||||||
|
sounds.Add(new CharacterSound(subElement));
|
||||||
|
break;
|
||||||
|
case "damageemitter":
|
||||||
|
damageEmitters.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
case "bloodemitter":
|
||||||
|
bloodEmitters.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
case "gibemitter":
|
||||||
|
gibEmitters.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hudProgressBars = new Dictionary<object, HUDProgressBar>();
|
hudProgressBars = new Dictionary<object, HUDProgressBar>();
|
||||||
@@ -76,14 +146,7 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
|
public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
|
||||||
{
|
{
|
||||||
if (!DisableControls)
|
if (DisableControls)
|
||||||
{
|
|
||||||
for (int i = 0; i < keys.Length; i++)
|
|
||||||
{
|
|
||||||
keys[i].SetState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
foreach (Key key in keys)
|
foreach (Key key in keys)
|
||||||
{
|
{
|
||||||
@@ -91,109 +154,124 @@ namespace Barotrauma
|
|||||||
key.Reset();
|
key.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (moveCam)
|
|
||||||
{
|
{
|
||||||
if (needsAir &&
|
for (int i = 0; i < keys.Length; i++)
|
||||||
pressureProtection < 80.0f &&
|
|
||||||
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
|
|
||||||
{
|
{
|
||||||
float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;
|
keys[i].SetState();
|
||||||
|
|
||||||
cam.Zoom = MathHelper.Lerp(cam.Zoom,
|
|
||||||
(pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
|
|
||||||
(pressure - 50.0f) / 50.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsHumanoid)
|
if (moveCam)
|
||||||
{
|
{
|
||||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
|
if (needsAir &&
|
||||||
}
|
pressureProtection < 80.0f &&
|
||||||
else
|
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
|
||||||
{
|
{
|
||||||
//increased visibility range when controlling large a non-humanoid
|
float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;
|
||||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
cam.Zoom = MathHelper.Lerp(cam.Zoom,
|
||||||
if (AnimController.CurrentHull != null && AnimController.CurrentHull.Submarine != null)
|
(pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
|
||||||
{
|
(pressure - 50.0f) / 50.0f);
|
||||||
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
|
if (IsHumanoid)
|
||||||
if (moveCam)
|
{
|
||||||
{
|
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
|
||||||
if (DebugConsole.IsOpen || GUI.PauseMenuOpen || IsUnconscious ||
|
}
|
||||||
(GameMain.GameSession?.CrewManager?.CrewCommander != null && GameMain.GameSession.CrewManager.CrewCommander.IsOpen))
|
else
|
||||||
|
{
|
||||||
|
//increased visibility range when controlling large a non-humanoid
|
||||||
|
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||||
|
if (AnimController.CurrentHull?.Submarine != null)
|
||||||
{
|
{
|
||||||
if (deltaTime > 0.0f) cam.OffsetAmount = 0.0f;
|
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
|
||||||
|
if (GUI.PauseMenuOpen)
|
||||||
|
{
|
||||||
|
cam.OffsetAmount = 0.0f;
|
||||||
|
}
|
||||||
|
else if (SelectedConstruction != null && SelectedConstruction.components.Any(ic => (ic.GuiFrame != null && GUI.IsMouseOn(ic.GuiFrame))))
|
||||||
|
{
|
||||||
|
cam.OffsetAmount = 0.0f;
|
||||||
}
|
}
|
||||||
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
|
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
|
||||||
{
|
{
|
||||||
Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
|
if (GUI.PauseMenuOpen || IsUnconscious)
|
||||||
Structure structure = body == null ? null : body.UserData as Structure;
|
|
||||||
|
|
||||||
float sightDist = Submarine.LastPickedFraction;
|
|
||||||
if (body?.UserData is Structure && !((Structure)body.UserData).CastShadow)
|
|
||||||
{
|
{
|
||||||
sightDist = 1.0f;
|
if (deltaTime > 0.0f) cam.OffsetAmount = 0.0f;
|
||||||
}
|
}
|
||||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, Math.Max(250.0f, sightDist * 500.0f), 0.05f);
|
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
|
||||||
}
|
{
|
||||||
}
|
Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
|
||||||
|
Structure structure = body == null ? null : body.UserData as Structure;
|
||||||
|
|
||||||
DoInteractionUpdate(deltaTime, mouseSimPos);
|
float sightDist = Submarine.LastPickedFraction;
|
||||||
|
if (body?.UserData is Structure && !((Structure)body.UserData).CastShadow)
|
||||||
|
{
|
||||||
|
sightDist = 1.0f;
|
||||||
|
}
|
||||||
|
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, Math.Max(250.0f, sightDist * 500.0f), 0.05f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoInteractionUpdate(deltaTime, mouseSimPos);
|
||||||
|
}
|
||||||
|
|
||||||
DisableControls = false;
|
DisableControls = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateControlled(float deltaTime,Camera cam)
|
partial void UpdateControlled(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (controlled != this) return;
|
if (controlled != this) return;
|
||||||
|
|
||||||
ControlLocalPlayer(deltaTime, cam);
|
ControlLocalPlayer(deltaTime, cam);
|
||||||
|
|
||||||
Lights.LightManager.ViewTarget = this;
|
Lights.LightManager.ViewTarget = this;
|
||||||
CharacterHUD.Update(deltaTime, this);
|
CharacterHUD.Update(deltaTime, this, cam);
|
||||||
|
|
||||||
|
bool removeProgressBars = false;
|
||||||
|
|
||||||
foreach (HUDProgressBar progressBar in hudProgressBars.Values)
|
foreach (HUDProgressBar progressBar in hudProgressBars.Values)
|
||||||
{
|
{
|
||||||
|
if (progressBar.FadeTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
removeProgressBars = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
progressBar.Update(deltaTime);
|
progressBar.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var pb in hudProgressBars.Where(pb => pb.Value.FadeTimer <= 0.0f).ToList())
|
if (removeProgressBars)
|
||||||
{
|
{
|
||||||
hudProgressBars.Remove(pb.Key);
|
// TODO: this generates garbage, can we fix anything here?
|
||||||
|
foreach (var pb in hudProgressBars.Where(pb => pb.Value.FadeTimer <= 0.0f).ToList())
|
||||||
|
{
|
||||||
|
hudProgressBars.Remove(pb.Key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void DamageHUD(float amount)
|
|
||||||
{
|
|
||||||
if (controlled == this) CharacterHUD.TakeDamage(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void UpdateOxygenProjSpecific(float prevOxygen)
|
|
||||||
{
|
|
||||||
if (prevOxygen > 0.0f && Oxygen <= 0.0f && controlled == this)
|
|
||||||
{
|
|
||||||
SoundPlayer.PlaySound("drown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void KillProjSpecific()
|
partial void KillProjSpecific()
|
||||||
{
|
{
|
||||||
if (GameMain.NetworkMember != null && controlled == this)
|
if (GameMain.NetworkMember != null && controlled == this)
|
||||||
{
|
{
|
||||||
string chatMessage = TextManager.Get("Self_CauseOfDeathDescription." + causeOfDeath.ToString());
|
string chatMessage = CauseOfDeath.Type == CauseOfDeathType.Affliction ?
|
||||||
|
CauseOfDeath.Affliction.SelfCauseOfDeathDescription :
|
||||||
|
TextManager.Get("Self_CauseOfDeathDescription." + CauseOfDeath.Type.ToString());
|
||||||
|
|
||||||
if (GameMain.Client != null) chatMessage += " " + TextManager.Get("DeathChatNotification");
|
if (GameMain.Client != null) chatMessage += " " + TextManager.Get("DeathChatNotification");
|
||||||
|
|
||||||
GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead);
|
GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead);
|
||||||
GameMain.LightManager.LosEnabled = false;
|
GameMain.LightManager.LosEnabled = false;
|
||||||
controlled = null;
|
controlled = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaySound(CharacterSound.SoundType.Die);
|
PlaySound(CharacterSound.SoundType.Die);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +292,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (info != null || health < maxHealth * 0.98f)
|
if (info != null || Vitality < MaxVitality * 0.98f)
|
||||||
{
|
{
|
||||||
hudInfoTimer -= deltaTime;
|
hudInfoTimer -= deltaTime;
|
||||||
if (hudInfoTimer <= 0.0f)
|
if (hudInfoTimer <= 0.0f)
|
||||||
@@ -233,11 +311,16 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Ideally it shouldn't send the character entirely if we can't see them but /shrug, this isn't the most hacker-proof game atm
|
//Ideally it shouldn't send the character entirely if we can't see them but /shrug, this isn't the most hacker-proof game atm
|
||||||
hudInfoVisible = controlled.CanSeeCharacter(this);
|
hudInfoVisible = controlled.CanSeeCharacter(this, controlled.ViewTarget == null ? controlled.WorldPosition : controlled.ViewTarget.WorldPosition);
|
||||||
}
|
}
|
||||||
hudInfoTimer = Rand.Range(0.5f, 1.0f);
|
hudInfoTimer = Rand.Range(0.5f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (controlled == this)
|
||||||
|
{
|
||||||
|
CharacterHealth.UpdateHUD(deltaTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddAllToGUIUpdateList()
|
public static void AddAllToGUIUpdateList()
|
||||||
@@ -253,19 +336,21 @@ namespace Barotrauma
|
|||||||
if (controlled == this)
|
if (controlled == this)
|
||||||
{
|
{
|
||||||
CharacterHUD.AddToGUIUpdateList(this);
|
CharacterHUD.AddToGUIUpdateList(this);
|
||||||
|
CharacterHealth.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch)
|
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||||
{
|
{
|
||||||
if (!Enabled) return;
|
if (!Enabled) return;
|
||||||
|
|
||||||
AnimController.Draw(spriteBatch);
|
AnimController.Draw(spriteBatch, cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam)
|
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, bool drawHealth = true)
|
||||||
{
|
{
|
||||||
CharacterHUD.Draw(spriteBatch, this, cam);
|
CharacterHUD.Draw(spriteBatch, this, cam);
|
||||||
|
if (drawHealth) CharacterHealth.DrawHUD(spriteBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||||
@@ -299,24 +384,50 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (speechBubbleTimer > 0.0f)
|
if (speechBubbleTimer > 0.0f)
|
||||||
{
|
{
|
||||||
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 100.0f,
|
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 30,
|
||||||
speechBubbleColor * Math.Min(speechBubbleTimer, 1.0f), 0.0f,
|
speechBubbleColor * Math.Min(speechBubbleTimer, 1.0f), 0.0f,
|
||||||
Math.Min(speechBubbleTimer, 1.0f));
|
Math.Min(speechBubbleTimer, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this == controlled) return;
|
if (this == controlled)
|
||||||
|
{
|
||||||
|
if (DebugDrawInteract)
|
||||||
|
{
|
||||||
|
Vector2 cursorPos = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||||
|
cursorPos.Y = -cursorPos.Y;
|
||||||
|
foreach (Item item in debugInteractablesAtCursor)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, cursorPos,
|
||||||
|
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), Color.LightGreen, width: 4);
|
||||||
|
}
|
||||||
|
foreach (Item item in debugInteractablesInRange)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y),
|
||||||
|
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), Color.White * 0.1f, width: 4);
|
||||||
|
}
|
||||||
|
foreach (Pair<Item, float> item in debugInteractablesNearCursor)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float hoverRange = 300.0f;
|
float hoverRange = 300.0f;
|
||||||
float fadeOutRange = 200.0f;
|
float fadeOutRange = 200.0f;
|
||||||
float cursorDist = Vector2.Distance(WorldPosition, cam.ScreenToWorld(PlayerInput.MousePosition));
|
float cursorDist = Vector2.Distance(WorldPosition, cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||||
float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f);
|
float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f);
|
||||||
|
|
||||||
if (hudInfoVisible && info != null)
|
if (hudInfoVisible && info != null &&
|
||||||
|
(controlled == null || this != controlled.focusedCharacter))
|
||||||
{
|
{
|
||||||
string name = Info.DisplayName;
|
string name = Info.DisplayName;
|
||||||
if (controlled == null && name != Info.Name) name += " " + TextManager.Get("Disguised");
|
if (controlled == null && name != Info.Name) name += " " + TextManager.Get("Disguised");
|
||||||
|
|
||||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(Info.Name) * 0.5f / cam.Zoom;
|
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(name) * 0.5f / cam.Zoom;
|
||||||
|
|
||||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||||
@@ -340,14 +451,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDead) return;
|
if (IsDead) return;
|
||||||
|
|
||||||
if (health < maxHealth * 0.98f && hudInfoVisible)
|
if (Vitality < MaxVitality * 0.98f && hudInfoVisible)
|
||||||
{
|
{
|
||||||
Vector2 healthBarPos = new Vector2(pos.X - 50, -pos.Y);
|
Vector2 healthBarPos = new Vector2(pos.X - 50, -pos.Y);
|
||||||
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
|
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
|
||||||
health / maxHealth,
|
Vitality / MaxVitality,
|
||||||
Color.Lerp(Color.Red, Color.Green, health / maxHealth) * 0.8f * hudInfoAlpha,
|
Color.Lerp(Color.Red, Color.Green, Vitality / MaxVitality) * 0.8f * hudInfoAlpha,
|
||||||
new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
|
new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,7 +493,7 @@ namespace Barotrauma
|
|||||||
if (matchingSounds.Count == 0) return;
|
if (matchingSounds.Count == 0) return;
|
||||||
|
|
||||||
var selectedSound = matchingSounds[Rand.Int(matchingSounds.Count)];
|
var selectedSound = matchingSounds[Rand.Int(matchingSounds.Count)];
|
||||||
selectedSound.Sound.Play(1.0f, selectedSound.Range, AnimController.WorldPosition);
|
SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, AnimController.WorldPosition, CurrentHull);
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void ImplodeFX()
|
partial void ImplodeFX()
|
||||||
|
|||||||
@@ -1,61 +1,64 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Barotrauma.Networking;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class CharacterHUD
|
class CharacterHUD
|
||||||
{
|
{
|
||||||
private static Sprite statusIcons;
|
private static Dictionary<Entity, int> orderIndicatorCount = new Dictionary<Entity, int>();
|
||||||
|
const float ItemOverlayDelay = 1.0f;
|
||||||
private static Sprite noiseOverlay, damageOverlay;
|
private static Item focusedItem;
|
||||||
|
private static float focusedItemOverlayTimer;
|
||||||
private static GUIButton cprButton;
|
|
||||||
|
|
||||||
private static GUIButton grabHoldButton;
|
private static List<Item> brokenItems = new List<Item>();
|
||||||
|
private static float brokenItemsCheckTimer;
|
||||||
|
|
||||||
private static GUIButton suicideButton;
|
private static Dictionary<string, string> cachedHudTexts = new Dictionary<string, string>();
|
||||||
|
|
||||||
private static GUIProgressBar oxygenBar, healthBar;
|
private static GUIFrame hudFrame;
|
||||||
|
public static GUIFrame HUDFrame
|
||||||
private static bool oxyMsgShown, pressureMsgShown;
|
|
||||||
private static float pressureMsgTimer;
|
|
||||||
|
|
||||||
public static float damageOverlayTimer { get; private set; }
|
|
||||||
|
|
||||||
public static void Reset()
|
|
||||||
{
|
{
|
||||||
damageOverlayTimer = 0.0f;
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (hudFrame == null)
|
||||||
|
{
|
||||||
|
hudFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return hudFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void TakeDamage(float amount)
|
private static string GetCachedHudText(string textTag, string keyBind)
|
||||||
{
|
{
|
||||||
healthBar?.Flash();
|
if (cachedHudTexts.TryGetValue(textTag + keyBind, out string text))
|
||||||
|
{
|
||||||
damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 1.0f);
|
return text;
|
||||||
|
}
|
||||||
|
text = TextManager.Get(textTag).Replace("[key]", keyBind);
|
||||||
|
cachedHudTexts.Add(textTag + keyBind, text);
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddToGUIUpdateList(Character character)
|
public static void AddToGUIUpdateList(Character character)
|
||||||
{
|
{
|
||||||
if (GUI.DisableHUD) return;
|
if (GUI.DisableHUD) return;
|
||||||
|
|
||||||
if (cprButton != null && cprButton.Visible) cprButton.AddToGUIUpdateList();
|
|
||||||
|
|
||||||
if (grabHoldButton != null && cprButton.Visible) grabHoldButton.AddToGUIUpdateList();
|
|
||||||
|
|
||||||
if (suicideButton != null && suicideButton.Visible) suicideButton.AddToGUIUpdateList();
|
|
||||||
|
|
||||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (character.Inventory != null)
|
if (character.Inventory != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
||||||
{
|
{
|
||||||
var item = character.Inventory.Items[i];
|
var item = character.Inventory.Items[i];
|
||||||
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
|
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
|
||||||
|
|
||||||
foreach (ItemComponent ic in item.components)
|
foreach (ItemComponent ic in item.components)
|
||||||
{
|
{
|
||||||
@@ -63,177 +66,116 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (character.IsHumanoid && character.SelectedCharacter != null)
|
||||||
|
{
|
||||||
|
character.SelectedCharacter.CharacterHealth.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HUDFrame.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Update(float deltaTime, Character character)
|
public static void Update(float deltaTime, Character character, Camera cam)
|
||||||
{
|
{
|
||||||
if (!pressureMsgShown)
|
if (GUI.DisableHUD) { return; }
|
||||||
{
|
|
||||||
float pressureFactor = (character.AnimController.CurrentHull == null) ?
|
|
||||||
100.0f : Math.Min(character.AnimController.CurrentHull.LethalPressure, 100.0f);
|
|
||||||
if (character.PressureProtection > 0.0f) pressureFactor = 0.0f;
|
|
||||||
|
|
||||||
if (pressureFactor > 0.0f)
|
|
||||||
{
|
|
||||||
pressureMsgTimer += deltaTime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pressureMsgTimer = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oxygenBar != null)
|
|
||||||
{
|
|
||||||
oxygenBar.Update(deltaTime);
|
|
||||||
if (character.Oxygen < 10.0f) oxygenBar.Flash();
|
|
||||||
}
|
|
||||||
if (healthBar != null) healthBar.Update(deltaTime);
|
|
||||||
|
|
||||||
if (Inventory.SelectedSlot == null)
|
|
||||||
{
|
|
||||||
if (cprButton != null && cprButton.Visible) cprButton.Update(deltaTime);
|
|
||||||
if (grabHoldButton != null && grabHoldButton.Visible) grabHoldButton.Update(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (suicideButton != null && suicideButton.Visible) suicideButton.Update(deltaTime);
|
|
||||||
|
|
||||||
if (damageOverlayTimer > 0.0f) damageOverlayTimer -= deltaTime;
|
|
||||||
|
|
||||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||||
{
|
{
|
||||||
if (character.Inventory != null)
|
if (character.Inventory != null)
|
||||||
{
|
{
|
||||||
if (!character.LockHands && character.Stun >= -0.1f)
|
if (!character.LockHands && character.Stun < 0.1f)
|
||||||
{
|
{
|
||||||
character.Inventory.Update(deltaTime);
|
character.Inventory.Update(deltaTime, cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
||||||
{
|
{
|
||||||
var item = character.Inventory.Items[i];
|
var item = character.Inventory.Items[i];
|
||||||
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
|
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
|
||||||
|
|
||||||
foreach (ItemComponent ic in item.components)
|
foreach (ItemComponent ic in item.components)
|
||||||
{
|
{
|
||||||
if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character);
|
if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character, deltaTime, cam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||||
{
|
{
|
||||||
character.SelectedCharacter.Inventory.Update(deltaTime);
|
if (character.SelectedCharacter.CanInventoryBeAccessed)
|
||||||
|
{
|
||||||
|
character.SelectedCharacter.Inventory.Update(deltaTime, cam);
|
||||||
|
}
|
||||||
|
character.SelectedCharacter.CharacterHealth.UpdateHUD(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory.UpdateDragging();
|
Inventory.UpdateDragging();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
|
if (focusedItem != null)
|
||||||
{
|
|
||||||
if (statusIcons == null)
|
|
||||||
{
|
{
|
||||||
statusIcons = new Sprite("Content/UI/statusIcons.png", Vector2.Zero);
|
if (character.FocusedItem != null)
|
||||||
}
|
|
||||||
|
|
||||||
if (noiseOverlay == null)
|
|
||||||
{
|
|
||||||
noiseOverlay = new Sprite("Content/UI/noise.png", Vector2.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (damageOverlay == null)
|
|
||||||
{
|
|
||||||
damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUI.DisableHUD) return;
|
|
||||||
|
|
||||||
if (character.Inventory != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
|
||||||
{
|
{
|
||||||
var item = character.Inventory.Items[i];
|
focusedItemOverlayTimer = Math.Min(focusedItemOverlayTimer + deltaTime, ItemOverlayDelay + 1.0f);
|
||||||
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
|
}
|
||||||
|
else
|
||||||
foreach (ItemComponent ic in item.components)
|
{
|
||||||
{
|
focusedItemOverlayTimer = Math.Max(focusedItemOverlayTimer - deltaTime, 0.0f);
|
||||||
if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character);
|
if (focusedItemOverlayTimer <= 0.0f) focusedItem = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawStatusIcons(spriteBatch, character);
|
if (brokenItemsCheckTimer > 0.0f)
|
||||||
|
{
|
||||||
|
brokenItemsCheckTimer -= deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
brokenItems.Clear();
|
||||||
|
brokenItemsCheckTimer = 1.0f;
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (item.CurrentHull == character.CurrentHull && item.Repairables.Any(r => item.Condition < r.ShowRepairUIThreshold))
|
||||||
|
{
|
||||||
|
brokenItems.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
|
||||||
|
{
|
||||||
|
if (GUI.DisableHUD) return;
|
||||||
|
|
||||||
|
character.CharacterHealth.Alignment = Alignment.Right;
|
||||||
|
|
||||||
|
if (GameMain.GameSession?.CrewManager != null)
|
||||||
|
{
|
||||||
|
orderIndicatorCount.Clear();
|
||||||
|
foreach (Pair<Order, float> timedOrder in GameMain.GameSession.CrewManager.ActiveOrders)
|
||||||
|
{
|
||||||
|
DrawOrderIndicator(spriteBatch, cam, character, timedOrder.First, MathHelper.Clamp(timedOrder.Second / 10.0f, 0.2f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (character.CurrentOrder != null)
|
||||||
|
{
|
||||||
|
DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Item brokenItem in brokenItems)
|
||||||
|
{
|
||||||
|
float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition);
|
||||||
|
Vector2 drawPos = brokenItem.DrawPosition;
|
||||||
|
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 / 100.0f) * alpha);
|
||||||
|
}
|
||||||
|
|
||||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||||
{
|
{
|
||||||
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
|
||||||
{
|
|
||||||
if (cprButton == null)
|
|
||||||
{
|
|
||||||
cprButton = new GUIButton(
|
|
||||||
new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(320, -30), new Point(130, 20)), "Perform CPR", "");
|
|
||||||
|
|
||||||
cprButton.OnClicked = (button, userData) =>
|
|
||||||
{
|
|
||||||
if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false;
|
|
||||||
|
|
||||||
Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ?
|
|
||||||
AnimController.Animation.None : AnimController.Animation.CPR;
|
|
||||||
|
|
||||||
Character.Controlled.SelectedCharacter.AnimController.ResetPullJoints();
|
|
||||||
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Repair });
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grabHoldButton == null)
|
|
||||||
{
|
|
||||||
grabHoldButton = new GUIButton(
|
|
||||||
new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(320, -60), new Point(130, 20)),
|
|
||||||
TextManager.Get("Grabbing") + ": " + TextManager.Get(character.AnimController.GrabLimb == LimbType.None ? "Hands" : character.AnimController.GrabLimb.ToString()), "");
|
|
||||||
|
|
||||||
grabHoldButton.OnClicked = (button, userData) =>
|
|
||||||
{
|
|
||||||
if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false;
|
|
||||||
|
|
||||||
Character.Controlled.AnimController.GrabLimb = Character.Controlled.AnimController.GrabLimb == LimbType.None ? LimbType.Torso : LimbType.None;
|
|
||||||
|
|
||||||
Character.Controlled.SelectedCharacter.AnimController.ResetPullJoints();
|
|
||||||
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Control });
|
|
||||||
}
|
|
||||||
|
|
||||||
grabHoldButton.Text = TextManager.Get("Grabbing") + ": " + TextManager.Get(character.AnimController.GrabLimb == LimbType.None ? "Hands" : character.AnimController.GrabLimb.ToString());
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cprButton.Visible) cprButton.Draw(spriteBatch);
|
|
||||||
if (grabHoldButton.Visible) grabHoldButton.Draw(spriteBatch);
|
|
||||||
|
|
||||||
character.SelectedCharacter.Inventory.DrawOffset = new Vector2(320.0f, 0.0f);
|
|
||||||
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (character.Inventory != null && !character.LockHands && character.Stun >= -0.1f)
|
|
||||||
{
|
|
||||||
character.Inventory.DrawOffset = Vector2.Zero;
|
|
||||||
character.Inventory.DrawOwn(spriteBatch);
|
|
||||||
}
|
|
||||||
if (character.Inventory != null && !character.LockHands && character.Stun >= -0.1f)
|
|
||||||
{
|
|
||||||
Inventory.DrawDragging(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
|
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
|
||||||
{
|
{
|
||||||
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
|
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
|
||||||
@@ -247,156 +189,173 @@ namespace Barotrauma
|
|||||||
Vector2 textPos = startPos;
|
Vector2 textPos = startPos;
|
||||||
textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20);
|
textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20);
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch, textPos, focusName, Color.White, Color.Black, 2);
|
GUI.DrawString(spriteBatch, textPos, focusName, Color.White, Color.Black * 0.7f, 2);
|
||||||
}
|
textPos.Y += 20;
|
||||||
else if (character.SelectedCharacter == null && character.FocusedItem != null && character.SelectedConstruction == null)
|
if (character.FocusedCharacter.CanInventoryBeAccessed)
|
||||||
{
|
|
||||||
var hudTexts = character.FocusedItem.GetHUDTexts(character);
|
|
||||||
|
|
||||||
Vector2 startPos = new Vector2((int)(GameMain.GraphicsWidth / 2.0f), GameMain.GraphicsHeight);
|
|
||||||
startPos.Y -= 50 + hudTexts.Count * 25;
|
|
||||||
|
|
||||||
Vector2 textPos = startPos;
|
|
||||||
textPos -= new Vector2((int)GUI.Font.MeasureString(character.FocusedItem.Name).X / 2, 20);
|
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch, textPos, character.FocusedItem.Name, Color.White, Color.Black * 0.7f, 2);
|
|
||||||
|
|
||||||
textPos.Y += 30.0f;
|
|
||||||
foreach (ColoredText coloredText in hudTexts)
|
|
||||||
{
|
{
|
||||||
textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X / 2);
|
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBind(InputType.Grab).ToString()),
|
||||||
|
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||||
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color, Color.Black * 0.7f, 2, GUI.SmallFont);
|
textPos.Y += 15;
|
||||||
|
}
|
||||||
textPos.Y += 25;
|
if (character.FocusedCharacter.CharacterHealth.UseHealthWindow)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBind(InputType.Health).ToString()),
|
||||||
|
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||||
|
textPos.Y += 15;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||||
|
textPos.Y += 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float circleSize = 1.0f;
|
||||||
|
if (character.FocusedItem != null)
|
||||||
|
{
|
||||||
|
if (focusedItem != character.FocusedItem)
|
||||||
|
{
|
||||||
|
focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer);
|
||||||
|
}
|
||||||
|
focusedItem = character.FocusedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focusedItem != null && focusedItemOverlayTimer > ItemOverlayDelay)
|
||||||
|
{
|
||||||
|
Vector2 circlePos = cam.WorldToScreen(focusedItem.DrawPosition);
|
||||||
|
circleSize = Math.Max(focusedItem.Rect.Width, focusedItem.Rect.Height) * 1.5f;
|
||||||
|
circleSize = MathHelper.Clamp(circleSize, 45.0f, 100.0f) * Math.Min((focusedItemOverlayTimer - 1.0f) * 5.0f, 1.0f);
|
||||||
|
if (circleSize > 0.0f)
|
||||||
|
{
|
||||||
|
Vector2 scale = new Vector2(circleSize / GUI.Style.FocusIndicator.FrameSize.X);
|
||||||
|
GUI.Style.FocusIndicator.Draw(spriteBatch,
|
||||||
|
(int)((focusedItemOverlayTimer - 1.0f) * GUI.Style.FocusIndicator.FrameCount * 3.0f),
|
||||||
|
circlePos,
|
||||||
|
Color.Orange * 0.3f,
|
||||||
|
origin: GUI.Style.FocusIndicator.FrameSize.ToVector2() / 2,
|
||||||
|
rotate: (float)Timing.TotalTime,
|
||||||
|
scale: scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
var hudTexts = focusedItem.GetHUDTexts(character);
|
||||||
|
|
||||||
|
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
|
||||||
|
Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition);
|
||||||
|
startPos.Y -= (hudTexts.Count + 1) * 20;
|
||||||
|
if (focusedItem.Sprite != null)
|
||||||
|
{
|
||||||
|
startPos.X += (int)(circleSize * 0.4f * dir);
|
||||||
|
startPos.Y -= (int)(circleSize * 0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 textPos = startPos;
|
||||||
|
if (dir == -1) textPos.X -= (int)GUI.Font.MeasureString(focusedItem.Name).X;
|
||||||
|
|
||||||
|
float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
GUI.DrawString(spriteBatch, textPos, focusedItem.Name, Color.White * alpha, Color.Black * alpha * 0.7f, 2);
|
||||||
|
textPos.Y += 20.0f;
|
||||||
|
foreach (ColoredText coloredText in hudTexts)
|
||||||
|
{
|
||||||
|
if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X);
|
||||||
|
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont);
|
||||||
|
textPos.Y += 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values)
|
foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values)
|
||||||
{
|
{
|
||||||
progressBar.Draw(spriteBatch, cam);
|
progressBar.Draw(spriteBatch, cam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Screen.Selected == GameMain.SubEditorScreen) return;
|
if (character.SelectedConstruction != null &&
|
||||||
|
(character.CanInteractWith(Character.Controlled.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen))
|
||||||
if (character.IsUnconscious || (character.Oxygen < 80.0f && !character.IsDead))
|
|
||||||
{
|
{
|
||||||
Vector2 offset = Rand.Vector(noiseOverlay.size.X);
|
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||||
offset.X = Math.Abs(offset.X);
|
|
||||||
offset.Y = Math.Abs(offset.Y);
|
|
||||||
|
|
||||||
float alpha = character.IsUnconscious ? 1.0f : Math.Min((80.0f - character.Oxygen)/50.0f, 0.8f);
|
|
||||||
|
|
||||||
noiseOverlay.DrawTiled(spriteBatch, Vector2.Zero - offset, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) + offset,
|
|
||||||
color: Color.White * alpha);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (suicideButton != null) suicideButton.Visible = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damageOverlayTimer>0.0f)
|
if (character.Inventory != null)
|
||||||
{
|
{
|
||||||
damageOverlay.Draw(spriteBatch, Vector2.Zero, Color.White * damageOverlayTimer, Vector2.Zero, 0.0f,
|
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
||||||
new Vector2(GameMain.GraphicsWidth / damageOverlay.size.X, GameMain.GraphicsHeight / damageOverlay.size.Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (character.IsUnconscious && !character.IsDead)
|
|
||||||
{
|
|
||||||
if (suicideButton == null)
|
|
||||||
{
|
{
|
||||||
suicideButton = new GUIButton(
|
var item = character.Inventory.Items[i];
|
||||||
new Rectangle(new Point(GameMain.GraphicsWidth / 2 - 60, 20), new Point(120, 20)), TextManager.Get("GiveInButton"), "");
|
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
|
||||||
|
|
||||||
|
foreach (ItemComponent ic in item.components)
|
||||||
suicideButton.ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer");
|
|
||||||
|
|
||||||
suicideButton.OnClicked = (button, userData) =>
|
|
||||||
{
|
{
|
||||||
GUIComponent.ForceMouseOn(null);
|
if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character);
|
||||||
if (Character.Controlled != null)
|
}
|
||||||
{
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Status });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Character.Controlled.Kill(Character.Controlled.CauseOfDeath);
|
|
||||||
Character.Controlled = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
bool drawPortraitToolTip = false;
|
||||||
|
if (character.Stun <= 0.1f && !character.IsDead)
|
||||||
|
{
|
||||||
|
if (CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null)
|
||||||
|
{
|
||||||
|
if (character.Info != null)
|
||||||
|
{
|
||||||
|
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), targetWidth: HUDLayoutSettings.PortraitArea.Width);
|
||||||
|
}
|
||||||
|
drawPortraitToolTip = HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition);
|
||||||
|
}
|
||||||
|
if (character.Inventory != null && !character.LockHands)
|
||||||
|
{
|
||||||
|
character.Inventory.DrawOwn(spriteBatch);
|
||||||
|
character.Inventory.CurrentLayout = CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null ?
|
||||||
|
CharacterInventory.Layout.Default :
|
||||||
|
CharacterInventory.Layout.Right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suicideButton.Visible = true;
|
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||||
suicideButton.Draw(spriteBatch);
|
{
|
||||||
|
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||||
|
{
|
||||||
|
if (character.SelectedCharacter.CanInventoryBeAccessed)
|
||||||
|
{
|
||||||
|
///character.Inventory.CurrentLayout = Alignment.Left;
|
||||||
|
character.SelectedCharacter.Inventory.CurrentLayout = CharacterInventory.Layout.Left;
|
||||||
|
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left;
|
||||||
|
}
|
||||||
|
if (CharacterHealth.OpenHealthWindow == character.SelectedCharacter.CharacterHealth)
|
||||||
|
{
|
||||||
|
character.SelectedCharacter.CharacterHealth.Alignment = Alignment.Left;
|
||||||
|
character.SelectedCharacter.CharacterHealth.DrawStatusHUD(spriteBatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (character.Inventory != null)
|
||||||
|
{
|
||||||
|
//character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawPortraitToolTip)
|
||||||
|
{
|
||||||
|
GUIComponent.DrawToolTip(
|
||||||
|
spriteBatch,
|
||||||
|
character.Info?.Job == null ? character.Name : character.Name + " (" + character.Info.Job.Name + ")",
|
||||||
|
HUDLayoutSettings.PortraitArea);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character)
|
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f)
|
||||||
{
|
{
|
||||||
if (GameMain.DebugDraw)
|
if (order.TargetAllCharacters && !order.HasAppropriateJob(character)) return;
|
||||||
{
|
|
||||||
GUI.DrawString(spriteBatch, new Vector2(30, GameMain.GraphicsHeight - 260), TextManager.Get("Stun") + ": " + character.Stun, Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oxygenBar == null)
|
Entity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetEntity;
|
||||||
{
|
if (target == null) return;
|
||||||
int width = 100, height = 20;
|
|
||||||
|
|
||||||
oxygenBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 200, width, height), Color.Blue, "", 1.0f, Alignment.TopLeft);
|
if (!orderIndicatorCount.ContainsKey(target)) orderIndicatorCount.Add(target, 0);
|
||||||
new GUIImage(new Rectangle(-27, -7, 20, 20), new Rectangle(17, 0, 20, 24), statusIcons, Alignment.TopLeft, oxygenBar);
|
|
||||||
|
|
||||||
healthBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 230, width, height), Color.Red, "", 1.0f, Alignment.TopLeft);
|
Vector2 drawPos = target.WorldPosition + Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
|
||||||
new GUIImage(new Rectangle(-26, -7, 20, 20), new Rectangle(0, 0, 13, 24), statusIcons, Alignment.TopLeft, healthBar);
|
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha);
|
||||||
}
|
|
||||||
|
|
||||||
oxygenBar.BarSize = character.Oxygen / 100.0f;
|
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
|
||||||
if (oxygenBar.BarSize < 0.99f)
|
}
|
||||||
{
|
|
||||||
oxygenBar.Draw(spriteBatch);
|
|
||||||
if (!oxyMsgShown)
|
|
||||||
{
|
|
||||||
GUI.AddMessage(TextManager.Get("OxygenBarInfo"), new Vector2(oxygenBar.Rect.Right + 10, oxygenBar.Rect.Y), Alignment.Left, Color.White, 5.0f);
|
|
||||||
oxyMsgShown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
healthBar.BarSize = character.Health / character.MaxHealth;
|
|
||||||
if (healthBar.BarSize < 1.0f)
|
|
||||||
{
|
|
||||||
healthBar.Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
float bloodDropCount = character.Bleeding;
|
|
||||||
bloodDropCount = MathHelper.Clamp(bloodDropCount, 0.0f, 5.0f);
|
|
||||||
for (int i = 0; i < Math.Ceiling(bloodDropCount); i++)
|
|
||||||
{
|
|
||||||
float alpha = MathHelper.Clamp(bloodDropCount-i, 0.2f, 1.0f);
|
|
||||||
spriteBatch.Draw(statusIcons.Texture, new Vector2(25.0f + 20 * i, healthBar.Rect.Y - 20.0f), new Rectangle(39, 3, 15, 19), Color.White * alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
float pressureFactor = (character.AnimController.CurrentHull == null) ?
|
|
||||||
100.0f : Math.Min(character.AnimController.CurrentHull.LethalPressure, 100.0f);
|
|
||||||
if (character.PressureProtection > 0.0f) pressureFactor = 0.0f;
|
|
||||||
|
|
||||||
if (pressureFactor > 0.0f)
|
|
||||||
{
|
|
||||||
float indicatorAlpha = ((float)Math.Sin(character.PressureTimer * 0.1f) + 1.0f) * 0.5f;
|
|
||||||
indicatorAlpha = MathHelper.Clamp(indicatorAlpha, 0.1f, pressureFactor / 100.0f);
|
|
||||||
|
|
||||||
if (pressureMsgTimer > 0.5f && !pressureMsgShown)
|
|
||||||
{
|
|
||||||
GUI.AddMessage(TextManager.Get("PressureInfo"), new Vector2(40.0f, healthBar.Rect.Y - 60.0f), Alignment.Left, Color.White, 5.0f);
|
|
||||||
pressureMsgShown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
spriteBatch.Draw(statusIcons.Texture, new Vector2(10.0f, healthBar.Rect.Y - 60.0f), new Rectangle(0, 24, 24, 25), Color.White * indicatorAlpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,69 +1,223 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class CharacterInfo
|
partial class CharacterInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
public GUIFrame CreateInfoFrame(Rectangle rect)
|
|
||||||
{
|
|
||||||
GUIFrame frame = new GUIFrame(rect, Color.Transparent);
|
|
||||||
frame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
|
|
||||||
|
|
||||||
return CreateInfoFrame(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIFrame CreateInfoFrame(GUIFrame frame)
|
public GUIFrame CreateInfoFrame(GUIFrame frame)
|
||||||
{
|
{
|
||||||
new GUIImage(new Rectangle(0, 0, 30, 30), HeadSprite, Alignment.TopLeft, frame);
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.7f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) })
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.03f
|
||||||
|
};
|
||||||
|
|
||||||
ScalableFont font = frame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
|
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), paddedFrame.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.05f,
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
int x = 0, y = 0;
|
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1.0f), headerArea.RectTransform),
|
||||||
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Name, "", frame, font);
|
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
|
||||||
y += 20;
|
|
||||||
|
ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
|
||||||
|
|
||||||
|
var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), headerArea.RectTransform))
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.05f,
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
|
Color? nameColor = null;
|
||||||
|
if (Job != null) { nameColor = Job.Prefab.UIColor; }
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
|
||||||
|
Name, textColor: nameColor, font: GUI.LargeFont)
|
||||||
|
{
|
||||||
|
Padding = Vector4.Zero,
|
||||||
|
AutoScale = true
|
||||||
|
};
|
||||||
|
|
||||||
if (Job != null)
|
if (Job != null)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Job.Name, "", frame, font);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
|
||||||
y += 30;
|
Job.Name, textColor: Job.Prefab.UIColor, font: font);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (personalityTrait != null)
|
||||||
|
{
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
|
||||||
|
TextManager.Get("PersonalityTrait") + ": " + personalityTrait.Name, font: font);
|
||||||
|
}
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), style: null);
|
||||||
|
|
||||||
|
if (Job != null)
|
||||||
|
{
|
||||||
var skills = Job.Skills;
|
var skills = Job.Skills;
|
||||||
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
|
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(x, y, 200, 20), TextManager.Get("Skills") + ":", "", frame, font);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
y += 20;
|
TextManager.Get("Skills") + ":", font: font);
|
||||||
|
|
||||||
foreach (Skill skill in skills)
|
foreach (Skill skill in skills)
|
||||||
{
|
{
|
||||||
Color textColor = Color.White * (0.5f + skill.Level / 200.0f);
|
Color textColor = Color.White * (0.5f + skill.Level / 200.0f);
|
||||||
new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Name, Color.Transparent, textColor, Alignment.Left, "", frame).Font = font;
|
|
||||||
new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Level.ToString(), Color.Transparent, textColor, Alignment.Right, "", frame).Font = font;
|
var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
y += 20;
|
TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font);
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform),
|
||||||
|
((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
|
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
|
||||||
{
|
{
|
||||||
GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 40), Color.Transparent, "ListBoxElement", parent);
|
GUIFrame frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, 40), parent.RectTransform) { IsFixedSize = false }, "ListBoxElement")
|
||||||
frame.UserData = userData;
|
{
|
||||||
|
UserData = userData
|
||||||
|
};
|
||||||
|
|
||||||
GUITextBlock textBlock = new GUITextBlock(
|
Color? textColor = null;
|
||||||
new Rectangle(40, 0, 0, 25),
|
if (Job != null) { textColor = Job.Prefab.UIColor; }
|
||||||
text,
|
|
||||||
null, null,
|
|
||||||
Alignment.Left, Alignment.Left,
|
|
||||||
"", frame, false);
|
|
||||||
textBlock.Font = GUI.SmallFont;
|
|
||||||
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
|
|
||||||
|
|
||||||
new GUIImage(new Rectangle(-5, -5, 0, 0), HeadSprite, Alignment.Left, frame);
|
|
||||||
|
|
||||||
|
GUITextBlock textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(40, 0) }, text, textColor: textColor, font: GUI.SmallFont);
|
||||||
|
new GUICustomComponent(new RectTransform(new Point(frame.Rect.Height, frame.Rect.Height), frame.RectTransform, Anchor.CenterLeft) { IsFixedSize = false },
|
||||||
|
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
|
||||||
|
{
|
||||||
|
if (newLevel - prevLevel > 0.1f)
|
||||||
|
{
|
||||||
|
GUI.AddMessage(
|
||||||
|
"+" + ((int)((newLevel - prevLevel) * 100.0f)).ToString() + " XP",
|
||||||
|
Color.Green,
|
||||||
|
textPopupPos,
|
||||||
|
Vector2.UnitY * 10.0f);
|
||||||
|
}
|
||||||
|
else if (prevLevel % 0.1f > 0.05f && newLevel % 0.1f < 0.05f)
|
||||||
|
{
|
||||||
|
GUI.AddMessage(
|
||||||
|
"+10 XP",
|
||||||
|
Color.Green,
|
||||||
|
textPopupPos,
|
||||||
|
Vector2.UnitY * 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)newLevel > (int)prevLevel)
|
||||||
|
{
|
||||||
|
GUI.AddMessage(
|
||||||
|
TextManager.Get("SkillIncreased")
|
||||||
|
.Replace("[name]", Name)
|
||||||
|
.Replace("[skillname]", TextManager.Get("SkillName." + skillIdentifier))
|
||||||
|
.Replace("[newlevel]", ((int)newLevel).ToString()),
|
||||||
|
Color.Green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void LoadAttachmentSprites()
|
||||||
|
{
|
||||||
|
if (attachmentSprites == null)
|
||||||
|
{
|
||||||
|
attachmentSprites = new List<WearableSprite>();
|
||||||
|
}
|
||||||
|
if (!IsAttachmentsLoaded)
|
||||||
|
{
|
||||||
|
LoadHeadAttachments();
|
||||||
|
}
|
||||||
|
FaceAttachment?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.FaceAttachment)));
|
||||||
|
BeardElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Beard)));
|
||||||
|
MoustacheElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Moustache)));
|
||||||
|
HairElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Hair)));
|
||||||
|
Job?.Prefab.ClothingElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, float targetWidth)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
Portrait.Draw(spriteBatch, screenPos + offset, scale: scale, spriteEffect: SpriteEffects.FlipHorizontally);
|
||||||
|
if (AttachmentsSprites != null)
|
||||||
|
{
|
||||||
|
float depthStep = 0.000001f;
|
||||||
|
foreach (var attachment in AttachmentsSprites)
|
||||||
|
{
|
||||||
|
DrawAttachmentSprite(spriteBatch, attachment, Portrait, screenPos + offset, scale, depthStep, SpriteEffects.FlipHorizontally);
|
||||||
|
depthStep += depthStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIcon(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 targetAreaSize)
|
||||||
|
{
|
||||||
|
if (HeadSprite != null)
|
||||||
|
{
|
||||||
|
float scale = Math.Min(targetAreaSize.X / HeadSprite.size.X, targetAreaSize.Y / HeadSprite.size.Y);
|
||||||
|
HeadSprite.Draw(spriteBatch, screenPos, scale: scale);
|
||||||
|
if (AttachmentsSprites != null)
|
||||||
|
{
|
||||||
|
float depthStep = 0.000001f;
|
||||||
|
foreach (var attachment in AttachmentsSprites)
|
||||||
|
{
|
||||||
|
DrawAttachmentSprite(spriteBatch, attachment, HeadSprite, screenPos, scale, depthStep);
|
||||||
|
depthStep += depthStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||||
|
{
|
||||||
|
var list = AttachmentsSprites.ToList();
|
||||||
|
if (attachment.InheritSourceRect)
|
||||||
|
{
|
||||||
|
if (attachment.SheetIndex.HasValue)
|
||||||
|
{
|
||||||
|
Point location = (head.SourceRect.Location + head.SourceRect.Size) * attachment.SheetIndex.Value;
|
||||||
|
attachment.Sprite.SourceRect = new Rectangle(location, head.SourceRect.Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attachment.Sprite.SourceRect = head.SourceRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector2 origin = attachment.Sprite.Origin;
|
||||||
|
if (attachment.InheritOrigin)
|
||||||
|
{
|
||||||
|
origin = head.Origin;
|
||||||
|
attachment.Sprite.Origin = origin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
origin = attachment.Sprite.Origin;
|
||||||
|
}
|
||||||
|
float depth = attachment.Sprite.Depth;
|
||||||
|
if (attachment.InheritLimbDepth)
|
||||||
|
{
|
||||||
|
depth = head.Depth - depthStep;
|
||||||
|
}
|
||||||
|
attachment.Sprite.Draw(spriteBatch, drawPos, Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
@@ -18,19 +19,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
case NetEntityEvent.Type.InventoryState:
|
case NetEntityEvent.Type.InventoryState:
|
||||||
msg.WriteRangedInteger(0, 3, 0);
|
msg.WriteRangedInteger(0, 3, 0);
|
||||||
inventory.ClientWrite(msg, extraData);
|
Inventory.ClientWrite(msg, extraData);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.Repair:
|
case NetEntityEvent.Type.Treatment:
|
||||||
msg.WriteRangedInteger(0, 3, 1);
|
msg.WriteRangedInteger(0, 3, 1);
|
||||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.Status:
|
case NetEntityEvent.Type.Status:
|
||||||
msg.WriteRangedInteger(0, 3, 2);
|
msg.WriteRangedInteger(0, 3, 2);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.Control:
|
|
||||||
msg.WriteRangedInteger(0, 3, 3);
|
|
||||||
msg.Write((byte)AnimController.GrabLimb);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -52,7 +49,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
msg.Write(memInput[i].intAim);
|
msg.Write(memInput[i].intAim);
|
||||||
}
|
}
|
||||||
if (memInput[i].states.HasFlag(InputNetFlags.Select) || memInput[i].states.HasFlag(InputNetFlags.Use))
|
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
|
||||||
|
memInput[i].states.HasFlag(InputNetFlags.Use) ||
|
||||||
|
memInput[i].states.HasFlag(InputNetFlags.Health) ||
|
||||||
|
memInput[i].states.HasFlag(InputNetFlags.Grab))
|
||||||
{
|
{
|
||||||
msg.Write(memInput[i].interact);
|
msg.Write(memInput[i].interact);
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,6 @@ namespace Barotrauma
|
|||||||
bool crouching = msg.ReadBoolean();
|
bool crouching = msg.ReadBoolean();
|
||||||
keys[(int)InputType.Crouch].Held = crouching;
|
keys[(int)InputType.Crouch].Held = crouching;
|
||||||
keys[(int)InputType.Crouch].SetState(false, crouching);
|
keys[(int)InputType.Crouch].SetState(false, crouching);
|
||||||
AnimController.GrabLimb = (LimbType)msg.ReadByte();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAttackLimb = msg.ReadBoolean();
|
bool hasAttackLimb = msg.ReadBoolean();
|
||||||
@@ -109,9 +108,7 @@ namespace Barotrauma
|
|||||||
if (aimInput)
|
if (aimInput)
|
||||||
{
|
{
|
||||||
double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI;
|
double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI;
|
||||||
cursorPosition = (ViewTarget == null ? AnimController.AimSourcePos : ViewTarget.Position)
|
cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
|
||||||
+ new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
|
|
||||||
|
|
||||||
TransformCursorPos();
|
TransformCursorPos();
|
||||||
}
|
}
|
||||||
bool ragdollInput = msg.ReadBoolean();
|
bool ragdollInput = msg.ReadBoolean();
|
||||||
@@ -170,11 +167,11 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case ServerNetObject.ENTITY_EVENT:
|
case ServerNetObject.ENTITY_EVENT:
|
||||||
|
|
||||||
int eventType = msg.ReadRangedInteger(0, 2);
|
int eventType = msg.ReadRangedInteger(0, 3);
|
||||||
switch (eventType)
|
switch (eventType)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if (inventory == null)
|
if (Inventory == null)
|
||||||
{
|
{
|
||||||
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ")";
|
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ")";
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
@@ -182,7 +179,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inventory?.ClientRead(type, msg, sendingTime);
|
Inventory.ClientRead(type, msg, sendingTime);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@@ -195,7 +192,7 @@ namespace Barotrauma
|
|||||||
LastNetworkUpdateID = controlled.LastNetworkUpdateID;
|
LastNetworkUpdateID = controlled.LastNetworkUpdateID;
|
||||||
}
|
}
|
||||||
|
|
||||||
controlled = this;
|
Controlled = this;
|
||||||
IsRemotePlayer = false;
|
IsRemotePlayer = false;
|
||||||
GameMain.Client.HasSpawned = true;
|
GameMain.Client.HasSpawned = true;
|
||||||
GameMain.Client.Character = this;
|
GameMain.Client.Character = this;
|
||||||
@@ -203,14 +200,22 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (controlled == this)
|
else if (controlled == this)
|
||||||
{
|
{
|
||||||
controlled = null;
|
Controlled = null;
|
||||||
IsRemotePlayer = ownerID > 0;
|
IsRemotePlayer = ownerID > 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ReadStatus(msg);
|
ReadStatus(msg);
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
int skillCount = msg.ReadByte();
|
||||||
|
for (int i = 0; i < skillCount; i++)
|
||||||
|
{
|
||||||
|
string skillIdentifier = msg.ReadString();
|
||||||
|
float skillLevel = msg.ReadSingle();
|
||||||
|
info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
msg.ReadPadBits();
|
msg.ReadPadBits();
|
||||||
break;
|
break;
|
||||||
@@ -222,9 +227,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (GameMain.Server != null) return null;
|
if (GameMain.Server != null) return null;
|
||||||
|
|
||||||
bool noInfo = inc.ReadBoolean();
|
bool noInfo = inc.ReadBoolean();
|
||||||
ushort id = inc.ReadUInt16();
|
ushort id = inc.ReadUInt16();
|
||||||
string configPath = inc.ReadString();
|
string configPath = inc.ReadString();
|
||||||
|
string seed = inc.ReadString();
|
||||||
|
|
||||||
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
||||||
|
|
||||||
@@ -237,63 +243,31 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!spawn) return null;
|
if (!spawn) return null;
|
||||||
|
|
||||||
character = Character.Create(configPath, position, null, true);
|
character = Character.Create(configPath, position, seed, null, true);
|
||||||
character.ID = id;
|
character.ID = id;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool hasOwner = inc.ReadBoolean();
|
bool hasOwner = inc.ReadBoolean();
|
||||||
int ownerId = hasOwner ? inc.ReadByte() : -1;
|
int ownerId = hasOwner ? inc.ReadByte() : -1;
|
||||||
|
byte teamID = inc.ReadByte();
|
||||||
|
bool hasAi = inc.ReadBoolean();
|
||||||
string newName = inc.ReadString();
|
|
||||||
byte teamID = inc.ReadByte();
|
|
||||||
|
|
||||||
bool hasAi = inc.ReadBoolean();
|
|
||||||
bool isFemale = inc.ReadBoolean();
|
|
||||||
int headSpriteID = inc.ReadByte();
|
|
||||||
string jobName = inc.ReadString();
|
|
||||||
|
|
||||||
JobPrefab jobPrefab = null;
|
|
||||||
Dictionary<string, int> skillLevels = new Dictionary<string, int>();
|
|
||||||
if (!string.IsNullOrEmpty(jobName))
|
|
||||||
{
|
|
||||||
jobPrefab = JobPrefab.List.Find(jp => jp.Name == jobName);
|
|
||||||
int skillCount = inc.ReadByte();
|
|
||||||
for (int i = 0; i < skillCount; i++)
|
|
||||||
{
|
|
||||||
string skillName = inc.ReadString();
|
|
||||||
int skillLevel = inc.ReadRangedInteger(0, 100);
|
|
||||||
|
|
||||||
skillLevels.Add(skillName, skillLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!spawn) return null;
|
if (!spawn) return null;
|
||||||
|
|
||||||
|
CharacterInfo info = CharacterInfo.ClientRead(configPath, inc);
|
||||||
|
|
||||||
CharacterInfo ch = new CharacterInfo(configPath, newName, isFemale ? Gender.Female : Gender.Male, jobPrefab);
|
character = Create(configPath, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
|
||||||
ch.HeadSpriteId = headSpriteID;
|
|
||||||
|
|
||||||
System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count);
|
|
||||||
if (ch.Job != null)
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string, int> skill in skillLevels)
|
|
||||||
{
|
|
||||||
Skill matchingSkill = ch.Job.Skills.Find(s => s.Name == skill.Key);
|
|
||||||
if (matchingSkill == null)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\"");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
matchingSkill.Level = skill.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
character = Create(configPath, position, ch, GameMain.Client.ID != ownerId, hasAi);
|
|
||||||
character.ID = id;
|
character.ID = id;
|
||||||
character.TeamID = teamID;
|
character.TeamID = teamID;
|
||||||
|
|
||||||
|
if (configPath == HumanConfigFile)
|
||||||
|
{
|
||||||
|
CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
|
||||||
|
GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
|
||||||
|
GameMain.GameSession.CrewManager.AddCharacter(character);
|
||||||
|
}
|
||||||
|
|
||||||
if (GameMain.Client.ID == ownerId)
|
if (GameMain.Client.ID == ownerId)
|
||||||
{
|
{
|
||||||
GameMain.Client.HasSpawned = true;
|
GameMain.Client.HasSpawned = true;
|
||||||
@@ -306,19 +280,6 @@ namespace Barotrauma
|
|||||||
character.memState.Clear();
|
character.memState.Clear();
|
||||||
character.memLocalState.Clear();
|
character.memLocalState.Clear();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var ownerClient = GameMain.Client.ConnectedClients.Find(c => c.ID == ownerId);
|
|
||||||
if (ownerClient != null)
|
|
||||||
{
|
|
||||||
ownerClient.Character = character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configPath == Character.HumanConfigFile)
|
|
||||||
{
|
|
||||||
GameMain.GameSession.CrewManager.AddCharacter(character);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
character.Enabled = Controlled == character || enabled;
|
character.Enabled = Controlled == character || enabled;
|
||||||
@@ -331,17 +292,24 @@ namespace Barotrauma
|
|||||||
bool isDead = msg.ReadBoolean();
|
bool isDead = msg.ReadBoolean();
|
||||||
if (isDead)
|
if (isDead)
|
||||||
{
|
{
|
||||||
causeOfDeath = (CauseOfDeath)msg.ReadByte();
|
CauseOfDeathType causeOfDeathType = (CauseOfDeathType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1);
|
||||||
|
AfflictionPrefab causeOfDeathAffliction = null;
|
||||||
|
if (causeOfDeathType == CauseOfDeathType.Affliction)
|
||||||
|
{
|
||||||
|
int afflictionIndex = msg.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1);
|
||||||
|
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
|
||||||
|
}
|
||||||
|
|
||||||
byte severedLimbCount = msg.ReadByte();
|
byte severedLimbCount = msg.ReadByte();
|
||||||
if (!IsDead)
|
if (!IsDead)
|
||||||
{
|
{
|
||||||
if (causeOfDeath == CauseOfDeath.Pressure)
|
if (causeOfDeathType == CauseOfDeathType.Pressure)
|
||||||
{
|
{
|
||||||
Implode(true);
|
Implode(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Kill(causeOfDeath, true);
|
Kill(causeOfDeathType, causeOfDeathAffliction?.Instantiate(1.0f), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,56 +321,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this.isDead) Revive();
|
if (IsDead) Revive();
|
||||||
|
|
||||||
health = msg.ReadRangedSingle(minHealth, maxHealth, 8);
|
CharacterHealth.ClientRead(msg);
|
||||||
|
|
||||||
bool lowOxygen = msg.ReadBoolean();
|
|
||||||
if (lowOxygen)
|
|
||||||
{
|
|
||||||
Oxygen = msg.ReadRangedSingle(-100.0f, 100.0f, 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Oxygen = 100.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBleeding = msg.ReadBoolean();
|
|
||||||
if (isBleeding)
|
|
||||||
{
|
|
||||||
bleeding = msg.ReadRangedSingle(0.0f, 5.0f, 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bleeding = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool stunned = msg.ReadBoolean();
|
|
||||||
if (stunned)
|
|
||||||
{
|
|
||||||
float newStunTimer = msg.ReadRangedSingle(0.0f, 60.0f, 8);
|
|
||||||
SetStun(newStunTimer, true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetStun(0.0f, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ragdolled = msg.ReadBoolean();
|
bool ragdolled = msg.ReadBoolean();
|
||||||
IsRagdolled = ragdolled;
|
IsRagdolled = ragdolled;
|
||||||
|
|
||||||
bool huskInfected = msg.ReadBoolean();
|
|
||||||
if (huskInfected)
|
|
||||||
{
|
|
||||||
HuskInfectionState = Math.Max(HuskInfectionState, 0.01f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HuskInfectionState = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Barotrauma.Sounds;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -10,17 +11,26 @@ namespace Barotrauma
|
|||||||
Idle, Attack, Die
|
Idle, Attack, Die
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly Sound Sound;
|
private readonly RoundSound roundSound;
|
||||||
|
|
||||||
public readonly SoundType Type;
|
public readonly SoundType Type;
|
||||||
|
|
||||||
public readonly float Range;
|
public float Volume
|
||||||
|
{
|
||||||
|
get { return roundSound.Volume; }
|
||||||
|
}
|
||||||
|
public float Range
|
||||||
|
{
|
||||||
|
get { return roundSound.Range; }
|
||||||
|
}
|
||||||
|
public Sound Sound
|
||||||
|
{
|
||||||
|
get { return roundSound.Sound; }
|
||||||
|
}
|
||||||
|
|
||||||
public CharacterSound(XElement element)
|
public CharacterSound(XElement element)
|
||||||
{
|
{
|
||||||
Sound = Sound.Load(element.Attribute("file").Value);
|
roundSound = Submarine.LoadRoundSound(element);
|
||||||
Range = element.GetAttributeFloat("range", 1000.0f);
|
|
||||||
|
|
||||||
Enum.TryParse<SoundType>(element.GetAttributeString("state", "Idle"), true, out Type);
|
Enum.TryParse<SoundType>(element.GetAttributeString("state", "Idle"), true, out Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
using Barotrauma.Extensions;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class AfflictionPsychosis : Affliction
|
||||||
|
{
|
||||||
|
class FakeFireSource
|
||||||
|
{
|
||||||
|
public Vector2 Size;
|
||||||
|
public Vector2 Position;
|
||||||
|
public Hull Hull;
|
||||||
|
|
||||||
|
public float LifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int MaxFakeFireSources = 10;
|
||||||
|
private float minFakeFireSourceInterval = 10.0f, maxFakeFireSourceInterval = 200.0f;
|
||||||
|
private float createFireSourceTimer;
|
||||||
|
private List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
|
||||||
|
|
||||||
|
enum FloodType
|
||||||
|
{
|
||||||
|
Minor,
|
||||||
|
Major,
|
||||||
|
HideFlooding
|
||||||
|
}
|
||||||
|
|
||||||
|
private float minSoundInterval = 10.0f, maxSoundInterval = 60.0f;
|
||||||
|
private FloodType currentFloodType;
|
||||||
|
private float soundTimer;
|
||||||
|
|
||||||
|
private float minFloodInterval = 30.0f, maxFloodInterval = 180.0f;
|
||||||
|
private float createFloodTimer;
|
||||||
|
private float currentFloodState;
|
||||||
|
private float currentFloodDuration;
|
||||||
|
|
||||||
|
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||||
|
{
|
||||||
|
if (Character.Controlled != characterHealth.Character) return;
|
||||||
|
UpdateFloods(deltaTime);
|
||||||
|
UpdateSounds(characterHealth.Character, deltaTime);
|
||||||
|
UpdateFires(characterHealth.Character, deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSounds(Character character, float deltaTime)
|
||||||
|
{
|
||||||
|
if (soundTimer < MathHelper.Lerp(maxSoundInterval, minSoundInterval, Strength / 100.0f))
|
||||||
|
{
|
||||||
|
soundTimer += deltaTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float impactStrength = MathHelper.Lerp(0.1f, 1.0f, Strength / 100.0f);
|
||||||
|
SoundPlayer.PlayDamageSound("StructureBlunt", Rand.Range(10.0f, 1000.0f), character.WorldPosition + Rand.Vector(500.0f));
|
||||||
|
GameMain.GameScreen.Cam.Shake = impactStrength * 10.0f;
|
||||||
|
GameMain.GameScreen.Cam.AngularVelocity = Rand.Range(-impactStrength, impactStrength);
|
||||||
|
soundTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFloods(float deltaTime)
|
||||||
|
{
|
||||||
|
if (currentFloodDuration > 0.0f)
|
||||||
|
{
|
||||||
|
currentFloodDuration -= deltaTime;
|
||||||
|
switch (currentFloodType)
|
||||||
|
{
|
||||||
|
case FloodType.Minor:
|
||||||
|
currentFloodState += deltaTime;
|
||||||
|
//lerp the water surface in all hulls 50 units above the floor within 10 seconds
|
||||||
|
foreach (Hull hull in Hull.hullList)
|
||||||
|
{
|
||||||
|
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 50.0f, currentFloodState / 10.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FloodType.Major:
|
||||||
|
currentFloodState += deltaTime;
|
||||||
|
//create a full flood in 10 seconds
|
||||||
|
foreach (Hull hull in Hull.hullList)
|
||||||
|
{
|
||||||
|
hull.DrawSurface = hull.Rect.Y - MathHelper.Lerp(hull.Rect.Height, 0.0f, currentFloodState / 10.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FloodType.HideFlooding:
|
||||||
|
//hide water inside hulls (the player can't see which hulls are flooded)
|
||||||
|
foreach (Hull hull in Hull.hullList)
|
||||||
|
{
|
||||||
|
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createFloodTimer < MathHelper.Lerp(maxFloodInterval, minFloodInterval, Strength / 100.0f))
|
||||||
|
{
|
||||||
|
createFloodTimer += deltaTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//probability of a fake flood goes from 0%-100%
|
||||||
|
if (Rand.Range(0.0f, 100.0f) < Strength)
|
||||||
|
{
|
||||||
|
if (Rand.Range(0.0f, 1.0f) < 0.5f)
|
||||||
|
{
|
||||||
|
currentFloodType = FloodType.HideFlooding;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentFloodType = Strength < 50.0f ? FloodType.Minor : FloodType.Major;
|
||||||
|
}
|
||||||
|
currentFloodDuration = Rand.Range(20.0f, 100.0f);
|
||||||
|
}
|
||||||
|
createFloodTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFires(Character character, float deltaTime)
|
||||||
|
{
|
||||||
|
createFireSourceTimer += deltaTime;
|
||||||
|
if (fakeFireSources.Count < MaxFakeFireSources &&
|
||||||
|
character.Submarine != null &&
|
||||||
|
createFireSourceTimer > MathHelper.Lerp(maxFakeFireSourceInterval, minFakeFireSourceInterval, Strength / 100.0f))
|
||||||
|
{
|
||||||
|
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
|
||||||
|
|
||||||
|
fakeFireSources.Add(new FakeFireSource()
|
||||||
|
{
|
||||||
|
Size = Vector2.One * 20.0f,
|
||||||
|
Hull = fireHull,
|
||||||
|
Position = new Vector2(Rand.Range(0.0f, fireHull.Rect.Width), 30.0f),
|
||||||
|
LifeTime = MathHelper.Lerp(10.0f, 100.0f, Strength / 100.0f)
|
||||||
|
});
|
||||||
|
createFireSourceTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FakeFireSource fakeFireSource in fakeFireSources)
|
||||||
|
{
|
||||||
|
if (fakeFireSource.Hull.Surface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
|
||||||
|
{
|
||||||
|
fakeFireSource.LifeTime -= deltaTime * 10.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeFireSource.LifeTime -= deltaTime;
|
||||||
|
float growAmount = deltaTime * 5.0f;
|
||||||
|
fakeFireSource.Size.X += growAmount;
|
||||||
|
fakeFireSource.Position.X = MathHelper.Clamp(fakeFireSource.Position.X - growAmount / 2.0f, 0.0f, fakeFireSource.Hull.Rect.Width);
|
||||||
|
fakeFireSource.Position.Y = MathHelper.Clamp(fakeFireSource.Position.Y, 0.0f, fakeFireSource.Hull.Rect.Height);
|
||||||
|
fakeFireSource.Size.X = Math.Min(fakeFireSource.Hull.Rect.Width - fakeFireSource.Position.X, fakeFireSource.Size.X);
|
||||||
|
fakeFireSource.Size.Y = Math.Min(fakeFireSource.Hull.Rect.Height - fakeFireSource.Position.Y, fakeFireSource.Size.Y);
|
||||||
|
|
||||||
|
FireSource.EmitParticles(
|
||||||
|
fakeFireSource.Size,
|
||||||
|
fakeFireSource.Hull.WorldRect.Location.ToVector2() + fakeFireSource.Position - Vector2.UnitY * fakeFireSource.Hull.Rect.Height,
|
||||||
|
fakeFireSource.Hull,
|
||||||
|
0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeFireSources.RemoveAll(fs => fs.LifeTime <= 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Microsoft.Xna.Framework;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
|
||||||
{
|
|
||||||
partial class HuskInfection
|
|
||||||
{
|
|
||||||
partial void UpdateProjSpecific(float prevTimer, Character character)
|
|
||||||
{
|
|
||||||
if (IncubationTimer < 0.5f)
|
|
||||||
{
|
|
||||||
if (prevTimer % 0.1f > 0.05f && IncubationTimer % 0.1f < 0.05f)
|
|
||||||
{
|
|
||||||
GUI.AddMessage(TextManager.Get("HuskDormant"), Color.Red, 4.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IncubationTimer < 1.0f)
|
|
||||||
{
|
|
||||||
if (state == InfectionState.Dormant && Character.Controlled == character)
|
|
||||||
{
|
|
||||||
new GUIMessageBox("", TextManager.Get("HuskCantSpeak"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (state != InfectionState.Active && Character.Controlled == character)
|
|
||||||
{
|
|
||||||
new GUIMessageBox("", TextManager.Get("HuskActivate"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,47 +4,37 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class JobPrefab
|
partial class JobPrefab
|
||||||
{
|
{
|
||||||
public GUIFrame CreateInfoFrame()
|
public GUIButton CreateInfoFrame()
|
||||||
{
|
{
|
||||||
int width = 500, height = 400;
|
int width = 500, height = 400;
|
||||||
|
|
||||||
GUIFrame backFrame = new GUIFrame(Rectangle.Empty, Color.Black * 0.5f);
|
GUIButton backFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
||||||
backFrame.Padding = Vector4.Zero;
|
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);
|
||||||
|
|
||||||
GUIFrame frame = new GUIFrame(new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), "", backFrame);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Name, font: GUI.LargeFont);
|
||||||
frame.Padding = new Vector4(30.0f, 30.0f, 30.0f, 30.0f);
|
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, 0, 100, 20), Name, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, 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 descriptionBlock = new GUITextBlock(new Rectangle(0, 40, 0, 0), Description, "", Alignment.TopLeft, Alignment.TopLeft, frame, true, GUI.SmallFont);
|
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 Rectangle(0, 40 + descriptionBlock.Rect.Height + 20, 100, 20), TextManager.Get("Skills") + ": ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
|
||||||
|
TextManager.Get("Skills") + ": ", font: GUI.LargeFont);
|
||||||
int y = 40 + descriptionBlock.Rect.Height + 50;
|
|
||||||
foreach (SkillPrefab skill in Skills)
|
foreach (SkillPrefab skill in Skills)
|
||||||
{
|
{
|
||||||
string skillDescription = Skill.GetLevelName((int)skill.LevelRange.X);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
|
||||||
string skillDescription2 = Skill.GetLevelName((int)skill.LevelRange.Y);
|
" - " + TextManager.Get("SkillName." + skill.Identifier) + ": " + (int)skill.LevelRange.X + " - " + (int)skill.LevelRange.Y, font: GUI.SmallFont);
|
||||||
|
|
||||||
if (skillDescription2 != skillDescription)
|
|
||||||
{
|
|
||||||
skillDescription += "/" + skillDescription2;
|
|
||||||
}
|
|
||||||
new GUITextBlock(new Rectangle(0, y, 100, 20),
|
|
||||||
" - " + skill.Name + ": " + skillDescription, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont);
|
|
||||||
|
|
||||||
y += 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(250, 40 + descriptionBlock.Rect.Height + 20, 0, 20), TextManager.Get("Items") + ": ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
|
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) });
|
||||||
y = 40 + descriptionBlock.Rect.Height + 50;
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
|
||||||
|
TextManager.Get("Items") + ": ", font: GUI.LargeFont);
|
||||||
foreach (string itemName in ItemNames)
|
foreach (string itemName in ItemNames)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new Rectangle(250, y, 100, 20),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
|
||||||
" - " + itemName, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont);
|
" - " + itemName, font: GUI.SmallFont);
|
||||||
|
|
||||||
y += 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return backFrame;
|
return backFrame;
|
||||||
|
|||||||
@@ -1,30 +1,145 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Lights;
|
||||||
using Barotrauma.Lights;
|
using Barotrauma.Particles;
|
||||||
|
using Barotrauma.SpriteDeformations;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
|
using FarseerPhysics.Dynamics.Joints;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
|
partial class LimbJoint : RevoluteJoint
|
||||||
|
{
|
||||||
|
public void UpdateDeformations(float deltaTime)
|
||||||
|
{
|
||||||
|
float jointMidAngle = (LowerLimit + UpperLimit) / 2.0f;
|
||||||
|
float jointAngle = this.JointAngle - jointMidAngle;
|
||||||
|
|
||||||
|
JointBendDeformation limbADeformation = LimbA.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
|
||||||
|
JointBendDeformation limbBDeformation = LimbB.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
|
||||||
|
|
||||||
|
if (limbADeformation != null && limbBDeformation != null)
|
||||||
|
{
|
||||||
|
UpdateBend(LimbA, limbADeformation, this.LocalAnchorA, -jointAngle);
|
||||||
|
UpdateBend(LimbB, limbBDeformation, this.LocalAnchorB, jointAngle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateBend(Limb limb, JointBendDeformation deformation, Vector2 localAnchor, float angle)
|
||||||
|
{
|
||||||
|
deformation.Scale = limb.DeformSprite.Size;
|
||||||
|
|
||||||
|
Vector2 displayAnchor = ConvertUnits.ToDisplayUnits(localAnchor);
|
||||||
|
displayAnchor.Y = -displayAnchor.Y;
|
||||||
|
Vector2 refPos = displayAnchor + limb.DeformSprite.Origin;
|
||||||
|
|
||||||
|
refPos.X /= limb.DeformSprite.Size.X;
|
||||||
|
refPos.Y /= limb.DeformSprite.Size.Y;
|
||||||
|
|
||||||
|
if (Math.Abs(localAnchor.X) > Math.Abs(localAnchor.Y))
|
||||||
|
{
|
||||||
|
if (localAnchor.X > 0.0f)
|
||||||
|
{
|
||||||
|
deformation.BendRightRefPos = refPos;
|
||||||
|
deformation.BendRight = angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deformation.BendLeftRefPos = refPos;
|
||||||
|
deformation.BendLeft = angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (localAnchor.Y > 0.0f)
|
||||||
|
{
|
||||||
|
deformation.BendUpRefPos = refPos;
|
||||||
|
deformation.BendUp = angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deformation.BendDownRefPos = refPos;
|
||||||
|
deformation.BendDown = angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
// A debug visualisation on the bezier curve between limbs.
|
||||||
|
var start = LimbA.WorldPosition;
|
||||||
|
var end = LimbB.WorldPosition;
|
||||||
|
var jointAPos = ConvertUnits.ToDisplayUnits(LocalAnchorA);
|
||||||
|
var control = start + Vector2.Transform(jointAPos, Matrix.CreateRotationZ(LimbA.Rotation));
|
||||||
|
start.Y = -start.Y;
|
||||||
|
end.Y = -end.Y;
|
||||||
|
control.Y = -control.Y;
|
||||||
|
//GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
|
||||||
|
//GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
|
||||||
|
//GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
partial class Limb
|
partial class Limb
|
||||||
{
|
{
|
||||||
|
//minimum duration between hit/attack sounds
|
||||||
|
public const float SoundInterval = 0.4f;
|
||||||
|
public float LastAttackSoundTime, LastImpactSoundTime;
|
||||||
|
|
||||||
|
private float wetTimer;
|
||||||
|
private float dripParticleTimer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Note that different limbs can share the same deformations.
|
||||||
|
/// Use ragdoll.SpriteDeformations for a collection that cannot have duplicates.
|
||||||
|
/// </summary>
|
||||||
|
public List<SpriteDeformation> Deformations { get; private set; } = new List<SpriteDeformation>();
|
||||||
|
|
||||||
|
public Sprite Sprite { get; protected set; }
|
||||||
|
public DeformableSprite DeformSprite { get; protected set; }
|
||||||
|
public Sprite ActiveSprite => DeformSprite != null ? DeformSprite.Sprite : Sprite;
|
||||||
|
|
||||||
|
public float TextureScale => limbParams.Ragdoll.TextureScale;
|
||||||
|
|
||||||
|
public Sprite DamagedSprite { get; set; }
|
||||||
|
|
||||||
|
public Color InitialLightSourceColor
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
public LightSource LightSource
|
public LightSource LightSource
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float damage, burnt, wetTimer;
|
private float damageOverlayStrength;
|
||||||
private float dripParticleTimer;
|
public float DamageOverlayStrength
|
||||||
|
|
||||||
public float Burnt
|
|
||||||
{
|
{
|
||||||
get { return burnt; }
|
get { return damageOverlayStrength; }
|
||||||
protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private float burnOverLayStrength;
|
||||||
|
public float BurnOverlayStrength
|
||||||
|
{
|
||||||
|
get { return burnOverLayStrength; }
|
||||||
|
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string HitSoundTag { get; private set; }
|
public string HitSoundTag { get; private set; }
|
||||||
@@ -35,8 +150,42 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
|
case "sprite":
|
||||||
|
Sprite = new Sprite(subElement, "", GetSpritePath(subElement));
|
||||||
|
break;
|
||||||
|
case "damagedsprite":
|
||||||
|
DamagedSprite = new Sprite(subElement, "", GetSpritePath(subElement));
|
||||||
|
break;
|
||||||
|
case "deformablesprite":
|
||||||
|
DeformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement));
|
||||||
|
foreach (XElement animationElement in subElement.Elements())
|
||||||
|
{
|
||||||
|
int sync = animationElement.GetAttributeInt("sync", -1);
|
||||||
|
SpriteDeformation deformation = null;
|
||||||
|
if (sync > -1)
|
||||||
|
{
|
||||||
|
// if the element is marked with the sync attribute, use a deformation of the same type with the same sync value, if there is one already.
|
||||||
|
string typeName = animationElement.GetAttributeString("type", "").ToLowerInvariant();
|
||||||
|
deformation = ragdoll.Limbs
|
||||||
|
.Where(l => l != null)
|
||||||
|
.SelectMany(l => l.Deformations)
|
||||||
|
.Where(d => d.TypeName == typeName && d.Sync == sync)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
if (deformation == null)
|
||||||
|
{
|
||||||
|
deformation = SpriteDeformation.Load(animationElement, character.SpeciesName);
|
||||||
|
if (deformation != null)
|
||||||
|
{
|
||||||
|
ragdoll.SpriteDeformations.Add(deformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deformation != null) Deformations.Add(deformation);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "lightsource":
|
case "lightsource":
|
||||||
LightSource = new LightSource(subElement);
|
LightSource = new LightSource(subElement);
|
||||||
|
InitialLightSourceColor = LightSource.Color;
|
||||||
break;
|
break;
|
||||||
case "sound":
|
case "sound":
|
||||||
HitSoundTag = subElement.GetAttributeString("tag", "");
|
HitSoundTag = subElement.GetAttributeString("tag", "");
|
||||||
@@ -50,11 +199,56 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List<DamageModifier> appliedDamageModifiers)
|
public void RecreateSprite()
|
||||||
{
|
{
|
||||||
|
if (Sprite == null) { return; }
|
||||||
|
var source = Sprite.SourceElement;
|
||||||
|
Sprite = new Sprite(source, file: GetSpritePath(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the full path of a limb sprite, taking into account tags, gender and head id
|
||||||
|
/// </summary>
|
||||||
|
private string GetSpritePath(XElement element)
|
||||||
|
{
|
||||||
|
string spritePath = element.Attribute("texture")?.Value ?? "";
|
||||||
|
string spritePathWithTags = spritePath;
|
||||||
|
if (character.Info != null && character.IsHumanoid)
|
||||||
|
{
|
||||||
|
spritePath = spritePath.Replace("[GENDER]", (character.Info.Gender == Gender.Female) ? "female" : "male");
|
||||||
|
spritePath = spritePath.Replace("[RACE]", character.Info.Race.ToString().ToLowerInvariant());
|
||||||
|
spritePath = spritePath.Replace("[HEADID]", character.Info.HeadSpriteId.ToString());
|
||||||
|
|
||||||
|
if (character.Info.HeadSprite != null && character.Info.SpriteTags.Any())
|
||||||
|
{
|
||||||
|
string tags = "";
|
||||||
|
character.Info.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
|
||||||
|
|
||||||
|
spritePathWithTags = Path.Combine(
|
||||||
|
Path.GetDirectoryName(spritePath),
|
||||||
|
Path.GetFileNameWithoutExtension(spritePath) + tags + Path.GetExtension(spritePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void LoadParamsProjSpecific()
|
||||||
|
{
|
||||||
|
bool isFlipped = dir == Direction.Left;
|
||||||
|
Sprite?.LoadParams(limbParams.normalSpriteParams, isFlipped);
|
||||||
|
DamagedSprite?.LoadParams(limbParams.damagedSpriteParams, isFlipped);
|
||||||
|
DeformSprite?.Sprite.LoadParams(limbParams.deformSpriteParams, isFlipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void AddDamageProjSpecific(Vector2 position, List<Affliction> afflictions, bool playSound, List<DamageModifier> appliedDamageModifiers)
|
||||||
|
{
|
||||||
|
float bleedingDamage = afflictions.FindAll(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
|
||||||
|
float damage = afflictions.FindAll(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
|
||||||
|
|
||||||
if (playSound)
|
if (playSound)
|
||||||
{
|
{
|
||||||
string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash";
|
string damageSoundType = (bleedingDamage > damage) ? "LimbSlash" : "LimbBlunt";
|
||||||
|
|
||||||
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
||||||
{
|
{
|
||||||
@@ -65,36 +259,32 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
|
SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (character.UseBloodParticles)
|
float damageParticleAmount = Math.Min(damage / 10, 1.0f);
|
||||||
|
foreach (ParticleEmitter emitter in character.DamageEmitters)
|
||||||
{
|
{
|
||||||
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
|
||||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
|
||||||
|
|
||||||
for (int i = 0; i < bloodParticleAmount; i++)
|
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
|
||||||
{
|
|
||||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
|
||||||
if (blood != null)
|
|
||||||
{
|
|
||||||
blood.Size *= bloodParticleSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bloodParticleAmount > 0 && character.CurrentHull != null)
|
|
||||||
{
|
|
||||||
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damageType == DamageType.Burn)
|
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f);
|
||||||
|
float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f);
|
||||||
|
foreach (ParticleEmitter emitter in character.BloodEmitters)
|
||||||
{
|
{
|
||||||
Burnt += amount * 10.0f;
|
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
|
||||||
|
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
|
||||||
|
|
||||||
|
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
damage += Math.Max(amount, bleedingAmount) / character.MaxHealth * 100.0f;
|
if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName))
|
||||||
|
{
|
||||||
|
character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateProjSpecific(float deltaTime)
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
@@ -103,8 +293,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!character.IsDead)
|
if (!character.IsDead)
|
||||||
{
|
{
|
||||||
damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
|
DamageOverlayStrength -= deltaTime;
|
||||||
Burnt -= deltaTime;
|
BurnOverlayStrength -= deltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inWater)
|
if (inWater)
|
||||||
@@ -137,11 +327,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch)
|
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
|
||||||
{
|
{
|
||||||
float brightness = 1.0f - (burnt / 100.0f) * 0.5f;
|
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
|
||||||
Color color = new Color(brightness, brightness, brightness);
|
Color color = new Color(brightness, brightness, brightness);
|
||||||
|
|
||||||
|
color = overrideColor ?? color;
|
||||||
|
|
||||||
if (isSevered)
|
if (isSevered)
|
||||||
{
|
{
|
||||||
if (severedFadeOutTimer > SeveredFadeOutTime)
|
if (severedFadeOutTimer > SeveredFadeOutTime)
|
||||||
@@ -156,14 +348,28 @@ namespace Barotrauma
|
|||||||
|
|
||||||
body.Dir = Dir;
|
body.Dir = Dir;
|
||||||
|
|
||||||
bool hideLimb = WearingItems.Any(w => w != null && w.HideLimb);
|
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
|
||||||
|
body.UpdateDrawPosition();
|
||||||
|
|
||||||
if (!hideLimb)
|
if (!hideLimb)
|
||||||
{
|
{
|
||||||
body.Draw(spriteBatch, sprite, color, null, Scale);
|
if (DeformSprite != null)
|
||||||
}
|
{
|
||||||
else
|
if (Deformations != null && Deformations.Any())
|
||||||
{
|
{
|
||||||
body.UpdateDrawPosition();
|
var deformation = SpriteDeformation.GetDeformation(Deformations, DeformSprite.Size);
|
||||||
|
DeformSprite.Deform(deformation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeformSprite.Reset();
|
||||||
|
}
|
||||||
|
body.Draw(DeformSprite, cam, Vector2.One * Scale * TextureScale, color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
body.Draw(spriteBatch, Sprite, color, null, Scale * TextureScale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LightSource != null)
|
if (LightSource != null)
|
||||||
@@ -171,57 +377,155 @@ namespace Barotrauma
|
|||||||
LightSource.Position = body.DrawPosition;
|
LightSource.Position = body.DrawPosition;
|
||||||
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||||
}
|
}
|
||||||
|
float depthStep = 0.000001f;
|
||||||
|
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
||||||
|
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
||||||
|
if (onlyDrawable == null)
|
||||||
|
{
|
||||||
|
foreach (WearableSprite wearable in OtherWearables)
|
||||||
|
{
|
||||||
|
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
||||||
|
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||||
|
depthStep += 0.000001f;
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach (WearableSprite wearable in WearingItems)
|
foreach (WearableSprite wearable in WearingItems)
|
||||||
{
|
{
|
||||||
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
if (onlyDrawable != null && onlyDrawable != wearable) continue;
|
||||||
|
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
||||||
Vector2 origin = wearable.Sprite.Origin;
|
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||||
if (body.Dir == -1.0f) origin.X = wearable.Sprite.SourceRect.Width - origin.X;
|
depthStep += 0.000001f;
|
||||||
|
|
||||||
float depth = wearable.Sprite.Depth;
|
|
||||||
|
|
||||||
if (wearable.InheritLimbDepth)
|
|
||||||
{
|
|
||||||
depth = sprite.Depth - 0.000001f;
|
|
||||||
if (wearable.DepthLimb != LimbType.None)
|
|
||||||
{
|
|
||||||
Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb);
|
|
||||||
if (depthLimb != null)
|
|
||||||
{
|
|
||||||
depth = depthLimb.sprite.Depth - 0.000001f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Color wearableColor = wearable.WearableComponent.Item.GetSpriteColor();
|
|
||||||
wearable.Sprite.Draw(spriteBatch,
|
|
||||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
|
||||||
new Color((color.R * wearableColor.R) / (255.0f * 255.0f), (color.G * wearableColor.G) / (255.0f * 255.0f), (color.B * wearableColor.B) / (255.0f * 255.0f)) * ((color.A * wearableColor.A) / (255.0f * 255.0f)),
|
|
||||||
origin, -body.DrawRotation,
|
|
||||||
Scale, spriteEffect, depth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damage > 0.0f && damagedSprite != null && !hideLimb)
|
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
|
||||||
{
|
{
|
||||||
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
float depth = ActiveSprite.Depth - 0.0000015f;
|
||||||
|
|
||||||
float depth = sprite.Depth - 0.0000015f;
|
DamagedSprite.Draw(spriteBatch,
|
||||||
|
|
||||||
damagedSprite.Draw(spriteBatch,
|
|
||||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||||
color * Math.Min(damage / 50.0f, 1.0f), sprite.Origin,
|
color * Math.Min(damageOverlayStrength / 50.0f, 1.0f), ActiveSprite.Origin,
|
||||||
-body.DrawRotation,
|
-body.DrawRotation,
|
||||||
1.0f, spriteEffect, depth);
|
1.0f, spriteEffect, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GameMain.DebugDraw) return;
|
if (GameMain.DebugDraw)
|
||||||
|
|
||||||
if (pullJoint != null)
|
|
||||||
{
|
{
|
||||||
Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
|
if (pullJoint != null)
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true);
|
{
|
||||||
|
Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true);
|
||||||
|
}
|
||||||
|
if (IsStuck)
|
||||||
|
{
|
||||||
|
Vector2 from = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorA);
|
||||||
|
from.Y = -from.Y;
|
||||||
|
Vector2 to = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorB);
|
||||||
|
to.Y = -to.Y;
|
||||||
|
var localFront = body.GetLocalFront(MathHelper.ToRadians(limbParams.Ragdoll.SpritesheetOrientation));
|
||||||
|
var front = ConvertUnits.ToDisplayUnits(body.FarseerBody.GetWorldPoint(localFront));
|
||||||
|
front.Y = -front.Y;
|
||||||
|
var drawPos = body.DrawPosition;
|
||||||
|
drawPos.Y = -drawPos.Y;
|
||||||
|
GUI.DrawLine(spriteBatch, drawPos, front, Color.Yellow, width: 2);
|
||||||
|
GUI.DrawLine(spriteBatch, from, to, Color.Red, width: 1);
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)from.X, (int)from.Y, 12, 12), Color.White, true);
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 12, 12), Color.White, true);
|
||||||
|
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)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(ragdoll.RagdollParams.SpritesheetOrientation))));
|
||||||
|
//mainLimbFront.Y = -mainLimbFront.Y;
|
||||||
|
//var mainLimbDrawPos = ragdoll.MainLimb.body.DrawPosition;
|
||||||
|
//mainLimbDrawPos.Y = -mainLimbDrawPos.Y;
|
||||||
|
//GUI.DrawLine(spriteBatch, mainLimbDrawPos, mainLimbFront, Color.White, width: 5);
|
||||||
|
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)mainLimbFront.X, (int)mainLimbFront.Y, 10, 10), Color.Yellow, true);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, SpriteEffects spriteEffect)
|
||||||
|
{
|
||||||
|
if (wearable.InheritSourceRect)
|
||||||
|
{
|
||||||
|
if (wearable.SheetIndex.HasValue)
|
||||||
|
{
|
||||||
|
Point location = (ActiveSprite.SourceRect.Location + ActiveSprite.SourceRect.Size) * wearable.SheetIndex.Value;
|
||||||
|
wearable.Sprite.SourceRect = new Rectangle(location, ActiveSprite.SourceRect.Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wearable.Sprite.SourceRect = ActiveSprite.SourceRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 origin = wearable.Sprite.Origin;
|
||||||
|
if (wearable.InheritOrigin)
|
||||||
|
{
|
||||||
|
origin = ActiveSprite.Origin;
|
||||||
|
wearable.Sprite.Origin = origin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
origin = wearable.Sprite.Origin;
|
||||||
|
// If the wearable inherits the origin, flipping is already handled.
|
||||||
|
if (body.Dir == -1.0f)
|
||||||
|
{
|
||||||
|
origin.X = wearable.Sprite.SourceRect.Width - origin.X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float depth = wearable.Sprite.Depth;
|
||||||
|
|
||||||
|
if (wearable.InheritLimbDepth)
|
||||||
|
{
|
||||||
|
depth = ActiveSprite.Depth - depthStep;
|
||||||
|
if (wearable.DepthLimb != LimbType.None)
|
||||||
|
{
|
||||||
|
Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb);
|
||||||
|
if (depthLimb != null)
|
||||||
|
{
|
||||||
|
depth = depthLimb.ActiveSprite.Depth - depthStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var wearableItemComponent = wearable.WearableComponent;
|
||||||
|
Color wearableColor = Color.White;
|
||||||
|
if (wearableItemComponent != null)
|
||||||
|
{
|
||||||
|
// Draw outer cloths on top of inner cloths.
|
||||||
|
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.OuterClothes))
|
||||||
|
{
|
||||||
|
depth -= depthStep;
|
||||||
|
}
|
||||||
|
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
||||||
|
}
|
||||||
|
float textureScale = wearable.InheritTextureScale ? TextureScale : 1;
|
||||||
|
|
||||||
|
wearable.Sprite.Draw(spriteBatch,
|
||||||
|
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||||
|
new Color((color.R * wearableColor.R) / (255.0f * 255.0f), (color.G * wearableColor.G) / (255.0f * 255.0f), (color.B * wearableColor.B) / (255.0f * 255.0f)) * ((color.A * wearableColor.A) / (255.0f * 255.0f)),
|
||||||
|
origin, -body.DrawRotation,
|
||||||
|
Scale * textureScale, spriteEffect, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void RemoveProjSpecific()
|
||||||
|
{
|
||||||
|
Sprite?.Remove();
|
||||||
|
Sprite = null;
|
||||||
|
|
||||||
|
DamagedSprite?.Remove();
|
||||||
|
DamagedSprite = null;
|
||||||
|
|
||||||
|
DeformSprite?.Sprite?.Remove();
|
||||||
|
DeformSprite = null;
|
||||||
|
|
||||||
|
LightSource?.Remove();
|
||||||
|
LightSource = null;
|
||||||
|
|
||||||
|
OtherWearables?.ForEach(w => w.Sprite.Remove());
|
||||||
|
OtherWearables = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,9 @@ namespace EventInput
|
|||||||
public class CharacterEventArgs : EventArgs
|
public class CharacterEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
private readonly char character;
|
private readonly char character;
|
||||||
private readonly int lParam;
|
private readonly long lParam;
|
||||||
|
|
||||||
public CharacterEventArgs(char character, int lParam)
|
public CharacterEventArgs(char character, long lParam)
|
||||||
{
|
{
|
||||||
this.character = character;
|
this.character = character;
|
||||||
this.lParam = lParam;
|
this.lParam = lParam;
|
||||||
@@ -50,12 +50,12 @@ namespace EventInput
|
|||||||
get { return character; }
|
get { return character; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Param
|
public long Param
|
||||||
{
|
{
|
||||||
get { return lParam; }
|
get { return lParam; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RepeatCount
|
public long RepeatCount
|
||||||
{
|
{
|
||||||
get { return lParam & 0xffff; }
|
get { return lParam & 0xffff; }
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,6 @@ namespace EventInput
|
|||||||
#if WINDOWS
|
#if WINDOWS
|
||||||
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
|
||||||
static IntPtr prevWndProc;
|
static IntPtr prevWndProc;
|
||||||
static WndProc hookProcDelegate;
|
static WndProc hookProcDelegate;
|
||||||
static IntPtr hIMC;
|
static IntPtr hIMC;
|
||||||
@@ -148,7 +147,7 @@ namespace EventInput
|
|||||||
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||||
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -165,8 +164,8 @@ namespace EventInput
|
|||||||
#if WINDOWS
|
#if WINDOWS
|
||||||
hookProcDelegate = HookProc;
|
hookProcDelegate = HookProc;
|
||||||
|
|
||||||
prevWndProc = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC,
|
prevWndProc = SetWindowLongPtr(window.Handle, GWL_WNDPROC,
|
||||||
(int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
|
Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
|
||||||
|
|
||||||
hIMC = ImmGetContext(window.Handle);
|
hIMC = ImmGetContext(window.Handle);
|
||||||
#else
|
#else
|
||||||
@@ -188,45 +187,60 @@ namespace EventInput
|
|||||||
#if WINDOWS
|
#if WINDOWS
|
||||||
static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
|
static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
|
||||||
{
|
{
|
||||||
IntPtr returnCode = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
|
IntPtr returnCode = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_GETDLGCODE:
|
||||||
|
returnCode = (IntPtr)(returnCode.ToInt32() | DLGC_WANTALLKEYS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (KeyDown != null)
|
||||||
|
KeyDown(null, new KeyEventArgs(HandleKeyInput(wParam)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_KEYUP:
|
||||||
|
if (KeyUp != null)
|
||||||
|
KeyUp(null, new KeyEventArgs(HandleKeyInput(wParam)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_CHAR:
|
||||||
|
if (CharEntered != null)
|
||||||
|
CharEntered(null, new CharacterEventArgs((char)wParam, lParam.ToInt64()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_IME_SETCONTEXT:
|
||||||
|
if (wParam.ToInt32() == 1)
|
||||||
|
ImmAssociateContext(hWnd, hIMC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_INPUTLANGCHANGE:
|
||||||
|
ImmAssociateContext(hWnd, hIMC);
|
||||||
|
returnCode = (IntPtr)1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Keys HandleKeyInput(IntPtr wParam)
|
||||||
{
|
{
|
||||||
case WM_GETDLGCODE:
|
// The conversion does not work for Shift or CTRL. Hence the hack.
|
||||||
returnCode = (IntPtr)(returnCode.ToInt32() | DLGC_WANTALLKEYS);
|
Keys key = (Keys)wParam;
|
||||||
break;
|
int k = (int)key;
|
||||||
|
if (k == 16)
|
||||||
case WM_KEYDOWN:
|
{
|
||||||
if (KeyDown != null)
|
// Could also be RightShift
|
||||||
KeyDown(null, new KeyEventArgs((Keys)wParam));
|
key = Keys.LeftShift;
|
||||||
|
}
|
||||||
break;
|
else if (k == 17)
|
||||||
|
{
|
||||||
case WM_KEYUP:
|
// Could also be RightControl
|
||||||
if (KeyUp != null)
|
key = Keys.LeftControl;
|
||||||
KeyUp(null, new KeyEventArgs((Keys)wParam));
|
}
|
||||||
break;
|
return key;
|
||||||
|
|
||||||
case WM_CHAR:
|
|
||||||
if (CharEntered != null)
|
|
||||||
CharEntered(null, new CharacterEventArgs((char)wParam, lParam.ToInt32()));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_IME_SETCONTEXT:
|
|
||||||
if (wParam.ToInt32() == 1)
|
|
||||||
ImmAssociateContext(hWnd, hIMC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_INPUTLANGCHANGE:
|
|
||||||
ImmAssociateContext(hWnd, hIMC);
|
|
||||||
returnCode = (IntPtr)1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -41,22 +41,26 @@ namespace EventInput
|
|||||||
return;
|
return;
|
||||||
if (char.IsControl(e.Character))
|
if (char.IsControl(e.Character))
|
||||||
{
|
{
|
||||||
//ctrl-v
|
_subscriber.ReceiveCommandInput(e.Character);
|
||||||
if (e.Character == 0x16)
|
// Doesn't work as expected. Not sure why this should be run in a separate thread.
|
||||||
{
|
//#if WINDOWS
|
||||||
#if WINDOWS
|
// //ctrl-v
|
||||||
//XNA runs in Multiple Thread Apartment state, which cannot recieve clipboard
|
// if (e.Character == 0x16) // 22
|
||||||
Thread thread = new Thread(PasteThread);
|
// {
|
||||||
thread.SetApartmentState(ApartmentState.STA);
|
// //XNA runs in Multiple Thread Apartment state, which cannot recieve clipboard
|
||||||
thread.Start();
|
// Thread thread = new Thread(PasteThread);
|
||||||
thread.Join();
|
// thread.SetApartmentState(ApartmentState.STA);
|
||||||
_subscriber.ReceiveTextInput(_pasteResult);
|
// thread.Start();
|
||||||
#endif
|
// thread.Join();
|
||||||
}
|
// _subscriber.ReceiveTextInput(_pasteResult);
|
||||||
else
|
// }
|
||||||
{
|
// else
|
||||||
_subscriber.ReceiveCommandInput(e.Character);
|
// {
|
||||||
}
|
// _subscriber.ReceiveCommandInput(e.Character);
|
||||||
|
// }
|
||||||
|
//#else
|
||||||
|
// _subscriber.ReceiveCommandInput(e.Character);
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class EventManager
|
||||||
|
{
|
||||||
|
private Graph intensityGraph;
|
||||||
|
private Graph targetIntensityGraph;
|
||||||
|
private float intensityGraphUpdateInterval;
|
||||||
|
private float lastIntensityUpdate;
|
||||||
|
|
||||||
|
public void DebugDraw(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
foreach (ScriptedEvent ev in events)
|
||||||
|
{
|
||||||
|
Vector2 drawPos = ev.DebugDrawPos;
|
||||||
|
drawPos.Y = -drawPos.Y;
|
||||||
|
|
||||||
|
GUI.SubmarineIcon.Draw(spriteBatch, drawPos, Color.White * 0.5f, GUI.SubmarineIcon.size / 2, 0.0f, 40.0f);
|
||||||
|
GUI.DrawString(spriteBatch, drawPos, ev.ToString(), Color.White, Color.Black, 0, GUI.LargeFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DebugDrawHUD(SpriteBatch spriteBatch, int y)
|
||||||
|
{
|
||||||
|
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 + 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);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
|
||||||
|
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.T))
|
||||||
|
{
|
||||||
|
eventCoolDown = 1.0f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (intensityGraph == null)
|
||||||
|
{
|
||||||
|
intensityGraph = new Graph();
|
||||||
|
targetIntensityGraph = new Graph();
|
||||||
|
}
|
||||||
|
|
||||||
|
intensityGraphUpdateInterval = 5.0f;
|
||||||
|
if (Timing.TotalTime > lastIntensityUpdate + intensityGraphUpdateInterval)
|
||||||
|
{
|
||||||
|
intensityGraph.Update(currentIntensity);
|
||||||
|
targetIntensityGraph.Update(targetIntensity);
|
||||||
|
lastIntensityUpdate = (float)Timing.TotalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
new Vector2(graphRect.Right, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)),
|
||||||
|
new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, 0, 1);
|
||||||
|
|
||||||
|
y = graphRect.Bottom + 20;
|
||||||
|
if (eventCoolDown > 0.0f)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Event cooldown active: " + (int)eventCoolDown, Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
y += 15;
|
||||||
|
}
|
||||||
|
else if (currentIntensity > eventThreshold)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||||
|
"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)
|
||||||
|
{
|
||||||
|
float distanceTraveled = MathHelper.Clamp(
|
||||||
|
(Submarine.MainSub.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X),
|
||||||
|
0.0f, 1.0f);
|
||||||
|
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
y += 12;
|
||||||
|
|
||||||
|
if ((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) &&
|
||||||
|
roundDuration < eventSet.MinMissionTime)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||||
|
" " + (int)(eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int)(distanceTraveled * 100.0f) + " %)",
|
||||||
|
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
y += 12;
|
||||||
|
}
|
||||||
|
if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||||
|
" intensity between " + ((int)eventSet.MinIntensity) + " and " + ((int)eventSet.MaxIntensity),
|
||||||
|
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
y += 12;
|
||||||
|
}
|
||||||
|
if (roundDuration < eventSet.MinMissionTime)
|
||||||
|
{
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||||
|
" " + (int)(eventSet.MinMissionTime - roundDuration) + " s",
|
||||||
|
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
if (scriptedEvent.IsFinished) { continue; }
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(graphRect.X + 5, y), scriptedEvent.ToString(), Color.White * 0.8f, null, 0, GUI.SmallFont);
|
||||||
|
y += 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
using SharpFont;
|
using SharpFont;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,12 @@ namespace Barotrauma
|
|||||||
public Rectangle texCoords;
|
public Rectangle texCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScalableFont(string filename, uint size, GraphicsDevice gd=null)
|
public ScalableFont(XElement element, GraphicsDevice gd = null)
|
||||||
|
: this (element.GetAttributeString("file", ""), (uint)element.GetAttributeInt("size", 14), gd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScalableFont(string filename, uint size, GraphicsDevice gd = null)
|
||||||
{
|
{
|
||||||
if (Lib == null) Lib = new Library();
|
if (Lib == null) Lib = new Library();
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
@@ -260,24 +266,39 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public Vector2 MeasureString(string text)
|
public Vector2 MeasureString(string text)
|
||||||
{
|
{
|
||||||
|
if (text == null)
|
||||||
|
{
|
||||||
|
return Vector2.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
float currentLineX = 0.0f;
|
float currentLineX = 0.0f;
|
||||||
Vector2 retVal = Vector2.Zero;
|
Vector2 retVal = Vector2.Zero;
|
||||||
retVal.Y = baseHeight*1.8f;
|
retVal.Y = baseHeight * 1.8f;
|
||||||
for (int i = 0; i < text.Length; i++)
|
for (int i = 0; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
if (text[i] == '\n')
|
if (text[i] == '\n')
|
||||||
{
|
{
|
||||||
currentLineX = 0.0f;
|
currentLineX = 0.0f;
|
||||||
retVal.Y += baseHeight*18/10;
|
retVal.Y += baseHeight * 18 / 10;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint charIndex = text[i];
|
uint charIndex = text[i];
|
||||||
GlyphData gd;
|
if (texCoords.TryGetValue(charIndex, out GlyphData gd))
|
||||||
if (texCoords.TryGetValue(charIndex, out gd))
|
|
||||||
{
|
{
|
||||||
currentLineX += gd.advance;
|
currentLineX += gd.advance;
|
||||||
}
|
}
|
||||||
retVal.X = Math.Max(retVal.X,currentLineX);
|
retVal.X = Math.Max(retVal.X, currentLineX);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 MeasureChar(char c)
|
||||||
|
{
|
||||||
|
Vector2 retVal = Vector2.Zero;
|
||||||
|
retVal.Y = baseHeight * 1.8f;
|
||||||
|
if (texCoords.TryGetValue(c, out GlyphData gd))
|
||||||
|
{
|
||||||
|
retVal.X = gd.advance;
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,357 @@
|
|||||||
|
using Barotrauma.Items.Components;
|
||||||
|
using Barotrauma.Networking;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class ChatBox
|
||||||
|
{
|
||||||
|
private static Sprite radioIcon;
|
||||||
|
|
||||||
|
private GUIFrame guiFrame;
|
||||||
|
|
||||||
|
private GUIListBox chatBox;
|
||||||
|
private GUITextBox inputBox;
|
||||||
|
|
||||||
|
private GUIButton toggleButton;
|
||||||
|
|
||||||
|
private GUIButton radioButton;
|
||||||
|
|
||||||
|
private Point screenResolution;
|
||||||
|
|
||||||
|
private bool isSinglePlayer;
|
||||||
|
public bool IsSinglePlayer => isSinglePlayer;
|
||||||
|
|
||||||
|
private bool toggleOpen = true;
|
||||||
|
private float openState;
|
||||||
|
|
||||||
|
private float prevUIScale;
|
||||||
|
|
||||||
|
//individual message texts that pop up when the chatbox is hidden
|
||||||
|
const float PopupMessageDuration = 5.0f;
|
||||||
|
private float popupMessageTimer;
|
||||||
|
private Queue<GUIComponent> popupMessages = new Queue<GUIComponent>();
|
||||||
|
|
||||||
|
public GUITextBox.OnEnterHandler OnEnterMessage
|
||||||
|
{
|
||||||
|
get { return inputBox.OnEnterPressed; }
|
||||||
|
set { inputBox.OnEnterPressed = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIFrame GUIFrame
|
||||||
|
{
|
||||||
|
get { return guiFrame; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIButton RadioButton
|
||||||
|
{
|
||||||
|
get { return radioButton; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUITextBox InputBox
|
||||||
|
{
|
||||||
|
get { return inputBox; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIButton ToggleButton
|
||||||
|
{
|
||||||
|
get { return toggleButton; }
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
guiFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ChatBoxArea, parent.RectTransform), style: null);
|
||||||
|
chatBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), guiFrame.RectTransform), style: "ChatBox");
|
||||||
|
toggleButton = new GUIButton(new RectTransform(new Point(toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Height), parent.RectTransform),
|
||||||
|
style: "UIToggleButton");
|
||||||
|
|
||||||
|
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||||
|
{
|
||||||
|
toggleOpen = !toggleOpen;
|
||||||
|
foreach (GUIComponent child in btn.Children)
|
||||||
|
{
|
||||||
|
child.SpriteEffects = toggleOpen == (HUDLayoutSettings.ChatBoxAlignment == Alignment.Right) ?
|
||||||
|
SpriteEffects.FlipHorizontally : SpriteEffects.None;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
inputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), guiFrame.RectTransform, Anchor.BottomCenter),
|
||||||
|
style: "ChatTextBox")
|
||||||
|
{
|
||||||
|
Font = GUI.SmallFont,
|
||||||
|
MaxTextLength = ChatMessage.MaxLength
|
||||||
|
};
|
||||||
|
|
||||||
|
radioButton = new GUIButton(new RectTransform(new Vector2(0.1f, 2.0f), inputBox.RectTransform,
|
||||||
|
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Anchor.BottomRight : Anchor.BottomLeft,
|
||||||
|
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Pivot.TopRight : Pivot.TopLeft),
|
||||||
|
style: null);
|
||||||
|
new GUIImage(new RectTransform(Vector2.One, radioButton.RectTransform), radioIcon, scaleToFit: true);
|
||||||
|
radioButton.OnClicked = (GUIButton btn, object userData) =>
|
||||||
|
{
|
||||||
|
if (inputBox.Selected)
|
||||||
|
{
|
||||||
|
inputBox.Text = "";
|
||||||
|
inputBox.Deselect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputBox.Select();
|
||||||
|
var radioItem = Character.Controlled?.Inventory?.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
|
||||||
|
if (radioItem != null && Character.Controlled.HasEquippedItem(radioItem) && radioItem.GetComponent<WifiComponent>().CanTransmit())
|
||||||
|
{
|
||||||
|
inputBox.Text = "r; ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TypingChatMessage(GUITextBox textBox, string text)
|
||||||
|
{
|
||||||
|
string command = ChatMessage.GetChatMessageCommand(text, out _);
|
||||||
|
if (IsSinglePlayer)
|
||||||
|
{
|
||||||
|
//radio is the only allowed special message type in single player
|
||||||
|
if (command != "r" && command != "radio")
|
||||||
|
{
|
||||||
|
command = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case "r":
|
||||||
|
case "radio":
|
||||||
|
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Radio];
|
||||||
|
break;
|
||||||
|
case "d":
|
||||||
|
case "dead":
|
||||||
|
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (Character.Controlled != null && (Character.Controlled.IsDead || Character.Controlled.SpeechImpediment >= 100.0f))
|
||||||
|
{
|
||||||
|
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
|
||||||
|
}
|
||||||
|
else if (command != "") //PMing
|
||||||
|
{
|
||||||
|
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Private];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMessage(ChatMessage message)
|
||||||
|
{
|
||||||
|
while (chatBox.Content.CountChildren > 20)
|
||||||
|
{
|
||||||
|
chatBox.RemoveChild(chatBox.Content.Children.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
float prevSize = chatBox.BarSize;
|
||||||
|
|
||||||
|
string displayedText = message.Text;
|
||||||
|
string senderName = "";
|
||||||
|
if (!string.IsNullOrWhiteSpace(message.SenderName))
|
||||||
|
{
|
||||||
|
senderName = (message.Type == ChatMessageType.Private ? "[PM] " : "") + message.SenderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgHolder = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.0f), chatBox.Content.RectTransform, Anchor.TopCenter), style: null,
|
||||||
|
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f);
|
||||||
|
|
||||||
|
GUITextBlock senderNameBlock = null;
|
||||||
|
if (!string.IsNullOrEmpty(senderName))
|
||||||
|
{
|
||||||
|
senderNameBlock = new GUITextBlock(new RectTransform(new Vector2(0.98f, 0.0f), msgHolder.RectTransform)
|
||||||
|
{ AbsoluteOffset = new Point((int)(5 * GUI.Scale), 0) },
|
||||||
|
senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), msgHolder.RectTransform)
|
||||||
|
{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), senderNameBlock == null ? 0 : senderNameBlock.Rect.Height) },
|
||||||
|
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null, wrap: true,
|
||||||
|
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f)
|
||||||
|
{
|
||||||
|
UserData = message.SenderName,
|
||||||
|
CanBeFocused = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (message is OrderChatMessage orderChatMsg &&
|
||||||
|
Character.Controlled != null &&
|
||||||
|
orderChatMsg.TargetCharacter == Character.Controlled)
|
||||||
|
{
|
||||||
|
msgHolder.Flash(Color.OrangeRed * 0.6f, flashDuration: 5.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msgHolder.Flash(Color.Yellow * 0.6f);
|
||||||
|
}
|
||||||
|
//resize the holder to match the size of the message and add some spacing
|
||||||
|
msgHolder.RectTransform.Resize(new Point(msgHolder.Rect.Width, msgHolder.Children.Sum(c => c.Rect.Height) + (int)(10 * GUI.Scale)), resizeChildren: false);
|
||||||
|
|
||||||
|
CoroutineManager.StartCoroutine(UpdateMessageAnimation(msgHolder, 0.5f));
|
||||||
|
|
||||||
|
chatBox.UpdateScrollBarSize();
|
||||||
|
|
||||||
|
if (!toggleOpen)
|
||||||
|
{
|
||||||
|
var popupMsg = new GUIFrame(new RectTransform(Vector2.One, guiFrame.RectTransform), style: "GUIToolTip")
|
||||||
|
{
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), popupMsg.RectTransform, Anchor.TopRight),
|
||||||
|
senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
var msgText = 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(
|
||||||
|
msgText.Font.MeasureString(msgText.WrappedText).X,
|
||||||
|
senderText.Font.MeasureString(senderText.WrappedText).X);
|
||||||
|
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
|
||||||
|
popupMessages.Enqueue(popupMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f;
|
||||||
|
|
||||||
|
GUISoundType soundType = GUISoundType.Message;
|
||||||
|
if (message.Type == ChatMessageType.Radio)
|
||||||
|
{
|
||||||
|
soundType = GUISoundType.RadioMessage;
|
||||||
|
}
|
||||||
|
else if (message.Type == ChatMessageType.Dead)
|
||||||
|
{
|
||||||
|
soundType = GUISoundType.DeadMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.PlayUISound(soundType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> UpdateMessageAnimation(GUIComponent message, float animDuration)
|
||||||
|
{
|
||||||
|
float timer = 0.0f;
|
||||||
|
while (timer < animDuration)
|
||||||
|
{
|
||||||
|
timer += CoroutineManager.DeltaTime;
|
||||||
|
float wavePhase = timer / animDuration * MathHelper.TwoPi;
|
||||||
|
message.RectTransform.ScreenSpaceOffset =
|
||||||
|
new Point((int)(Math.Sin(wavePhase) * (1.0f - timer / animDuration) * 50.0f), 0);
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
}
|
||||||
|
message.RectTransform.ScreenSpaceOffset = Point.Zero;
|
||||||
|
yield return CoroutineStatus.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetUILayout()
|
||||||
|
{
|
||||||
|
guiFrame.RectTransform.AbsoluteOffset = Point.Zero;
|
||||||
|
guiFrame.RectTransform.RelativeOffset = new Vector2(
|
||||||
|
HUDLayoutSettings.ChatBoxArea.X / (float)GameMain.GraphicsWidth,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
guiFrame.RectTransform.NonScaledSize -= 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
|
||||||
|
{
|
||||||
|
SetUILayout();
|
||||||
|
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
prevUIScale = GUI.Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (toggleOpen || (inputBox != null && inputBox.Selected))
|
||||||
|
{
|
||||||
|
openState += deltaTime * 5.0f;
|
||||||
|
//delete all popup messages when the chatbox is open
|
||||||
|
while (popupMessages.Count > 0)
|
||||||
|
{
|
||||||
|
var popupMsg = popupMessages.Dequeue();
|
||||||
|
popupMsg.Parent.RemoveChild(popupMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
openState -= deltaTime * 5.0f;
|
||||||
|
|
||||||
|
//make the first popup message visible
|
||||||
|
var popupMsg = popupMessages.Count > 0 ? popupMessages.Peek() : null;
|
||||||
|
if (popupMsg != null)
|
||||||
|
{
|
||||||
|
popupMsg.Visible = true;
|
||||||
|
//popup messages appear and disappear faster when there's more pending messages
|
||||||
|
popupMessageTimer += deltaTime * popupMessages.Count * popupMessages.Count;
|
||||||
|
if (popupMessageTimer > PopupMessageDuration)
|
||||||
|
{
|
||||||
|
//move the message out of the screen and delete it
|
||||||
|
popupMsg.RectTransform.ScreenSpaceOffset =
|
||||||
|
new Point((int)MathHelper.SmoothStep(-popupMsg.Rect.Width - toggleButton.Rect.Width * 2, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
|
||||||
|
if (popupMessageTimer > PopupMessageDuration + 1.0f)
|
||||||
|
{
|
||||||
|
popupMessageTimer = 0.0f;
|
||||||
|
popupMsg.Parent.RemoveChild(popupMsg);
|
||||||
|
popupMessages.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//move the message on the screen
|
||||||
|
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
|
||||||
|
(int)MathHelper.SmoothStep(0, -popupMsg.Rect.Width - toggleButton.Rect.Width * 2 - (int)(35 * GUI.Scale), popupMessageTimer * 5.0f), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openState = MathHelper.Clamp(openState, 0.0f, 1.0f);
|
||||||
|
int hiddenBoxOffset = guiFrame.Rect.Width + toggleButton.Rect.Width;
|
||||||
|
if (radioButton != null) hiddenBoxOffset += (int)(radioButton.Rect.Width * 1.5f);
|
||||||
|
guiFrame.RectTransform.AbsoluteOffset =
|
||||||
|
new Point((int)MathHelper.SmoothStep(hiddenBoxOffset * (HUDLayoutSettings.ChatBoxAlignment == Alignment.Left ? -1 : 1), 0, openState), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,46 +5,6 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
public class UISprite
|
|
||||||
{
|
|
||||||
public Sprite Sprite
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Tile
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Slice
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rectangle[] Slices
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MaintainAspectRatio
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UISprite(Sprite sprite, bool tile, bool maintainAspectRatio)
|
|
||||||
{
|
|
||||||
Sprite = sprite;
|
|
||||||
Tile = tile;
|
|
||||||
MaintainAspectRatio = maintainAspectRatio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GUIComponentStyle
|
public class GUIComponentStyle
|
||||||
{
|
{
|
||||||
public readonly Vector4 Padding;
|
public readonly Vector4 Padding;
|
||||||
@@ -55,6 +15,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public readonly Color HoverColor;
|
public readonly Color HoverColor;
|
||||||
public readonly Color SelectedColor;
|
public readonly Color SelectedColor;
|
||||||
|
public readonly Color PressedColor;
|
||||||
|
|
||||||
public readonly Color OutlineColor;
|
public readonly Color OutlineColor;
|
||||||
|
|
||||||
@@ -74,68 +35,34 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Padding = element.GetAttributeVector4("padding", Vector4.Zero);
|
Padding = element.GetAttributeVector4("padding", Vector4.Zero);
|
||||||
|
|
||||||
Vector4 colorVector = element.GetAttributeVector4("color", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
|
Color = element.GetAttributeColor("color", Color.Transparent);
|
||||||
Color = new Color(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W);
|
textColor = element.GetAttributeColor("textcolor", Color.Black);
|
||||||
|
HoverColor = element.GetAttributeColor("hovercolor", Color.Transparent);
|
||||||
|
SelectedColor = element.GetAttributeColor("selectedcolor", Color.Transparent);
|
||||||
|
PressedColor = element.GetAttributeColor("pressedcolor", Color.Transparent);
|
||||||
|
OutlineColor = element.GetAttributeColor("outlinecolor", Color.Transparent);
|
||||||
|
|
||||||
colorVector = element.GetAttributeVector4("textcolor", new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
|
|
||||||
textColor = new Color(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W);
|
|
||||||
|
|
||||||
colorVector = element.GetAttributeVector4("hovercolor", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
|
|
||||||
HoverColor = new Color(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W);
|
|
||||||
|
|
||||||
colorVector = element.GetAttributeVector4("selectedcolor", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
|
|
||||||
SelectedColor = new Color(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W);
|
|
||||||
|
|
||||||
colorVector = element.GetAttributeVector4("outlinecolor", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
|
|
||||||
OutlineColor = new Color(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W);
|
|
||||||
|
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "sprite":
|
case "sprite":
|
||||||
Sprite sprite = new Sprite(subElement);
|
UISprite newSprite = new UISprite(subElement);
|
||||||
bool maintainAspect = subElement.GetAttributeBool("maintainaspectratio",false);
|
|
||||||
bool tile = subElement.GetAttributeBool("tile", true);
|
|
||||||
|
|
||||||
string stateStr = subElement.GetAttributeString("state", "None");
|
|
||||||
GUIComponent.ComponentState spriteState = GUIComponent.ComponentState.None;
|
GUIComponent.ComponentState spriteState = GUIComponent.ComponentState.None;
|
||||||
Enum.TryParse(stateStr, out spriteState);
|
if (subElement.Attribute("state") != null)
|
||||||
|
|
||||||
UISprite newSprite = new UISprite(sprite, tile, maintainAspect);
|
|
||||||
|
|
||||||
Vector4 sliceVec = subElement.GetAttributeVector4("slice", Vector4.Zero);
|
|
||||||
if (sliceVec != Vector4.Zero)
|
|
||||||
{
|
{
|
||||||
Rectangle slice = new Rectangle((int)sliceVec.X, (int)sliceVec.Y, (int)(sliceVec.Z - sliceVec.X), (int)(sliceVec.W - sliceVec.Y));
|
string stateStr = subElement.GetAttributeString("state", "None");
|
||||||
|
Enum.TryParse(stateStr, out spriteState);
|
||||||
newSprite.Slice = true;
|
Sprites[spriteState].Add(newSprite);
|
||||||
|
}
|
||||||
newSprite.Slices = new Rectangle[9];
|
else
|
||||||
|
{
|
||||||
//top-left
|
foreach (GUIComponent.ComponentState state in Enum.GetValues(typeof(GUIComponent.ComponentState)))
|
||||||
newSprite.Slices[0] = new Rectangle(newSprite.Sprite.SourceRect.Location, slice.Location - newSprite.Sprite.SourceRect.Location);
|
{
|
||||||
//top-mid
|
Sprites[state].Add(newSprite);
|
||||||
newSprite.Slices[1] = new Rectangle(slice.Location.X, newSprite.Slices[0].Y, slice.Width, newSprite.Slices[0].Height);
|
}
|
||||||
//top-right
|
|
||||||
newSprite.Slices[2] = new Rectangle(slice.Right, newSprite.Slices[0].Y, newSprite.Sprite.SourceRect.Right - slice.Right, newSprite.Slices[0].Height);
|
|
||||||
|
|
||||||
//mid-left
|
|
||||||
newSprite.Slices[3] = new Rectangle(newSprite.Slices[0].X, slice.Y, newSprite.Slices[0].Width, slice.Height);
|
|
||||||
//center
|
|
||||||
newSprite.Slices[4] = slice;
|
|
||||||
//mid-right
|
|
||||||
newSprite.Slices[5] = new Rectangle(newSprite.Slices[2].X, slice.Y, newSprite.Slices[2].Width, slice.Height);
|
|
||||||
|
|
||||||
//bottom-left
|
|
||||||
newSprite.Slices[6] = new Rectangle(newSprite.Slices[0].X, slice.Bottom, newSprite.Slices[0].Width, newSprite.Sprite.SourceRect.Bottom - slice.Bottom);
|
|
||||||
//bottom-mid
|
|
||||||
newSprite.Slices[7] = new Rectangle(newSprite.Slices[1].X, slice.Bottom, newSprite.Slices[1].Width, newSprite.Sprite.SourceRect.Bottom - slice.Bottom);
|
|
||||||
//bottom-right
|
|
||||||
newSprite.Slices[8] = new Rectangle(newSprite.Slices[2].X, slice.Bottom, newSprite.Slices[2].Width, newSprite.Sprite.SourceRect.Bottom - slice.Bottom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprites[spriteState].Add(newSprite);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ChildStyles.Add(subElement.Name.ToString().ToLowerInvariant(), new GUIComponentStyle(subElement));
|
ChildStyles.Add(subElement.Name.ToString().ToLowerInvariant(), new GUIComponentStyle(subElement));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,9 @@ namespace Barotrauma
|
|||||||
public class GUIButton : GUIComponent
|
public class GUIButton : GUIComponent
|
||||||
{
|
{
|
||||||
protected GUITextBlock textBlock;
|
protected GUITextBlock textBlock;
|
||||||
|
public GUITextBlock TextBlock { get { return textBlock; } }
|
||||||
protected GUIFrame frame;
|
protected GUIFrame frame;
|
||||||
|
public GUIFrame Frame { get { return frame; } }
|
||||||
|
|
||||||
public delegate bool OnClickedHandler(GUIButton button, object obj);
|
public delegate bool OnClickedHandler(GUIButton button, object obj);
|
||||||
public OnClickedHandler OnClicked;
|
public OnClickedHandler OnClicked;
|
||||||
@@ -14,11 +16,12 @@ namespace Barotrauma
|
|||||||
public delegate bool OnPressedHandler();
|
public delegate bool OnPressedHandler();
|
||||||
public OnPressedHandler OnPressed;
|
public OnPressedHandler OnPressed;
|
||||||
|
|
||||||
|
public delegate bool OnButtonDownHandler();
|
||||||
|
public OnButtonDownHandler OnButtonDown;
|
||||||
|
|
||||||
public bool CanBeSelected = true;
|
public bool CanBeSelected = true;
|
||||||
|
|
||||||
private bool enabled;
|
public override bool Enabled
|
||||||
|
|
||||||
public bool Enabled
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -28,7 +31,6 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == enabled) return;
|
if (value == enabled) return;
|
||||||
|
|
||||||
enabled = value;
|
enabled = value;
|
||||||
frame.Color = enabled ? color : Color.Gray * 0.7f;
|
frame.Color = enabled ? color : Color.Gray * 0.7f;
|
||||||
}
|
}
|
||||||
@@ -67,6 +69,19 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Color PressedColor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.PressedColor;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.PressedColor = value;
|
||||||
|
frame.PressedColor = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override Color OutlineColor
|
public override Color OutlineColor
|
||||||
{
|
{
|
||||||
get { return base.OutlineColor; }
|
get { return base.OutlineColor; }
|
||||||
@@ -114,62 +129,22 @@ namespace Barotrauma
|
|||||||
base.ToolTip = value;
|
base.ToolTip = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Rectangle Rect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base.Rect = value;
|
|
||||||
|
|
||||||
frame.Rect = new Rectangle(value.X, value.Y, frame.Rect.Width, frame.Rect.Height);
|
|
||||||
textBlock.Rect = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Selected { get; set; }
|
public bool Selected { get; set; }
|
||||||
|
|
||||||
public GUIButton(Rectangle rect, string text, string style, GUIComponent parent = null)
|
public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : base(style, rectT)
|
||||||
: this(rect, text, null, Alignment.Left, style, parent)
|
|
||||||
{
|
{
|
||||||
}
|
if (color.HasValue)
|
||||||
|
{
|
||||||
public GUIButton(Rectangle rect, string text, Alignment alignment, string style, GUIComponent parent = null)
|
this.color = color.Value;
|
||||||
: this(rect, text, null, alignment, style, parent)
|
}
|
||||||
{
|
frame = new GUIFrame(new RectTransform(Vector2.One, rectT), style);
|
||||||
}
|
if (style != null) GUI.Style.Apply(frame, style == "" ? "GUIButton" : style);
|
||||||
|
textBlock = new GUITextBlock(new RectTransform(Vector2.One, rectT), text, textAlignment: textAlignment, style: null)
|
||||||
public GUIButton(Rectangle rect, string text, Color? color, string style, GUIComponent parent = null)
|
{
|
||||||
: this(rect, text, color, (Alignment.Left | Alignment.Top), style, parent)
|
TextColor = this.style == null ? Color.Black : this.style.textColor
|
||||||
{
|
};
|
||||||
}
|
GUI.Style.Apply(textBlock, "", this);
|
||||||
|
|
||||||
public GUIButton(Rectangle rect, string text, Color? color, Alignment alignment, string style = "", GUIComponent parent = null)
|
|
||||||
: this(rect, text, color, alignment, Alignment.Center, style, parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIButton(Rectangle rect, string text, Color? color, Alignment alignment, Alignment textAlignment, string style = "", GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
if (color != null) this.color = (Color)color;
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
if (parent != null) parent.AddChild(this);
|
|
||||||
|
|
||||||
frame = new GUIFrame(Rectangle.Empty, style, this);
|
|
||||||
GUI.Style.Apply(frame, style == "" ? "GUIButton" : style);
|
|
||||||
|
|
||||||
textBlock = new GUITextBlock(Rectangle.Empty, text,
|
|
||||||
Color.Transparent, (this.style == null) ? Color.Black : this.style.textColor,
|
|
||||||
textAlignment, null, this);
|
|
||||||
GUI.Style.Apply(textBlock, style, this);
|
|
||||||
|
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,28 +153,36 @@ namespace Barotrauma
|
|||||||
base.ApplyStyle(style);
|
base.ApplyStyle(style);
|
||||||
|
|
||||||
if (frame != null) frame.ApplyStyle(style);
|
if (frame != null) frame.ApplyStyle(style);
|
||||||
if (textBlock != null) textBlock.ApplyStyle(style);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
//do nothing
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
protected override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
if (rect.Contains(PlayerInput.MousePosition) && CanBeSelected && Enabled && (MouseOn == null || MouseOn == this || IsParentOf(MouseOn)))
|
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && Enabled && GUI.IsMouseOn(this))
|
||||||
{
|
{
|
||||||
state = ComponentState.Hover;
|
state = ComponentState.Hover;
|
||||||
|
if (PlayerInput.LeftButtonDown())
|
||||||
|
{
|
||||||
|
OnButtonDown?.Invoke();
|
||||||
|
}
|
||||||
if (PlayerInput.LeftButtonHeld())
|
if (PlayerInput.LeftButtonHeld())
|
||||||
{
|
{
|
||||||
if (OnPressed != null)
|
if (OnPressed != null)
|
||||||
{
|
{
|
||||||
if (OnPressed()) state = ComponentState.Pressed;
|
if (OnPressed())
|
||||||
|
{
|
||||||
|
state = ComponentState.Pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = ComponentState.Pressed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (PlayerInput.LeftButtonClicked())
|
else if (PlayerInput.LeftButtonClicked())
|
||||||
@@ -207,7 +190,10 @@ namespace Barotrauma
|
|||||||
GUI.PlayUISound(GUISoundType.Click);
|
GUI.PlayUISound(GUISoundType.Click);
|
||||||
if (OnClicked != null)
|
if (OnClicked != null)
|
||||||
{
|
{
|
||||||
if (OnClicked(this, UserData) && CanBeSelected) state = ComponentState.Selected;
|
if (OnClicked(this, UserData) && CanBeSelected)
|
||||||
|
{
|
||||||
|
state = ComponentState.Selected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -220,7 +206,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
state = Selected ? ComponentState.Selected : ComponentState.None;
|
state = Selected ? ComponentState.Selected : ComponentState.None;
|
||||||
}
|
}
|
||||||
frame.State = state;
|
|
||||||
|
foreach (GUIComponent child in Children)
|
||||||
|
{
|
||||||
|
child.State = state;
|
||||||
|
}
|
||||||
|
//frame.State = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
public class GUICanvas : RectTransform
|
||||||
|
{
|
||||||
|
protected GUICanvas() : base(Vector2.One, parent: null) { }
|
||||||
|
|
||||||
|
private static GUICanvas _instance;
|
||||||
|
public static GUICanvas Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = new GUICanvas();
|
||||||
|
if (GameMain.Instance != null)
|
||||||
|
{
|
||||||
|
GameMain.Instance.OnResolutionChanged += RecalculateSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn public, if there is a need to call this manually.
|
||||||
|
private static void RecalculateSize()
|
||||||
|
{
|
||||||
|
Instance.Resize(Vector2.One, resizeChildren: true);
|
||||||
|
Instance.GetAllChildren().Select(c => c.GUIComponent as GUITextBlock).ForEach(t => t?.SetTextPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,96 +1,134 @@
|
|||||||
using EventInput;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
public abstract class GUIComponent
|
public abstract class GUIComponent
|
||||||
{
|
{
|
||||||
const float FlashDuration = 1.5f;
|
#region Hierarchy
|
||||||
|
public GUIComponent Parent => RectTransform.Parent?.GUIComponent;
|
||||||
|
|
||||||
public static GUIComponent MouseOn
|
public IEnumerable<GUIComponent> Children => RectTransform.Children.Select(c => c.GUIComponent);
|
||||||
|
|
||||||
|
public T GetChild<T>() where T : GUIComponent
|
||||||
{
|
{
|
||||||
get;
|
return Children.FirstOrDefault(c => c is T) as T;
|
||||||
private set;
|
|
||||||
}
|
|
||||||
public static void ForceMouseOn(GUIComponent c)
|
|
||||||
{
|
|
||||||
MouseOn = c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static List<GUIComponent> ComponentsToUpdate = new List<GUIComponent>();
|
public T GetAnyChild<T>() where T : GUIComponent
|
||||||
|
|
||||||
public virtual void AddToGUIUpdateList()
|
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
return GetAllChildren().FirstOrDefault(c => c is T) as T;
|
||||||
if (ComponentsToUpdate.Contains(this)) return;
|
}
|
||||||
ComponentsToUpdate.Add(this);
|
|
||||||
|
public GUIComponent GetChild(int index)
|
||||||
List<GUIComponent> fixedChildren = new List<GUIComponent>(children);
|
{
|
||||||
foreach (GUIComponent c in fixedChildren)
|
if (index < 0 || index >= CountChildren) return null;
|
||||||
|
return RectTransform.GetChild(index).GUIComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetChildIndex(GUIComponent child)
|
||||||
|
{
|
||||||
|
if (child == null) return -1;
|
||||||
|
return RectTransform.GetChildIndex(child.RectTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIComponent GetChildByUserData(object obj)
|
||||||
|
{
|
||||||
|
foreach (GUIComponent child in Children)
|
||||||
{
|
{
|
||||||
c.AddToGUIUpdateList();
|
if (child.UserData == obj || (child.userData != null && child.userData.Equals(obj))) return child;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ClearUpdateList()
|
/// <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()
|
||||||
{
|
{
|
||||||
if (keyboardDispatcher != null &&
|
return RectTransform.GetAllChildren().Select(c => c.GUIComponent);
|
||||||
KeyboardDispatcher.Subscriber is GUIComponent &&
|
|
||||||
!ComponentsToUpdate.Contains((GUIComponent)KeyboardDispatcher.Subscriber))
|
|
||||||
{
|
|
||||||
KeyboardDispatcher.Subscriber = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentsToUpdate.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GUIComponent UpdateMouseOn()
|
public bool IsParentOf(GUIComponent component, bool recursive = true)
|
||||||
{
|
{
|
||||||
MouseOn = null;
|
if (component == null) { return false; }
|
||||||
for (int i = ComponentsToUpdate.Count - 1; i >= 0; i--)
|
return RectTransform.IsParentOf(component.RectTransform, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void RemoveChild(GUIComponent child)
|
||||||
|
{
|
||||||
|
if (child == null) return;
|
||||||
|
child.RectTransform.Parent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: refactor?
|
||||||
|
public GUIComponent FindChild(object userData, bool recursive = false)
|
||||||
|
{
|
||||||
|
var matchingChild = Children.FirstOrDefault(c => c.userData == userData);
|
||||||
|
if (recursive && matchingChild == null)
|
||||||
{
|
{
|
||||||
GUIComponent c = ComponentsToUpdate[i];
|
foreach (GUIComponent child in Children)
|
||||||
if (c.MouseRect.Contains(PlayerInput.MousePosition))
|
|
||||||
{
|
{
|
||||||
MouseOn = c;
|
matchingChild = child.FindChild(userData, recursive);
|
||||||
break;
|
if (matchingChild != null) return matchingChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MouseOn;
|
|
||||||
|
return matchingChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static KeyboardDispatcher keyboardDispatcher;
|
public IEnumerable<GUIComponent> FindChildren(object userData)
|
||||||
|
{
|
||||||
|
return Children.Where(c => c.userData == userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ClearChildren()
|
||||||
|
{
|
||||||
|
RectTransform.ClearChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAsLastChild()
|
||||||
|
{
|
||||||
|
RectTransform.SetAsLastChild();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public bool AutoUpdate { get; set; } = true;
|
||||||
|
public bool AutoDraw { get; set; } = true;
|
||||||
|
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 };
|
||||||
|
|
||||||
protected Alignment alignment;
|
protected Alignment alignment;
|
||||||
|
|
||||||
protected GUIComponentStyle style;
|
protected GUIComponentStyle style;
|
||||||
|
|
||||||
protected object userData;
|
protected object userData;
|
||||||
|
|
||||||
protected Rectangle rect;
|
|
||||||
|
|
||||||
public bool CanBeFocused;
|
public bool CanBeFocused;
|
||||||
|
|
||||||
protected Vector4 padding;
|
|
||||||
|
|
||||||
protected Color color;
|
protected Color color;
|
||||||
protected Color hoverColor;
|
protected Color hoverColor;
|
||||||
protected Color selectedColor;
|
protected Color selectedColor;
|
||||||
|
protected Color pressedColor;
|
||||||
protected GUIComponent parent;
|
|
||||||
public List<GUIComponent> children;
|
|
||||||
|
|
||||||
protected ComponentState state;
|
protected ComponentState state;
|
||||||
|
|
||||||
protected Color flashColor;
|
protected Color flashColor;
|
||||||
|
protected float flashDuration = 1.5f;
|
||||||
protected float flashTimer;
|
protected float flashTimer;
|
||||||
|
|
||||||
|
public bool IgnoreLayoutGroups;
|
||||||
|
|
||||||
public virtual ScalableFont Font
|
public virtual ScalableFont Font
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -114,26 +152,26 @@ namespace Barotrauma
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bool enabled;
|
||||||
|
public virtual bool Enabled
|
||||||
|
{
|
||||||
|
get { return enabled; }
|
||||||
|
set { enabled = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public bool TileSprites;
|
public bool TileSprites;
|
||||||
|
|
||||||
private static GUITextBlock toolTipBlock;
|
private static GUITextBlock toolTipBlock;
|
||||||
|
|
||||||
//protected float alpha;
|
|
||||||
|
|
||||||
public GUIComponent Parent
|
|
||||||
{
|
|
||||||
get { return parent; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 Center
|
public Vector2 Center
|
||||||
{
|
{
|
||||||
get { return new Vector2(rect.Center.X, rect.Center.Y); }
|
get { return new Vector2(Rect.Center.X, Rect.Center.Y); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Rectangle ClampRect(Rectangle r)
|
protected Rectangle ClampRect(Rectangle r)
|
||||||
{
|
{
|
||||||
if (parent == null || !ClampMouseRectToParent) return r;
|
if (Parent == null || !ClampMouseRectToParent) return r;
|
||||||
Rectangle parentRect = parent.ClampRect(parent.rect);
|
Rectangle parentRect = Parent.ClampRect(Parent.Rect);
|
||||||
if (parentRect.Width <= 0 || parentRect.Height <= 0) return Rectangle.Empty;
|
if (parentRect.Width <= 0 || parentRect.Height <= 0) return Rectangle.Empty;
|
||||||
if (parentRect.X > r.X)
|
if (parentRect.X > r.X)
|
||||||
{
|
{
|
||||||
@@ -163,46 +201,23 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public virtual Rectangle Rect
|
public virtual Rectangle Rect
|
||||||
{
|
{
|
||||||
get { return rect; }
|
get { return RectTransform.Rect; }
|
||||||
set
|
|
||||||
{
|
|
||||||
int prevX = rect.X, prevY = rect.Y;
|
|
||||||
int prevWidth = rect.Width, prevHeight = rect.Height;
|
|
||||||
|
|
||||||
rect = value;
|
|
||||||
|
|
||||||
if (prevX == rect.X && prevY == rect.Y && rect.Width == prevWidth && rect.Height == prevHeight) return;
|
|
||||||
|
|
||||||
//TODO: fix this (or replace with something better in the new GUI system)
|
|
||||||
//simply expanding the rects by the same amount as their parent only works correctly in some special cases
|
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
{
|
|
||||||
child.Rect = new Rectangle(
|
|
||||||
child.rect.X + (rect.X - prevX),
|
|
||||||
child.rect.Y + (rect.Y - prevY),
|
|
||||||
Math.Max(child.rect.Width + (rect.Width - prevWidth),0),
|
|
||||||
Math.Max(child.rect.Height + (rect.Height - prevHeight),0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent != null && parent is GUIListBox)
|
|
||||||
{
|
|
||||||
((GUIListBox)parent).UpdateScrollBarSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ClampMouseRectToParent = true;
|
public bool ClampMouseRectToParent { get; set; } = false;
|
||||||
public virtual Rectangle MouseRect
|
public virtual Rectangle MouseRect
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!CanBeFocused) return Rectangle.Empty;
|
if (!CanBeFocused) return Rectangle.Empty;
|
||||||
return ClampMouseRectToParent ? ClampRect(rect) : rect;
|
return ClampMouseRectToParent ? ClampRect(Rect) : Rect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<ComponentState, List<UISprite>> sprites;
|
public Dictionary<ComponentState, List<UISprite>> sprites;
|
||||||
|
|
||||||
|
public SpriteEffects SpriteEffects;
|
||||||
|
|
||||||
public virtual Color OutlineColor { get; set; }
|
public virtual Color OutlineColor { get; set; }
|
||||||
|
|
||||||
public ComponentState State
|
public ComponentState State
|
||||||
@@ -216,16 +231,10 @@ namespace Barotrauma
|
|||||||
get { return userData; }
|
get { return userData; }
|
||||||
set { userData = value; }
|
set { userData = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Vector4 Padding
|
|
||||||
{
|
|
||||||
get { return padding; }
|
|
||||||
set { padding = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CountChildren
|
public int CountChildren
|
||||||
{
|
{
|
||||||
get { return children.Count; }
|
get { return RectTransform.CountChildren; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Color Color
|
public virtual Color Color
|
||||||
@@ -246,9 +255,33 @@ namespace Barotrauma
|
|||||||
set { selectedColor = value; }
|
set { selectedColor = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static KeyboardDispatcher KeyboardDispatcher
|
public virtual Color PressedColor
|
||||||
{
|
{
|
||||||
get { return keyboardDispatcher; }
|
get { return pressedColor; }
|
||||||
|
set { pressedColor = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private RectTransform rectTransform;
|
||||||
|
public RectTransform RectTransform
|
||||||
|
{
|
||||||
|
get { return rectTransform; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
rectTransform = value;
|
||||||
|
// This is the only place where the element should be assigned!
|
||||||
|
if (rectTransform != null)
|
||||||
|
{
|
||||||
|
rectTransform.GUIComponent = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the new constructor.
|
||||||
|
/// </summary>
|
||||||
|
protected GUIComponent(string style, RectTransform rectT) : this(style)
|
||||||
|
{
|
||||||
|
RectTransform = rectT;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GUIComponent(string style)
|
protected GUIComponent(string style)
|
||||||
@@ -260,8 +293,6 @@ namespace Barotrauma
|
|||||||
OutlineColor = Color.Transparent;
|
OutlineColor = Color.Transparent;
|
||||||
|
|
||||||
Font = GUI.Font;
|
Font = GUI.Font;
|
||||||
|
|
||||||
children = new List<GUIComponent>();
|
|
||||||
|
|
||||||
CanBeFocused = true;
|
CanBeFocused = true;
|
||||||
|
|
||||||
@@ -269,50 +300,198 @@ namespace Barotrauma
|
|||||||
GUI.Style.Apply(this, style);
|
GUI.Style.Apply(this, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Init(GameWindow window)
|
#region Updating
|
||||||
|
public virtual void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||||
{
|
{
|
||||||
keyboardDispatcher = new KeyboardDispatcher(window);
|
if (!Visible) return;
|
||||||
|
|
||||||
|
UpdateOrder = order;
|
||||||
|
GUI.AddToUpdateList(this);
|
||||||
|
if (!ignoreChildren)
|
||||||
|
{
|
||||||
|
RectTransform.AddChildrenToGUIUpdateList(ignoreChildren, order);
|
||||||
|
}
|
||||||
|
OnAddedToGUIUpdateList?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetChild<T>() where T : GUIComponent
|
public void RemoveFromGUIUpdateList(bool alsoChildren = true)
|
||||||
{
|
{
|
||||||
foreach (GUIComponent child in children)
|
GUI.RemoveFromUpdateList(this, alsoChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Only GUI should call this method. Auto updating follows the order of GUI update list. This order can be tweaked by changing the UpdateOrder property.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateAuto(float deltaTime)
|
||||||
|
{
|
||||||
|
if (AutoUpdate)
|
||||||
{
|
{
|
||||||
if (child is T) return (T)(object)child;
|
Update(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// By default, all the gui elements are updated automatically in the same order they appear on the update list.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateManually(float deltaTime, bool alsoChildren = false, bool recursive = true)
|
||||||
|
{
|
||||||
|
if (!Visible) return;
|
||||||
|
|
||||||
|
AutoUpdate = false;
|
||||||
|
Update(deltaTime);
|
||||||
|
if (alsoChildren)
|
||||||
|
{
|
||||||
|
UpdateChildren(deltaTime, recursive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!Visible) return;
|
||||||
|
if (flashTimer > 0.0f)
|
||||||
|
{
|
||||||
|
flashTimer -= deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates all the children manually.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateChildren(float deltaTime, bool recursive)
|
||||||
|
{
|
||||||
|
RectTransform.Children.ForEach(c => c.GUIComponent.UpdateManually(deltaTime, recursive, recursive));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Drawing
|
||||||
|
/// <summary>
|
||||||
|
/// Only GUI should call this method. Auto drawing follows the order of GUI update list. This order can be tweaked by changing the UpdateOrder property.
|
||||||
|
/// </summary>
|
||||||
|
public void DrawAuto(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
if (AutoDraw)
|
||||||
|
{
|
||||||
|
Draw(spriteBatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// By default, all the gui elements are drawn automatically in the same order they appear on the update list.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void DrawManually(SpriteBatch spriteBatch, bool alsoChildren = false, bool recursive = true)
|
||||||
|
{
|
||||||
|
if (!Visible) return;
|
||||||
|
|
||||||
|
AutoDraw = false;
|
||||||
|
Draw(spriteBatch);
|
||||||
|
if (alsoChildren)
|
||||||
|
{
|
||||||
|
DrawChildren(spriteBatch, recursive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws all the children manually.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void DrawChildren(SpriteBatch spriteBatch, bool recursive)
|
||||||
|
{
|
||||||
|
RectTransform.Children.ForEach(c => c.GUIComponent.DrawManually(spriteBatch, recursive, recursive));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Color GetCurrentColor(ComponentState state)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case ComponentState.Hover:
|
||||||
|
return HoverColor;
|
||||||
|
case ComponentState.Pressed:
|
||||||
|
return PressedColor;
|
||||||
|
case ComponentState.Selected:
|
||||||
|
return SelectedColor;
|
||||||
|
default:
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
foreach (UISprite uiSprite in sprites[state])
|
||||||
|
{
|
||||||
|
uiSprite.Draw(spriteBatch, rect, currColor * (currColor.A / 255.0f), SpriteEffects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return default(T);
|
if (flashTimer > 0.0f)
|
||||||
}
|
|
||||||
|
|
||||||
public GUIComponent GetChild(object obj)
|
|
||||||
{
|
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
{
|
{
|
||||||
if (child.UserData == obj) return child;
|
//the number of flashes depends on the duration, 1 flash per 1 full second
|
||||||
|
int flashCycleCount = (int)Math.Max(flashDuration, 1);
|
||||||
|
float flashCycleDuration = flashDuration / flashCycleCount;
|
||||||
|
|
||||||
|
//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
|
||||||
|
GUI.UIGlow.Draw(spriteBatch,
|
||||||
|
rect,
|
||||||
|
flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsParentOf(GUIComponent component)
|
/// <summary>
|
||||||
|
/// Creates and draws a tooltip.
|
||||||
|
/// </summary>
|
||||||
|
public void DrawToolTip(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
for(int i = children.Count - 1; i >= 0; i--)
|
if (!Visible) return;
|
||||||
|
|
||||||
|
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle targetElement)
|
||||||
|
{
|
||||||
|
int width = 400;
|
||||||
|
if (toolTipBlock == null || (string)toolTipBlock.userData != toolTip)
|
||||||
{
|
{
|
||||||
if (children[i] == component) return true;
|
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, 18), null), toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
|
||||||
if (children[i].IsParentOf(component)) return true;
|
toolTipBlock.RectTransform.NonScaledSize = new Point(
|
||||||
|
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + 20),
|
||||||
|
toolTipBlock.WrappedText.Split('\n').Length * 18 + 7);
|
||||||
|
toolTipBlock.userData = toolTip;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
toolTipBlock.RectTransform.AbsoluteOffset = new Point(targetElement.Center.X, targetElement.Bottom);
|
||||||
|
if (toolTipBlock.Rect.Right > GameMain.GraphicsWidth - 10)
|
||||||
|
{
|
||||||
|
toolTipBlock.RectTransform.AbsoluteOffset -= new Point(toolTipBlock.Rect.Width, 0);
|
||||||
|
}
|
||||||
|
if (toolTipBlock.Rect.Bottom > GameMain.GraphicsHeight - 10)
|
||||||
|
{
|
||||||
|
toolTipBlock.RectTransform.AbsoluteOffset -= new Point(
|
||||||
|
(targetElement.Width / 2) * Math.Sign(targetElement.Center.X - toolTipBlock.Center.X),
|
||||||
|
toolTipBlock.Rect.Bottom - (GameMain.GraphicsHeight - 10));
|
||||||
|
}
|
||||||
|
toolTipBlock.SetTextPos();
|
||||||
|
|
||||||
|
toolTipBlock.DrawManually(spriteBatch);
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
protected virtual void SetAlpha(float a)
|
protected virtual void SetAlpha(float a)
|
||||||
{
|
{
|
||||||
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
|
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Flash(Color? color = null)
|
public virtual void Flash(Color? color = null, float flashDuration = 1.5f)
|
||||||
{
|
{
|
||||||
flashTimer = FlashDuration;
|
flashTimer = flashDuration;
|
||||||
flashColor = (color == null) ? Color.Red * 0.8f : (Color)color;
|
this.flashDuration = flashDuration;
|
||||||
|
flashColor = (color == null) ? Color.Red : (Color)color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FadeOut(float duration, bool removeAfter)
|
public void FadeOut(float duration, bool removeAfter)
|
||||||
@@ -336,206 +515,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
SetAlpha(to);
|
SetAlpha(to);
|
||||||
|
|
||||||
if (removeAfter && parent != null)
|
if (removeAfter && Parent != null)
|
||||||
{
|
{
|
||||||
parent.RemoveChild(this);
|
Parent.RemoveChild(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
Color currColor = color;
|
|
||||||
if (state == ComponentState.Selected) currColor = selectedColor;
|
|
||||||
if (state == ComponentState.Hover) currColor = hoverColor;
|
|
||||||
|
|
||||||
if (flashTimer > 0.0f)
|
|
||||||
{
|
|
||||||
GUI.DrawRectangle(spriteBatch,
|
|
||||||
new Rectangle(rect.X - 5, rect.Y - 5, rect.Width + 10, rect.Height + 10),
|
|
||||||
flashColor * (flashTimer / FlashDuration), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
foreach (UISprite uiSprite in sprites[state])
|
|
||||||
{
|
|
||||||
if (uiSprite.Slice)
|
|
||||||
{
|
|
||||||
Vector2 pos = new Vector2(rect.X, rect.Y);
|
|
||||||
|
|
||||||
int centerWidth = Math.Max(rect.Width - uiSprite.Slices[0].Width - uiSprite.Slices[2].Width, 0);
|
|
||||||
int centerHeight = Math.Max(rect.Height - uiSprite.Slices[0].Height - uiSprite.Slices[8].Height, 0);
|
|
||||||
|
|
||||||
Vector2 scale = new Vector2(
|
|
||||||
MathHelper.Clamp((float)rect.Width / (uiSprite.Slices[0].Width + uiSprite.Slices[2].Width),0, 1),
|
|
||||||
MathHelper.Clamp((float)rect.Height / (uiSprite.Slices[0].Height + uiSprite.Slices[6].Height), 0, 1));
|
|
||||||
|
|
||||||
for (int x = 0; x < 3; x++)
|
|
||||||
{
|
|
||||||
float width = (x == 1 ? centerWidth : uiSprite.Slices[x].Width) * scale.X;
|
|
||||||
for (int y = 0; y < 3; y++)
|
|
||||||
{
|
|
||||||
float height = (y == 1 ? centerHeight : uiSprite.Slices[x + y * 3].Height) * scale.Y;
|
|
||||||
|
|
||||||
spriteBatch.Draw(uiSprite.Sprite.Texture,
|
|
||||||
new Rectangle((int)pos.X, (int)pos.Y, (int)width, (int)height),
|
|
||||||
uiSprite.Slices[x + y * 3],
|
|
||||||
currColor * (currColor.A / 255.0f));
|
|
||||||
|
|
||||||
pos.Y += height;
|
|
||||||
}
|
|
||||||
pos.X += width;
|
|
||||||
pos.Y = rect.Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (uiSprite.Tile)
|
|
||||||
{
|
|
||||||
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
|
||||||
Vector2 size = new Vector2(Math.Min(uiSprite.Sprite.SourceRect.Width, rect.Width), Math.Min(uiSprite.Sprite.SourceRect.Height, rect.Height));
|
|
||||||
|
|
||||||
if (uiSprite.Sprite.size.X == 0.0f) size.X = rect.Width;
|
|
||||||
if (uiSprite.Sprite.size.Y == 0.0f) size.Y = rect.Height;
|
|
||||||
|
|
||||||
uiSprite.Sprite.DrawTiled(spriteBatch, startPos, size, color: currColor * (currColor.A / 255.0f));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (uiSprite.MaintainAspectRatio)
|
|
||||||
{
|
|
||||||
float scale = (float)(rect.Width) / uiSprite.Sprite.SourceRect.Width;
|
|
||||||
|
|
||||||
spriteBatch.Draw(uiSprite.Sprite.Texture, rect,
|
|
||||||
new Rectangle(uiSprite.Sprite.SourceRect.X, uiSprite.Sprite.SourceRect.Y, (int)(uiSprite.Sprite.SourceRect.Width), (int)(rect.Height / scale)),
|
|
||||||
currColor * (currColor.A / 255.0f), 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(uiSprite.Sprite.Texture, rect, uiSprite.Sprite.SourceRect, currColor * (currColor.A / 255.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawToolTip(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
int width = 400;
|
|
||||||
if (toolTipBlock == null || (string)toolTipBlock.userData != ToolTip)
|
|
||||||
{
|
|
||||||
toolTipBlock = new GUITextBlock(new Rectangle(0, 0, width, 18), ToolTip, "GUIToolTip", Alignment.TopLeft, Alignment.TopLeft, null, true, GUI.SmallFont);
|
|
||||||
toolTipBlock.padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
|
||||||
toolTipBlock.rect.Width = (int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + 20);
|
|
||||||
toolTipBlock.rect.Height = toolTipBlock.WrappedText.Split('\n').Length * 18 + 7;
|
|
||||||
toolTipBlock.userData = ToolTip;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
toolTipBlock.rect = new Rectangle(MouseOn.Rect.Center.X, MouseOn.rect.Bottom, toolTipBlock.rect.Width, toolTipBlock.rect.Height);
|
|
||||||
if (toolTipBlock.rect.Right > GameMain.GraphicsWidth - 10)
|
|
||||||
{
|
|
||||||
toolTipBlock.rect.Location -= new Point(toolTipBlock.rect.Right - (GameMain.GraphicsWidth - 10), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
toolTipBlock.Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Update(float deltaTime)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
if (flashTimer>0.0f) flashTimer -= deltaTime;
|
|
||||||
|
|
||||||
/*if (CanBeFocused)
|
|
||||||
{
|
|
||||||
if (rect.Contains(PlayerInput.MousePosition))
|
|
||||||
{
|
|
||||||
MouseOn = this;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (MouseOn == this) MouseOn = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//use a fixed list since children can change their order in the main children list
|
|
||||||
//TODO: maybe find a more efficient way of handling changes in list order
|
|
||||||
List<GUIComponent> fixedChildren = new List<GUIComponent>(children);
|
|
||||||
foreach (GUIComponent c in fixedChildren)
|
|
||||||
{
|
|
||||||
if (!c.Visible) continue;
|
|
||||||
c.Update(deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void SetDimensions(Point size, bool expandChildren = false)
|
|
||||||
{
|
|
||||||
Point expandAmount = size - rect.Size;
|
|
||||||
|
|
||||||
rect = new Rectangle(rect.X, rect.Y, size.X, size.Y);
|
|
||||||
|
|
||||||
if (expandChildren)
|
|
||||||
{
|
|
||||||
//TODO: fix this (or replace with something better in the new GUI system)
|
|
||||||
//simply expanding the rects by the same amount as their parent only works correctly in some special cases
|
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
{
|
|
||||||
child.Rect = new Rectangle(
|
|
||||||
child.rect.X,
|
|
||||||
child.rect.Y,
|
|
||||||
child.rect.Width + expandAmount.X,
|
|
||||||
child.rect.Height + expandAmount.Y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void UpdateDimensions(GUIComponent parent = null)
|
|
||||||
{
|
|
||||||
Rectangle parentRect = (parent == null) ? new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight) : parent.rect;
|
|
||||||
|
|
||||||
Vector4 padding = (parent == null) ? Vector4.Zero : parent.padding;
|
|
||||||
|
|
||||||
if (rect.Width == 0) rect.Width = parentRect.Width - rect.X
|
|
||||||
- (int)padding.X - (int)padding.Z;
|
|
||||||
|
|
||||||
if (rect.Height == 0) rect.Height = parentRect.Height - rect.Y
|
|
||||||
- (int)padding.Y - (int)padding.W;
|
|
||||||
|
|
||||||
if (alignment.HasFlag(Alignment.CenterX))
|
|
||||||
{
|
|
||||||
rect.X += parentRect.X + (int)parentRect.Width / 2 - (int)rect.Width / 2;
|
|
||||||
}
|
|
||||||
else if (alignment.HasFlag(Alignment.Right))
|
|
||||||
{
|
|
||||||
rect.X += parentRect.X + (int)parentRect.Width - (int)padding.Z - (int)rect.Width;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rect.X += parentRect.X + (int)padding.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alignment.HasFlag(Alignment.CenterY))
|
|
||||||
{
|
|
||||||
rect.Y += parentRect.Y + (int)parentRect.Height / 2 - (int)rect.Height / 2;
|
|
||||||
}
|
|
||||||
else if (alignment.HasFlag(Alignment.Bottom))
|
|
||||||
{
|
|
||||||
rect.Y += parentRect.Y + (int)parentRect.Height - (int)padding.W - (int)rect.Height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rect.Y += parentRect.Y + (int)padding.Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ApplyStyle(GUIComponentStyle style)
|
public virtual void ApplyStyle(GUIComponentStyle style)
|
||||||
{
|
{
|
||||||
if (style == null) return;
|
if (style == null) return;
|
||||||
@@ -543,77 +530,13 @@ namespace Barotrauma
|
|||||||
color = style.Color;
|
color = style.Color;
|
||||||
hoverColor = style.HoverColor;
|
hoverColor = style.HoverColor;
|
||||||
selectedColor = style.SelectedColor;
|
selectedColor = style.SelectedColor;
|
||||||
|
pressedColor = style.PressedColor;
|
||||||
|
|
||||||
padding = style.Padding;
|
|
||||||
sprites = style.Sprites;
|
sprites = style.Sprites;
|
||||||
|
|
||||||
OutlineColor = style.OutlineColor;
|
OutlineColor = style.OutlineColor;
|
||||||
|
|
||||||
this.style = style;
|
this.style = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void DrawChildren(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < children.Count; i++ )
|
|
||||||
{
|
|
||||||
children[i].Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void AddChild(GUIComponent child)
|
|
||||||
{
|
|
||||||
if (child == null) return;
|
|
||||||
if (child.IsParentOf(this))
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Tried to add the parent of a GUIComponent as a child.\n" + Environment.StackTrace);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (child == this)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Tried to add a GUIComponent as its own child\n" + Environment.StackTrace);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (children.Contains(child))
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Tried to add a the same child twice to a GUIComponent" + Environment.StackTrace);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
child.parent = this;
|
|
||||||
child.UpdateDimensions(this);
|
|
||||||
|
|
||||||
children.Add(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void RemoveChild(GUIComponent child)
|
|
||||||
{
|
|
||||||
if (child == null) return;
|
|
||||||
if (children.Contains(child)) children.Remove(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIComponent FindChild(object userData, bool recursive = false)
|
|
||||||
{
|
|
||||||
var matchingChild = children.FirstOrDefault(c => c.userData == userData);
|
|
||||||
if (recursive && matchingChild == null)
|
|
||||||
{
|
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
{
|
|
||||||
matchingChild = child.FindChild(userData, recursive);
|
|
||||||
if (matchingChild != null) return matchingChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchingChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<GUIComponent> FindChildren(object userData)
|
|
||||||
{
|
|
||||||
return children.FindAll(c => c.userData == userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ClearChildren()
|
|
||||||
{
|
|
||||||
children.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GUIComponent that can be used to render custom content on the UI
|
||||||
|
/// </summary>
|
||||||
|
class GUICustomComponent : GUIComponent
|
||||||
|
{
|
||||||
|
public Action<SpriteBatch, GUICustomComponent> OnDraw;
|
||||||
|
public Action<float, GUICustomComponent> OnUpdate;
|
||||||
|
|
||||||
|
public bool HideElementsOutsideFrame;
|
||||||
|
|
||||||
|
public GUICustomComponent(RectTransform rectT, Action<SpriteBatch, GUICustomComponent> onDraw = null, Action<float, GUICustomComponent> onUpdate = null) : base(null, rectT)
|
||||||
|
{
|
||||||
|
OnDraw = onDraw;
|
||||||
|
OnUpdate = onUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
if (!Visible) return;
|
||||||
|
|
||||||
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
|
if (HideElementsOutsideFrame)
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Rect);
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnDraw?.Invoke(spriteBatch, this);
|
||||||
|
|
||||||
|
if (HideElementsOutsideFrame)
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (Visible) OnUpdate?.Invoke(deltaTime, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -13,18 +14,23 @@ namespace Barotrauma
|
|||||||
private GUIButton button;
|
private GUIButton button;
|
||||||
private GUIListBox listBox;
|
private GUIListBox listBox;
|
||||||
|
|
||||||
|
private RectTransform currentListBoxParent;
|
||||||
|
private List<RectTransform> parentHierarchy = new List<RectTransform>();
|
||||||
|
|
||||||
|
private bool selectMultiple;
|
||||||
|
|
||||||
public bool Dropped { get; set; }
|
public bool Dropped { get; set; }
|
||||||
|
|
||||||
public object SelectedItemData
|
public object SelectedItemData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (listBox.Selected == null) return null;
|
if (listBox.SelectedComponent == null) return null;
|
||||||
return listBox.Selected.UserData;
|
return listBox.SelectedComponent.UserData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled
|
public override bool Enabled
|
||||||
{
|
{
|
||||||
get { return listBox.Enabled; }
|
get { return listBox.Enabled; }
|
||||||
set { listBox.Enabled = value; }
|
set { listBox.Enabled = value; }
|
||||||
@@ -32,7 +38,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public GUIComponent Selected
|
public GUIComponent Selected
|
||||||
{
|
{
|
||||||
get { return listBox.Selected; }
|
get { return listBox.SelectedComponent; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIListBox ListBox
|
public GUIListBox ListBox
|
||||||
@@ -44,7 +50,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (listBox.Selected == null) ? null : listBox.Selected.UserData;
|
return listBox.SelectedComponent?.UserData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +58,29 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (listBox.Selected == null) return -1;
|
if (listBox.SelectedComponent == null) return -1;
|
||||||
return listBox.children.FindIndex(x => x == listBox.Selected);
|
return listBox.Content.GetChildIndex(listBox.SelectedComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<object> selectedDataMultiple = new List<object>();
|
||||||
|
public IEnumerable<object> SelectedDataMultiple
|
||||||
|
{
|
||||||
|
get { return selectedDataMultiple; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<int> selectedIndexMultiple = new List<int>();
|
||||||
|
public IEnumerable<int> SelectedIndexMultiple
|
||||||
|
{
|
||||||
|
get { return selectedIndexMultiple; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return button.Text; }
|
||||||
|
set { button.Text = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToolTip
|
public override string ToolTip
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -70,56 +94,108 @@ namespace Barotrauma
|
|||||||
listBox.ToolTip = value;
|
listBox.ToolTip = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GUIDropDown(RectTransform rectT, string text = "", int elementCount = 4, string style = "", bool selectMultiple = false) : base(style, rectT)
|
||||||
public override Rectangle Rect
|
|
||||||
{
|
{
|
||||||
get
|
this.selectMultiple = selectMultiple;
|
||||||
|
|
||||||
|
button = new GUIButton(new RectTransform(Vector2.One, rectT), text, Alignment.CenterLeft, style: "GUIDropDown")
|
||||||
{
|
{
|
||||||
return base.Rect;
|
OnClicked = OnClicked
|
||||||
}
|
};
|
||||||
|
GUI.Style.Apply(button, "", this);
|
||||||
set
|
|
||||||
|
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, Anchor.BottomLeft, Pivot.TopLeft)
|
||||||
|
{ IsFixedSize = false }, style: style)
|
||||||
{
|
{
|
||||||
Point moveAmount = value.Location - rect.Location;
|
Enabled = !selectMultiple,
|
||||||
base.Rect = value;
|
OnSelected = SelectItem
|
||||||
|
};
|
||||||
|
|
||||||
button.Rect = new Rectangle(button.Rect.Location + moveAmount, button.Rect.Size);
|
currentListBoxParent = FindListBoxParent();
|
||||||
listBox.Rect = new Rectangle(listBox.Rect.Location + moveAmount, listBox.Rect.Size);
|
currentListBoxParent.GUIComponent.OnAddedToGUIUpdateList += AddListBoxToGUIUpdateList;
|
||||||
|
rectT.ParentChanged += (RectTransform newParent) =>
|
||||||
|
{
|
||||||
|
currentListBoxParent.GUIComponent.OnAddedToGUIUpdateList -= AddListBoxToGUIUpdateList;
|
||||||
|
if (newParent != null)
|
||||||
|
{
|
||||||
|
currentListBoxParent = FindListBoxParent();
|
||||||
|
currentListBoxParent.GUIComponent.OnAddedToGUIUpdateList += AddListBoxToGUIUpdateList;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the component after which the listbox should be drawn. Usually the parent of the dropdown, but if the dropdown
|
||||||
|
/// is the child of another GUIListBox, we need to draw our listbox after that because listboxes clip everything outside their rect.
|
||||||
|
/// </summary>
|
||||||
|
private RectTransform FindListBoxParent()
|
||||||
|
{
|
||||||
|
parentHierarchy.Clear();
|
||||||
|
parentHierarchy = new List<RectTransform>() { RectTransform.Parent };
|
||||||
|
while (parentHierarchy.Last().Parent != null)
|
||||||
|
{
|
||||||
|
parentHierarchy.Add(parentHierarchy.Last().Parent);
|
||||||
}
|
}
|
||||||
|
//find the parent GUIListBox highest in the hierarchy
|
||||||
|
for (int i = parentHierarchy.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (parentHierarchy[i].GUIComponent is GUIListBox) return parentHierarchy[i];
|
||||||
|
}
|
||||||
|
//or just go with the direct parent if there are no listboxes in the hierarchy
|
||||||
|
parentHierarchy.Clear();
|
||||||
|
parentHierarchy.Add(RectTransform.Parent);
|
||||||
|
return RectTransform.Parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIDropDown(Rectangle rect, string text, string style, GUIComponent parent = null)
|
|
||||||
: this(rect, text, style, Alignment.TopLeft, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIDropDown(Rectangle rect, string text, string style, Alignment alignment, GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
|
|
||||||
if (parent != null) parent.AddChild(this);
|
|
||||||
|
|
||||||
button = new GUIButton(this.rect, text, Color.White, alignment, Alignment.CenterLeft, "GUIDropDown", null);
|
|
||||||
GUI.Style.Apply(button, style, this);
|
|
||||||
|
|
||||||
button.OnClicked = OnClicked;
|
|
||||||
|
|
||||||
listBox = new GUIListBox(new Rectangle(this.rect.X, this.rect.Bottom, this.rect.Width, 200), style, null);
|
|
||||||
listBox.OnSelected = SelectItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddChild(GUIComponent child)
|
|
||||||
{
|
|
||||||
listBox.AddChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddItem(string text, object userData = null, string toolTip = "")
|
public void AddItem(string text, object userData = null, string toolTip = "")
|
||||||
{
|
{
|
||||||
GUITextBlock textBlock = new GUITextBlock(new Rectangle(0,0,0,20), text, "ListBoxElement", Alignment.TopLeft, Alignment.CenterLeft, listBox);
|
if (selectMultiple)
|
||||||
textBlock.UserData = userData;
|
{
|
||||||
textBlock.ToolTip = toolTip;
|
var frame = new GUIFrame(new RectTransform(new Point(button.Rect.Width, button.Rect.Height), listBox.Content.RectTransform)
|
||||||
|
{ IsFixedSize = false }, style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
UserData = userData,
|
||||||
|
ToolTip = toolTip
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITickBox(new RectTransform(new Point((int)(button.Rect.Height * 0.8f)), frame.RectTransform, anchor: Anchor.CenterLeft), text)
|
||||||
|
{
|
||||||
|
UserData = userData,
|
||||||
|
ToolTip = toolTip,
|
||||||
|
OnSelected = (GUITickBox tb) =>
|
||||||
|
{
|
||||||
|
List<string> texts = new List<string>();
|
||||||
|
selectedDataMultiple.Clear();
|
||||||
|
selectedIndexMultiple.Clear();
|
||||||
|
int i = 0;
|
||||||
|
foreach (GUIComponent child in ListBox.Content.Children)
|
||||||
|
{
|
||||||
|
var tickBox = child.GetChild<GUITickBox>();
|
||||||
|
if (tickBox.Selected)
|
||||||
|
{
|
||||||
|
selectedDataMultiple.Add(child.UserData);
|
||||||
|
selectedIndexMultiple.Add(i);
|
||||||
|
texts.Add(tickBox.Text);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
button.Text = string.Join(", ", texts);
|
||||||
|
OnSelected?.Invoke(tb.Parent, tb.Parent.UserData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new GUITextBlock(new RectTransform(new Point(button.Rect.Width, button.Rect.Height), listBox.Content.RectTransform)
|
||||||
|
{ IsFixedSize = false }, text, style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
UserData = userData,
|
||||||
|
ToolTip = toolTip
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClearChildren()
|
public override void ClearChildren()
|
||||||
@@ -127,44 +203,63 @@ namespace Barotrauma
|
|||||||
listBox.ClearChildren();
|
listBox.ClearChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GUIComponent> GetChildren()
|
public IEnumerable<GUIComponent> GetChildren()
|
||||||
{
|
{
|
||||||
return listBox.children;
|
return listBox.Content.Children;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectItem(GUIComponent component, object obj)
|
private bool SelectItem(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
GUITextBlock textBlock = component as GUITextBlock;
|
if (selectMultiple)
|
||||||
if (textBlock == null)
|
|
||||||
{
|
{
|
||||||
textBlock = component.GetChild<GUITextBlock>();
|
foreach (GUIComponent child in ListBox.Content.Children)
|
||||||
if (textBlock == null) return false;
|
{
|
||||||
|
var tickBox = child.GetChild<GUITickBox>();
|
||||||
|
if (obj == child.UserData) { tickBox.Selected = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUITextBlock textBlock = component as GUITextBlock;
|
||||||
|
if (textBlock == null)
|
||||||
|
{
|
||||||
|
textBlock = component.GetChild<GUITextBlock>();
|
||||||
|
if (textBlock == null) return false;
|
||||||
|
}
|
||||||
|
button.Text = textBlock.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.Text = textBlock.Text;
|
|
||||||
Dropped = false;
|
Dropped = false;
|
||||||
|
OnSelected?.Invoke(component, component.UserData);
|
||||||
if (OnSelected != null) OnSelected(component, component.UserData);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectItem(object userData)
|
public void SelectItem(object userData)
|
||||||
{
|
{
|
||||||
//GUIComponent child = listBox.children.FirstOrDefault(c => c.UserData == userData);
|
if (selectMultiple)
|
||||||
|
{
|
||||||
//if (child == null) return;
|
SelectItem(listBox.Content.FindChild(userData), userData);
|
||||||
|
}
|
||||||
listBox.Select(userData);
|
else
|
||||||
|
{
|
||||||
//SelectItem(child, userData);
|
listBox.Select(userData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select(int index)
|
public void Select(int index)
|
||||||
{
|
{
|
||||||
listBox.Select(index);
|
if (selectMultiple)
|
||||||
|
{
|
||||||
|
var child = listBox.Content.GetChild(index);
|
||||||
|
if (child != null)
|
||||||
|
{
|
||||||
|
SelectItem(null, child.UserData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
listBox.Select(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool wasOpened;
|
private bool wasOpened;
|
||||||
|
|
||||||
@@ -174,60 +269,68 @@ namespace Barotrauma
|
|||||||
|
|
||||||
wasOpened = true;
|
wasOpened = true;
|
||||||
Dropped = !Dropped;
|
Dropped = !Dropped;
|
||||||
|
if (Dropped && Enabled)
|
||||||
if (Dropped)
|
|
||||||
{
|
{
|
||||||
if (Enabled) OnDropped?.Invoke(this, userData);
|
OnDropped?.Invoke(this, userData);
|
||||||
if (parent.children[parent.children.Count - 1] != this)
|
listBox.UpdateScrollBarSize();
|
||||||
{
|
|
||||||
parent.children.Remove(this);
|
|
||||||
parent.children.Add(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
private void AddListBoxToGUIUpdateList(GUIComponent parent)
|
||||||
{
|
{
|
||||||
base.AddToGUIUpdateList();
|
//the parent is not our parent anymore :(
|
||||||
button.AddToGUIUpdateList();
|
//can happen when subscribed to a parent higher in the hierarchy (instead of the direct parent),
|
||||||
if (Dropped) listBox.AddToGUIUpdateList();
|
//and somewhere between this component and the higher parent a component was removed
|
||||||
|
for (int i = 1; i < parentHierarchy.Count; i++)
|
||||||
|
{
|
||||||
|
if (!parentHierarchy[i].IsParentOf(parentHierarchy[i - 1], recursive: false))
|
||||||
|
{
|
||||||
|
parent.OnAddedToGUIUpdateList -= AddListBoxToGUIUpdateList;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dropped)
|
||||||
|
{
|
||||||
|
listBox.AddToGUIUpdateList(false, UpdateOrder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void DrawManually(SpriteBatch spriteBatch, bool alsoChildren = false, bool recursive = true)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
|
AutoDraw = false;
|
||||||
|
Draw(spriteBatch);
|
||||||
|
if (alsoChildren)
|
||||||
|
{
|
||||||
|
button.DrawManually(spriteBatch, alsoChildren, recursive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||||
|
{
|
||||||
|
base.AddToGUIUpdateList(true, order);
|
||||||
|
if (!ignoreChildren)
|
||||||
|
{
|
||||||
|
button.AddToGUIUpdateList(false, order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!Visible) return;
|
||||||
wasOpened = false;
|
wasOpened = false;
|
||||||
|
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
|
|
||||||
if (Dropped && PlayerInput.LeftButtonClicked())
|
if (Dropped && PlayerInput.LeftButtonClicked())
|
||||||
{
|
{
|
||||||
Rectangle listBoxRect = listBox.Rect;
|
Rectangle listBoxRect = listBox.Rect;
|
||||||
listBoxRect.Width += 20;
|
|
||||||
if (!listBoxRect.Contains(PlayerInput.MousePosition) && !button.Rect.Contains(PlayerInput.MousePosition))
|
if (!listBoxRect.Contains(PlayerInput.MousePosition) && !button.Rect.Contains(PlayerInput.MousePosition))
|
||||||
{
|
{
|
||||||
Dropped = false;
|
Dropped = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.Update(deltaTime);
|
|
||||||
|
|
||||||
if (Dropped) listBox.Update(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
base.Draw(spriteBatch);
|
|
||||||
|
|
||||||
button.Draw(spriteBatch);
|
|
||||||
|
|
||||||
if (!Dropped) return;
|
|
||||||
listBox.Draw(spriteBatch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,32 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
public class GUIFrame : GUIComponent
|
public class GUIFrame : GUIComponent
|
||||||
{
|
{
|
||||||
public GUIFrame(Rectangle rect, string style = "", GUIComponent parent = null)
|
public GUIFrame(RectTransform rectT, string style = "", Color? color = null) : base(style, rectT)
|
||||||
: this(rect, null, (Alignment.Left | Alignment.Top), style, parent)
|
|
||||||
{
|
{
|
||||||
}
|
if (color.HasValue)
|
||||||
|
|
||||||
|
|
||||||
public GUIFrame(Rectangle rect, Color color, string style = "", GUIComponent parent = null)
|
|
||||||
: this(rect, color, (Alignment.Left | Alignment.Top), style, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIFrame(Rectangle rect, Color? color, Alignment alignment, string style = "", GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
if (color != null) this.color = (Color)color;
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
{
|
{
|
||||||
parent.AddChild(this);
|
this.color = color.Value;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateDimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (style != null) ApplyStyle(style);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
Color currColor = color;
|
|
||||||
if (state == ComponentState.Selected) currColor = selectedColor;
|
|
||||||
if (state == ComponentState.Hover) currColor = hoverColor;
|
|
||||||
|
|
||||||
if (sprites == null || !sprites.Any()) GUI.DrawRectangle(spriteBatch, rect, currColor * (currColor.A/255.0f), true);
|
Color currColor = GetCurrentColor(state);
|
||||||
|
|
||||||
|
if (sprites == null || !sprites.Any()) GUI.DrawRectangle(spriteBatch, Rect, currColor * (currColor.A/255.0f), true);
|
||||||
base.Draw(spriteBatch);
|
base.Draw(spriteBatch);
|
||||||
|
|
||||||
if (OutlineColor != Color.Transparent)
|
if (OutlineColor != Color.Transparent)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch, rect, OutlineColor * (OutlineColor.A/255.0f), false);
|
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Rectangle sourceRect;
|
private Rectangle sourceRect;
|
||||||
|
|
||||||
bool crop;
|
private bool crop;
|
||||||
|
|
||||||
|
private bool scaleToFit;
|
||||||
|
|
||||||
public bool Crop
|
public bool Crop
|
||||||
{
|
{
|
||||||
@@ -43,55 +45,88 @@ namespace Barotrauma
|
|||||||
set { sourceRect = value; }
|
set { sourceRect = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIImage(Rectangle rect, string spritePath, Alignment alignment, GUIComponent parent = null)
|
public Sprite Sprite
|
||||||
: this(rect, new Sprite(spritePath, Vector2.Zero), alignment, parent)
|
{
|
||||||
|
get { return sprite; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (sprite == value) return;
|
||||||
|
sprite = value;
|
||||||
|
sourceRect = sprite.SourceRect;
|
||||||
|
if (scaleToFit) RecalculateScale();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIImage(RectTransform rectT, string style)
|
||||||
|
: this(rectT, null, null, false, style)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIImage(Rectangle rect, Sprite sprite, Alignment alignment, GUIComponent parent = null)
|
public GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect = null, bool scaleToFit = false)
|
||||||
: this(rect, sprite==null ? Rectangle.Empty : sprite.SourceRect, sprite, alignment, parent)
|
: this(rectT, sprite, sourceRect, scaleToFit, null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIImage(Rectangle rect, Rectangle sourceRect, Sprite sprite, Alignment alignment, GUIComponent parent = null)
|
private GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect, bool scaleToFit, string style) : base(style, rectT)
|
||||||
: base(null)
|
|
||||||
{
|
{
|
||||||
this.rect = rect;
|
this.scaleToFit = scaleToFit;
|
||||||
|
Sprite = sprite;
|
||||||
this.alignment = alignment;
|
if (sourceRect.HasValue)
|
||||||
|
{
|
||||||
color = Color.White;
|
this.sourceRect = sourceRect.Value;
|
||||||
|
}
|
||||||
//alpha = 1.0f;
|
else
|
||||||
|
{
|
||||||
Scale = 1.0f;
|
this.sourceRect = sprite == null ? Rectangle.Empty : sprite.SourceRect;
|
||||||
|
}
|
||||||
this.sprite = sprite;
|
if (style == null)
|
||||||
|
{
|
||||||
if (rect.Width == 0) this.rect.Width = (int)sprite.size.X;
|
color = Color.White;
|
||||||
if (rect.Height == 0) this.rect.Height = (int)Math.Min(sprite.size.Y, sprite.size.Y * (this.rect.Width / sprite.size.X));
|
hoverColor = Color.White;
|
||||||
|
selectedColor = Color.White;
|
||||||
this.sourceRect = sourceRect;
|
}
|
||||||
|
if (!scaleToFit)
|
||||||
if (parent != null) parent.AddChild(this);
|
{
|
||||||
this.parent = parent;
|
Scale = 1.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rectT.SizeChanged += RecalculateScale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
Color currColor = GetCurrentColor(state);
|
||||||
Color currColor = color;
|
if (style != null)
|
||||||
if (state == ComponentState.Hover) currColor = hoverColor;
|
|
||||||
if (state == ComponentState.Selected) currColor = selectedColor;
|
|
||||||
|
|
||||||
if (sprite != null && sprite.Texture != null)
|
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(sprite.Texture, new Vector2(rect.X, rect.Y), sourceRect, currColor * (currColor.A / 255.0f), Rotation, Vector2.Zero,
|
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,
|
||||||
|
Scale * scale, SpriteEffects.None, 0.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uiSprite.Draw(spriteBatch, Rect, currColor * (currColor.A / 255.0f), SpriteEffects.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sprite?.Texture != null)
|
||||||
|
{
|
||||||
|
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currColor * (currColor.A / 255.0f), Rotation, sprite.size / 2,
|
||||||
Scale, SpriteEffects.None, 0.0f);
|
Scale, SpriteEffects.None, 0.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
|
private void RecalculateScale()
|
||||||
|
{
|
||||||
|
Scale = sprite.SourceRect.Width == 0 || sprite.SourceRect.Height == 0 ?
|
||||||
|
1.0f :
|
||||||
|
Math.Min(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
public class GUILayoutGroup : GUIComponent
|
||||||
|
{
|
||||||
|
private bool isHorizontal;
|
||||||
|
public bool IsHorizontal
|
||||||
|
{
|
||||||
|
get { return isHorizontal; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
isHorizontal = value;
|
||||||
|
needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool stretch;
|
||||||
|
/// <summary>
|
||||||
|
/// Note that stretching cannot be undone, because the previous child sizes are not stored.
|
||||||
|
/// </summary>
|
||||||
|
public bool Stretch
|
||||||
|
{
|
||||||
|
get { return stretch; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
stretch = value;
|
||||||
|
needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int absoluteSpacing;
|
||||||
|
public int AbsoluteSpacing
|
||||||
|
{
|
||||||
|
get { return absoluteSpacing; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
absoluteSpacing = MathHelper.Clamp(value, 0, int.MaxValue);
|
||||||
|
needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float relativeSpacing;
|
||||||
|
public float RelativeSpacing
|
||||||
|
{
|
||||||
|
get { return relativeSpacing; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
relativeSpacing = MathHelper.Clamp(value, -1, 1);
|
||||||
|
needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Anchor childAnchor;
|
||||||
|
public Anchor ChildAnchor
|
||||||
|
{
|
||||||
|
get { return childAnchor; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
childAnchor = value;
|
||||||
|
needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool needsToRecalculate;
|
||||||
|
public bool NeedsToRecalculate
|
||||||
|
{
|
||||||
|
get { return needsToRecalculate; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUILayoutGroup(RectTransform rectT, bool isHorizontal = false, Anchor childAnchor = Anchor.TopLeft) : base(null, rectT)
|
||||||
|
{
|
||||||
|
this.isHorizontal = isHorizontal;
|
||||||
|
this.childAnchor = childAnchor;
|
||||||
|
rectT.ChildrenChanged += (child) => needsToRecalculate = true;
|
||||||
|
rectT.ScaleChanged += () => needsToRecalculate = true;
|
||||||
|
rectT.SizeChanged += () => needsToRecalculate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Recalculate()
|
||||||
|
{
|
||||||
|
float stretchFactor = 1.0f;
|
||||||
|
if (stretch && RectTransform.Children.Count() > 0)
|
||||||
|
{
|
||||||
|
float totalSize = RectTransform.Children
|
||||||
|
.Where(c => !c.GUIComponent.IgnoreLayoutGroups)
|
||||||
|
.Sum(c => isHorizontal ? c.Rect.Width : c.Rect.Height);
|
||||||
|
|
||||||
|
totalSize +=
|
||||||
|
(RectTransform.Children.Count() - 1) *
|
||||||
|
(absoluteSpacing + relativeSpacing * (isHorizontal ? Rect.Width : Rect.Height));
|
||||||
|
|
||||||
|
stretchFactor = totalSize <= 0.0f ? 1.0f : (isHorizontal ? Rect.Width: Rect.Height) / totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int absPos = 0;
|
||||||
|
float relPos = 0;
|
||||||
|
foreach (var child in RectTransform.Children)
|
||||||
|
{
|
||||||
|
if (child.GUIComponent.IgnoreLayoutGroups) { continue; }
|
||||||
|
child.SetPosition(childAnchor);
|
||||||
|
if (isHorizontal)
|
||||||
|
{
|
||||||
|
child.RelativeOffset = new Vector2(relPos, child.RelativeOffset.Y);
|
||||||
|
child.AbsoluteOffset = new Point(absPos, child.AbsoluteOffset.Y);
|
||||||
|
absPos += (int)((child.Rect.Width + 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)((child.Rect.Height + absoluteSpacing) * stretchFactor);
|
||||||
|
if (stretch)
|
||||||
|
{
|
||||||
|
child.RelativeSize = new Vector2(child.RelativeSize.X, child.RelativeSize.Y * stretchFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relPos += relativeSpacing * stretchFactor;
|
||||||
|
}
|
||||||
|
needsToRecalculate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
base.Update(deltaTime);
|
||||||
|
if (needsToRecalculate)
|
||||||
|
{
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using EventInput;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
public class GUIListBox : GUIComponent
|
public class GUIListBox : GUIComponent, IKeyboardSubscriber
|
||||||
{
|
{
|
||||||
protected List<GUIComponent> selected;
|
protected List<GUIComponent> selected;
|
||||||
|
|
||||||
@@ -16,28 +19,44 @@ namespace Barotrauma
|
|||||||
public delegate object CheckSelectedHandler();
|
public delegate object CheckSelectedHandler();
|
||||||
public CheckSelectedHandler CheckSelected;
|
public CheckSelectedHandler CheckSelected;
|
||||||
|
|
||||||
private GUIScrollBar scrollBar;
|
public GUIScrollBar ScrollBar { get; private set; }
|
||||||
private GUIFrame frame;
|
public GUIFrame Content { get; private set; }
|
||||||
|
|
||||||
private int totalSize;
|
private int totalSize;
|
||||||
|
|
||||||
private int spacing;
|
private int spacing;
|
||||||
|
|
||||||
private bool scrollBarEnabled;
|
private bool childrenNeedsRecalculation;
|
||||||
private bool scrollBarHidden;
|
private bool scrollBarNeedsRecalculation;
|
||||||
|
|
||||||
private bool enabled;
|
|
||||||
|
|
||||||
public bool SelectMultiple;
|
public bool SelectMultiple;
|
||||||
|
|
||||||
public GUIComponent Selected
|
public bool HideChildrenOutsideFrame = true;
|
||||||
|
|
||||||
|
private bool useGridLayout;
|
||||||
|
|
||||||
|
public bool UseGridLayout
|
||||||
|
{
|
||||||
|
get { return useGridLayout; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (useGridLayout == value) return;
|
||||||
|
useGridLayout = value;
|
||||||
|
childrenNeedsRecalculation = true;
|
||||||
|
scrollBarNeedsRecalculation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIComponent SelectedComponent
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return selected.Any() ? selected[0] : null;
|
return selected.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Selected { get; set; }
|
||||||
|
|
||||||
public List<GUIComponent> AllSelected
|
public List<GUIComponent> AllSelected
|
||||||
{
|
{
|
||||||
get { return selected; }
|
get { return selected; }
|
||||||
@@ -47,7 +66,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (Selected == null) ? null : Selected.UserData;
|
return SelectedComponent?.UserData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,20 +74,25 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Selected == null) return -1;
|
if (SelectedComponent == null) return -1;
|
||||||
return children.FindIndex(x => x == Selected);
|
return Content.RectTransform.GetChildIndex(SelectedComponent.RectTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float BarScroll
|
public float BarScroll
|
||||||
{
|
{
|
||||||
get { return scrollBar.BarScroll; }
|
get { return ScrollBar.BarScroll; }
|
||||||
set { scrollBar.BarScroll = value; }
|
set { ScrollBar.BarScroll = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public float BarSize
|
public float BarSize
|
||||||
{
|
{
|
||||||
get { return scrollBar.BarSize; }
|
get { return ScrollBar.BarSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float TotalSize
|
||||||
|
{
|
||||||
|
get { return totalSize; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Spacing
|
public int Spacing
|
||||||
@@ -77,32 +101,6 @@ namespace Barotrauma
|
|||||||
set { spacing = value; }
|
set { spacing = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled
|
|
||||||
{
|
|
||||||
get { return enabled; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
enabled = value;
|
|
||||||
//scrollBar.Enabled = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rectangle Rect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base.Rect = value;
|
|
||||||
frame.Rect = value;
|
|
||||||
scrollBar.Rect = scrollBar.IsHorizontal ?
|
|
||||||
new Rectangle(rect.X, rect.Bottom - 20, rect.Width, 20) :
|
|
||||||
new Rectangle(rect.Right - 20, rect.Y, 20, rect.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Color Color
|
public override Color Color
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -113,145 +111,201 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
base.Color = value;
|
base.Color = value;
|
||||||
|
|
||||||
frame.Color = value;
|
Content.Color = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disables the scroll bar without hiding it.
|
||||||
|
/// </summary>
|
||||||
|
public bool ScrollBarEnabled { get; set; } = true;
|
||||||
|
|
||||||
public bool ScrollBarEnabled
|
public bool ScrollBarVisible
|
||||||
{
|
{
|
||||||
get { return scrollBarEnabled; }
|
get
|
||||||
|
{
|
||||||
|
return ScrollBar.Visible;
|
||||||
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
scrollBarEnabled = value;
|
ScrollBar.Visible = value;
|
||||||
|
AutoHideScrollBar = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIListBox(Rectangle rect, string style, GUIComponent parent = null)
|
/// <summary>
|
||||||
: this(rect, style, Alignment.TopLeft, parent)
|
/// Automatically hides the scroll bar when the content fits in.
|
||||||
{
|
/// </summary>
|
||||||
}
|
public bool AutoHideScrollBar { get; set; } = true;
|
||||||
|
|
||||||
public GUIListBox(Rectangle rect, string style, Alignment alignment, GUIComponent parent = null)
|
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "") : base(style, rectT)
|
||||||
: this(rect, null, alignment, style, parent, false)
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public GUIListBox(Rectangle rect, Color? color, string style = null, GUIComponent parent = null)
|
|
||||||
: this(rect, color, (Alignment.Left | Alignment.Top), style, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIListBox(Rectangle rect, Color? color, Alignment alignment, string style = null, GUIComponent parent = null, bool isHorizontal = false)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
selected = new List<GUIComponent>();
|
selected = new List<GUIComponent>();
|
||||||
|
|
||||||
if (color != null) this.color = (Color)color;
|
Point frameSize = isHorizontal ?
|
||||||
|
new Point(rectT.NonScaledSize.X, rectT.NonScaledSize.Y - 20) :
|
||||||
|
new Point(rectT.NonScaledSize.X - 20, rectT.NonScaledSize.Y);
|
||||||
|
|
||||||
if (parent != null)
|
Content = new GUIFrame(new RectTransform(frameSize, rectT), style)
|
||||||
parent.AddChild(this);
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
Content.RectTransform.ChildrenChanged += (_) =>
|
||||||
|
{
|
||||||
|
scrollBarNeedsRecalculation = true;
|
||||||
|
childrenNeedsRecalculation = true;
|
||||||
|
};
|
||||||
|
|
||||||
scrollBarHidden = true;
|
if (style != null) GUI.Style.Apply(Content, "", this);
|
||||||
|
|
||||||
|
if (color.HasValue)
|
||||||
|
{
|
||||||
|
this.color = color.Value;
|
||||||
|
}
|
||||||
|
|
||||||
if (isHorizontal)
|
if (isHorizontal)
|
||||||
{
|
{
|
||||||
scrollBar = new GUIScrollBar(
|
ScrollBar = new GUIScrollBar(new RectTransform(new Point(Rect.Width, 20), rectT, Anchor.BottomLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, 20) }, isHorizontal: isHorizontal);
|
||||||
new Rectangle(this.rect.X, this.rect.Bottom - 20, this.rect.Width, 20), null, 1.0f, "");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scrollBar = new GUIScrollBar(
|
ScrollBar = new GUIScrollBar(new RectTransform(new Point(20, Rect.Height), rectT, Anchor.TopRight, Pivot.TopLeft) { AbsoluteOffset = new Point(20, 0) }, isHorizontal: isHorizontal);
|
||||||
new Rectangle(this.rect.Right - 20, this.rect.Y, 20, this.rect.Height), null, 1.0f, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollBar.IsHorizontal = isHorizontal;
|
|
||||||
|
|
||||||
frame = new GUIFrame(new Rectangle(0, 0, this.rect.Width, this.rect.Height), style, this);
|
|
||||||
if (style != null) GUI.Style.Apply(frame, style, this);
|
|
||||||
|
|
||||||
UpdateScrollBarSize();
|
UpdateScrollBarSize();
|
||||||
|
Enabled = true;
|
||||||
|
ScrollBar.BarScroll = 0.0f;
|
||||||
|
|
||||||
|
RectTransform.ScaleChanged += UpdateDimensions;
|
||||||
|
RectTransform.SizeChanged += UpdateDimensions;
|
||||||
|
}
|
||||||
|
|
||||||
children.Clear();
|
private void UpdateDimensions()
|
||||||
|
{
|
||||||
enabled = true;
|
if (!ScrollBarEnabled)
|
||||||
|
{
|
||||||
scrollBarEnabled = true;
|
Content.RectTransform.NonScaledSize = Rect.Size;
|
||||||
|
}
|
||||||
scrollBar.BarScroll = 0.0f;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select(object userData, bool force = false)
|
public void Select(object userData, bool force = false, bool autoScroll = true)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < children.Count; i++)
|
var children = Content.Children;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (GUIComponent child in children)
|
||||||
{
|
{
|
||||||
if ((children[i].UserData != null && children[i].UserData.Equals(userData)) ||
|
if ((child.UserData != null && child.UserData.Equals(userData)) ||
|
||||||
(children[i].UserData == null && userData == null))
|
(child.UserData == null && userData == null))
|
||||||
{
|
{
|
||||||
Select(i, force);
|
Select(i, force, autoScroll);
|
||||||
if (!SelectMultiple) return;
|
if (!SelectMultiple) return;
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetDimensions(Point size, bool expandChildren = false)
|
private void RepositionChildren()
|
||||||
{
|
{
|
||||||
base.SetDimensions(size, expandChildren);
|
var children = Content.Children;
|
||||||
frame.SetDimensions(size, expandChildren);
|
int x = 0, y = 0;
|
||||||
|
if (ScrollBar.BarSize < 1.0f)
|
||||||
if (scrollBar.IsHorizontal)
|
|
||||||
{
|
{
|
||||||
scrollBar.Rect = new Rectangle(this.rect.X, this.rect.Bottom - 20, this.rect.Width, 20);
|
if (ScrollBar.IsHorizontal)
|
||||||
}
|
{
|
||||||
else
|
x -= (int)((totalSize - Content.Rect.Width) * ScrollBar.BarScroll);
|
||||||
{
|
}
|
||||||
scrollBar.Rect = new Rectangle(this.rect.Right - 20, this.rect.Y, 20, this.rect.Height);
|
else
|
||||||
|
{
|
||||||
|
y -= (int)((totalSize - Content.Rect.Height) * ScrollBar.BarScroll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateScrollBarSize();
|
for (int i = 0; i < Content.CountChildren; i++)
|
||||||
|
{
|
||||||
|
GUIComponent child = Content.GetChild(i);
|
||||||
|
if (!child.Visible) { continue; }
|
||||||
|
if (RectTransform != null)
|
||||||
|
{
|
||||||
|
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
|
||||||
|
{
|
||||||
|
child.RectTransform.AbsoluteOffset = new Point(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useGridLayout)
|
||||||
|
{
|
||||||
|
if (ScrollBar.IsHorizontal)
|
||||||
|
{
|
||||||
|
if (y + child.Rect.Height + spacing > Content.Rect.Height)
|
||||||
|
{
|
||||||
|
y = 0;
|
||||||
|
x += child.Rect.Width + spacing;
|
||||||
|
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
|
||||||
|
{
|
||||||
|
child.RectTransform.AbsoluteOffset = new Point(x, y);
|
||||||
|
}
|
||||||
|
y += child.Rect.Height + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
y += child.Rect.Height + spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (x + child.Rect.Width + spacing > Content.Rect.Width)
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y += child.Rect.Height + spacing;
|
||||||
|
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
|
||||||
|
{
|
||||||
|
child.RectTransform.AbsoluteOffset = new Point(x, y);
|
||||||
|
}
|
||||||
|
x += child.Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x += child.Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ScrollBar.IsHorizontal)
|
||||||
|
{
|
||||||
|
x += child.Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
y += child.Rect.Height + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateChildrenRect(float deltaTime)
|
private void UpdateChildrenRect()
|
||||||
{
|
{
|
||||||
int x = rect.X, y = rect.Y;
|
for (int i = 0; i < Content.CountChildren; i++)
|
||||||
|
|
||||||
if (!scrollBarHidden)
|
|
||||||
{
|
{
|
||||||
if (scrollBar.IsHorizontal)
|
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
|
||||||
{
|
if (child == null) continue;
|
||||||
x -= (int)((totalSize - rect.Width) * scrollBar.BarScroll);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
y -= (int)((totalSize - rect.Height) * scrollBar.BarScroll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < children.Count; i++)
|
// selecting
|
||||||
{
|
if (Enabled && child.CanBeFocused && (GUI.IsMouseOn(child)) && child.Rect.Contains(PlayerInput.MousePosition))
|
||||||
GUIComponent child = children[i];
|
|
||||||
if (child == frame || !child.Visible) continue;
|
|
||||||
|
|
||||||
child.Rect = new Rectangle(x, y, child.Rect.Width, child.Rect.Height);
|
|
||||||
if (scrollBar.IsHorizontal)
|
|
||||||
{
|
|
||||||
x += child.Rect.Width + spacing;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
y += child.Rect.Height + spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deltaTime>0.0f) child.Update(deltaTime);
|
|
||||||
if (enabled && child.CanBeFocused &&
|
|
||||||
(MouseOn == this || (MouseOn != null && this.IsParentOf(MouseOn))) && child.Rect.Contains(PlayerInput.MousePosition))
|
|
||||||
{
|
{
|
||||||
child.State = ComponentState.Hover;
|
child.State = ComponentState.Hover;
|
||||||
if (PlayerInput.LeftButtonClicked())
|
if (PlayerInput.LeftButtonClicked())
|
||||||
{
|
{
|
||||||
Select(i);
|
Select(i, autoScroll: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (selected.Contains(child))
|
else if (selected.Contains(child))
|
||||||
@@ -270,186 +324,328 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) { return; }
|
||||||
if (ComponentsToUpdate.Contains(this)) return;
|
|
||||||
ComponentsToUpdate.Add(this);
|
|
||||||
|
|
||||||
List<GUIComponent> fixedChildren = new List<GUIComponent>(children);
|
|
||||||
int lastVisible = 0;
|
|
||||||
for (int i = 0; i < fixedChildren.Count; i++)
|
|
||||||
{
|
|
||||||
if (fixedChildren[i] == frame) continue;
|
|
||||||
|
|
||||||
if (!IsChildVisible(fixedChildren[i]))
|
if (childrenNeedsRecalculation)
|
||||||
|
{
|
||||||
|
foreach (GUIComponent child in Content.Children)
|
||||||
|
{
|
||||||
|
ClampChildMouseRects(child);
|
||||||
|
}
|
||||||
|
RepositionChildren();
|
||||||
|
childrenNeedsRecalculation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateOrder = order;
|
||||||
|
GUI.AddToUpdateList(this);
|
||||||
|
|
||||||
|
if (ignoreChildren)
|
||||||
|
{
|
||||||
|
OnAddedToGUIUpdateList?.Invoke(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Content.AddToGUIUpdateList(true, order);
|
||||||
|
int lastVisible = 0;
|
||||||
|
for (int i = 0; i < Content.CountChildren; i++)
|
||||||
|
{
|
||||||
|
var child = Content.GetChild(i);
|
||||||
|
if (!child.Visible) continue;
|
||||||
|
if (!IsChildInsideFrame(child))
|
||||||
{
|
{
|
||||||
if (lastVisible > 0) break;
|
if (lastVisible > 0) break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVisible = i;
|
lastVisible = i;
|
||||||
fixedChildren[i].AddToGUIUpdateList();
|
child.AddToGUIUpdateList(false, order);
|
||||||
}
|
}
|
||||||
|
if (ScrollBar.Enabled)
|
||||||
if (scrollBarEnabled && !scrollBarHidden) scrollBar.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rectangle MouseRect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
{
|
||||||
return ClampMouseRectToParent ? ClampRect(rect) : rect;
|
ScrollBar.AddToGUIUpdateList(false, order);
|
||||||
|
}
|
||||||
|
OnAddedToGUIUpdateList?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClampChildMouseRects(GUIComponent child)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
foreach (GUIComponent grandChild in child.Children)
|
||||||
|
{
|
||||||
|
ClampChildMouseRects(grandChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
protected override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
UpdateChildrenRect(deltaTime);
|
UpdateChildrenRect();
|
||||||
|
RepositionChildren();
|
||||||
if (scrollBarEnabled && !scrollBarHidden) scrollBar.Update(deltaTime);
|
|
||||||
|
|
||||||
if ((MouseOn == this || MouseOn == scrollBar || IsParentOf(MouseOn)) && PlayerInput.ScrollWheelSpeed != 0)
|
if (scrollBarNeedsRecalculation)
|
||||||
{
|
{
|
||||||
scrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
UpdateScrollBarSize();
|
||||||
|
scrollBarNeedsRecalculation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.Enabled = ScrollBarEnabled && ScrollBar.BarSize < 1.0f;
|
||||||
|
if (AutoHideScrollBar)
|
||||||
|
{
|
||||||
|
ScrollBar.Visible = ScrollBar.BarSize < 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && PlayerInput.ScrollWheelSpeed != 0)
|
||||||
|
{
|
||||||
|
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select(int childIndex, bool force = false)
|
public void SelectNext(bool force = false, bool autoScroll = true)
|
||||||
{
|
{
|
||||||
if (childIndex >= children.Count || childIndex < 0) return;
|
Select(Math.Min(Content.CountChildren - 1, SelectedIndex + 1), force, autoScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectPrevious(bool force = false, bool autoScroll = true)
|
||||||
|
{
|
||||||
|
Select(Math.Max(0, SelectedIndex - 1), force, autoScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Select(int childIndex, bool force = false, bool autoScroll = true)
|
||||||
|
{
|
||||||
|
if (childIndex >= Content.CountChildren || childIndex < 0) return;
|
||||||
|
|
||||||
|
GUIComponent child = Content.GetChild(childIndex);
|
||||||
|
|
||||||
bool wasSelected = true;
|
bool wasSelected = true;
|
||||||
if (OnSelected != null) wasSelected = OnSelected(children[childIndex], children[childIndex].UserData) || force;
|
if (OnSelected != null) wasSelected = force || OnSelected(child, child.UserData);
|
||||||
|
|
||||||
if (!wasSelected) return;
|
if (!wasSelected) return;
|
||||||
|
|
||||||
if (SelectMultiple)
|
if (SelectMultiple)
|
||||||
{
|
{
|
||||||
if (selected.Contains(children[childIndex]))
|
if (selected.Contains(child))
|
||||||
{
|
{
|
||||||
selected.Remove(children[childIndex]);
|
selected.Remove(child);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selected.Add(children[childIndex]);
|
selected.Add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selected.Clear();
|
selected.Clear();
|
||||||
selected.Add(children[childIndex]);
|
selected.Add(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that the selected element is visible. This may not be the case, if the selection is run from code. (e.g. if we have two list boxes that are synced)
|
||||||
|
// TODO: This method only works when moving one item up/down (e.g. when using the up and down arrows)
|
||||||
|
if (autoScroll)
|
||||||
|
{
|
||||||
|
if (ScrollBar.IsHorizontal)
|
||||||
|
{
|
||||||
|
if (child.Rect.X < MouseRect.X)
|
||||||
|
{
|
||||||
|
//child outside the left edge of the frame -> move left
|
||||||
|
ScrollBar.BarScroll -= (float)(MouseRect.X - child.Rect.X) / (totalSize - Content.Rect.Width);
|
||||||
|
}
|
||||||
|
else if (child.Rect.Right > MouseRect.Right)
|
||||||
|
{
|
||||||
|
//child outside the right edge of the frame -> move right
|
||||||
|
ScrollBar.BarScroll += (float)(child.Rect.Right - MouseRect.Right) / (totalSize - Content.Rect.Width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (child.Rect.Y < MouseRect.Y)
|
||||||
|
{
|
||||||
|
//child above the top of the frame -> move up
|
||||||
|
ScrollBar.BarScroll -= (float)(MouseRect.Y - child.Rect.Y) / (totalSize - Content.Rect.Height);
|
||||||
|
}
|
||||||
|
else if (child.Rect.Bottom > MouseRect.Bottom)
|
||||||
|
{
|
||||||
|
//child below the bottom of the frame -> move down
|
||||||
|
ScrollBar.BarScroll += (float)(child.Rect.Bottom - MouseRect.Bottom) / (totalSize - Content.Rect.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one of the children is the subscriber, we don't want to register, because it will unregister the child.
|
||||||
|
if (RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||||
|
{
|
||||||
|
Selected = true;
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deselect()
|
public void Deselect()
|
||||||
{
|
{
|
||||||
|
Selected = false;
|
||||||
|
if (GUI.KeyboardDispatcher.Subscriber == this)
|
||||||
|
{
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = null;
|
||||||
|
}
|
||||||
selected.Clear();
|
selected.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateScrollBarSize()
|
public void UpdateScrollBarSize()
|
||||||
{
|
{
|
||||||
totalSize = (int)(padding.Y + padding.W);
|
if (Content == null) return;
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
|
totalSize = 0;
|
||||||
|
var children = Content.Children.Where(c => c.Visible);
|
||||||
|
if (useGridLayout)
|
||||||
{
|
{
|
||||||
if (child == frame || !child.Visible) continue;
|
int pos = 0;
|
||||||
totalSize += (scrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
|
foreach (GUIComponent child in children)
|
||||||
|
{
|
||||||
|
if (ScrollBar.IsHorizontal)
|
||||||
|
{
|
||||||
|
if (pos + child.Rect.Height + spacing > Content.Rect.Height || child == children.Last())
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
totalSize += child.Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += child.Rect.Height + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pos + child.Rect.Width + spacing > Content.Rect.Width || child == children.Last())
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
totalSize += child.Rect.Height + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += child.Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (GUIComponent child in children)
|
||||||
|
{
|
||||||
|
totalSize += (ScrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
|
||||||
|
}
|
||||||
|
totalSize += Content.CountChildren * spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalSize += (children.Count - 1) * spacing;
|
|
||||||
|
|
||||||
scrollBar.BarSize = scrollBar.IsHorizontal ?
|
ScrollBar.BarSize = ScrollBar.IsHorizontal ?
|
||||||
Math.Max(Math.Min((float)rect.Width / (float)totalSize, 1.0f), 5.0f / rect.Width) :
|
Math.Max(Math.Min(Content.Rect.Width / (float)totalSize, 1.0f), 5.0f / Content.Rect.Width) :
|
||||||
Math.Max(Math.Min((float)rect.Height / (float)totalSize, 1.0f), 5.0f / rect.Height);
|
Math.Max(Math.Min(Content.Rect.Height / (float)totalSize, 1.0f), 5.0f / Content.Rect.Height);
|
||||||
|
|
||||||
scrollBarHidden = scrollBar.BarSize >= 1.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddChild(GUIComponent child)
|
|
||||||
{
|
|
||||||
//temporarily reduce the size of the rect to prevent the child from expanding over the scrollbar
|
|
||||||
if (scrollBar.IsHorizontal)
|
|
||||||
rect.Height -= scrollBar.Rect.Height;
|
|
||||||
else
|
|
||||||
rect.Width -= scrollBar.Rect.Width;
|
|
||||||
|
|
||||||
base.AddChild(child);
|
|
||||||
|
|
||||||
if (scrollBar.IsHorizontal)
|
|
||||||
rect.Height += scrollBar.Rect.Height;
|
|
||||||
else
|
|
||||||
rect.Width += scrollBar.Rect.Width;
|
|
||||||
|
|
||||||
UpdateScrollBarSize();
|
|
||||||
UpdateChildrenRect(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ClearChildren()
|
public override void ClearChildren()
|
||||||
{
|
{
|
||||||
base.ClearChildren();
|
Content.ClearChildren();
|
||||||
selected.Clear();
|
selected.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RemoveChild(GUIComponent child)
|
public override void RemoveChild(GUIComponent child)
|
||||||
{
|
{
|
||||||
if (child == null) return;
|
if (child == null) return;
|
||||||
|
child.RectTransform.Parent = null;
|
||||||
base.RemoveChild(child);
|
|
||||||
if (selected.Contains(child)) selected.Remove(child);
|
if (selected.Contains(child)) selected.Remove(child);
|
||||||
UpdateScrollBarSize();
|
UpdateScrollBarSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
public override void DrawChildren(SpriteBatch spriteBatch, bool recursive)
|
||||||
|
{
|
||||||
|
//do nothing (the children have to be drawn in the Draw method after the ScissorRectangle has been set)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
|
Content.DrawManually(spriteBatch, alsoChildren: false);
|
||||||
|
|
||||||
frame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
if (!scrollBarHidden) scrollBar.Draw(spriteBatch);
|
|
||||||
|
|
||||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, frame.Rect);
|
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
|
||||||
|
if (HideChildrenOutsideFrame)
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Content.Rect);
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
var children = Content.Children;
|
||||||
int lastVisible = 0;
|
int lastVisible = 0;
|
||||||
for (int i = 0; i < children.Count; i++)
|
|
||||||
{
|
|
||||||
GUIComponent child = children[i];
|
|
||||||
if (child == frame || !child.Visible) continue;
|
|
||||||
|
|
||||||
if (!IsChildVisible(child))
|
int i = 0;
|
||||||
|
foreach (GUIComponent child in Content.Children)
|
||||||
|
{
|
||||||
|
if (!child.Visible) continue;
|
||||||
|
if (!IsChildInsideFrame(child))
|
||||||
{
|
{
|
||||||
if (lastVisible > 0) break;
|
if (lastVisible > 0) break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
lastVisible = i;
|
||||||
lastVisible = i;
|
child.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
|
||||||
child.Draw(spriteBatch);
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
if (HideChildrenOutsideFrame)
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: prevRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ScrollBar.Visible) ScrollBar.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsChildVisible(GUIComponent child)
|
private bool IsChildInsideFrame(GUIComponent child)
|
||||||
{
|
{
|
||||||
if (child == null) return false;
|
if (child == null) return false;
|
||||||
|
|
||||||
if (scrollBar.IsHorizontal)
|
if (ScrollBar.IsHorizontal)
|
||||||
{
|
{
|
||||||
if (child.Rect.Right < rect.X) return false;
|
if (child.Rect.Right < Content.Rect.X) return false;
|
||||||
if (child.Rect.X > rect.Right) return false;
|
if (child.Rect.X > Content.Rect.Right) return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (child.Rect.Bottom < rect.Y) return false;
|
if (child.Rect.Bottom < Content.Rect.Y) return false;
|
||||||
if (child.Rect.Y > rect.Bottom) return false;
|
if (child.Rect.Y > Content.Rect.Bottom) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReceiveTextInput(char inputChar)
|
||||||
|
{
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = null;
|
||||||
|
}
|
||||||
|
public void ReceiveTextInput(string text) { }
|
||||||
|
public void ReceiveCommandInput(char command) { }
|
||||||
|
|
||||||
|
public void ReceiveSpecialInput(Keys key)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Keys.Down:
|
||||||
|
SelectNext();
|
||||||
|
break;
|
||||||
|
case Keys.Up:
|
||||||
|
SelectPrevious();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
|
|
||||||
|
public readonly bool WorldSpace;
|
||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get { return coloredText.Text; }
|
get { return coloredText.Text; }
|
||||||
@@ -27,57 +29,69 @@ namespace Barotrauma
|
|||||||
set { pos = value; }
|
set { pos = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 Size
|
public Vector2 Velocity
|
||||||
{
|
|
||||||
get { return size; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 Origin;
|
|
||||||
|
|
||||||
public float LifeTime
|
|
||||||
{
|
|
||||||
get { return lifeTime; }
|
|
||||||
set { lifeTime = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Alignment Alignment
|
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 Size
|
||||||
|
{
|
||||||
|
get { return size; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 Origin;
|
||||||
|
|
||||||
/// <summary>
|
public float Timer;
|
||||||
/// Autocentered messages are automatically placed at the center of the screen and prevented from overlapping with each other
|
|
||||||
/// </summary>
|
|
||||||
public bool AutoCenter;
|
|
||||||
|
|
||||||
public GUIMessage(string text, Color color, Vector2 position, float lifeTime, Alignment textAlignment, bool autoCenter)
|
public float LifeTime
|
||||||
|
{
|
||||||
|
get { return lifeTime; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScalableFont Font
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIMessage(string text, Color color, float lifeTime, ScalableFont font = null)
|
||||||
{
|
{
|
||||||
coloredText = new ColoredText(text, color, false);
|
coloredText = new ColoredText(text, color, false);
|
||||||
pos = position;
|
|
||||||
this.lifeTime = lifeTime;
|
this.lifeTime = lifeTime;
|
||||||
this.Alignment = textAlignment;
|
Timer = lifeTime;
|
||||||
this.AutoCenter = autoCenter;
|
|
||||||
|
|
||||||
size = GUI.Font.MeasureString(text);
|
size = font.MeasureString(text);
|
||||||
|
Origin = new Vector2(0, size.Y * 0.5f);
|
||||||
|
|
||||||
|
Font = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIMessage(string text, Color color, Vector2 worldPosition, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null)
|
||||||
|
{
|
||||||
|
coloredText = new ColoredText(text, color, false);
|
||||||
|
WorldSpace = true;
|
||||||
|
pos = worldPosition;
|
||||||
|
Timer = lifeTime;
|
||||||
|
Velocity = velocity;
|
||||||
|
this.lifeTime = lifeTime;
|
||||||
|
|
||||||
|
Font = font;
|
||||||
|
|
||||||
|
size = font.MeasureString(text);
|
||||||
|
|
||||||
|
Origin = new Vector2((int)(0.5f * size.X), (int)(0.5f * size.Y));
|
||||||
if (textAlignment.HasFlag(Alignment.Left))
|
if (textAlignment.HasFlag(Alignment.Left))
|
||||||
Origin.X += size.X * 0.5f;
|
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Right))
|
|
||||||
Origin.X -= size.X * 0.5f;
|
Origin.X -= size.X * 0.5f;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Top))
|
if (textAlignment.HasFlag(Alignment.Right))
|
||||||
Origin.Y += size.Y * 0.5f;
|
Origin.X += size.X * 0.5f;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Bottom))
|
if (textAlignment.HasFlag(Alignment.Top))
|
||||||
Origin.Y -= size.Y * 0.5f;
|
Origin.Y -= size.Y * 0.5f;
|
||||||
|
|
||||||
if (autoCenter)
|
if (textAlignment.HasFlag(Alignment.Bottom))
|
||||||
{
|
Origin.Y += size.Y * 0.5f;
|
||||||
Origin = new Vector2((int)(0.5f * size.X), (int)(0.5f * size.Y));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -9,48 +12,41 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public const int DefaultWidth = 400, DefaultHeight = 250;
|
public const int DefaultWidth = 400, DefaultHeight = 250;
|
||||||
|
|
||||||
public GUIButton[] Buttons;
|
public List<GUIButton> Buttons { get; private set; } = new List<GUIButton>();
|
||||||
|
//public GUIFrame BackgroundFrame { get; private set; }
|
||||||
public static GUIComponent VisibleBox
|
public GUILayoutGroup Content { get; private set; }
|
||||||
{
|
public GUIFrame InnerFrame { get; private set; }
|
||||||
get { return MessageBoxes.Count == 0 ? null : MessageBoxes[0]; }
|
public GUITextBlock Header { get; private set; }
|
||||||
}
|
public GUITextBlock Text { get; private set; }
|
||||||
|
|
||||||
public GUIFrame InnerFrame
|
|
||||||
{
|
|
||||||
get { return children[0] as GUIFrame; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get { return (children[0].children[1] as GUITextBlock).Text; }
|
|
||||||
set { (children[0].children[1] as GUITextBlock).Text = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
|
||||||
|
|
||||||
public GUIMessageBox(string headerText, string text)
|
public GUIMessageBox(string headerText, string text)
|
||||||
: this(headerText, text, new string[] {"OK"}, DefaultWidth, 0)
|
: this(headerText, text, new string[] {"OK"}, DefaultWidth, 0)
|
||||||
{
|
{
|
||||||
this.Buttons[0].OnClicked = Close;
|
this.Buttons[0].OnClicked = Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIMessageBox(string headerText, string text, int width, int height)
|
public GUIMessageBox(string headerText, string text, int width, int height)
|
||||||
: this(headerText, text, new string[] { "OK" }, width, height)
|
: this(headerText, text, new string[] { "OK" }, width, height)
|
||||||
{
|
{
|
||||||
this.Buttons[0].OnClicked = Close;
|
this.Buttons[0].OnClicked = Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIMessageBox(string headerText, string text, string[] buttons, int width = DefaultWidth, int height = 0, Alignment textAlignment = Alignment.TopLeft, GUIComponent parent = null)
|
// TODO: allow to use a relative size.
|
||||||
: base(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
|
public GUIMessageBox(string headerText, string text, string[] buttons, int width = DefaultWidth, int height = 0, Alignment textAlignment = Alignment.TopLeft)
|
||||||
Color.Black * 0.5f, Alignment.TopLeft, null, parent)
|
: base(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "")
|
||||||
{
|
{
|
||||||
int headerHeight = 30;
|
int headerHeight = 30;
|
||||||
|
|
||||||
var frame = new GUIFrame(new Rectangle(0, 0, width, height), null, Alignment.Center, "", this);
|
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, Anchor.Center) { IsFixedSize = false }, style: null);
|
||||||
GUI.Style.Apply(frame, "", this);
|
GUI.Style.Apply(InnerFrame, "", this);
|
||||||
|
|
||||||
|
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
|
||||||
|
|
||||||
if (height == 0)
|
if (height == 0)
|
||||||
{
|
{
|
||||||
string wrappedText = ToolBox.WrapText(text, frame.Rect.Width - frame.Padding.X - frame.Padding.Z, GUI.Font);
|
string wrappedText = ToolBox.WrapText(text, Content.Rect.Width, GUI.Font);
|
||||||
string[] lines = wrappedText.Split('\n');
|
string[] lines = wrappedText.Split('\n');
|
||||||
foreach (string line in lines)
|
foreach (string line in lines)
|
||||||
{
|
{
|
||||||
@@ -58,33 +54,103 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
height += string.IsNullOrWhiteSpace(headerText) ? 220 : 220 - headerHeight;
|
height += string.IsNullOrWhiteSpace(headerText) ? 220 : 220 - headerHeight;
|
||||||
}
|
}
|
||||||
frame.Rect = new Rectangle(frame.Rect.X, GameMain.GraphicsHeight / 2 - height/2, frame.Rect.Width, height);
|
InnerFrame.RectTransform.NonScaledSize = new Point(InnerFrame.Rect.Width, height);
|
||||||
|
|
||||||
var header = new GUITextBlock(new Rectangle(0, 0, 0, headerHeight), headerText, null, null, textAlignment, "", frame, true);
|
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
|
||||||
GUI.Style.Apply(header, "", this);
|
headerText, textAlignment: Alignment.Center, wrap: true);
|
||||||
|
GUI.Style.Apply(Header, "", this);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(text))
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
var textBlock = new GUITextBlock(new Rectangle(0, string.IsNullOrWhiteSpace(headerText) ? 0 : headerHeight, 0, height - 70), text,
|
Text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
|
||||||
null, null, textAlignment, "", frame, true);
|
text, textAlignment: textAlignment, wrap: true);
|
||||||
GUI.Style.Apply(textBlock, "", this);
|
GUI.Style.Apply(Text, "", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = 0;
|
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter),
|
||||||
this.Buttons = new GUIButton[buttons.Length];
|
isHorizontal: true, childAnchor: Anchor.BottomLeft)
|
||||||
|
{
|
||||||
|
AbsoluteSpacing = 5,
|
||||||
|
IgnoreLayoutGroups = true
|
||||||
|
};
|
||||||
|
|
||||||
|
Buttons = new List<GUIButton>(buttons.Length);
|
||||||
for (int i = 0; i < buttons.Length; i++)
|
for (int i = 0; i < buttons.Length; i++)
|
||||||
{
|
{
|
||||||
this.Buttons[i] = new GUIButton(new Rectangle(x, 0, 150, 30), buttons[i], Alignment.Left | Alignment.Bottom, "", frame);
|
var button = new GUIButton(new RectTransform(new Vector2(Math.Min(0.9f / buttons.Length, 0.5f), 1.0f), buttonContainer.RectTransform, maxSize: new Point(300, 30)), buttons[i]);
|
||||||
|
Buttons.Add(button);
|
||||||
x += this.Buttons[i].Rect.Width + 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBoxes.Add(this);
|
MessageBoxes.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// This is the new constructor.
|
||||||
|
///// TODO: for some reason the background does not prohibit input on the elements that are behind the box
|
||||||
|
///// TODO: allow providing buttons in the constructor
|
||||||
|
///// </summary>
|
||||||
|
/*public GUIMessageBox(RectTransform rectT, string headerText, string text, Alignment textAlignment = Alignment.TopCenter)
|
||||||
|
: base(rectT, "")
|
||||||
|
{
|
||||||
|
//BackgroundFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), rectT, Anchor.Center), null, Color.Black * 0.5f);
|
||||||
|
float headerHeight = 0.2f;
|
||||||
|
float margin = 0.05f;
|
||||||
|
InnerFrame = new GUIFrame(rectT);
|
||||||
|
GUI.Style.Apply(InnerFrame, "", this);
|
||||||
|
Header = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(headerText))
|
||||||
|
{
|
||||||
|
Header = new GUITextBlock(new RectTransform(new Vector2(1, headerHeight), InnerFrame.RectTransform, Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
RelativeOffset = new Vector2(0, margin)
|
||||||
|
}, headerText, textAlignment: Alignment.Center);
|
||||||
|
GUI.Style.Apply(Header, "", this);
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
float offset = headerHeight + margin;
|
||||||
|
var size = Header == null ? Vector2.One : new Vector2(1 - margin * 2, 1 - offset + margin);
|
||||||
|
Text = new GUITextBlock(new RectTransform(size, InnerFrame.RectTransform, Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
RelativeOffset = new Vector2(0, offset)
|
||||||
|
}, text, textAlignment: textAlignment, wrap: true);
|
||||||
|
GUI.Style.Apply(Text, "", this);
|
||||||
|
}
|
||||||
|
MessageBoxes.Add(this);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//public override void AddToGUIUpdateList(bool ignoreChildren = false, bool updateLast = false)
|
||||||
|
//{
|
||||||
|
// base.AddToGUIUpdateList(ignoreChildren, updateLast);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public override void Draw(SpriteBatch spriteBatch, bool drawChildren = true)
|
||||||
|
//{
|
||||||
|
// if (RectTransform == null)
|
||||||
|
// {
|
||||||
|
// base.Draw(spriteBatch, drawChildren);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // Custom draw order so that the background is rendered behind the parent.
|
||||||
|
// if (drawChildren)
|
||||||
|
// {
|
||||||
|
// BackgroundFrame?.Draw(spriteBatch);
|
||||||
|
// }
|
||||||
|
// base.Draw(spriteBatch, false);
|
||||||
|
// if (drawChildren)
|
||||||
|
// {
|
||||||
|
// InnerFrame?.Draw(spriteBatch);
|
||||||
|
// Header?.Draw(spriteBatch);
|
||||||
|
// Text?.Draw(spriteBatch);
|
||||||
|
// Buttons.ForEach(b => b.Draw(spriteBatch));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
if (parent != null) parent.RemoveChild(this);
|
if (Parent != null) Parent.RemoveChild(this);
|
||||||
if (MessageBoxes.Contains(this)) MessageBoxes.Remove(this);
|
if (MessageBoxes.Contains(this)) MessageBoxes.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,5 +165,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
MessageBoxes.Clear();
|
MessageBoxes.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parent does not matter. It's overridden.
|
||||||
|
/// </summary>
|
||||||
|
public void AddButton(RectTransform rectT, string text, GUIButton.OnClickedHandler onClick)
|
||||||
|
{
|
||||||
|
rectT.Parent = RectTransform;
|
||||||
|
Buttons.Add(new GUIButton(rectT, text) { OnClicked = onClick });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -16,8 +15,9 @@ namespace Barotrauma
|
|||||||
public delegate void OnValueChangedHandler(GUINumberInput numberInput);
|
public delegate void OnValueChangedHandler(GUINumberInput numberInput);
|
||||||
public OnValueChangedHandler OnValueChanged;
|
public OnValueChangedHandler OnValueChanged;
|
||||||
|
|
||||||
private GUITextBox textBox;
|
public GUITextBox TextBox { get; private set; }
|
||||||
private GUIButton plusButton, minusButton;
|
public GUIButton PlusButton { get; private set; }
|
||||||
|
public GUIButton MinusButton { get; private set; }
|
||||||
|
|
||||||
private NumberType inputType;
|
private NumberType inputType;
|
||||||
public NumberType InputType
|
public NumberType InputType
|
||||||
@@ -26,12 +26,37 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
inputType = value;
|
inputType = value;
|
||||||
plusButton.Visible = inputType == NumberType.Int;
|
PlusButton.Visible = inputType == NumberType.Int ||
|
||||||
minusButton.Visible = inputType == NumberType.Int;
|
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
|
||||||
|
MinusButton.Visible = PlusButton.Visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float? MinValueFloat, MaxValueFloat;
|
private float? minValueFloat, maxValueFloat;
|
||||||
|
public float? MinValueFloat
|
||||||
|
{
|
||||||
|
get { return minValueFloat; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
minValueFloat = value;
|
||||||
|
ClampFloatValue();
|
||||||
|
PlusButton.Visible = inputType == NumberType.Int ||
|
||||||
|
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
|
||||||
|
MinusButton.Visible = PlusButton.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float? MaxValueFloat
|
||||||
|
{
|
||||||
|
get { return maxValueFloat; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
maxValueFloat = value;
|
||||||
|
ClampFloatValue();
|
||||||
|
PlusButton.Visible = inputType == NumberType.Int ||
|
||||||
|
(inputType == NumberType.Float && MinValueFloat > float.MinValue && MaxValueFloat < float.MaxValue);
|
||||||
|
MinusButton.Visible = PlusButton.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private float floatValue;
|
private float floatValue;
|
||||||
public float FloatValue
|
public float FloatValue
|
||||||
@@ -40,24 +65,27 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == floatValue) return;
|
if (value == floatValue) return;
|
||||||
|
|
||||||
floatValue = value;
|
floatValue = value;
|
||||||
if (MinValueFloat != null)
|
ClampFloatValue();
|
||||||
{
|
float newValue = floatValue;
|
||||||
floatValue = Math.Max(floatValue, MinValueFloat.Value);
|
UpdateText();
|
||||||
minusButton.Enabled = floatValue > MinValueFloat;
|
//UpdateText may remove decimals from the value, force to full accuracy
|
||||||
}
|
floatValue = newValue;
|
||||||
if (MaxValueFloat != null)
|
|
||||||
{
|
|
||||||
floatValue = Math.Min(floatValue, MaxValueFloat.Value);
|
|
||||||
plusButton.Enabled = floatValue < MaxValueFloat;
|
|
||||||
}
|
|
||||||
textBox.Text = floatValue.ToString("G", CultureInfo.InvariantCulture);
|
|
||||||
|
|
||||||
OnValueChanged?.Invoke(this);
|
OnValueChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int decimalsToDisplay = 1;
|
||||||
|
public int DecimalsToDisplay
|
||||||
|
{
|
||||||
|
get { return decimalsToDisplay; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
decimalsToDisplay = value;
|
||||||
|
UpdateText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int? MinValueInt, MaxValueInt;
|
public int? MinValueInt, MaxValueInt;
|
||||||
|
|
||||||
private int intValue;
|
private int intValue;
|
||||||
@@ -67,93 +95,145 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == intValue) return;
|
if (value == intValue) return;
|
||||||
|
|
||||||
intValue = value;
|
intValue = value;
|
||||||
if (MinValueInt != null)
|
UpdateText();
|
||||||
{
|
|
||||||
intValue = Math.Max(intValue, MinValueInt.Value);
|
|
||||||
minusButton.Enabled = intValue > MinValueInt;
|
|
||||||
}
|
|
||||||
if (MaxValueInt != null)
|
|
||||||
{
|
|
||||||
intValue = Math.Min(intValue, MaxValueInt.Value);
|
|
||||||
plusButton.Enabled = intValue < MaxValueInt;
|
|
||||||
}
|
|
||||||
textBox.Text = this.intValue.ToString();
|
|
||||||
|
|
||||||
OnValueChanged?.Invoke(this);
|
OnValueChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUINumberInput(Rectangle rect, string style, NumberType inputType, GUIComponent parent = null)
|
public float valueStep;
|
||||||
: this(rect, style, inputType, Alignment.TopLeft, parent)
|
|
||||||
|
private float pressedTimer;
|
||||||
|
private float pressedDelay = 0.5f;
|
||||||
|
private bool IsPressedTimerRunning { get { return pressedTimer > 0; } }
|
||||||
|
|
||||||
|
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center) : base(style, rectT)
|
||||||
{
|
{
|
||||||
}
|
int buttonHeight = Rect.Height / 2;
|
||||||
|
int margin = 2;
|
||||||
|
Point buttonSize = new Point(buttonHeight - margin, buttonHeight - margin);
|
||||||
|
TextBox = new GUITextBox(new RectTransform(new Point(Rect.Width, Rect.Height), rectT), textAlignment: textAlignment, style: style)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
};
|
||||||
|
TextBox.OnTextChanged += TextChanged;
|
||||||
|
var buttonArea = new GUIFrame(new RectTransform(new Point(buttonSize.X, buttonSize.Y * 2), rectT, Anchor.CenterRight), style: null);
|
||||||
|
PlusButton = new GUIButton(new RectTransform(buttonSize, buttonArea.RectTransform), "+");
|
||||||
|
PlusButton.OnButtonDown += () =>
|
||||||
|
{
|
||||||
|
pressedTimer = pressedDelay;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
PlusButton.OnClicked += (button, data) =>
|
||||||
|
{
|
||||||
|
IncreaseValue();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
PlusButton.OnPressed += () =>
|
||||||
|
{
|
||||||
|
if (!IsPressedTimerRunning)
|
||||||
|
{
|
||||||
|
IncreaseValue();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
PlusButton.Visible = inputType == NumberType.Int;
|
||||||
|
|
||||||
public GUINumberInput(Rectangle rect, string style, NumberType inputType, Alignment alignment, GUIComponent parent = null)
|
MinusButton = new GUIButton(new RectTransform(buttonSize, buttonArea.RectTransform, Anchor.BottomRight), "-");
|
||||||
: base(style)
|
MinusButton.OnButtonDown += () =>
|
||||||
{
|
{
|
||||||
this.rect = rect;
|
pressedTimer = pressedDelay;
|
||||||
|
return true;
|
||||||
this.alignment = alignment;
|
};
|
||||||
|
MinusButton.OnClicked += (button, data) =>
|
||||||
if (parent != null)
|
{
|
||||||
parent.AddChild(this);
|
ReduceValue();
|
||||||
|
return true;
|
||||||
textBox = new GUITextBox(Rectangle.Empty, style, this);
|
};
|
||||||
textBox.OnTextChanged += TextChanged;
|
MinusButton.OnPressed += () =>
|
||||||
|
{
|
||||||
plusButton = new GUIButton(new Rectangle(0, 0, 15, rect.Height / 2), "+", null, Alignment.TopRight, Alignment.Center, style, this);
|
if (!IsPressedTimerRunning)
|
||||||
plusButton.OnClicked += ChangeIntValue;
|
{
|
||||||
plusButton.Visible = inputType == NumberType.Int;
|
ReduceValue();
|
||||||
minusButton = new GUIButton(new Rectangle(0, 0, 15, rect.Height / 2), "-", null, Alignment.BottomRight, Alignment.Center, style, this);
|
}
|
||||||
minusButton.OnClicked += ChangeIntValue;
|
return true;
|
||||||
minusButton.Visible = inputType == NumberType.Int;
|
};
|
||||||
|
MinusButton.Visible = inputType == NumberType.Int;
|
||||||
|
|
||||||
if (inputType == NumberType.Int)
|
if (inputType == NumberType.Int)
|
||||||
{
|
{
|
||||||
textBox.Text = "0";
|
UpdateText();
|
||||||
textBox.OnEnterPressed += (txtBox, txt) =>
|
TextBox.OnEnterPressed += (txtBox, txt) =>
|
||||||
{
|
{
|
||||||
textBox.Text = IntValue.ToString();
|
UpdateText();
|
||||||
textBox.Deselect();
|
TextBox.Deselect();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
textBox.OnDeselected += (txtBox, key) =>
|
TextBox.OnDeselected += (txtBox, key) => UpdateText();
|
||||||
{
|
|
||||||
textBox.Text = IntValue.ToString();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else if (inputType == NumberType.Float)
|
else if (inputType == NumberType.Float)
|
||||||
{
|
{
|
||||||
textBox.Text = "0.0";
|
UpdateText();
|
||||||
textBox.OnDeselected += (txtBox, key) =>
|
TextBox.OnDeselected += (txtBox, key) => UpdateText();
|
||||||
|
TextBox.OnEnterPressed += (txtBox, txt) =>
|
||||||
{
|
{
|
||||||
textBox.Text = FloatValue.ToString("G", CultureInfo.InvariantCulture);
|
UpdateText();
|
||||||
};
|
TextBox.Deselect();
|
||||||
textBox.OnEnterPressed += (txtBox, txt) =>
|
|
||||||
{
|
|
||||||
textBox.Text = FloatValue.ToString("G", CultureInfo.InvariantCulture);
|
|
||||||
textBox.Deselect();
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
InputType = inputType;
|
InputType = inputType;
|
||||||
|
switch (InputType)
|
||||||
|
{
|
||||||
|
case NumberType.Int:
|
||||||
|
TextBox.textFilterFunction = text => new string(text.Where(c => char.IsNumber(c)).ToArray());
|
||||||
|
break;
|
||||||
|
case NumberType.Float:
|
||||||
|
TextBox.textFilterFunction = text => new string(text.Where(c => char.IsDigit(c) || c == '.' || c == '-').ToArray());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ChangeIntValue(GUIButton button, object userData)
|
|
||||||
{
|
|
||||||
if (button == plusButton)
|
|
||||||
{
|
|
||||||
IntValue++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IntValue--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
private void ReduceValue()
|
||||||
|
{
|
||||||
|
if (inputType == NumberType.Int)
|
||||||
|
{
|
||||||
|
IntValue -= valueStep > 0 ? (int)valueStep : 1;
|
||||||
|
}
|
||||||
|
else if (maxValueFloat.HasValue && minValueFloat.HasValue)
|
||||||
|
{
|
||||||
|
FloatValue -= valueStep > 0 ? valueStep : Round();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IncreaseValue()
|
||||||
|
{
|
||||||
|
if (inputType == NumberType.Int)
|
||||||
|
{
|
||||||
|
IntValue += valueStep > 0 ? (int)valueStep : 1;
|
||||||
|
}
|
||||||
|
else if (inputType == NumberType.Float)
|
||||||
|
{
|
||||||
|
FloatValue += valueStep > 0 ? valueStep : Round();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates one percent between the range as the increment/decrement.
|
||||||
|
/// This value is rounded so that the bigger it is, the less decimals are used (min 0, max 3).
|
||||||
|
/// Return value is clamped between 0.1f and 1000.
|
||||||
|
/// </summary>
|
||||||
|
private float Round()
|
||||||
|
{
|
||||||
|
if (!maxValueFloat.HasValue || !minValueFloat.HasValue) return 0;
|
||||||
|
float onePercent = MathHelper.Lerp(minValueFloat.Value, maxValueFloat.Value, 0.01f);
|
||||||
|
float diff = maxValueFloat.Value - minValueFloat.Value;
|
||||||
|
int decimals = (int)MathHelper.Lerp(3, 0, MathUtils.InverseLerp(10, 1000, diff));
|
||||||
|
return MathHelper.Clamp((float)Math.Round(onePercent, decimals), 0.1f, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TextChanged(GUITextBox textBox, string text)
|
private bool TextChanged(GUITextBox textBox, string text)
|
||||||
@@ -162,50 +242,81 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
case NumberType.Int:
|
case NumberType.Int:
|
||||||
int newIntValue = IntValue;
|
int newIntValue = IntValue;
|
||||||
if (text == "" || text == "-")
|
if (string.IsNullOrWhiteSpace(text) || text == "-")
|
||||||
{
|
{
|
||||||
IntValue = 0;
|
intValue = 0;
|
||||||
textBox.Text = text;
|
|
||||||
}
|
}
|
||||||
else if (int.TryParse(text, out newIntValue))
|
else if (int.TryParse(text, out newIntValue))
|
||||||
{
|
{
|
||||||
IntValue = newIntValue;
|
intValue = newIntValue;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
textBox.Text = IntValue.ToString();
|
|
||||||
}
|
}
|
||||||
|
ClampIntValue();
|
||||||
break;
|
break;
|
||||||
case NumberType.Float:
|
case NumberType.Float:
|
||||||
float newFloatValue = FloatValue;
|
float newFloatValue = FloatValue;
|
||||||
|
if (string.IsNullOrWhiteSpace(text) || text == "-")
|
||||||
text = new string(text.Where(c => char.IsDigit(c) || c == '.' || c == '-').ToArray());
|
|
||||||
|
|
||||||
if (text == "" || text == "-")
|
|
||||||
{
|
{
|
||||||
FloatValue = 0;
|
floatValue = 0;
|
||||||
textBox.Text = text;
|
|
||||||
}
|
}
|
||||||
else if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out newFloatValue))
|
else if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out newFloatValue))
|
||||||
{
|
{
|
||||||
FloatValue = newFloatValue;
|
floatValue = newFloatValue;
|
||||||
textBox.Text = text;
|
|
||||||
}
|
}
|
||||||
/*else
|
ClampFloatValue();
|
||||||
{
|
|
||||||
textBox.Text = FloatValue.ToString("G", CultureInfo.InvariantCulture);
|
|
||||||
}*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
OnValueChanged?.Invoke(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
private void ClampFloatValue()
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (MinValueFloat != null)
|
||||||
|
{
|
||||||
|
floatValue = Math.Max(floatValue, MinValueFloat.Value);
|
||||||
|
MinusButton.Enabled = floatValue > MinValueFloat;
|
||||||
|
}
|
||||||
|
if (MaxValueFloat != null)
|
||||||
|
{
|
||||||
|
floatValue = Math.Min(floatValue, MaxValueFloat.Value);
|
||||||
|
PlusButton.Enabled = floatValue < MaxValueFloat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
private void ClampIntValue()
|
||||||
|
{
|
||||||
|
if (MinValueInt != null)
|
||||||
|
{
|
||||||
|
intValue = Math.Max(intValue, MinValueInt.Value);
|
||||||
|
MinusButton.Enabled = intValue > MinValueInt;
|
||||||
|
}
|
||||||
|
if (MaxValueInt != null)
|
||||||
|
{
|
||||||
|
intValue = Math.Min(intValue, MaxValueInt.Value);
|
||||||
|
PlusButton.Enabled = intValue < MaxValueInt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateText()
|
||||||
|
{
|
||||||
|
switch (InputType)
|
||||||
|
{
|
||||||
|
case NumberType.Float:
|
||||||
|
TextBox.Text = FloatValue.Format(decimalsToDisplay);
|
||||||
|
break;
|
||||||
|
case NumberType.Int:
|
||||||
|
TextBox.Text = IntValue.ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
base.Update(deltaTime);
|
||||||
|
if (IsPressedTimerRunning)
|
||||||
|
{
|
||||||
|
pressedTimer -= deltaTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,102 +24,76 @@ namespace Barotrauma
|
|||||||
get { return barSize; }
|
get { return barSize; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
float oldBarSize = barSize;
|
|
||||||
barSize = MathHelper.Clamp(value, 0.0f, 1.0f);
|
barSize = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||||
if (barSize != oldBarSize) UpdateRect();
|
//UpdateRect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIProgressBar(Rectangle rect, Color color, float barSize, GUIComponent parent = null)
|
public GUIProgressBar(RectTransform rectT, float barSize, Color? color = null, string style = "") : base(style, rectT)
|
||||||
: this(rect, color, barSize, (Alignment.Left | Alignment.Top), parent)
|
|
||||||
{
|
{
|
||||||
}
|
if (color.HasValue)
|
||||||
|
{
|
||||||
public GUIProgressBar(Rectangle rect, Color color, float barSize, Alignment alignment, GUIComponent parent = null)
|
this.color = color.Value;
|
||||||
: this(rect, color, null, barSize, alignment, parent)
|
}
|
||||||
{
|
isHorizontal = (Rect.Width > Rect.Height);
|
||||||
|
frame = new GUIFrame(new RectTransform(Vector2.One, rectT));
|
||||||
}
|
|
||||||
|
|
||||||
public GUIProgressBar(Rectangle rect, Color color, string style, float barSize, Alignment alignment, GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
this.color = color;
|
|
||||||
isHorizontal = (rect.Width > rect.Height);
|
|
||||||
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
parent.AddChild(this);
|
|
||||||
|
|
||||||
frame = new GUIFrame(new Rectangle(0, 0, 0, 0), null, this);
|
|
||||||
GUI.Style.Apply(frame, "", this);
|
GUI.Style.Apply(frame, "", this);
|
||||||
|
slider = new GUIFrame(new RectTransform(Vector2.One, rectT));
|
||||||
slider = new GUIFrame(new Rectangle(0, 0, 0, 0), null);
|
|
||||||
GUI.Style.Apply(slider, "Slider", this);
|
GUI.Style.Apply(slider, "Slider", this);
|
||||||
|
|
||||||
this.barSize = barSize;
|
this.barSize = barSize;
|
||||||
UpdateRect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public override void ApplyStyle(GUIComponentStyle style)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
|
||||||
if (frame == null) return;
|
|
||||||
|
|
||||||
frame.Color = style.Color;
|
|
||||||
frame.HoverColor = style.HoverColor;
|
|
||||||
frame.SelectedColor = style.SelectedColor;
|
|
||||||
|
|
||||||
Padding = style.Padding;
|
|
||||||
|
|
||||||
frame.OutlineColor = style.OutlineColor;
|
|
||||||
|
|
||||||
this.style = style;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private void UpdateRect()
|
|
||||||
{
|
|
||||||
slider.Rect = new Rectangle(
|
|
||||||
(int)(frame.Rect.X + padding.X),
|
|
||||||
(int)(frame.Rect.Y + padding.Y),
|
|
||||||
isHorizontal ? (int)((frame.Rect.Width - padding.X - padding.Z) * barSize) : frame.Rect.Width,
|
|
||||||
isHorizontal ? (int)(frame.Rect.Height - padding.Y - padding.W) : (int)(frame.Rect.Height * barSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
if (ProgressGetter != null) BarSize = ProgressGetter();
|
if (ProgressGetter != null) BarSize = ProgressGetter();
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
Rectangle sliderRect = new Rectangle(
|
||||||
|
frame.Rect.X,
|
||||||
Color currColor = color;
|
(int)(frame.Rect.Y + (isHorizontal ? 0 : frame.Rect.Height * (1.0f - barSize))),
|
||||||
if (state == ComponentState.Selected) currColor = selectedColor;
|
isHorizontal ? (int)((frame.Rect.Width) * barSize) : frame.Rect.Width,
|
||||||
if (state == ComponentState.Hover) currColor = hoverColor;
|
isHorizontal ? (int)(frame.Rect.Height) : (int)(frame.Rect.Height * barSize));
|
||||||
|
|
||||||
if (slider.sprites != null && slider.sprites[state].Count > 0)
|
frame.Visible = true;
|
||||||
|
slider.Visible = true;
|
||||||
|
if (AutoDraw)
|
||||||
{
|
{
|
||||||
foreach (UISprite uiSprite in slider.sprites[state])
|
frame.DrawAuto(spriteBatch);
|
||||||
{
|
}
|
||||||
if (uiSprite.Tile)
|
else
|
||||||
{
|
{
|
||||||
uiSprite.Sprite.DrawTiled(spriteBatch, slider.Rect.Location.ToVector2(), slider.Rect.Size.ToVector2(), color: currColor);
|
frame.DrawManually(spriteBatch);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
spriteBatch.Draw(uiSprite.Sprite.Texture,
|
if (BarSize <= 1.0f)
|
||||||
slider.Rect, new Rectangle(
|
{
|
||||||
uiSprite.Sprite.SourceRect.X,
|
spriteBatch.End();
|
||||||
uiSprite.Sprite.SourceRect.Y,
|
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, sliderRect);
|
||||||
(int)(uiSprite.Sprite.SourceRect.Width * (isHorizontal ? barSize : 1.0f)),
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
(int)(uiSprite.Sprite.SourceRect.Height * (isHorizontal ? 1.0f : barSize))),
|
}
|
||||||
currColor);
|
|
||||||
}
|
Color currColor = GetCurrentColor(state);
|
||||||
}
|
|
||||||
|
slider.Color = currColor;
|
||||||
|
if (AutoDraw)
|
||||||
|
{
|
||||||
|
slider.DrawAuto(spriteBatch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slider.DrawManually(spriteBatch);
|
||||||
|
}
|
||||||
|
//hide the slider, we've already drawn it manually
|
||||||
|
frame.Visible = false;
|
||||||
|
slider.Visible = false;
|
||||||
|
if (BarSize <= 1.0f)
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Barotrauma.Extensions;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -10,36 +11,79 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool isHorizontal;
|
private bool isHorizontal;
|
||||||
|
|
||||||
private GUIFrame frame;
|
public GUIFrame Frame { get; private set; }
|
||||||
private GUIButton bar;
|
public GUIButton Bar { get; private set; }
|
||||||
private float barSize;
|
private float barSize;
|
||||||
private float barScroll;
|
private float barScroll;
|
||||||
|
|
||||||
private float step;
|
private float step;
|
||||||
|
|
||||||
private bool enabled;
|
|
||||||
|
|
||||||
public delegate bool OnMovedHandler(GUIScrollBar scrollBar, float barScroll);
|
public delegate bool OnMovedHandler(GUIScrollBar scrollBar, float barScroll);
|
||||||
public OnMovedHandler OnMoved;
|
public OnMovedHandler OnMoved;
|
||||||
|
|
||||||
|
public bool IsBooleanSwitch;
|
||||||
|
|
||||||
|
public override string ToolTip
|
||||||
|
{
|
||||||
|
get { return base.ToolTip; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.ToolTip = value;
|
||||||
|
Frame.ToolTip = value;
|
||||||
|
Bar.ToolTip = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float minValue;
|
||||||
|
public float MinValue
|
||||||
|
{
|
||||||
|
get { return minValue; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
minValue = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||||
|
BarScroll = Math.Max(minValue, barScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float maxValue = 1.0f;
|
||||||
|
public float MaxValue
|
||||||
|
{
|
||||||
|
get { return maxValue; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
maxValue = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||||
|
BarScroll = Math.Min(maxValue, barScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsHorizontal
|
public bool IsHorizontal
|
||||||
{
|
{
|
||||||
get { return isHorizontal; }
|
get { return isHorizontal; }
|
||||||
set
|
/*set
|
||||||
{
|
{
|
||||||
if (isHorizontal == value) return;
|
if (isHorizontal == value) return;
|
||||||
isHorizontal = value;
|
isHorizontal = value;
|
||||||
UpdateRect();
|
UpdateRect();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled
|
public override bool Enabled
|
||||||
{
|
{
|
||||||
get { return enabled; }
|
get { return enabled; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
enabled = value;
|
enabled = value;
|
||||||
bar.Enabled = value;
|
Bar.Enabled = value;
|
||||||
|
if (!enabled) Bar.Selected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector4 Padding
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Frame?.Style == null) return Vector4.Zero;
|
||||||
|
return Frame.Style.Padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,25 +92,27 @@ namespace Barotrauma
|
|||||||
get { return step == 0.0f ? barScroll : MathUtils.RoundTowardsClosest(barScroll, step); }
|
get { return step == 0.0f ? barScroll : MathUtils.RoundTowardsClosest(barScroll, step); }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
barScroll = MathHelper.Clamp(value, 0.0f, 1.0f);
|
if (float.IsNaN(value))
|
||||||
int newX = bar.Rect.X - frame.Rect.X;
|
{
|
||||||
int newY = bar.Rect.Y - frame.Rect.Y;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
barScroll = MathHelper.Clamp(value, minValue, maxValue);
|
||||||
|
int newX = Bar.RectTransform.AbsoluteOffset.X;
|
||||||
|
int newY = Bar.RectTransform.AbsoluteOffset.Y;
|
||||||
float newScroll = step == 0.0f ? barScroll : MathUtils.RoundTowardsClosest(barScroll, step);
|
float newScroll = step == 0.0f ? barScroll : MathUtils.RoundTowardsClosest(barScroll, step);
|
||||||
|
|
||||||
if (isHorizontal)
|
if (isHorizontal)
|
||||||
{
|
{
|
||||||
newX = (int)(frame.Padding.X + newScroll * (frame.Rect.Width - bar.Rect.Width - frame.Padding.X - frame.Padding.Z));
|
newX = (int)(Padding.X + newScroll * (Frame.Rect.Width - Bar.Rect.Width - Padding.X - Padding.Z));
|
||||||
newX = MathHelper.Clamp(newX, (int)frame.Padding.X, frame.Rect.Width - bar.Rect.Width - (int)frame.Padding.Z);
|
newX = MathHelper.Clamp(newX, (int)Padding.X, Frame.Rect.Width - Bar.Rect.Width - (int)Padding.Z);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newY = (int)(frame.Padding.Y + newScroll * (frame.Rect.Height - bar.Rect.Height - frame.Padding.Y - frame.Padding.W));
|
newY = (int)(Padding.Y + newScroll * (Frame.Rect.Height - Bar.Rect.Height - Padding.Y - Padding.W));
|
||||||
newY = MathHelper.Clamp(newY, (int)frame.Padding.Y, frame.Rect.Height - bar.Rect.Height - (int)frame.Padding.W);
|
newY = MathHelper.Clamp(newY, (int)Padding.Y, Frame.Rect.Height - Bar.Rect.Height - (int)Padding.W);
|
||||||
|
|
||||||
}
|
}
|
||||||
bar.Rect = new Rectangle(newX + frame.Rect.X, newY + frame.Rect.Y, bar.Rect.Width, bar.Rect.Height);
|
|
||||||
|
Bar.RectTransform.AbsoluteOffset = new Point(newX, newY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,79 +133,39 @@ namespace Barotrauma
|
|||||||
get { return barSize; }
|
get { return barSize; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
float oldBarSize = barSize;
|
|
||||||
barSize = Math.Min(Math.Max(value, 0.0f), 1.0f);
|
barSize = Math.Min(Math.Max(value, 0.0f), 1.0f);
|
||||||
if (barSize != oldBarSize) UpdateRect();
|
UpdateRect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIScrollBar(Rectangle rect, string style, float barSize, GUIComponent parent = null)
|
public GUIScrollBar(RectTransform rectT, float barSize = 1, Color? color = null, string style = "", bool? isHorizontal = null) : base(style, rectT)
|
||||||
: this(rect, null, barSize, style, parent)
|
|
||||||
{
|
{
|
||||||
}
|
this.isHorizontal = isHorizontal ?? (Rect.Width > Rect.Height);
|
||||||
|
Frame = new GUIFrame(new RectTransform(Vector2.One, rectT));
|
||||||
public GUIScrollBar(Rectangle rect, Color? color, float barSize, string style = "", GUIComponent parent = null)
|
GUI.Style.Apply(Frame, IsHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this);
|
||||||
: this(rect, color, barSize, Alignment.TopLeft, style, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public GUIScrollBar(Rectangle rect, Color? color, float barSize, Alignment alignment, string style = "", GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.rect = rect;
|
|
||||||
//GetDimensions(parent);
|
|
||||||
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
parent.AddChild(this);
|
|
||||||
|
|
||||||
isHorizontal = (rect.Width > rect.Height);
|
|
||||||
frame = new GUIFrame(new Rectangle(0,0,0,0), style, this);
|
|
||||||
GUI.Style.Apply(frame, isHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this);
|
|
||||||
|
|
||||||
this.barSize = barSize;
|
this.barSize = barSize;
|
||||||
|
Bar = new GUIButton(new RectTransform(Vector2.One, rectT, IsHorizontal ? Anchor.CenterLeft : Anchor.TopCenter), color: color);
|
||||||
bar = new GUIButton(new Rectangle(0, 0, 0, 0), "", color, "", this);
|
GUI.Style.Apply(Bar, IsHorizontal ? "GUIButtonHorizontal" : "GUIButtonVertical", this);
|
||||||
GUI.Style.Apply(bar, isHorizontal ? "GUIButtonHorizontal" : "GUIButtoneVertical", this);
|
Bar.OnPressed = SelectBar;
|
||||||
|
|
||||||
bar.OnPressed = SelectBar;
|
|
||||||
|
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
|
||||||
UpdateRect();
|
UpdateRect();
|
||||||
|
BarScroll = 0.0f;
|
||||||
|
|
||||||
|
rectT.SizeChanged += UpdateRect;
|
||||||
|
rectT.ScaleChanged += UpdateRect;
|
||||||
|
Bar.RectTransform.SizeChanged += () => { BarScroll = barScroll; };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateRect()
|
private void UpdateRect()
|
||||||
{
|
{
|
||||||
float width = frame.Rect.Width - frame.Padding.X - frame.Padding.Z;
|
Vector4 padding = Frame.Style.Padding;
|
||||||
float height = frame.Rect.Height - frame.Padding.Y - frame.Padding.W;
|
var newSize = new Point((int)(Rect.Size.X - padding.X - padding.Z), (int)(Rect.Size.Y - padding.Y - padding.W));
|
||||||
|
newSize = IsHorizontal ? newSize.Multiply(new Vector2(BarSize, 1)) : newSize.Multiply(new Vector2(1, BarSize));
|
||||||
bar.Rect = new Rectangle(
|
Bar.RectTransform.Resize(newSize);
|
||||||
bar.Rect.X,
|
BarScroll = barScroll;
|
||||||
bar.Rect.Y,
|
|
||||||
isHorizontal ? (int)(width * barSize) : (int)width,
|
|
||||||
isHorizontal ? (int)height : (int)(height * barSize));
|
|
||||||
|
|
||||||
ClampRect();
|
|
||||||
|
|
||||||
foreach (GUIComponent child in bar.children)
|
|
||||||
{
|
|
||||||
child.Rect = bar.Rect;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClampRect()
|
protected override void Update(float deltaTime)
|
||||||
{
|
|
||||||
bar.Rect = new Rectangle(
|
|
||||||
(int)MathHelper.Clamp(bar.Rect.X, frame.Rect.X + frame.Padding.X, frame.Rect.Right - bar.Rect.Width - frame.Padding.X - frame.Padding.Z),
|
|
||||||
(int)MathHelper.Clamp(bar.Rect.Y, frame.Rect.Y + frame.Padding.Y, frame.Rect.Bottom - bar.Rect.Height - frame.Padding.Y - frame.Padding.W),
|
|
||||||
bar.Rect.Width,
|
|
||||||
bar.Rect.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
@@ -167,33 +173,42 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
|
|
||||||
if (MouseOn == frame)
|
if (IsBooleanSwitch &&
|
||||||
|
(!PlayerInput.LeftButtonHeld() || (GUI.MouseOn != this && !IsParentOf(GUI.MouseOn))))
|
||||||
|
{
|
||||||
|
int dir = Math.Sign(barScroll - (minValue + maxValue) / 2.0f);
|
||||||
|
if (dir == 0) dir = 1;
|
||||||
|
if ((barScroll <= maxValue && dir > 0) ||
|
||||||
|
(barScroll > minValue && dir < 0))
|
||||||
|
{
|
||||||
|
BarScroll += dir * 0.1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (draggingBar == this)
|
||||||
|
{
|
||||||
|
if (!PlayerInput.LeftButtonHeld()) draggingBar = null;
|
||||||
|
if ((isHorizontal && PlayerInput.MousePosition.X > Rect.X && PlayerInput.MousePosition.X < Rect.Right) ||
|
||||||
|
(!isHorizontal && PlayerInput.MousePosition.Y > Rect.Y && PlayerInput.MousePosition.Y < Rect.Bottom))
|
||||||
|
{
|
||||||
|
MoveButton(PlayerInput.MouseSpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (GUI.MouseOn == Frame)
|
||||||
{
|
{
|
||||||
if (PlayerInput.LeftButtonClicked())
|
if (PlayerInput.LeftButtonClicked())
|
||||||
{
|
{
|
||||||
MoveButton(new Vector2(
|
MoveButton(new Vector2(
|
||||||
Math.Sign(PlayerInput.MousePosition.X - bar.Rect.Center.X) * bar.Rect.Width,
|
Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width,
|
||||||
Math.Sign(PlayerInput.MousePosition.Y - bar.Rect.Center.Y) * bar.Rect.Height));
|
Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (draggingBar == this)
|
|
||||||
{
|
|
||||||
if (!PlayerInput.LeftButtonHeld()) draggingBar = null;
|
|
||||||
MoveButton(PlayerInput.MouseSpeed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SelectBar()
|
private bool SelectBar()
|
||||||
{
|
{
|
||||||
if (!enabled) return false;
|
if (!enabled) return false;
|
||||||
|
// This doesn't work
|
||||||
if (barSize == 1.0f) return false;
|
if (barSize == 1.0f) return false;
|
||||||
|
|
||||||
draggingBar = this;
|
draggingBar = this;
|
||||||
@@ -202,23 +217,23 @@ namespace Barotrauma
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoveButton(Vector2 moveAmount)
|
public void MoveButton(Vector2 moveAmount)
|
||||||
{
|
{
|
||||||
|
float newScroll = barScroll;
|
||||||
if (isHorizontal)
|
if (isHorizontal)
|
||||||
{
|
{
|
||||||
moveAmount.Y = 0.0f;
|
moveAmount.Y = 0.0f;
|
||||||
barScroll += moveAmount.X / (frame.Rect.Width - bar.Rect.Width - frame.Padding.X - frame.Padding.Z);
|
newScroll += moveAmount.X / (Frame.Rect.Width - Bar.Rect.Width - Padding.X - Padding.Z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
moveAmount.X = 0.0f;
|
moveAmount.X = 0.0f;
|
||||||
barScroll += moveAmount.Y / (frame.Rect.Height - bar.Rect.Height - frame.Padding.Y - frame.Padding.W);
|
newScroll += moveAmount.Y / (Frame.Rect.Height - Bar.Rect.Height - Padding.Y - Padding.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
BarScroll = barScroll;
|
BarScroll = newScroll;
|
||||||
|
|
||||||
if (moveAmount != Vector2.Zero && OnMoved != null) OnMoved(this, BarScroll);
|
if (moveAmount != Vector2.Zero && OnMoved != null) OnMoved(this, BarScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
@@ -7,8 +8,18 @@ namespace Barotrauma
|
|||||||
public class GUIStyle
|
public class GUIStyle
|
||||||
{
|
{
|
||||||
private Dictionary<string, GUIComponentStyle> componentStyles;
|
private Dictionary<string, GUIComponentStyle> componentStyles;
|
||||||
|
|
||||||
public GUIStyle(string file)
|
public ScalableFont Font { get; private set; }
|
||||||
|
public ScalableFont SmallFont { get; private set; }
|
||||||
|
public ScalableFont LargeFont { get; private set; }
|
||||||
|
|
||||||
|
public Sprite CursorSprite { get; private set; }
|
||||||
|
|
||||||
|
public UISprite UIGlow { get; private set; }
|
||||||
|
|
||||||
|
public SpriteSheet FocusIndicator { get; private set; }
|
||||||
|
|
||||||
|
public GUIStyle(string file, GraphicsDevice graphicsDevice)
|
||||||
{
|
{
|
||||||
componentStyles = new Dictionary<string, GUIComponentStyle>();
|
componentStyles = new Dictionary<string, GUIComponentStyle>();
|
||||||
|
|
||||||
@@ -16,7 +27,7 @@ namespace Barotrauma
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ToolBox.IsProperFilenameCase(file);
|
ToolBox.IsProperFilenameCase(file);
|
||||||
doc = XDocument.Load(file);
|
doc = XDocument.Load(file, LoadOptions.SetBaseUri);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -26,17 +37,45 @@ namespace Barotrauma
|
|||||||
|
|
||||||
foreach (XElement subElement in doc.Root.Elements())
|
foreach (XElement subElement in doc.Root.Elements())
|
||||||
{
|
{
|
||||||
GUIComponentStyle componentStyle = new GUIComponentStyle(subElement);
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
componentStyles.Add(subElement.Name.ToString().ToLowerInvariant(), componentStyle);
|
{
|
||||||
|
case "font":
|
||||||
|
Font = new ScalableFont(subElement, graphicsDevice);
|
||||||
|
break;
|
||||||
|
case "smallfont":
|
||||||
|
SmallFont = new ScalableFont(subElement, graphicsDevice);
|
||||||
|
break;
|
||||||
|
case "largefont":
|
||||||
|
LargeFont = new ScalableFont(subElement, graphicsDevice);
|
||||||
|
break;
|
||||||
|
case "cursor":
|
||||||
|
CursorSprite = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "uiglow":
|
||||||
|
UIGlow = new UISprite(subElement);
|
||||||
|
break;
|
||||||
|
case "focusindicator":
|
||||||
|
FocusIndicator = new SpriteSheet(subElement);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUIComponentStyle componentStyle = new GUIComponentStyle(subElement);
|
||||||
|
componentStyles.Add(subElement.Name.ToString().ToLowerInvariant(), componentStyle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GUIComponentStyle GetComponentStyle(string name)
|
||||||
|
{
|
||||||
|
componentStyles.TryGetValue(name.ToLowerInvariant(), out GUIComponentStyle style);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
public void Apply(GUIComponent targetComponent, string styleName = "", GUIComponent parent = null)
|
public void Apply(GUIComponent targetComponent, string styleName = "", GUIComponent parent = null)
|
||||||
{
|
{
|
||||||
GUIComponentStyle componentStyle = null;
|
GUIComponentStyle componentStyle = null;
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
GUIComponentStyle parentStyle = parent.Style;
|
GUIComponentStyle parentStyle = parent.Style;
|
||||||
|
|
||||||
if (parent.Style == null)
|
if (parent.Style == null)
|
||||||
@@ -49,8 +88,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string childStyleName = string.IsNullOrEmpty(styleName) ? targetComponent.GetType().Name : styleName;
|
string childStyleName = string.IsNullOrEmpty(styleName) ? targetComponent.GetType().Name : styleName;
|
||||||
parentStyle.ChildStyles.TryGetValue(childStyleName.ToLowerInvariant(), out componentStyle);
|
parentStyle.ChildStyles.TryGetValue(childStyleName.ToLowerInvariant(), out componentStyle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected Alignment textAlignment;
|
protected Alignment textAlignment;
|
||||||
|
|
||||||
private float textScale;
|
private float textScale = 1;
|
||||||
|
|
||||||
protected Vector2 textPos;
|
protected Vector2 textPos;
|
||||||
protected Vector2 origin;
|
protected Vector2 origin;
|
||||||
|
|
||||||
protected Vector2 caretPos;
|
|
||||||
|
|
||||||
protected Color textColor;
|
protected Color textColor;
|
||||||
|
|
||||||
private string wrappedText;
|
private string wrappedText;
|
||||||
@@ -30,7 +28,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private float textDepth;
|
private float textDepth;
|
||||||
|
|
||||||
public override Vector4 Padding
|
public Vector2 TextOffset { get; set; }
|
||||||
|
|
||||||
|
private Vector4 padding;
|
||||||
|
public Vector4 Padding
|
||||||
{
|
{
|
||||||
get { return padding; }
|
get { return padding; }
|
||||||
set
|
set
|
||||||
@@ -40,6 +41,20 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override ScalableFont Font
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.Font;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (base.Font == value) return;
|
||||||
|
base.Font = value;
|
||||||
|
SetTextPos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get { return text; }
|
get { return text; }
|
||||||
@@ -47,6 +62,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (Text == value) return;
|
if (Text == value) return;
|
||||||
|
|
||||||
|
//reset scale, it gets recalculated in SetTextPos
|
||||||
|
if (autoScale) textScale = 1.0f;
|
||||||
|
|
||||||
text = value;
|
text = value;
|
||||||
wrappedText = value;
|
wrappedText = value;
|
||||||
SetTextPos();
|
SetTextPos();
|
||||||
@@ -57,35 +75,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get { return wrappedText; }
|
get { return wrappedText; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Rectangle Rect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return base.Rect;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (base.Rect == value) return;
|
|
||||||
foreach (GUIComponent child in children)
|
|
||||||
{
|
|
||||||
child.Rect = new Rectangle(child.Rect.X + value.X - rect.X, child.Rect.Y + value.Y - rect.Y, child.Rect.Width, child.Rect.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point moveAmount = value.Location - rect.Location;
|
|
||||||
|
|
||||||
rect = value;
|
|
||||||
if (value.Width != rect.Width || value.Height != rect.Height)
|
|
||||||
{
|
|
||||||
SetTextPos();
|
|
||||||
}
|
|
||||||
else if (moveAmount != Point.Zero)
|
|
||||||
{
|
|
||||||
caretPos += moveAmount.ToVector2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float TextDepth
|
public float TextDepth
|
||||||
{
|
{
|
||||||
get { return textDepth; }
|
get { return textDepth; }
|
||||||
@@ -110,142 +100,146 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool autoScale;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When enabled, the text is automatically scaled down to fit the textblock.
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoScale
|
||||||
|
{
|
||||||
|
get { return autoScale; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (autoScale == value) return;
|
||||||
|
autoScale = value;
|
||||||
|
if (autoScale)
|
||||||
|
{
|
||||||
|
SetTextPos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Vector2 Origin
|
public Vector2 Origin
|
||||||
{
|
{
|
||||||
get { return origin; }
|
get { return origin; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 TextSize
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
public Color TextColor
|
public Color TextColor
|
||||||
{
|
{
|
||||||
get { return textColor; }
|
get { return textColor; }
|
||||||
set { textColor = value; }
|
set { textColor = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 CaretPos
|
public Alignment TextAlignment
|
||||||
{
|
{
|
||||||
get { return caretPos; }
|
get { return textAlignment; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (textAlignment == value) return;
|
||||||
|
textAlignment = value;
|
||||||
|
SetTextPos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the new constructor.
|
||||||
|
/// If the rectT height is set 0, the height is calculated from the text.
|
||||||
|
/// </summary>
|
||||||
|
public GUITextBlock(RectTransform rectT, string text, Color? textColor = null, ScalableFont font = null,
|
||||||
|
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||||
|
: base(style, rectT)
|
||||||
|
{
|
||||||
|
if (color.HasValue)
|
||||||
|
{
|
||||||
|
this.color = color.Value;
|
||||||
|
}
|
||||||
|
if (textColor.HasValue)
|
||||||
|
{
|
||||||
|
this.textColor = textColor.Value;
|
||||||
|
}
|
||||||
|
this.Font = font ?? GUI.Font;
|
||||||
|
this.textAlignment = textAlignment;
|
||||||
|
this.Wrap = wrap;
|
||||||
|
this.Text = text ?? "";
|
||||||
|
if (rectT.Rect.Height == 0 && !string.IsNullOrEmpty(text))
|
||||||
|
{
|
||||||
|
CalculateHeightFromText();
|
||||||
|
}
|
||||||
|
SetTextPos();
|
||||||
|
|
||||||
|
RectTransform.ScaleChanged += SetTextPos;
|
||||||
|
RectTransform.SizeChanged += SetTextPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CalculateHeightFromText()
|
||||||
|
{
|
||||||
|
if (wrappedText == null) { return; }
|
||||||
|
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText).Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITextBlock(Rectangle rect, string text, string style, GUIComponent parent, ScalableFont font)
|
|
||||||
: this(rect, text, style, Alignment.TopLeft, Alignment.TopLeft, parent, false, font)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public GUITextBlock(Rectangle rect, string text, string style, GUIComponent parent = null, bool wrap = false)
|
|
||||||
: this(rect, text, style, Alignment.TopLeft, Alignment.TopLeft, parent, wrap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUITextBlock(Rectangle rect, string text, Color? color, Color? textColor, Alignment textAlignment = Alignment.Left, string style = null, GUIComponent parent = null, bool wrap = false)
|
|
||||||
: this(rect, text,color, textColor, Alignment.TopLeft, textAlignment, style, parent, wrap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateDimensions(GUIComponent parent = null)
|
|
||||||
{
|
|
||||||
base.UpdateDimensions(parent);
|
|
||||||
|
|
||||||
SetTextPos();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ApplyStyle(GUIComponentStyle style)
|
public override void ApplyStyle(GUIComponentStyle style)
|
||||||
{
|
{
|
||||||
if (style == null) return;
|
if (style == null) return;
|
||||||
base.ApplyStyle(style);
|
base.ApplyStyle(style);
|
||||||
|
padding = style.Padding;
|
||||||
|
|
||||||
textColor = style.textColor;
|
textColor = style.textColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public GUITextBlock(Rectangle rect, string text, Color? color, Color? textColor, Alignment alignment, Alignment textAlignment = Alignment.Left, string style = null, GUIComponent parent = null, bool wrap = false, ScalableFont font = null)
|
|
||||||
: this (rect, text, style, alignment, textAlignment, parent, wrap, font)
|
|
||||||
{
|
|
||||||
if (color != null) this.color = (Color)color;
|
|
||||||
if (textColor != null) this.textColor = (Color)textColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUITextBlock(Rectangle rect, string text, string style, Alignment alignment = Alignment.TopLeft, Alignment textAlignment = Alignment.TopLeft, GUIComponent parent = null, bool wrap = false, ScalableFont font = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
|
||||||
this.Font = font == null ? GUI.Font : font;
|
|
||||||
|
|
||||||
this.rect = rect;
|
|
||||||
|
|
||||||
this.text = text;
|
|
||||||
|
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
this.padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
|
||||||
|
|
||||||
this.textAlignment = textAlignment;
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
parent.AddChild(this);
|
|
||||||
|
|
||||||
this.Wrap = wrap;
|
|
||||||
|
|
||||||
SetTextPos();
|
|
||||||
|
|
||||||
TextScale = 1.0f;
|
|
||||||
|
|
||||||
if (rect.Height == 0 && !string.IsNullOrEmpty(Text))
|
|
||||||
{
|
|
||||||
this.rect.Height = (int)Font.MeasureString(wrappedText).Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTextPos()
|
public void SetTextPos()
|
||||||
{
|
{
|
||||||
if (text == null) return;
|
if (text == null) return;
|
||||||
|
|
||||||
|
var rect = Rect;
|
||||||
|
|
||||||
overflowClipActive = false;
|
overflowClipActive = false;
|
||||||
|
|
||||||
wrappedText = text;
|
wrappedText = text;
|
||||||
|
|
||||||
Vector2 size = MeasureText(text);
|
TextSize = MeasureText(text);
|
||||||
|
|
||||||
if (Wrap && rect.Width > 0)
|
if (Wrap && rect.Width > 0)
|
||||||
{
|
{
|
||||||
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale);
|
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale);
|
||||||
size = MeasureText(wrappedText);
|
TextSize = MeasureText(wrappedText);
|
||||||
}
|
}
|
||||||
else if (OverflowClip)
|
else if (OverflowClip)
|
||||||
{
|
{
|
||||||
overflowClipActive = size.X > rect.Width;
|
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))
|
||||||
|
{
|
||||||
|
TextScale -= 0.05f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
textPos = new Vector2(rect.Width / 2.0f, rect.Height / 2.0f);
|
textPos = new Vector2(rect.Width / 2.0f, rect.Height / 2.0f);
|
||||||
origin = size * 0.5f;
|
origin = TextSize / textScale * 0.5f;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive)
|
if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive)
|
||||||
origin.X += (rect.Width / 2.0f - padding.X) - size.X / 2;
|
origin.X += (rect.Width / 2.0f - TextSize.X / 2) / textScale - padding.X;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive)
|
if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive)
|
||||||
origin.X -= (rect.Width / 2.0f - padding.Z) - size.X / 2;
|
origin.X -= (rect.Width / 2.0f - TextSize.X / 2) / textScale - padding.Z;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Top))
|
if (textAlignment.HasFlag(Alignment.Top))
|
||||||
origin.Y += (rect.Height / 2.0f - padding.Y) - size.Y / 2;
|
origin.Y += (rect.Height / 2.0f - TextSize.Y / 2) / textScale - padding.Y;
|
||||||
|
|
||||||
if (textAlignment.HasFlag(Alignment.Bottom))
|
if (textAlignment.HasFlag(Alignment.Bottom))
|
||||||
origin.Y -= (rect.Height / 2.0f - padding.W) - size.Y / 2;
|
origin.Y -= (rect.Height / 2.0f - TextSize.Y / 2) / textScale - padding.W;
|
||||||
|
|
||||||
origin.X = (int)origin.X;
|
origin.X = (int)(origin.X);
|
||||||
origin.Y = (int)origin.Y;
|
origin.Y = (int)(origin.Y);
|
||||||
|
|
||||||
textPos.X = (int)textPos.X;
|
textPos.X = (int)textPos.X;
|
||||||
textPos.Y = (int)textPos.Y;
|
textPos.Y = (int)textPos.Y;
|
||||||
|
|
||||||
if (wrappedText.Contains("\n"))
|
|
||||||
{
|
|
||||||
string[] lines = wrappedText.Split('\n');
|
|
||||||
Vector2 lastLineSize = MeasureText(lines[lines.Length-1]);
|
|
||||||
caretPos = new Vector2(rect.X + lastLineSize.X, rect.Y + size.Y - lastLineSize.Y) + textPos - origin;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
caretPos = new Vector2(rect.X + size.X, rect.Y) + textPos - origin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 MeasureText(string text)
|
private Vector2 MeasureText(string text)
|
||||||
@@ -268,37 +262,32 @@ namespace Barotrauma
|
|||||||
textColor = new Color(textColor.R, textColor.G, textColor.B, a);
|
textColor = new Color(textColor.R, textColor.G, textColor.B, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
|
||||||
Draw(spriteBatch, Vector2.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, Vector2 offset)
|
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
Color currColor = color;
|
Color currColor = GetCurrentColor(state);
|
||||||
if (state == ComponentState.Hover) currColor = hoverColor;
|
|
||||||
if (state == ComponentState.Selected) currColor = selectedColor;
|
var rect = Rect;
|
||||||
|
|
||||||
Rectangle drawRect = rect;
|
|
||||||
if (offset != Vector2.Zero) drawRect.Location += offset.ToPoint();
|
|
||||||
|
|
||||||
base.Draw(spriteBatch);
|
base.Draw(spriteBatch);
|
||||||
|
|
||||||
if (TextGetter != null) Text = TextGetter();
|
if (TextGetter != null) Text = TextGetter();
|
||||||
|
|
||||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
if (overflowClipActive)
|
if (overflowClipActive)
|
||||||
{
|
{
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = rect;
|
spriteBatch.End();
|
||||||
|
Rectangle scissorRect = new Rectangle(rect.X + (int)padding.X, rect.Y, rect.Width - (int)padding.X - (int)padding.Z, rect.Height);
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = scissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(text))
|
if (!string.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
Font.DrawString(spriteBatch,
|
Font.DrawString(spriteBatch,
|
||||||
Wrap ? wrappedText : text,
|
Wrap ? wrappedText : text,
|
||||||
new Vector2(rect.X, rect.Y) + textPos + offset,
|
rect.Location.ToVector2() + textPos + TextOffset,
|
||||||
textColor * (textColor.A / 255.0f),
|
textColor * (textColor.A / 255.0f),
|
||||||
0.0f, origin, TextScale,
|
0.0f, origin, TextScale,
|
||||||
SpriteEffects.None, textDepth);
|
SpriteEffects.None, textDepth);
|
||||||
@@ -306,11 +295,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (overflowClipActive)
|
if (overflowClipActive)
|
||||||
{
|
{
|
||||||
|
spriteBatch.End();
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
|
|
||||||
if (OutlineColor.A * currColor.A > 0.0f) GUI.DrawRectangle(spriteBatch, rect, OutlineColor * (currColor.A / 255.0f), false);
|
if (OutlineColor.A * currColor.A > 0.0f) GUI.DrawRectangle(spriteBatch, rect, OutlineColor * (currColor.A / 255.0f), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -15,8 +18,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
bool caretVisible;
|
bool caretVisible;
|
||||||
float caretTimer;
|
float caretTimer;
|
||||||
|
|
||||||
GUITextBlock textBlock;
|
private GUIFrame frame;
|
||||||
|
private GUITextBlock textBlock;
|
||||||
|
|
||||||
|
public Func<string, string> textFilterFunction;
|
||||||
|
|
||||||
public delegate bool OnEnterHandler(GUITextBox textBox, string text);
|
public delegate bool OnEnterHandler(GUITextBox textBox, string text);
|
||||||
public OnEnterHandler OnEnterPressed;
|
public OnEnterHandler OnEnterPressed;
|
||||||
@@ -24,22 +30,73 @@ namespace Barotrauma
|
|||||||
public event TextBoxEvent OnKeyHit;
|
public event TextBoxEvent OnKeyHit;
|
||||||
|
|
||||||
public delegate bool OnTextChangedHandler(GUITextBox textBox, string text);
|
public delegate bool OnTextChangedHandler(GUITextBox textBox, string text);
|
||||||
public OnTextChangedHandler OnTextChanged;
|
/// <summary>
|
||||||
|
/// Don't set the Text property on delegates that register to this event, because modifying the Text will launch this event -> stack overflow.
|
||||||
|
/// If the event launches, the text should already be up to date!
|
||||||
|
/// </summary>
|
||||||
|
public event OnTextChangedHandler OnTextChanged;
|
||||||
|
|
||||||
public bool CaretEnabled;
|
public bool CaretEnabled { get; set; }
|
||||||
|
public Color? CaretColor { get; set; }
|
||||||
|
|
||||||
private int? maxTextLength;
|
private int? maxTextLength;
|
||||||
|
|
||||||
|
private int _caretIndex;
|
||||||
|
private int CaretIndex
|
||||||
|
{
|
||||||
|
get { return _caretIndex; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
previousCaretIndex = _caretIndex;
|
||||||
|
_caretIndex = value;
|
||||||
|
caretPosDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool caretPosDirty;
|
||||||
|
protected Vector2 caretPos;
|
||||||
|
public Vector2 CaretScreenPos => Rect.Location.ToVector2() + caretPos;
|
||||||
|
|
||||||
|
private bool isSelecting;
|
||||||
|
private string selectedText = string.Empty;
|
||||||
|
private string clipboard = string.Empty;
|
||||||
|
private int selectedCharacters;
|
||||||
|
private int selectionStartIndex;
|
||||||
|
private int selectionEndIndex;
|
||||||
|
private bool IsLeftToRight => selectionStartIndex <= selectionEndIndex;
|
||||||
|
private int previousCaretIndex;
|
||||||
|
private Vector2 selectionStartPos;
|
||||||
|
private Vector2 selectionEndPos;
|
||||||
|
private Vector2 selectionRectSize;
|
||||||
|
|
||||||
|
private readonly Memento<string> memento = new Memento<string>();
|
||||||
|
|
||||||
public GUITextBlock.TextGetterHandler TextGetter
|
public GUITextBlock.TextGetterHandler TextGetter
|
||||||
{
|
{
|
||||||
get { return textBlock.TextGetter; }
|
get { return textBlock.TextGetter; }
|
||||||
set { textBlock.TextGetter = value; }
|
set { textBlock.TextGetter = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Selected
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Wrap
|
public bool Wrap
|
||||||
{
|
{
|
||||||
get { return textBlock.Wrap; }
|
get { return textBlock.Wrap; }
|
||||||
set { textBlock.Wrap = value; }
|
set
|
||||||
|
{
|
||||||
|
textBlock.Wrap = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//should the text be limited to the size of the box
|
||||||
|
//ignored when MaxTextLength is set or text wrapping is enabled
|
||||||
|
public bool ClampText
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? MaxTextLength
|
public int? MaxTextLength
|
||||||
@@ -51,11 +108,18 @@ namespace Barotrauma
|
|||||||
maxTextLength = value;
|
maxTextLength = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled
|
public override bool Enabled
|
||||||
{
|
{
|
||||||
get;
|
get { return enabled; }
|
||||||
set;
|
set
|
||||||
|
{
|
||||||
|
enabled = value;
|
||||||
|
if (!enabled && Selected)
|
||||||
|
{
|
||||||
|
Deselect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToolTip
|
public override string ToolTip
|
||||||
@@ -110,23 +174,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Rectangle Rect
|
// TODO: should this be defined in the stylesheet?
|
||||||
{
|
public Color SelectionColor { get; set; } = Color.White * 0.25f;
|
||||||
get
|
|
||||||
{
|
|
||||||
return base.Rect;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base.Rect = value;
|
|
||||||
|
|
||||||
if (textBlock != null)
|
|
||||||
{
|
|
||||||
textBlock.Rect = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -135,132 +185,229 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (textBlock.Text == value) return;
|
SetText(value, store: false);
|
||||||
|
CaretIndex = Text.Length;
|
||||||
textBlock.Text = value;
|
OnTextChanged?.Invoke(this, Text);
|
||||||
if (textBlock.Text == null) textBlock.Text = "";
|
|
||||||
|
|
||||||
if (textBlock.Text != "")
|
|
||||||
{
|
|
||||||
if (!Wrap)
|
|
||||||
{
|
|
||||||
if (maxTextLength != null)
|
|
||||||
{
|
|
||||||
if (Text.Length > maxTextLength)
|
|
||||||
{
|
|
||||||
Text = textBlock.Text.Substring(0, (int)maxTextLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Font.MeasureString(textBlock.Text).X > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z))
|
|
||||||
{
|
|
||||||
Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITextBox(Rectangle rect, string style = null, GUIComponent parent = null)
|
public string WrappedText
|
||||||
: this(rect, null, null, Alignment.Left, Alignment.Left, style, parent)
|
|
||||||
{
|
{
|
||||||
|
get { return textBlock.WrappedText; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITextBox(Rectangle rect, Alignment alignment = Alignment.Left, string style = null, GUIComponent parent = null)
|
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, ScalableFont font = null,
|
||||||
: this(rect, null, null, alignment, Alignment.Left, style, parent)
|
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||||
{
|
: base(style, rectT)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUITextBox(Rectangle rect, Color? color, Color? textColor, Alignment alignment, Alignment textAlignment = Alignment.CenterLeft, string style = null, GUIComponent parent = null)
|
|
||||||
: base(style)
|
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
|
this.color = color ?? Color.White;
|
||||||
this.rect = rect;
|
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
||||||
|
GUI.Style.Apply(frame, style == "" ? "GUITextBox" : style);
|
||||||
if (color != null) this.color = (Color)color;
|
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.Center), text, textColor, font, textAlignment, wrap);
|
||||||
|
GUI.Style.Apply(textBlock, "", this);
|
||||||
this.alignment = alignment;
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
parent.AddChild(this);
|
|
||||||
|
|
||||||
|
|
||||||
textBlock = new GUITextBlock(new Rectangle(0,0,0,0), "", color, textColor, textAlignment, style, this);
|
|
||||||
|
|
||||||
Font = GUI.Font;
|
|
||||||
|
|
||||||
GUI.Style.Apply(textBlock, style == "" ? "GUITextBox" : style);
|
|
||||||
textBlock.Padding = new Vector4(3.0f, 0.0f, 3.0f, 0.0f);
|
|
||||||
|
|
||||||
CaretEnabled = true;
|
CaretEnabled = true;
|
||||||
|
caretPosDirty = true;
|
||||||
|
|
||||||
|
Font = textBlock.Font;
|
||||||
|
|
||||||
|
rectT.SizeChanged += () => { caretPosDirty = true; };
|
||||||
|
rectT.ScaleChanged += () => { caretPosDirty = true; };
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SetText(string text, bool store = true)
|
||||||
|
{
|
||||||
|
if (textFilterFunction != null)
|
||||||
|
{
|
||||||
|
text = textFilterFunction(text);
|
||||||
|
}
|
||||||
|
if (textBlock.Text == text) { return false; }
|
||||||
|
textBlock.Text = text;
|
||||||
|
if (textBlock.Text == null) textBlock.Text = "";
|
||||||
|
if (textBlock.Text != "" && !Wrap)
|
||||||
|
{
|
||||||
|
if (maxTextLength != null)
|
||||||
|
{
|
||||||
|
if (textBlock.Text.Length > maxTextLength)
|
||||||
|
{
|
||||||
|
textBlock.Text = textBlock.Text.Substring(0, (int)maxTextLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ClampText && Font.MeasureString(textBlock.Text).X > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z))
|
||||||
|
{
|
||||||
|
textBlock.Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (store)
|
||||||
|
{
|
||||||
|
memento.Store(textBlock.Text);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateCaretPos()
|
||||||
|
{
|
||||||
|
if (textBlock.WrappedText.Contains("\n"))
|
||||||
|
{
|
||||||
|
string[] lines = textBlock.WrappedText.Split('\n');
|
||||||
|
int totalIndex = 0;
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
int currentLineLength = lines[i].Length;
|
||||||
|
totalIndex += currentLineLength;
|
||||||
|
// The caret is on this line
|
||||||
|
if (CaretIndex < totalIndex || totalIndex == textBlock.Text.Length)
|
||||||
|
{
|
||||||
|
int diff = totalIndex - CaretIndex;
|
||||||
|
int index = currentLineLength - diff;
|
||||||
|
Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index));
|
||||||
|
Vector2 lastLineSize = Font.MeasureString(lines[i]);
|
||||||
|
float totalTextHeight = Font.MeasureString(textBlock.WrappedText.Substring(0, totalIndex)).Y;
|
||||||
|
caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector2 textSize = Font.MeasureString(textBlock.Text.Substring(0, CaretIndex));
|
||||||
|
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin;
|
||||||
|
}
|
||||||
|
caretPosDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Tuple<Vector2, int>> GetAllPositions()
|
||||||
|
{
|
||||||
|
var positions = new List<Tuple<Vector2, int>>();
|
||||||
|
if (textBlock.WrappedText.Contains("\n"))
|
||||||
|
{
|
||||||
|
string[] lines = textBlock.WrappedText.Split('\n');
|
||||||
|
int index = 0;
|
||||||
|
int totalIndex = 0;
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
string line = lines[i];
|
||||||
|
totalIndex += line.Length;
|
||||||
|
float totalTextHeight = Font.MeasureString(textBlock.WrappedText.Substring(0, totalIndex)).Y;
|
||||||
|
for (int j = 0; j <= line.Length; j++)
|
||||||
|
{
|
||||||
|
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j));
|
||||||
|
Vector2 indexPos = new Vector2(lineTextSize.X + textBlock.Padding.X, totalTextHeight + textBlock.Padding.Y);
|
||||||
|
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
|
||||||
|
positions.Add(new Tuple<Vector2, int>(textBlock.Rect.Location.ToVector2() + indexPos, index + j));
|
||||||
|
}
|
||||||
|
index = totalIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i <= textBlock.Text.Length; i++)
|
||||||
|
{
|
||||||
|
Vector2 textSize = Font.MeasureString(textBlock.Text.Substring(0, i));
|
||||||
|
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y);
|
||||||
|
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
|
||||||
|
positions.Add(new Tuple<Vector2, int>(textBlock.Rect.Location.ToVector2() + indexPos, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetCaretIndexFromScreenPos(Vector2 pos)
|
||||||
|
{
|
||||||
|
var positions = GetAllPositions().OrderBy(p => Vector2.DistanceSquared(p.Item1, pos));
|
||||||
|
var posIndex = positions.FirstOrDefault();
|
||||||
|
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
|
||||||
|
return posIndex != null ? posIndex.Item2 : textBlock.Text.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select()
|
public void Select()
|
||||||
{
|
{
|
||||||
|
if (memento.Current == null)
|
||||||
|
{
|
||||||
|
memento.Store(Text);
|
||||||
|
}
|
||||||
Selected = true;
|
Selected = true;
|
||||||
keyboardDispatcher.Subscriber = this;
|
CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
|
||||||
//if (Clicked != null) Clicked(this);
|
ClearSelection();
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = this;
|
||||||
|
OnSelected?.Invoke(this, Keys.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deselect()
|
public void Deselect()
|
||||||
{
|
{
|
||||||
|
memento.Clear();
|
||||||
Selected = false;
|
Selected = false;
|
||||||
if (keyboardDispatcher.Subscriber == this) keyboardDispatcher.Subscriber = null;
|
if (GUI.KeyboardDispatcher.Subscriber == this)
|
||||||
|
{
|
||||||
|
GUI.KeyboardDispatcher.Subscriber = null;
|
||||||
|
}
|
||||||
OnDeselected?.Invoke(this, Keys.None);
|
OnDeselected?.Invoke(this, Keys.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flash(Color? color = null)
|
public override void Flash(Color? color = null, float flashDuration = 1.5f)
|
||||||
{
|
{
|
||||||
textBlock.Flash(color);
|
textBlock.Flash(color, flashDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
protected override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
if (flashTimer > 0.0f) flashTimer -= deltaTime;
|
if (flashTimer > 0.0f) flashTimer -= deltaTime;
|
||||||
if (!Enabled) return;
|
if (!Enabled) return;
|
||||||
|
if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || GUI.IsMouseOn(this)))
|
||||||
if (MouseRect.Contains(PlayerInput.MousePosition) && Enabled &&
|
|
||||||
(MouseOn == null || MouseOn == this || IsParentOf(MouseOn) || MouseOn.IsParentOf(this)))
|
|
||||||
{
|
{
|
||||||
state = ComponentState.Hover;
|
state = ComponentState.Hover;
|
||||||
if (PlayerInput.LeftButtonClicked())
|
if (PlayerInput.LeftButtonDown())
|
||||||
{
|
{
|
||||||
Select();
|
Select();
|
||||||
OnSelected?.Invoke(this, Keys.None);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isSelecting = PlayerInput.LeftButtonHeld();
|
||||||
|
}
|
||||||
|
if (PlayerInput.DoubleClicked())
|
||||||
|
{
|
||||||
|
SelectAll();
|
||||||
|
}
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
if (!MathUtils.NearlyEqual(PlayerInput.MouseSpeed.X, 0))
|
||||||
|
{
|
||||||
|
CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
|
||||||
|
CalculateCaretPos();
|
||||||
|
CalculateSelection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
isSelecting = false;
|
||||||
state = ComponentState.None;
|
state = ComponentState.None;
|
||||||
}
|
}
|
||||||
|
if (!isSelecting)
|
||||||
|
{
|
||||||
|
isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
|
||||||
|
}
|
||||||
|
|
||||||
if (CaretEnabled)
|
if (CaretEnabled)
|
||||||
{
|
{
|
||||||
caretTimer += deltaTime;
|
caretTimer += deltaTime;
|
||||||
caretVisible = ((caretTimer * 1000.0f) % 1000) < 500;
|
caretVisible = ((caretTimer * 1000.0f) % 1000) < 500;
|
||||||
|
if (caretVisible && caretPosDirty)
|
||||||
|
{
|
||||||
|
CalculateCaretPos();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboardDispatcher.Subscriber == this)
|
if (GUI.KeyboardDispatcher.Subscriber == this)
|
||||||
{
|
{
|
||||||
state = ComponentState.Selected;
|
state = ComponentState.Selected;
|
||||||
Character.DisableControls = true;
|
Character.DisableControls = true;
|
||||||
if (OnEnterPressed != null && PlayerInput.KeyHit(Keys.Enter))
|
if (OnEnterPressed != null && PlayerInput.KeyHit(Keys.Enter))
|
||||||
{
|
{
|
||||||
string input = Text;
|
OnEnterPressed(this, Text);
|
||||||
Text = "";
|
|
||||||
OnEnterPressed(this, input);
|
|
||||||
}
|
}
|
||||||
#if LINUX
|
|
||||||
else if (PlayerInput.KeyHit(Keys.Back) && Text.Length>0)
|
|
||||||
{
|
|
||||||
Text = Text.Substring(0, Text.Length-1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (Selected)
|
else if (Selected)
|
||||||
{
|
{
|
||||||
@@ -268,40 +415,133 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
textBlock.State = state;
|
textBlock.State = state;
|
||||||
textBlock.Update(deltaTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
protected override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
base.Draw(spriteBatch);
|
||||||
DrawChildren(spriteBatch);
|
// Frame is not used in the old system.
|
||||||
|
frame?.DrawManually(spriteBatch);
|
||||||
if (!CaretEnabled) return;
|
textBlock.DrawManually(spriteBatch);
|
||||||
|
if (Selected)
|
||||||
Vector2 caretPos = textBlock.CaretPos;
|
|
||||||
|
|
||||||
if (caretVisible && Selected)
|
|
||||||
{
|
{
|
||||||
GUI.DrawLine(spriteBatch,
|
if (caretVisible )
|
||||||
new Vector2((int)caretPos.X + 2, caretPos.Y + 3),
|
{
|
||||||
new Vector2((int)caretPos.X + 2, caretPos.Y + Font.MeasureString("I").Y - 3),
|
GUI.DrawLine(spriteBatch,
|
||||||
textBlock.TextColor * (textBlock.TextColor.A / 255.0f));
|
new Vector2(Rect.X + (int)caretPos.X + 2, Rect.Y + caretPos.Y + 3),
|
||||||
|
new Vector2(Rect.X + (int)caretPos.X + 2, Rect.Y + caretPos.Y + Font.MeasureString("I").Y - 3),
|
||||||
|
CaretColor ?? textBlock.TextColor * (textBlock.TextColor.A / 255.0f));
|
||||||
|
}
|
||||||
|
if (selectedCharacters > 0)
|
||||||
|
{
|
||||||
|
DrawSelectionRect(spriteBatch);
|
||||||
|
}
|
||||||
|
//GUI.DrawString(spriteBatch, new Vector2(100, 0), selectedCharacters.ToString(), Color.LightBlue, Color.Black);
|
||||||
|
//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, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSelectionRect(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
if (textBlock.WrappedText.Contains("\n"))
|
||||||
|
{
|
||||||
|
// Multiline selection
|
||||||
|
string[] lines = textBlock.WrappedText.Split('\n');
|
||||||
|
int totalIndex = 0;
|
||||||
|
int previousCharacters = 0;
|
||||||
|
Vector2 offset = textBlock.TextPos - textBlock.Origin;
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
string currentLine = lines[i];
|
||||||
|
int currentLineLength = currentLine.Length;
|
||||||
|
totalIndex += currentLineLength;
|
||||||
|
bool containsSelection = IsLeftToRight
|
||||||
|
? selectionStartIndex < totalIndex && selectionEndIndex > previousCharacters
|
||||||
|
: selectionEndIndex < totalIndex && selectionStartIndex > previousCharacters;
|
||||||
|
if (containsSelection)
|
||||||
|
{
|
||||||
|
Vector2 currentLineSize = Font.MeasureString(currentLine);
|
||||||
|
if ((IsLeftToRight && selectionStartIndex < previousCharacters && selectionEndIndex > totalIndex)
|
||||||
|
|| !IsLeftToRight && selectionEndIndex < previousCharacters && selectionStartIndex > totalIndex)
|
||||||
|
{
|
||||||
|
// select the whole line
|
||||||
|
Vector2 topLeft = offset + new Vector2(0, currentLineSize.Y * i);
|
||||||
|
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, currentLineSize, SelectionColor, isFilled: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IsLeftToRight)
|
||||||
|
{
|
||||||
|
bool selectFromTheBeginning = selectionStartIndex <= previousCharacters;
|
||||||
|
int startIndex = selectFromTheBeginning ? 0 : Math.Abs(selectionStartIndex - previousCharacters);
|
||||||
|
int endIndex = Math.Abs(selectionEndIndex - previousCharacters);
|
||||||
|
int characters = Math.Min(endIndex - startIndex, currentLineLength - startIndex);
|
||||||
|
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(startIndex, characters));
|
||||||
|
Vector2 topLeft = selectFromTheBeginning
|
||||||
|
? new Vector2(offset.X, offset.Y + currentLineSize.Y * i)
|
||||||
|
: new Vector2(selectionStartPos.X, offset.Y + currentLineSize.Y * i);
|
||||||
|
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool selectFromTheBeginning = selectionStartIndex >= totalIndex;
|
||||||
|
bool selectFromTheStart = selectionEndIndex <= previousCharacters;
|
||||||
|
int startIndex = selectFromTheBeginning ? currentLineLength : Math.Abs(selectionStartIndex - previousCharacters);
|
||||||
|
int endIndex = selectFromTheStart ? 0 : Math.Abs(selectionEndIndex - previousCharacters);
|
||||||
|
int characters = Math.Min(Math.Abs(endIndex - startIndex), currentLineLength);
|
||||||
|
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(endIndex, characters));
|
||||||
|
Vector2 topLeft = selectFromTheBeginning
|
||||||
|
? new Vector2(offset.X + currentLineSize.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i)
|
||||||
|
: new Vector2(selectionStartPos.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i);
|
||||||
|
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousCharacters = totalIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Single line selection
|
||||||
|
Vector2 topLeft = IsLeftToRight ? selectionStartPos : selectionEndPos;
|
||||||
|
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectionRectSize, SelectionColor, isFilled: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReceiveTextInput(char inputChar)
|
public void ReceiveTextInput(char inputChar)
|
||||||
{
|
{
|
||||||
Text = Text + inputChar;
|
if (selectedCharacters > 0)
|
||||||
|
{
|
||||||
if (OnTextChanged!=null) OnTextChanged(this, Text);
|
RemoveSelectedText();
|
||||||
|
}
|
||||||
|
if (SetText(Text.Insert(CaretIndex, inputChar.ToString())))
|
||||||
|
{
|
||||||
|
CaretIndex = Math.Min(Text.Length, CaretIndex + 1);
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void ReceiveTextInput(string text)
|
|
||||||
|
public void ReceiveTextInput(string input)
|
||||||
{
|
{
|
||||||
Text = Text + text;
|
if (selectedCharacters > 0)
|
||||||
|
{
|
||||||
if (OnTextChanged != null) OnTextChanged(this, Text);
|
RemoveSelectedText();
|
||||||
|
}
|
||||||
|
if (SetText(Text.Insert(CaretIndex, input)))
|
||||||
|
{
|
||||||
|
CaretIndex = Math.Min(Text.Length, CaretIndex + input.Length);
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReceiveCommandInput(char command)
|
public void ReceiveCommandInput(char command)
|
||||||
{
|
{
|
||||||
if (Text == null) Text = "";
|
if (Text == null) Text = "";
|
||||||
@@ -309,24 +549,260 @@ namespace Barotrauma
|
|||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
case '\b': //backspace
|
case '\b': //backspace
|
||||||
if (Text.Length > 0) Text = Text.Substring(0, Text.Length - 1);
|
if (selectedCharacters > 0)
|
||||||
if (OnTextChanged != null) OnTextChanged(this, Text);
|
{
|
||||||
|
RemoveSelectedText();
|
||||||
|
}
|
||||||
|
else if (Text.Length > 0 && CaretIndex > 0)
|
||||||
|
{
|
||||||
|
CaretIndex--;
|
||||||
|
SetText(Text.Remove(CaretIndex, 1));
|
||||||
|
CalculateCaretPos();
|
||||||
|
ClearSelection();
|
||||||
|
}
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
break;
|
||||||
|
case (char)0x3: // ctrl-c
|
||||||
|
CopySelectedText();
|
||||||
|
break;
|
||||||
|
case (char)0x16: // ctrl-v
|
||||||
|
string text = GetCopiedText();
|
||||||
|
RemoveSelectedText();
|
||||||
|
if (SetText(Text.Insert(CaretIndex, text)))
|
||||||
|
{
|
||||||
|
CaretIndex = Math.Min(Text.Length, CaretIndex + text.Length);
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case (char)0x18: // ctrl-x
|
||||||
|
CopySelectedText();
|
||||||
|
RemoveSelectedText();
|
||||||
|
break;
|
||||||
|
case (char)0x1: // ctrl-a
|
||||||
|
SelectAll();
|
||||||
|
break;
|
||||||
|
case (char)0x1A: // ctrl-z
|
||||||
|
text = memento.Undo();
|
||||||
|
if (text != Text)
|
||||||
|
{
|
||||||
|
SetText(text, false);
|
||||||
|
CaretIndex = Text.Length;
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case (char)0x12: // ctrl-r
|
||||||
|
text = memento.Redo();
|
||||||
|
if (text != Text)
|
||||||
|
{
|
||||||
|
SetText(text, false);
|
||||||
|
CaretIndex = Text.Length;
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReceiveSpecialInput(Keys key)
|
public void ReceiveSpecialInput(Keys key)
|
||||||
{
|
{
|
||||||
if (OnKeyHit != null) OnKeyHit(this, key);
|
switch (key)
|
||||||
|
{
|
||||||
|
case Keys.Left:
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
}
|
||||||
|
CaretIndex = Math.Max(CaretIndex - 1, 0);
|
||||||
|
caretTimer = 0;
|
||||||
|
HandleSelection();
|
||||||
|
break;
|
||||||
|
case Keys.Right:
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
}
|
||||||
|
CaretIndex = Math.Min(CaretIndex + 1, Text.Length);
|
||||||
|
caretTimer = 0;
|
||||||
|
HandleSelection();
|
||||||
|
break;
|
||||||
|
case Keys.Up:
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
}
|
||||||
|
float lineHeight = Font.MeasureString(Text).Y;
|
||||||
|
int newIndex = GetCaretIndexFromScreenPos(new Vector2(CaretScreenPos.X, CaretScreenPos.Y - lineHeight / 2));
|
||||||
|
CaretIndex = newIndex != CaretIndex ? newIndex : 0;
|
||||||
|
caretTimer = 0;
|
||||||
|
HandleSelection();
|
||||||
|
break;
|
||||||
|
case Keys.Down:
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
}
|
||||||
|
lineHeight = Font.MeasureString(Text).Y;
|
||||||
|
newIndex = GetCaretIndexFromScreenPos(new Vector2(CaretScreenPos.X, CaretScreenPos.Y + lineHeight * 2));
|
||||||
|
CaretIndex = newIndex != CaretIndex ? newIndex : Text.Length;
|
||||||
|
caretTimer = 0;
|
||||||
|
HandleSelection();
|
||||||
|
break;
|
||||||
|
case Keys.Delete:
|
||||||
|
if (selectedCharacters > 0)
|
||||||
|
{
|
||||||
|
RemoveSelectedText();
|
||||||
|
}
|
||||||
|
else if (Text.Length > 0 && CaretIndex < Text.Length)
|
||||||
|
{
|
||||||
|
SetText(Text.Remove(CaretIndex, 1));
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
caretPosDirty = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Tab:
|
||||||
|
// Select the next text box.
|
||||||
|
var editor = RectTransform.GetParents().Select(p => p.GUIComponent as SerializableEntityEditor).FirstOrDefault(e => e != null);
|
||||||
|
if (editor == null) { break; }
|
||||||
|
var allTextBoxes = GetAndSortTextBoxes(editor).ToList();
|
||||||
|
if (allTextBoxes.Any())
|
||||||
|
{
|
||||||
|
int currentIndex = allTextBoxes.IndexOf(this);
|
||||||
|
int nextIndex = Math.Min(allTextBoxes.Count - 1, currentIndex + 1);
|
||||||
|
var next = allTextBoxes[nextIndex];
|
||||||
|
if (next != this)
|
||||||
|
{
|
||||||
|
next.Select();
|
||||||
|
next.Flash(Color.White * 0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Select the first text box in the next editor that has text boxes.
|
||||||
|
var listBox = RectTransform.GetParents().Select(p => p.GUIComponent as GUIListBox).FirstOrDefault(lb => lb != null);
|
||||||
|
if (listBox == null) { break; }
|
||||||
|
// TODO: The get's out of focus if the selection is out of view.
|
||||||
|
// Not sure how's that possible, but it seems to work when the auto scroll is disabled and you handle the scrolling manually.
|
||||||
|
listBox.SelectNext();
|
||||||
|
while (SelectNextTextBox(listBox) == null)
|
||||||
|
{
|
||||||
|
var previous = listBox.SelectedComponent;
|
||||||
|
listBox.SelectNext();
|
||||||
|
if (listBox.SelectedComponent == previous) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
GUITextBox SelectNextTextBox(GUIListBox listBox)
|
||||||
|
{
|
||||||
|
var textBoxes = GetAndSortTextBoxes(listBox.SelectedComponent);
|
||||||
|
if (textBoxes.Any())
|
||||||
|
{
|
||||||
|
var next = textBoxes.First();
|
||||||
|
next.Select();
|
||||||
|
next.Flash(Color.White * 0.5f, 0.5f);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OnKeyHit?.Invoke(this, key);
|
||||||
|
void HandleSelection()
|
||||||
|
{
|
||||||
|
if (isSelecting)
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
CalculateSelection();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public event TextBoxEvent OnTabPressed;
|
public void SelectAll()
|
||||||
|
|
||||||
public bool Selected
|
|
||||||
{
|
{
|
||||||
get;
|
CaretIndex = 0;
|
||||||
set;
|
CalculateCaretPos();
|
||||||
|
selectionStartPos = caretPos;
|
||||||
|
selectionStartIndex = 0;
|
||||||
|
CaretIndex = Text.Length;
|
||||||
|
CalculateSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CopySelectedText()
|
||||||
|
{
|
||||||
|
#if WINDOWS
|
||||||
|
System.Windows.Clipboard.SetText(selectedText);
|
||||||
|
#else
|
||||||
|
clipboard = selectedText;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearSelection()
|
||||||
|
{
|
||||||
|
selectedCharacters = 0;
|
||||||
|
selectionStartIndex = -1;
|
||||||
|
selectionEndIndex = -1;
|
||||||
|
selectedText = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCopiedText()
|
||||||
|
{
|
||||||
|
string t;
|
||||||
|
#if WINDOWS
|
||||||
|
t = System.Windows.Clipboard.GetText();
|
||||||
|
#else
|
||||||
|
t = clipboard;
|
||||||
|
#endif
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveSelectedText()
|
||||||
|
{
|
||||||
|
if (selectedText.Length == 0) { return; }
|
||||||
|
if (IsLeftToRight)
|
||||||
|
{
|
||||||
|
SetText(Text.Remove(selectionStartIndex, selectedText.Length));
|
||||||
|
CaretIndex = Math.Min(Text.Length, selectionStartIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetText(Text.Remove(selectionEndIndex, selectedText.Length));
|
||||||
|
CaretIndex = Math.Min(Text.Length, selectionEndIndex);
|
||||||
|
}
|
||||||
|
ClearSelection();
|
||||||
|
OnTextChanged?.Invoke(this, Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitSelectionStart()
|
||||||
|
{
|
||||||
|
if (caretPosDirty)
|
||||||
|
{
|
||||||
|
CalculateCaretPos();
|
||||||
|
}
|
||||||
|
if (selectionStartIndex == -1)
|
||||||
|
{
|
||||||
|
selectionStartIndex = CaretIndex;
|
||||||
|
selectionStartPos = caretPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateSelection()
|
||||||
|
{
|
||||||
|
InitSelectionStart();
|
||||||
|
selectionEndIndex = CaretIndex;
|
||||||
|
selectionEndPos = caretPos;
|
||||||
|
selectedCharacters = Math.Abs(selectionStartIndex - selectionEndIndex);
|
||||||
|
if (IsLeftToRight)
|
||||||
|
{
|
||||||
|
selectedText = Text.Substring(selectionStartIndex, selectedCharacters);
|
||||||
|
selectionRectSize = Font.MeasureString(textBlock.WrappedText.Substring(selectionStartIndex, selectedCharacters));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selectedText = Text.Substring(selectionEndIndex, selectedCharacters);
|
||||||
|
selectionRectSize = Font.MeasureString(textBlock.WrappedText.Substring(selectionEndIndex, selectedCharacters));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -11,6 +12,10 @@ namespace Barotrauma
|
|||||||
public delegate bool OnSelectedHandler(GUITickBox obj);
|
public delegate bool OnSelectedHandler(GUITickBox obj);
|
||||||
public OnSelectedHandler OnSelected;
|
public OnSelectedHandler OnSelected;
|
||||||
|
|
||||||
|
public static int size = 20;
|
||||||
|
|
||||||
|
private List<GUITickBox> radioButtonGroup;
|
||||||
|
|
||||||
private bool selected;
|
private bool selected;
|
||||||
|
|
||||||
public bool Selected
|
public bool Selected
|
||||||
@@ -19,42 +24,33 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == selected) return;
|
if (value == selected) return;
|
||||||
|
if (radioButtonGroup != null && !value) return;
|
||||||
|
|
||||||
selected = value;
|
selected = value;
|
||||||
state = (selected) ? ComponentState.Selected : ComponentState.None;
|
state = (selected) ? ComponentState.Selected : ComponentState.None;
|
||||||
|
|
||||||
box.State = state;
|
box.State = state;
|
||||||
|
if (radioButtonGroup != null)
|
||||||
|
{
|
||||||
|
foreach (GUITickBox tickBox in radioButtonGroup)
|
||||||
|
{
|
||||||
|
if (tickBox == this) continue;
|
||||||
|
tickBox.selected = false;
|
||||||
|
tickBox.state = tickBox.box.State = ComponentState.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnSelected?.Invoke(this);
|
||||||
|
if (radioButtonGroup != null)
|
||||||
|
{
|
||||||
|
foreach (GUITickBox tickBox in radioButtonGroup)
|
||||||
|
{
|
||||||
|
if (tickBox == this) continue;
|
||||||
|
tickBox.OnSelected?.Invoke(tickBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool enabled;
|
|
||||||
|
|
||||||
public bool Enabled
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
enabled = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rectangle Rect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base.Rect = value;
|
|
||||||
|
|
||||||
if (box != null) box.Rect = new Rectangle(value.X,value.Y,box.Rect.Width,box.Rect.Height);
|
|
||||||
if (text != null) text.Rect = new Rectangle(box.Rect.Right, box.Rect.Y + 2, 20, box.Rect.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color TextColor
|
public Color TextColor
|
||||||
{
|
{
|
||||||
get { return text.TextColor; }
|
get { return text.TextColor; }
|
||||||
@@ -63,7 +59,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override Rectangle MouseRect
|
public override Rectangle MouseRect
|
||||||
{
|
{
|
||||||
get { return ClampMouseRectToParent ? ClampRect(box.Rect) : box.Rect; }
|
get
|
||||||
|
{
|
||||||
|
if (!CanBeFocused) return Rectangle.Empty;
|
||||||
|
return ClampMouseRectToParent ? ClampRect(box.Rect) : box.Rect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScalableFont Font
|
public override ScalableFont Font
|
||||||
@@ -80,37 +80,70 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITickBox(Rectangle rect, string label, Alignment alignment, GUIComponent parent)
|
public GUIFrame Box
|
||||||
: this(rect, label, alignment, GUI.Font, parent)
|
|
||||||
{
|
{
|
||||||
|
get { return box; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITickBox(Rectangle rect, string label, Alignment alignment, ScalableFont font, GUIComponent parent)
|
public override string ToolTip
|
||||||
: base(null)
|
|
||||||
{
|
{
|
||||||
if (parent != null)
|
get { return base.ToolTip; }
|
||||||
parent.AddChild(this);
|
set
|
||||||
|
{
|
||||||
|
base.ToolTip = value;
|
||||||
|
box.ToolTip = value;
|
||||||
|
text.ToolTip = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
box = new GUIFrame(rect, Color.DarkGray, "", this);
|
public string Text
|
||||||
box.HoverColor = Color.Gray;
|
{
|
||||||
box.SelectedColor = Color.DarkGray;
|
get { return text.Text; }
|
||||||
box.CanBeFocused = false;
|
set { text.Text = value; }
|
||||||
|
}
|
||||||
|
|
||||||
GUI.Style.Apply(box, "GUITickBox");
|
public GUITickBox(RectTransform rectT, string label, ScalableFont font = null, string style = "") : base(null, rectT)
|
||||||
|
{
|
||||||
text = new GUITextBlock(new Rectangle(rect.Right, rect.Y, 20, rect.Height), label, "", Alignment.TopLeft, Alignment.Left | Alignment.CenterY, this, false, font);
|
box = new GUIFrame(new RectTransform(new Point(rectT.Rect.Height, rectT.Rect.Height), rectT, Anchor.CenterLeft)
|
||||||
|
{
|
||||||
|
IsFixedSize = false
|
||||||
|
}, string.Empty, Color.DarkGray)
|
||||||
|
{
|
||||||
|
HoverColor = Color.Gray,
|
||||||
|
SelectedColor = Color.DarkGray,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
GUI.Style.Apply(box, style == "" ? "GUITickBox" : style);
|
||||||
|
text = new GUITextBlock(new RectTransform(Vector2.One, rectT, Anchor.CenterLeft) { AbsoluteOffset = new Point(box.Rect.Width, 0) }, label, font: font, textAlignment: Alignment.CenterLeft);
|
||||||
GUI.Style.Apply(text, "GUIButtonHorizontal", this);
|
GUI.Style.Apply(text, "GUIButtonHorizontal", this);
|
||||||
|
|
||||||
this.rect = new Rectangle(box.Rect.X, box.Rect.Y, 240, rect.Height);
|
|
||||||
|
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
|
|
||||||
|
ResizeBox();
|
||||||
|
|
||||||
|
rectT.ScaleChanged += ResizeBox;
|
||||||
|
rectT.SizeChanged += ResizeBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateRadioButtonGroup(IEnumerable<GUITickBox> tickBoxes)
|
||||||
|
{
|
||||||
|
var group = new List<GUITickBox>(tickBoxes);
|
||||||
|
foreach (GUITickBox tickBox in tickBoxes)
|
||||||
|
{
|
||||||
|
tickBox.radioButtonGroup = group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResizeBox()
|
||||||
|
{
|
||||||
|
box.RectTransform.NonScaledSize = new Point(RectTransform.NonScaledSize.Y);
|
||||||
|
text.RectTransform.AbsoluteOffset = new Point(box.Rect.Width, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
protected override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (!Visible) return;
|
if (!Visible) return;
|
||||||
|
|
||||||
if (MouseOn == this && Enabled)
|
if (GUI.MouseOn == this && Enabled)
|
||||||
{
|
{
|
||||||
box.State = ComponentState.Hover;
|
box.State = ComponentState.Hover;
|
||||||
|
|
||||||
@@ -121,8 +154,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (PlayerInput.LeftButtonClicked())
|
if (PlayerInput.LeftButtonClicked())
|
||||||
{
|
{
|
||||||
Selected = !Selected;
|
if (radioButtonGroup == null)
|
||||||
if (OnSelected != null) OnSelected(this);
|
{
|
||||||
|
Selected = !Selected;
|
||||||
|
}
|
||||||
|
else if (!selected)
|
||||||
|
{
|
||||||
|
Selected = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -135,12 +174,5 @@ namespace Barotrauma
|
|||||||
box.State = ComponentState.Selected;
|
box.State = ComponentState.Selected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
if (!Visible) return;
|
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class Graph
|
||||||
|
{
|
||||||
|
private float[] values;
|
||||||
|
|
||||||
|
public Graph(int arraySize = 100)
|
||||||
|
{
|
||||||
|
values = new float[arraySize];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LargestValue()
|
||||||
|
{
|
||||||
|
float maxValue = 0.0f;
|
||||||
|
for (int i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
if (values[i] > maxValue) maxValue = values[i];
|
||||||
|
}
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Average()
|
||||||
|
{
|
||||||
|
return values.Length == 0 ? 0.0f : values.Average();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float newValue)
|
||||||
|
{
|
||||||
|
for (int i = values.Length - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
values[i] = values[i - 1];
|
||||||
|
}
|
||||||
|
values[0] = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxVal, float xOffset, Color color)
|
||||||
|
{
|
||||||
|
float graphMaxVal = 1.0f;
|
||||||
|
if (maxVal == null)
|
||||||
|
{
|
||||||
|
graphMaxVal = LargestValue();
|
||||||
|
}
|
||||||
|
else if (maxVal > 0.0f)
|
||||||
|
{
|
||||||
|
graphMaxVal = (float)maxVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, Color.White);
|
||||||
|
|
||||||
|
if (values.Length == 0) return;
|
||||||
|
|
||||||
|
float lineWidth = (float)rect.Width / (float)(values.Length - 2);
|
||||||
|
float yScale = (float)rect.Height / graphMaxVal;
|
||||||
|
|
||||||
|
Vector2 prevPoint = new Vector2(rect.Right, rect.Bottom - (values[1] + (values[0] - values[1]) * xOffset) * yScale);
|
||||||
|
float currX = rect.Right - ((xOffset - 1.0f) * lineWidth);
|
||||||
|
for (int i = 1; i < values.Length - 1; i++)
|
||||||
|
{
|
||||||
|
currX -= lineWidth;
|
||||||
|
Vector2 newPoint = new Vector2(currX, rect.Bottom - values[i] * yScale);
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
|
||||||
|
prevPoint = newPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 lastPoint = new Vector2(rect.X,
|
||||||
|
rect.Bottom - (values[values.Length - 1] + (values[values.Length - 2] - values[values.Length - 1]) * xOffset) * yScale);
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
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 InventoryAreaUpper
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle CrewArea
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle ChatBoxArea
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Alignment ChatBoxAlignment
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle InventoryAreaLower
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle HealthBarAreaLeft
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
public static Rectangle AfflictionAreaLeft
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle HealthBarAreaRight
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
public static Rectangle AfflictionAreaRight
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle HealthWindowAreaLeft
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle HealthWindowAreaRight
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)(10 * GUI.Scale);
|
||||||
|
|
||||||
|
if (inventoryTopY == 0) inventoryTopY = GameMain.GraphicsHeight;
|
||||||
|
|
||||||
|
//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 crewAreaHeight = (int)Math.Max(GameMain.GraphicsHeight * 0.22f, 150);
|
||||||
|
CrewArea = new Rectangle(Padding, ButtonAreaTop.Bottom + Padding, GameMain.GraphicsWidth - InventoryAreaUpper.Width - Padding * 3, crewAreaHeight);
|
||||||
|
|
||||||
|
int portraitSize = (int)(120 * GUI.Scale);
|
||||||
|
PortraitArea = new Rectangle(GameMain.GraphicsWidth - portraitSize - Padding, GameMain.GraphicsHeight - portraitSize - Padding, portraitSize, portraitSize);
|
||||||
|
|
||||||
|
//horizontal slices at the corners of the screen for health bar and affliction icons
|
||||||
|
int healthBarWidth = (int)Math.Max(250 * GUI.Scale, 150);
|
||||||
|
int healthBarHeight = (int)Math.Max(20 * GUI.Scale, 15);
|
||||||
|
int afflictionAreaHeight = (int)(60 * GUI.Scale);
|
||||||
|
HealthBarAreaLeft = new Rectangle(Padding, GameMain.GraphicsHeight - healthBarHeight - Padding, healthBarWidth, healthBarHeight);
|
||||||
|
AfflictionAreaLeft = new Rectangle(Padding, HealthBarAreaLeft.Y - afflictionAreaHeight - Padding, healthBarWidth, afflictionAreaHeight);
|
||||||
|
|
||||||
|
HealthBarAreaRight = new Rectangle(PortraitArea.X - Padding - healthBarWidth, Math.Min(PortraitArea.Y + Padding * 3, inventoryTopY - healthBarHeight), healthBarWidth, HealthBarAreaLeft.Height);
|
||||||
|
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 - Padding - afflictionAreaHeight, healthBarWidth, afflictionAreaHeight);
|
||||||
|
|
||||||
|
int messageAreaPos = GameMain.GraphicsWidth - HealthBarAreaRight.X;
|
||||||
|
MessageAreaTop = new Rectangle(messageAreaPos + Padding, ButtonAreaTop.Bottom, GameMain.GraphicsWidth - (messageAreaPos + Padding) * 2, ButtonAreaTop.Height);
|
||||||
|
|
||||||
|
//slice for the upper slots of the inventory (clothes, id card, headset)
|
||||||
|
int inventoryAreaUpperWidth = (int)(GameMain.GraphicsWidth * 0.2f);
|
||||||
|
int inventoryAreaUpperHeight = (int)(GameMain.GraphicsHeight * 0.2f);
|
||||||
|
InventoryAreaUpper = new Rectangle(GameMain.GraphicsWidth - inventoryAreaUpperWidth - Padding, CrewArea.Y, inventoryAreaUpperWidth, inventoryAreaUpperHeight);
|
||||||
|
|
||||||
|
//chatbox between upper and lower inventory areas, can be on either side depending on the alignment
|
||||||
|
ChatBoxAlignment = Alignment.Right;
|
||||||
|
int chatBoxWidth = (int)(500 * GUI.Scale);
|
||||||
|
int chatBoxHeight = crewAreaHeight;
|
||||||
|
ChatBoxArea = ChatBoxAlignment == Alignment.Left ?
|
||||||
|
new Rectangle(Padding, CrewArea.Y, chatBoxWidth, chatBoxHeight) :
|
||||||
|
new Rectangle(GameMain.GraphicsWidth - Padding - chatBoxWidth, CrewArea.Y, chatBoxWidth, chatBoxHeight);
|
||||||
|
|
||||||
|
int lowerAreaHeight = (int)Math.Min(GameMain.GraphicsHeight * 0.25f, 280);
|
||||||
|
InventoryAreaLower = new Rectangle(Padding, GameMain.GraphicsHeight - lowerAreaHeight, GameMain.GraphicsWidth - Padding * 2, lowerAreaHeight);
|
||||||
|
|
||||||
|
int healthWindowY = CrewArea.Bottom + Padding;
|
||||||
|
Rectangle healthWindowArea = ChatBoxAlignment == Alignment.Left ?
|
||||||
|
new Rectangle(ChatBoxArea.Right + Padding, healthWindowY, GameMain.GraphicsWidth - ChatBoxArea.Width - inventoryAreaUpperWidth, GameMain.GraphicsHeight - healthWindowY - lowerAreaHeight / 2) :
|
||||||
|
new Rectangle(Padding - ChatBoxArea.Width, healthWindowY, GameMain.GraphicsWidth - ChatBoxArea.Width - inventoryAreaUpperWidth, GameMain.GraphicsHeight - healthWindowY - lowerAreaHeight / 2);
|
||||||
|
|
||||||
|
int healthWindowPadding = Padding * 3;
|
||||||
|
HealthWindowAreaLeft = new Rectangle(healthWindowPadding, healthWindowY, GameMain.GraphicsWidth / 2 - healthWindowPadding, GameMain.GraphicsHeight - healthWindowY - lowerAreaHeight);
|
||||||
|
HealthWindowAreaRight = new Rectangle(GameMain.GraphicsWidth / 2, healthWindowY, GameMain.GraphicsWidth / 2 - healthWindowPadding, GameMain.GraphicsHeight - healthWindowY - lowerAreaHeight);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Draw(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, ButtonAreaTop, Color.White * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, MessageAreaTop, Color.Orange * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, InventoryAreaUpper, Color.Yellow * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, CrewArea, Color.Blue * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, ChatBoxArea, Color.Cyan * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, HealthBarAreaLeft, Color.Red * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, AfflictionAreaLeft, Color.Red * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, HealthBarAreaRight, Color.Red * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, AfflictionAreaRight, Color.Red * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, InventoryAreaLower, Color.Yellow * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, HealthWindowAreaLeft, Color.Red * 0.5f);
|
||||||
|
GUI.DrawRectangle(spriteBatch, HealthWindowAreaRight, Color.Red * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HUD
|
||||||
|
{
|
||||||
|
public static bool CloseHUD(Rectangle rect)
|
||||||
|
{
|
||||||
|
//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.LeftButtonDown() || PlayerInput.RightButtonClicked();
|
||||||
|
return input && !rect.Contains(PlayerInput.MousePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,23 +4,26 @@ using Microsoft.Xna.Framework.Input;
|
|||||||
using Microsoft.Xna.Framework.Media;
|
using Microsoft.Xna.Framework.Media;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class LoadingScreen
|
class LoadingScreen
|
||||||
{
|
{
|
||||||
private Texture2D backgroundTexture,monsterTexture,titleTexture;
|
private Texture2D backgroundTexture, monsterTexture, titleTexture;
|
||||||
|
|
||||||
readonly RenderTarget2D renderTarget;
|
private RenderTarget2D renderTarget;
|
||||||
|
|
||||||
float state;
|
private float state;
|
||||||
|
|
||||||
|
private string selectedTip;
|
||||||
|
|
||||||
public Vector2 CenterPosition;
|
public Vector2 CenterPosition;
|
||||||
|
|
||||||
public Vector2 TitlePosition;
|
public Vector2 TitlePosition;
|
||||||
|
|
||||||
private float? loadState;
|
private float? loadState;
|
||||||
#if !LINUX
|
#if !(LINUX || OSX)
|
||||||
Video splashScreenVideo;
|
Video splashScreenVideo;
|
||||||
VideoPlayer videoPlayer;
|
VideoPlayer videoPlayer;
|
||||||
#endif
|
#endif
|
||||||
@@ -57,13 +60,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public LoadingScreen(GraphicsDevice graphics)
|
public LoadingScreen(GraphicsDevice graphics)
|
||||||
{
|
{
|
||||||
#if !LINUX
|
#if !(LINUX || OSX)
|
||||||
|
|
||||||
if (GameMain.Config.EnableSplashScreen)
|
if (GameMain.Config.EnableSplashScreen)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
splashScreenVideo = GameMain.Instance.Content.Load<Video>("utg_4");
|
splashScreenVideo = GameMain.Instance.Content.Load<Video>("splashscreen");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -80,14 +83,20 @@ namespace Barotrauma
|
|||||||
titleTexture = TextureLoader.FromFile("Content/UI/titleText.png");
|
titleTexture = TextureLoader.FromFile("Content/UI/titleText.png");
|
||||||
|
|
||||||
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
GameMain.Instance.OnResolutionChanged += () =>
|
||||||
|
{
|
||||||
|
renderTarget?.Dispose();
|
||||||
|
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
};
|
||||||
|
|
||||||
DrawLoadingText = true;
|
DrawLoadingText = true;
|
||||||
|
selectedTip = TextManager.Get("LoadingScreenTip", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphics, float deltaTime)
|
public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphics, float deltaTime)
|
||||||
{
|
{
|
||||||
#if !LINUX
|
#if !(LINUX || OSX)
|
||||||
if (GameMain.Config.EnableSplashScreen && splashScreenVideo != null)
|
if (GameMain.Config.EnableSplashScreen && splashScreenVideo != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -103,18 +112,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
drawn = true;
|
drawn = true;
|
||||||
|
|
||||||
graphics.SetRenderTarget(renderTarget);
|
graphics.SetRenderTarget(renderTarget);
|
||||||
|
|
||||||
Scale = GameMain.GraphicsHeight/1500.0f;
|
Scale = GameMain.GraphicsHeight / 1500.0f;
|
||||||
|
|
||||||
state += deltaTime;
|
state += deltaTime;
|
||||||
|
|
||||||
if (DrawLoadingText)
|
if (DrawLoadingText)
|
||||||
{
|
{
|
||||||
CenterPosition = new Vector2(GameMain.GraphicsWidth*0.3f, GameMain.GraphicsHeight/2.0f);
|
CenterPosition = new Vector2(GameMain.GraphicsWidth * 0.3f, GameMain.GraphicsHeight / 2.0f);
|
||||||
TitlePosition = CenterPosition + new Vector2(-0.0f + (float)Math.Sqrt(state) * 220.0f, 0.0f) * Scale;
|
TitlePosition = CenterPosition + new Vector2(-0.0f + (float)Math.Sqrt(state) * 220.0f, 0.0f) * Scale;
|
||||||
TitlePosition.X = Math.Min(TitlePosition.X, (float)GameMain.GraphicsWidth / 2.0f);
|
TitlePosition.X = Math.Min(TitlePosition.X, (float)GameMain.GraphicsWidth / 2.0f);
|
||||||
}
|
}
|
||||||
@@ -124,7 +133,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
spriteBatch.Draw(backgroundTexture, CenterPosition, null, Color.White * Math.Min(state / 5.0f, 1.0f), 0.0f,
|
spriteBatch.Draw(backgroundTexture, CenterPosition, null, Color.White * Math.Min(state / 5.0f, 1.0f), 0.0f,
|
||||||
new Vector2(backgroundTexture.Width / 2.0f, backgroundTexture.Height / 2.0f),
|
new Vector2(backgroundTexture.Width / 2.0f, backgroundTexture.Height / 2.0f),
|
||||||
Scale*1.5f, SpriteEffects.None, 0.2f);
|
Scale * 1.5f, SpriteEffects.None, 0.2f);
|
||||||
|
|
||||||
spriteBatch.Draw(monsterTexture,
|
spriteBatch.Draw(monsterTexture,
|
||||||
CenterPosition + new Vector2((state % 40) * 100.0f - 1800.0f, (state % 40) * 30.0f - 200.0f) * Scale, null,
|
CenterPosition + new Vector2((state % 40) * 100.0f - 1800.0f, (state % 40) * 30.0f - 200.0f) * Scale, null,
|
||||||
@@ -133,19 +142,19 @@ namespace Barotrauma
|
|||||||
spriteBatch.Draw(titleTexture,
|
spriteBatch.Draw(titleTexture,
|
||||||
TitlePosition, null,
|
TitlePosition, null,
|
||||||
Color.White * Math.Min((state - 1.0f) / 5.0f, 1.0f), 0.0f, new Vector2(titleTexture.Width / 2.0f, titleTexture.Height / 2.0f), Scale, SpriteEffects.None, 0.0f);
|
Color.White * Math.Min((state - 1.0f) / 5.0f, 1.0f), 0.0f, new Vector2(titleTexture.Width / 2.0f, titleTexture.Height / 2.0f), Scale, SpriteEffects.None, 0.0f);
|
||||||
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
graphics.SetRenderTarget(null);
|
graphics.SetRenderTarget(null);
|
||||||
|
|
||||||
if (Hull.renderer != null)
|
if (WaterRenderer.Instance != null)
|
||||||
{
|
{
|
||||||
Hull.renderer.ScrollWater(deltaTime);
|
WaterRenderer.Instance.ScrollWater(Vector2.One * 10.0f, deltaTime);
|
||||||
Hull.renderer.RenderBack(spriteBatch, renderTarget, 0.0f);
|
WaterRenderer.Instance.RenderWater(spriteBatch, renderTarget, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
|
||||||
|
|
||||||
spriteBatch.Draw(titleTexture,
|
spriteBatch.Draw(titleTexture,
|
||||||
TitlePosition, null,
|
TitlePosition, null,
|
||||||
Color.White * Math.Min((state - 3.0f) / 5.0f, 1.0f), 0.0f, new Vector2(titleTexture.Width / 2.0f, titleTexture.Height / 2.0f), Scale, SpriteEffects.None, 0.0f);
|
Color.White * Math.Min((state - 3.0f) / 5.0f, 1.0f), 0.0f, new Vector2(titleTexture.Width / 2.0f, titleTexture.Height / 2.0f), Scale, SpriteEffects.None, 0.0f);
|
||||||
@@ -169,16 +178,27 @@ namespace Barotrauma
|
|||||||
if (GUI.LargeFont != null)
|
if (GUI.LargeFont != null)
|
||||||
{
|
{
|
||||||
GUI.LargeFont.DrawString(spriteBatch, loadText,
|
GUI.LargeFont.DrawString(spriteBatch, loadText,
|
||||||
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText).X / 2.0f, GameMain.GraphicsHeight * 0.8f),
|
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText).X / 2.0f, GameMain.GraphicsHeight * 0.7f),
|
||||||
Color.White);
|
Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GUI.Font != null && selectedTip != null)
|
||||||
|
{
|
||||||
|
string wrappedTip = ToolBox.WrapText(selectedTip, GameMain.GraphicsWidth * 0.5f, GUI.Font);
|
||||||
|
string[] lines = wrappedTip.Split('\n');
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
GUI.Font.DrawString(spriteBatch, lines[i],
|
||||||
|
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.Font.MeasureString(lines[i]).X / 2.0f, GameMain.GraphicsHeight * 0.78f + i * 15), Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !LINUX
|
#if !(LINUX || OSX)
|
||||||
private void DrawSplashScreen(SpriteBatch spriteBatch)
|
private void DrawSplashScreen(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (videoPlayer == null)
|
if (videoPlayer == null)
|
||||||
@@ -222,7 +242,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
drawn = false;
|
drawn = false;
|
||||||
LoadState = null;
|
LoadState = null;
|
||||||
|
selectedTip = TextManager.Get("LoadingScreenTip", true);
|
||||||
|
|
||||||
while (!drawn)
|
while (!drawn)
|
||||||
{
|
{
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class ParamsEditor
|
||||||
|
{
|
||||||
|
private static ParamsEditor _instance;
|
||||||
|
public static ParamsEditor Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = new ParamsEditor();
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIListBox EditorBox { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Uses Linq queries. Don't use too frequently or reimplement.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<SerializableEntityEditor> FindEntityEditors() => EditorBox.Content.RectTransform.Children
|
||||||
|
.Select(c => c.GUIComponent as SerializableEntityEditor)
|
||||||
|
.Where(c => c != null);
|
||||||
|
|
||||||
|
public GUIListBox CreateEditorBox(RectTransform rectT = null)
|
||||||
|
{
|
||||||
|
rectT = rectT ?? new RectTransform(new Vector2(0.25f, 0.95f), GUI.Canvas) { MinSize = new Point(340, GameMain.GraphicsHeight) };
|
||||||
|
rectT.SetPosition(Anchor.TopRight);
|
||||||
|
rectT.RelativeOffset = new Vector2(0.16f, 0);
|
||||||
|
EditorBox = new GUIListBox(rectT)
|
||||||
|
{
|
||||||
|
Spacing = 10,
|
||||||
|
Color = Color.Black
|
||||||
|
};
|
||||||
|
return EditorBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
EditorBox.ClearChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParamsEditor(RectTransform rectT = null)
|
||||||
|
{
|
||||||
|
EditorBox = CreateEditorBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
public enum Anchor
|
||||||
|
{
|
||||||
|
TopLeft, TopCenter, TopRight,
|
||||||
|
CenterLeft, Center, CenterRight,
|
||||||
|
BottomLeft, BottomCenter, BottomRight
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Pivot
|
||||||
|
{
|
||||||
|
TopLeft, TopCenter, TopRight,
|
||||||
|
CenterLeft, Center, CenterRight,
|
||||||
|
BottomLeft, BottomCenter, BottomRight
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RectTransform
|
||||||
|
{
|
||||||
|
#region Fields and Properties
|
||||||
|
/// <summary>
|
||||||
|
/// Should be assigned only by GUIComponent.
|
||||||
|
/// Note that RectTransform is created first and the GUIComponent after that.
|
||||||
|
/// This means the GUIComponent is not set before the GUIComponent is initialized.
|
||||||
|
/// </summary>
|
||||||
|
public GUIComponent GUIComponent { get; set; }
|
||||||
|
|
||||||
|
private RectTransform parent;
|
||||||
|
public RectTransform Parent
|
||||||
|
{
|
||||||
|
get { return parent; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (parent == value || value == this) { return; }
|
||||||
|
// Remove the child from the old parent
|
||||||
|
RemoveFromHierarchy(displayErrors: false);
|
||||||
|
parent = value;
|
||||||
|
if (parent != null && !parent.children.Contains(this))
|
||||||
|
{
|
||||||
|
parent.children.Add(this);
|
||||||
|
RecalculateAll(false, true, true);
|
||||||
|
ParentChanged?.Invoke(parent);
|
||||||
|
Parent.ChildrenChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RectTransform> children = new List<RectTransform>();
|
||||||
|
public IEnumerable<RectTransform> Children => children;
|
||||||
|
|
||||||
|
public int CountChildren => children.Count;
|
||||||
|
|
||||||
|
private Vector2 relativeSize = Vector2.One;
|
||||||
|
/// <summary>
|
||||||
|
/// Relative to the parent rect.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 RelativeSize
|
||||||
|
{
|
||||||
|
get { return relativeSize; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (relativeSize.NearlyEquals(value)) { return; }
|
||||||
|
relativeSize = value;
|
||||||
|
RecalculateAll(resize: true, scale: false, withChildren: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point? minSize;
|
||||||
|
/// <summary>
|
||||||
|
/// Min size in pixels.
|
||||||
|
/// Does not affect scaling.
|
||||||
|
/// </summary>
|
||||||
|
public Point MinSize
|
||||||
|
{
|
||||||
|
get { return minSize ?? Point.Zero; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (minSize == value) { return; }
|
||||||
|
minSize = value;
|
||||||
|
RecalculateAll(true, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Point maxPoint = new Point(int.MaxValue, int.MaxValue);
|
||||||
|
private Point? maxSize;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Max size in pixels.
|
||||||
|
/// Does not affect scaling.
|
||||||
|
/// </summary>
|
||||||
|
public Point MaxSize
|
||||||
|
{
|
||||||
|
get { return maxSize ?? maxPoint; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (maxSize == value) { return; }
|
||||||
|
maxSize = value;
|
||||||
|
RecalculateAll(true, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point nonScaledSize;
|
||||||
|
/// <summary>
|
||||||
|
/// Size before scale multiplications.
|
||||||
|
/// </summary>
|
||||||
|
public Point NonScaledSize
|
||||||
|
{
|
||||||
|
get { return nonScaledSize; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (nonScaledSize == value) { return; }
|
||||||
|
nonScaledSize = value.Clamp(MinSize, MaxSize);
|
||||||
|
RecalculateRelativeSize();
|
||||||
|
RecalculateAnchorPoint();
|
||||||
|
RecalculatePivotOffset();
|
||||||
|
RecalculateChildren(resize: true, scale: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Size after scale multiplications.
|
||||||
|
/// </summary>
|
||||||
|
public Point ScaledSize => NonScaledSize.Multiply(Scale);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applied to all RectTransforms.
|
||||||
|
/// The elements are not automatically resized, if the global scale changes.
|
||||||
|
/// You have to manually call RecalculateScale() for all elements after changing the global scale.
|
||||||
|
/// This is because there is currently no easy way to inform all the elements without having a reference to them.
|
||||||
|
/// Having a reference (static list, or event) is problematic, because deconstructing the elements is not handled manually.
|
||||||
|
/// This means that the uncleared references would bloat the memory.
|
||||||
|
/// We could recalculate the scale each time it's needed,
|
||||||
|
/// but in that case the calculation would need to be very lightweight and garbage free, which it currently is not.
|
||||||
|
/// </summary>
|
||||||
|
public static Vector2 globalScale = Vector2.One;
|
||||||
|
|
||||||
|
private Vector2 localScale = Vector2.One;
|
||||||
|
public Vector2 LocalScale
|
||||||
|
{
|
||||||
|
get { return localScale; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (localScale.NearlyEquals(value)) { return; }
|
||||||
|
localScale = value;
|
||||||
|
RecalculateAll(resize: false, scale: true, withChildren: true);
|
||||||
|
ScaleChanged?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 Scale { get; private set; }
|
||||||
|
|
||||||
|
private Vector2 relativeOffset = Vector2.Zero;
|
||||||
|
private Point absoluteOffset = Point.Zero;
|
||||||
|
private Point screenSpaceOffset = Point.Zero;
|
||||||
|
/// <summary>
|
||||||
|
/// Defined as portions of the parent size.
|
||||||
|
/// Also the direction of the offset is relative, calculated away from the anchor point.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 RelativeOffset
|
||||||
|
{
|
||||||
|
get { return relativeOffset; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (relativeOffset.NearlyEquals(value)) { return; }
|
||||||
|
relativeOffset = value;
|
||||||
|
RecalculateChildren(false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Absolute in pixels but relative to the anchor point.
|
||||||
|
/// Calculated away from the anchor point, like a padding.
|
||||||
|
/// Use RelativeOffset to set an amount relative to the parent size.
|
||||||
|
/// </summary>
|
||||||
|
public Point AbsoluteOffset
|
||||||
|
{
|
||||||
|
get { return absoluteOffset; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (absoluteOffset == value) { return; }
|
||||||
|
absoluteOffset = value;
|
||||||
|
recalculateRect = true;
|
||||||
|
RecalculateChildren(false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Screen space offset. From top left corner. In pixels.
|
||||||
|
/// </summary>
|
||||||
|
public Point ScreenSpaceOffset
|
||||||
|
{
|
||||||
|
get { return screenSpaceOffset; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (screenSpaceOffset == value) { return; }
|
||||||
|
screenSpaceOffset = value;
|
||||||
|
recalculateRect = true;
|
||||||
|
RecalculateChildren(false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated from the selected pivot. In pixels.
|
||||||
|
/// </summary>
|
||||||
|
public Point PivotOffset { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Screen space point in pixels.
|
||||||
|
/// </summary>
|
||||||
|
public Point AnchorPoint { get; private set; }
|
||||||
|
|
||||||
|
public Point TopLeft
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Point absoluteOffset = ConvertOffsetRelativeToAnchor(AbsoluteOffset, Anchor);
|
||||||
|
Point relativeOffset = ParentRect.MultiplySize(RelativeOffset);
|
||||||
|
relativeOffset = ConvertOffsetRelativeToAnchor(relativeOffset, Anchor);
|
||||||
|
return AnchorPoint + PivotOffset + absoluteOffset + relativeOffset + ScreenSpaceOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Point NonScaledTopLeft
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Point absoluteOffset = ConvertOffsetRelativeToAnchor(AbsoluteOffset, Anchor);
|
||||||
|
Point relativeOffset = NonScaledParentRect.MultiplySize(RelativeOffset);
|
||||||
|
relativeOffset = ConvertOffsetRelativeToAnchor(relativeOffset, Anchor);
|
||||||
|
return AnchorPoint + PivotOffset + absoluteOffset + relativeOffset + ScreenSpaceOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool recalculateRect = true;
|
||||||
|
private Rectangle _rect;
|
||||||
|
public Rectangle Rect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (recalculateRect)
|
||||||
|
{
|
||||||
|
_rect = new Rectangle(TopLeft, ScaledSize);
|
||||||
|
recalculateRect = false;
|
||||||
|
}
|
||||||
|
return _rect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Rectangle ParentRect => Parent != null ? Parent.Rect : ScreenRect;
|
||||||
|
|
||||||
|
protected Rectangle NonScaledRect => new Rectangle(NonScaledTopLeft, NonScaledSize);
|
||||||
|
protected Rectangle NonScaledParentRect => parent != null ? Parent.NonScaledRect : ScreenRect;
|
||||||
|
protected Rectangle ScreenRect => new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
|
||||||
|
private Pivot pivot;
|
||||||
|
/// <summary>
|
||||||
|
/// Does not automatically calculate children.
|
||||||
|
/// Note also that if you change the pivot point with this property, the pivot does not automatically match the anchor.
|
||||||
|
/// You can use SetPosition to change everything automatcally or MatchPivotToAnchor to match the pivot to anchor.
|
||||||
|
/// </summary>
|
||||||
|
public Pivot Pivot
|
||||||
|
{
|
||||||
|
get { return pivot; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (pivot == value) { return; }
|
||||||
|
pivot = value;
|
||||||
|
RecalculatePivotOffset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Anchor anchor;
|
||||||
|
/// <summary>
|
||||||
|
/// Does not automatically calculate children.
|
||||||
|
/// Note also that if you change the anchor point with this property, the pivot does not automatically match the anchor.
|
||||||
|
/// You can use SetPosition to change everything automatically or MatchPivotToAnchor to match the pivot to anchor.
|
||||||
|
/// </summary>
|
||||||
|
public Anchor Anchor
|
||||||
|
{
|
||||||
|
get { return anchor; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (anchor == value) { return; }
|
||||||
|
anchor = value;
|
||||||
|
RecalculateAnchorPoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLastChild
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Parent == null) { return false; }
|
||||||
|
var last = Parent.Children.LastOrDefault();
|
||||||
|
if (last == null) { return false; }
|
||||||
|
return last == this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFirstChild
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Parent == null) { return false; }
|
||||||
|
var first = Parent.Children.FirstOrDefault();
|
||||||
|
if (first == null) { return false; }
|
||||||
|
return first == this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
public event Action<RectTransform> ParentChanged;
|
||||||
|
/// <summary>
|
||||||
|
/// The element provided as the argument is the changed child. It may be new in the hierarchy or just repositioned.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<RectTransform> ChildrenChanged;
|
||||||
|
public event Action ScaleChanged;
|
||||||
|
public event Action SizeChanged;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Initialization
|
||||||
|
public RectTransform(Vector2 relativeSize, RectTransform parent, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null)
|
||||||
|
{
|
||||||
|
Init(parent, anchor, pivot);
|
||||||
|
this.relativeSize = relativeSize;
|
||||||
|
this.minSize = minSize;
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
RecalculateScale();
|
||||||
|
RecalculateAbsoluteSize();
|
||||||
|
RecalculateAnchorPoint();
|
||||||
|
RecalculatePivotOffset();
|
||||||
|
parent?.ChildrenChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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.
|
||||||
|
/// </summary>
|
||||||
|
public RectTransform(Point absoluteSize, RectTransform parent = null, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null)
|
||||||
|
{
|
||||||
|
Init(parent, anchor, pivot);
|
||||||
|
this.nonScaledSize = absoluteSize;
|
||||||
|
RecalculateScale();
|
||||||
|
RecalculateRelativeSize();
|
||||||
|
RecalculateAnchorPoint();
|
||||||
|
RecalculatePivotOffset();
|
||||||
|
IsFixedSize = true;
|
||||||
|
parent?.ChildrenChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectTransform Load(XElement element, RectTransform parent)
|
||||||
|
{
|
||||||
|
Enum.TryParse(element.GetAttributeString("anchor", "Center"), out Anchor anchor);
|
||||||
|
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));
|
||||||
|
|
||||||
|
RectTransform rectTransform;
|
||||||
|
if (element.Attribute("relativesize") != null)
|
||||||
|
{
|
||||||
|
rectTransform = new RectTransform(element.GetAttributeVector2("relativesize", Vector2.One), parent, anchor, pivot, minSize, maxSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rectTransform = new RectTransform(element.GetAttributePoint("absolutesize", new Point(1000, 1000)), parent, anchor, pivot)
|
||||||
|
{
|
||||||
|
minSize = minSize,
|
||||||
|
maxSize = maxSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
rectTransform.RelativeOffset = element.GetAttributeVector2("relativeoffset", Vector2.Zero);
|
||||||
|
rectTransform.AbsoluteOffset = element.GetAttributePoint("absoluteoffset", Point.Zero);
|
||||||
|
return rectTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init(RectTransform parent = null, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
parent?.children.Add(this);
|
||||||
|
Anchor = anchor;
|
||||||
|
Pivot = pivot ?? MatchPivotToAnchor(Anchor);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Protected methods
|
||||||
|
protected void RecalculateScale()
|
||||||
|
{
|
||||||
|
var scale = LocalScale * globalScale;
|
||||||
|
var parents = GetParents();
|
||||||
|
Scale = parents.Any() ? parents.Select(rt => rt.LocalScale).Aggregate((parent, child) => parent * child) * scale : scale;
|
||||||
|
recalculateRect = true;
|
||||||
|
ScaleChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RecalculatePivotOffset()
|
||||||
|
{
|
||||||
|
PivotOffset = CalculatePivotOffset(Pivot, ScaledSize);
|
||||||
|
recalculateRect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RecalculateAnchorPoint()
|
||||||
|
{
|
||||||
|
AnchorPoint = CalculateAnchorPoint(Anchor, ParentRect);
|
||||||
|
recalculateRect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RecalculateRelativeSize()
|
||||||
|
{
|
||||||
|
relativeSize = new Vector2(NonScaledSize.X, NonScaledSize.Y) / new Vector2(NonScaledParentRect.Width, NonScaledParentRect.Height);
|
||||||
|
recalculateRect = true;
|
||||||
|
SizeChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RecalculateAbsoluteSize()
|
||||||
|
{
|
||||||
|
nonScaledSize = NonScaledParentRect.Size.Multiply(RelativeSize).Clamp(MinSize, MaxSize);
|
||||||
|
recalculateRect = true;
|
||||||
|
SizeChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If false, the element will resize if the parent is resized (with the children).
|
||||||
|
/// If true, the element will resize only when explicitly resized.
|
||||||
|
/// Note that scaling always affects the elements.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFixedSize { get; set; }
|
||||||
|
|
||||||
|
protected void RecalculateAll(bool resize, bool scale = true, bool withChildren = true)
|
||||||
|
{
|
||||||
|
if (scale)
|
||||||
|
{
|
||||||
|
RecalculateScale();
|
||||||
|
}
|
||||||
|
if (resize && !IsFixedSize)
|
||||||
|
{
|
||||||
|
RecalculateAbsoluteSize();
|
||||||
|
}
|
||||||
|
RecalculateAnchorPoint();
|
||||||
|
RecalculatePivotOffset();
|
||||||
|
if (withChildren)
|
||||||
|
{
|
||||||
|
RecalculateChildren(resize, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RemoveFromHierarchy(bool displayErrors = true, bool recalculate = true)
|
||||||
|
{
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
if (displayErrors)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Parent null" + Environment.StackTrace);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Parent.children.Contains(this))
|
||||||
|
{
|
||||||
|
if (displayErrors)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("The children of the parent does not contain this child. This should not be possible! " + Environment.StackTrace);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Parent.children.Remove(this))
|
||||||
|
{
|
||||||
|
if (displayErrors)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Unable to remove the child from the parent. " + Environment.StackTrace);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public instance methods
|
||||||
|
public void SetPosition(Anchor anchor, Pivot? pivot = null)
|
||||||
|
{
|
||||||
|
Anchor = anchor;
|
||||||
|
Pivot = pivot ?? MatchPivotToAnchor(anchor);
|
||||||
|
ScreenSpaceOffset = Point.Zero;
|
||||||
|
recalculateRect = true;
|
||||||
|
RecalculateChildren(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resize(Point absoluteSize, bool resizeChildren = true)
|
||||||
|
{
|
||||||
|
nonScaledSize = absoluteSize;
|
||||||
|
RecalculateRelativeSize();
|
||||||
|
RecalculateAll(resize: false, scale: false, withChildren: false);
|
||||||
|
RecalculateChildren(resizeChildren, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resize(Vector2 relativeSize, bool resizeChildren = true)
|
||||||
|
{
|
||||||
|
this.relativeSize = relativeSize;
|
||||||
|
RecalculateAll(resize: true, scale: false, withChildren: false);
|
||||||
|
RecalculateChildren(resizeChildren, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeScale(Vector2 newScale)
|
||||||
|
{
|
||||||
|
LocalScale = newScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetScale()
|
||||||
|
{
|
||||||
|
ChangeScale(Vector2.One);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Currently this needs to be manually called only when the global scale changes.
|
||||||
|
/// If the local scale changes, the scale is automatically recalculated.
|
||||||
|
/// </summary>
|
||||||
|
public void RecalculateScale(bool withChildren)
|
||||||
|
{
|
||||||
|
RecalculateScale();
|
||||||
|
if (withChildren)
|
||||||
|
{
|
||||||
|
RecalculateChildren(resize: false, scale: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manipulates ScreenSpaceOffset.
|
||||||
|
/// If you want to manipulate some other offset, access the property setters directly.
|
||||||
|
/// </summary>
|
||||||
|
public void Translate(Point translation)
|
||||||
|
{
|
||||||
|
ScreenSpaceOffset += translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all parent elements in the hierarchy.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<RectTransform> GetParents()
|
||||||
|
{
|
||||||
|
var parents = new List<RectTransform>();
|
||||||
|
if (Parent != null)
|
||||||
|
{
|
||||||
|
parents.Add(Parent);
|
||||||
|
return parents.Concat(Parent.GetParents());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return parents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all child elements in the hierarchy.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<RectTransform> GetAllChildren()
|
||||||
|
{
|
||||||
|
return children.SelectManyRecursive(c => c.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetChildIndex(RectTransform rectT)
|
||||||
|
{
|
||||||
|
return children.IndexOf(rectT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RectTransform GetChild(int index)
|
||||||
|
{
|
||||||
|
return children[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsParentOf(RectTransform rectT, bool recursive = true)
|
||||||
|
{
|
||||||
|
return children.Contains(rectT) || (recursive && children.Any(c => c.IsParentOf(rectT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearChildren()
|
||||||
|
{
|
||||||
|
children.ForEachMod(c => c.Parent = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SortChildren(Comparison<RectTransform> comparison)
|
||||||
|
{
|
||||||
|
children.Sort(comparison);
|
||||||
|
RecalculateAll(false, true, true);
|
||||||
|
Parent.ChildrenChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAsLastChild()
|
||||||
|
{
|
||||||
|
if (IsLastChild) { return; }
|
||||||
|
if (!RemoveFromHierarchy(displayErrors: true)) { return; }
|
||||||
|
parent.children.Add(this);
|
||||||
|
RecalculateAll(false, true, true);
|
||||||
|
parent.ChildrenChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAsFirstChild()
|
||||||
|
{
|
||||||
|
if (IsFirstChild) { return; }
|
||||||
|
RepositionChildInHierarchy(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RepositionChildInHierarchy(int index)
|
||||||
|
{
|
||||||
|
if (!RemoveFromHierarchy(displayErrors: true)) { return false; }
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Parent.children.Insert(index, this);
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError(e.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RecalculateAll(false, true, true);
|
||||||
|
Parent.ChildrenChanged?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecalculateChildren(bool resize, bool scale = true)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < children.Count; i++)
|
||||||
|
{
|
||||||
|
children[i].RecalculateAll(resize, scale, withChildren: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddChildrenToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < children.Count; i++)
|
||||||
|
{
|
||||||
|
children[i].GUIComponent.AddToGUIUpdateList(ignoreChildren, order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Static methods
|
||||||
|
public static Pivot MatchPivotToAnchor(Anchor anchor)
|
||||||
|
{
|
||||||
|
if (!Enum.TryParse(anchor.ToString(), out Pivot pivot))
|
||||||
|
{
|
||||||
|
throw new Exception($"[RectTransform] Cannot match pivot to anchor {anchor}");
|
||||||
|
}
|
||||||
|
return pivot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the offset so that the direction is always away from the anchor point.
|
||||||
|
/// </summary>
|
||||||
|
public static Point ConvertOffsetRelativeToAnchor(Point offset, Anchor anchor)
|
||||||
|
{
|
||||||
|
switch (anchor)
|
||||||
|
{
|
||||||
|
case Anchor.BottomRight:
|
||||||
|
return offset.Inverse();
|
||||||
|
case Anchor.BottomLeft:
|
||||||
|
case Anchor.BottomCenter:
|
||||||
|
return new Point(offset.X, -offset.Y);
|
||||||
|
case Anchor.TopRight:
|
||||||
|
case Anchor.CenterRight:
|
||||||
|
return new Point(-offset.X, offset.Y);
|
||||||
|
default:
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point CalculatePivotOffset(Pivot pivot, Point size)
|
||||||
|
{
|
||||||
|
int width = size.X;
|
||||||
|
int height = size.Y;
|
||||||
|
switch (pivot)
|
||||||
|
{
|
||||||
|
case Pivot.TopLeft:
|
||||||
|
return Point.Zero;
|
||||||
|
case Pivot.TopCenter:
|
||||||
|
return new Point(-width / 2, 0);
|
||||||
|
case Pivot.TopRight:
|
||||||
|
return new Point(-width, 0);
|
||||||
|
case Pivot.CenterLeft:
|
||||||
|
return new Point(0, -height / 2);
|
||||||
|
case Pivot.Center:
|
||||||
|
return size.Divide(2).Inverse();
|
||||||
|
case Pivot.CenterRight:
|
||||||
|
return new Point(-width, -height / 2);
|
||||||
|
case Pivot.BottomLeft:
|
||||||
|
return new Point(0, -height);
|
||||||
|
case Pivot.BottomCenter:
|
||||||
|
return new Point(-width / 2, -height);
|
||||||
|
case Pivot.BottomRight:
|
||||||
|
return new Point(-width, -height);
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(pivot.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point CalculateAnchorPoint(Anchor anchor, Rectangle parent)
|
||||||
|
{
|
||||||
|
switch (anchor)
|
||||||
|
{
|
||||||
|
case Anchor.TopLeft:
|
||||||
|
return parent.Location;
|
||||||
|
case Anchor.TopCenter:
|
||||||
|
return new Point(parent.Center.X, parent.Top);
|
||||||
|
case Anchor.TopRight:
|
||||||
|
return new Point(parent.Right, parent.Top);
|
||||||
|
case Anchor.CenterLeft:
|
||||||
|
return new Point(parent.Left, parent.Center.Y);
|
||||||
|
case Anchor.Center:
|
||||||
|
return parent.Center;
|
||||||
|
case Anchor.CenterRight:
|
||||||
|
return new Point(parent.Right, parent.Center.Y);
|
||||||
|
case Anchor.BottomLeft:
|
||||||
|
return new Point(parent.Left, parent.Bottom);
|
||||||
|
case Anchor.BottomCenter:
|
||||||
|
return new Point(parent.Center.X, parent.Bottom);
|
||||||
|
case Anchor.BottomRight:
|
||||||
|
return new Point(parent.Right, parent.Bottom);
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(anchor.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The elements are not automatically resized, if the global scale changes.
|
||||||
|
/// You have to manually call RecalculateScale() for all elements after changing the global scale.
|
||||||
|
/// This is because there is currently no easy way to inform all the elements without having a reference to them.
|
||||||
|
/// Having a reference (static list, or event) is problematic, because deconstructing the elements is not handled manually.
|
||||||
|
/// This means that the uncleared references would bloat the memory.
|
||||||
|
/// We could recalculate the scale each time it's needed,
|
||||||
|
/// but in that case the calculation would need to be very lightweight and garbage free, which it currently is not.
|
||||||
|
/// </summary>
|
||||||
|
public static void ResetGlobalScale()
|
||||||
|
{
|
||||||
|
globalScale = Vector2.One;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sprite batch extensions for drawing primitive shapes
|
||||||
|
/// Modified from: https://github.com/craftworkgames/MonoGame.Extended/blob/develop/Source/MonoGame.Extended/ShapeExtensions.cs
|
||||||
|
/// </summary>
|
||||||
|
public static class ShapeExtensions
|
||||||
|
{
|
||||||
|
private static Texture2D _whitePixelTexture;
|
||||||
|
|
||||||
|
private static Texture2D GetTexture(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
if (_whitePixelTexture == null)
|
||||||
|
{
|
||||||
|
_whitePixelTexture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
|
||||||
|
_whitePixelTexture.SetData(new[] { Color.White });
|
||||||
|
}
|
||||||
|
|
||||||
|
return _whitePixelTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a closed polygon from a <see cref="Polygon" /> shape
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawPolygon(this SpriteBatch spriteBatch, Vector2 position, Polygon polygon, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
DrawPolygon(spriteBatch, position, polygon.Vertices, color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a closed polygon from an array of points
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawPolygon(this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
if (points.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (points.Count == 1)
|
||||||
|
{
|
||||||
|
DrawPoint(spriteBatch, points[0], color, (int)thickness);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var texture = GetTexture(spriteBatch);
|
||||||
|
|
||||||
|
for (var i = 0; i < points.Count - 1; i++)
|
||||||
|
DrawPolygonEdge(spriteBatch, texture, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||||
|
|
||||||
|
DrawPolygonEdge(spriteBatch, texture, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||||
|
thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Texture2D texture, Vector2 point1, Vector2 point2,
|
||||||
|
Color color, float thickness)
|
||||||
|
{
|
||||||
|
var length = Vector2.Distance(point1, point2);
|
||||||
|
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||||
|
var scale = new Vector2(length, thickness);
|
||||||
|
spriteBatch.Draw(texture, point1, color: color, rotation: angle, scale: scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a line from point1 to point2 with an offset
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawLine(this SpriteBatch spriteBatch, float x1, float y1, float x2, float y2, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
DrawLine(spriteBatch, new Vector2(x1, y1), new Vector2(x2, y2), color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a line from point1 to point2 with an offset
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
// calculate the distance between the two vectors
|
||||||
|
var distance = Vector2.Distance(point1, point2);
|
||||||
|
|
||||||
|
// calculate the angle between the two vectors
|
||||||
|
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||||
|
|
||||||
|
DrawLine(spriteBatch, point1, distance, angle, color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a line from point1 to point2 with an offset
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point, float length, float angle, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
var origin = new Vector2(0f, 0.5f);
|
||||||
|
var scale = new Vector2(length, thickness);
|
||||||
|
spriteBatch.Draw(GetTexture(spriteBatch), point, null, color, angle, origin, scale, SpriteEffects.None, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a point at the specified x, y position. The center of the point will be at the position.
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawPoint(this SpriteBatch spriteBatch, float x, float y, Color color, float size = 1f)
|
||||||
|
{
|
||||||
|
DrawPoint(spriteBatch, new Vector2(x, y), color, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a point at the specified position. The center of the point will be at the position.
|
||||||
|
/// </summary>
|
||||||
|
public static void DrawPoint(this SpriteBatch spriteBatch, Vector2 position, Color color, float size = 1f)
|
||||||
|
{
|
||||||
|
var scale = Vector2.One * size;
|
||||||
|
var offset = new Vector2(0.5f) - new Vector2(size * 0.5f);
|
||||||
|
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, color: color, scale: scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color,
|
||||||
|
float thickness = 1f)
|
||||||
|
{
|
||||||
|
DrawPolygon(spriteBatch, center, CreateCircle(radius, sides), color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawCircle(this SpriteBatch spriteBatch, float x, float y, float radius, int sides,
|
||||||
|
Color color, float thickness = 1f)
|
||||||
|
{
|
||||||
|
DrawPolygon(spriteBatch, new Vector2(x, y), CreateCircle(radius, sides), color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawSector(this SpriteBatch spriteBatch, Vector2 center, float radius, float radians, int sides, Color color, float offset = 0, float thickness = 1)
|
||||||
|
{
|
||||||
|
DrawPolygon(spriteBatch, center, CreateSector(radius, sides, radians, offset), color, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2[] CreateSector(double radius, int sides, float radians, float offset = 0)
|
||||||
|
{
|
||||||
|
//circle sectors need one extra point at the center
|
||||||
|
var points = new Vector2[radians < MathHelper.TwoPi ? sides + 1 : sides];
|
||||||
|
var step = radians / sides;
|
||||||
|
|
||||||
|
double theta = offset;
|
||||||
|
for (var i = 0; i < sides; i++)
|
||||||
|
{
|
||||||
|
points[i] = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * (float)radius;
|
||||||
|
theta += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2[] CreateCircle(double radius, int sides)
|
||||||
|
{
|
||||||
|
return CreateSector(radius, sides, MathHelper.TwoPi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original source: https://github.com/craftworkgames/MonoGame.Extended/blob/develop/Source/MonoGame.Extended/Shapes/Polygon.cs
|
||||||
|
/// </summary>
|
||||||
|
public class Polygon : IEquatable<Polygon>
|
||||||
|
{
|
||||||
|
public Polygon(IEnumerable<Vector2> vertices)
|
||||||
|
{
|
||||||
|
_localVertices = vertices.ToArray();
|
||||||
|
_transformedVertices = _localVertices;
|
||||||
|
_offset = Vector2.Zero;
|
||||||
|
_rotation = 0;
|
||||||
|
_scale = Vector2.One;
|
||||||
|
_isDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Vector2[] _localVertices;
|
||||||
|
private Vector2[] _transformedVertices;
|
||||||
|
private Vector2 _offset;
|
||||||
|
private float _rotation;
|
||||||
|
private Vector2 _scale;
|
||||||
|
private bool _isDirty;
|
||||||
|
|
||||||
|
public Vector2[] Vertices
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_isDirty)
|
||||||
|
{
|
||||||
|
_transformedVertices = GetTransformedVertices();
|
||||||
|
_isDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _transformedVertices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Left
|
||||||
|
{
|
||||||
|
get { return Vertices.Min(v => v.X); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Right
|
||||||
|
{
|
||||||
|
get { return Vertices.Max(v => v.X); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Top
|
||||||
|
{
|
||||||
|
get { return Vertices.Min(v => v.Y); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Bottom
|
||||||
|
{
|
||||||
|
get { return Vertices.Max(v => v.Y); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Offset(Vector2 amount)
|
||||||
|
{
|
||||||
|
_offset += amount;
|
||||||
|
_isDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rotate(float amount)
|
||||||
|
{
|
||||||
|
_rotation += amount;
|
||||||
|
_isDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Scale(Vector2 amount)
|
||||||
|
{
|
||||||
|
_scale += amount;
|
||||||
|
_isDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2[] GetTransformedVertices()
|
||||||
|
{
|
||||||
|
var newVertices = new Vector2[_localVertices.Length];
|
||||||
|
var isScaled = _scale != Vector2.One;
|
||||||
|
|
||||||
|
for (var i = 0; i < _localVertices.Length; i++)
|
||||||
|
{
|
||||||
|
var p = _localVertices[i];
|
||||||
|
|
||||||
|
if (isScaled)
|
||||||
|
p *= _scale;
|
||||||
|
|
||||||
|
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||||
|
if (_rotation != 0)
|
||||||
|
{
|
||||||
|
var cos = (float)Math.Cos(_rotation);
|
||||||
|
var sin = (float)Math.Sin(_rotation);
|
||||||
|
p = new Vector2(cos * p.X - sin * p.Y, sin * p.X + cos * p.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
newVertices[i] = p + _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Polygon TransformedCopy(Vector2 offset, float rotation, Vector2 scale)
|
||||||
|
{
|
||||||
|
var polygon = new Polygon(_localVertices);
|
||||||
|
polygon.Offset(offset);
|
||||||
|
polygon.Rotate(rotation);
|
||||||
|
polygon.Scale(scale - Vector2.One);
|
||||||
|
return new Polygon(polygon.Vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(Vector2 point)
|
||||||
|
{
|
||||||
|
return Contains(point.X, point.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(float x, float y)
|
||||||
|
{
|
||||||
|
var intersects = 0;
|
||||||
|
var vertices = Vertices;
|
||||||
|
|
||||||
|
for (var i = 0; i < vertices.Length; i++)
|
||||||
|
{
|
||||||
|
var x1 = vertices[i].X;
|
||||||
|
var y1 = vertices[i].Y;
|
||||||
|
var x2 = vertices[(i + 1) % vertices.Length].X;
|
||||||
|
var y2 = vertices[(i + 1) % vertices.Length].Y;
|
||||||
|
|
||||||
|
if ((((y1 <= y) && (y < y2)) || ((y2 <= y) && (y < y1))) && (x < (x2 - x1) / (y2 - y1) * (y - y1) + x1))
|
||||||
|
intersects++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (intersects & 1) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Polygon a, Polygon b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Polygon a, Polygon b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
return obj is Polygon && Equals((Polygon)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Polygon other)
|
||||||
|
{
|
||||||
|
return Vertices.SequenceEqual(other.Vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return Vertices.Aggregate(27, (current, v) => current + 13 * current + v.GetHashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class SpriteSheetPlayer
|
||||||
|
{
|
||||||
|
private SpriteSheet[] playingSheets;
|
||||||
|
private SpriteSheet currentSheet;
|
||||||
|
private List<PreloadedContent> preloadedSheets;
|
||||||
|
|
||||||
|
private GUIFrame background, videoFrame;
|
||||||
|
private GUITextBlock title;
|
||||||
|
private GUICustomComponent sheetView;
|
||||||
|
|
||||||
|
private float totalElapsed = 0;
|
||||||
|
private float animationSpeed = 0.1f;
|
||||||
|
private float loopTimer = 0.0f;
|
||||||
|
private float loopDelay = 0.0f;
|
||||||
|
|
||||||
|
private int currentSheetIndex = 0;
|
||||||
|
private int currentFrameIndex = 0;
|
||||||
|
|
||||||
|
private Color backgroundColor = new Color(0f, 0f, 0f, 1f);
|
||||||
|
|
||||||
|
private bool isPlaying;
|
||||||
|
public bool IsPlaying
|
||||||
|
{
|
||||||
|
get { return isPlaying; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (isPlaying == value) return;
|
||||||
|
isPlaying = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Vector2 defaultResolution = new Vector2(520, 300);
|
||||||
|
private readonly int borderSize = 20;
|
||||||
|
|
||||||
|
private class PreloadedContent
|
||||||
|
{
|
||||||
|
public string ContentName;
|
||||||
|
public string ContentTag;
|
||||||
|
public SpriteSheet[] Sheets;
|
||||||
|
|
||||||
|
public PreloadedContent(string name, string tag, SpriteSheet[] sheets)
|
||||||
|
{
|
||||||
|
ContentName = name;
|
||||||
|
ContentTag = tag;
|
||||||
|
Sheets = sheets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpriteSheetPlayer()
|
||||||
|
{
|
||||||
|
int width = (int)defaultResolution.X;
|
||||||
|
int height = (int)defaultResolution.Y;
|
||||||
|
|
||||||
|
background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor);
|
||||||
|
videoFrame = new GUIFrame(new RectTransform(new Point(width + borderSize, height + borderSize), background.RectTransform, Anchor.Center), "SonarFrame");
|
||||||
|
sheetView = new GUICustomComponent(new RectTransform(new Point(width, height), videoFrame.RectTransform, Anchor.Center),
|
||||||
|
(spriteBatch, guiCustomComponent) => { DrawSheetView(spriteBatch, guiCustomComponent.Rect); }, UpdateSheetView);
|
||||||
|
title = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), videoFrame.RectTransform, Anchor.TopCenter, Pivot.BottomCenter), string.Empty, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||||
|
|
||||||
|
preloadedSheets = new List<PreloadedContent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PreloadContent(string contentPath, string contentTag, string contentId, XElement contentElement)
|
||||||
|
{
|
||||||
|
if (preloadedSheets.Find(s => s.ContentName == contentId) != null) return; // Already loaded
|
||||||
|
preloadedSheets.Add(new PreloadedContent(contentId, contentTag, CreateSpriteSheets(contentPath, contentElement)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllPreloaded()
|
||||||
|
{
|
||||||
|
if (preloadedSheets == null || preloadedSheets.Count == 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < preloadedSheets.Count; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < preloadedSheets[i].Sheets.Length; j++)
|
||||||
|
{
|
||||||
|
preloadedSheets[i].Sheets[j].Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadedSheets.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePreloadedByTag(string tag)
|
||||||
|
{
|
||||||
|
if (preloadedSheets == null || preloadedSheets.Count == 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < preloadedSheets.Count; i++)
|
||||||
|
{
|
||||||
|
if (preloadedSheets[i].ContentTag != tag) continue;
|
||||||
|
for (int j = 0; j < preloadedSheets[i].Sheets.Length; j++)
|
||||||
|
{
|
||||||
|
preloadedSheets[i].Sheets[j].Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadedSheets[i] = null;
|
||||||
|
preloadedSheets.RemoveAt(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Play()
|
||||||
|
{
|
||||||
|
isPlaying = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
isPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
if (!isPlaying) return;
|
||||||
|
background.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadContent(string contentPath, XElement videoElement, string contentId, bool startPlayback)
|
||||||
|
{
|
||||||
|
totalElapsed = loopTimer = 0.0f;
|
||||||
|
animationSpeed = videoElement.GetAttributeFloat("animationspeed", 0.1f);
|
||||||
|
loopDelay = videoElement.GetAttributeFloat("loopdelay", 0.0f); ;
|
||||||
|
|
||||||
|
if (playingSheets != null)
|
||||||
|
{
|
||||||
|
foreach (SpriteSheet existingSheet in playingSheets)
|
||||||
|
{
|
||||||
|
existingSheet.Remove();
|
||||||
|
}
|
||||||
|
playingSheets = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
playingSheets = preloadedSheets.Find(s => s.ContentName == contentId).Sheets;
|
||||||
|
|
||||||
|
if (playingSheets == null) // No preloaded sheets found, create sheets
|
||||||
|
{
|
||||||
|
playingSheets = CreateSpriteSheets(contentPath, videoElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSheet = playingSheets[0];
|
||||||
|
|
||||||
|
Point resolution = currentSheet.FrameSize;
|
||||||
|
|
||||||
|
videoFrame.RectTransform.NonScaledSize = resolution + new Point(borderSize, borderSize);
|
||||||
|
sheetView.RectTransform.NonScaledSize = resolution;
|
||||||
|
|
||||||
|
title.Text = TextManager.Get(contentId);
|
||||||
|
title.RectTransform.NonScaledSize = new Point(resolution.X, 30);
|
||||||
|
|
||||||
|
if (startPlayback) Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpriteSheet[] CreateSpriteSheets(string contentPath, XElement videoElement)
|
||||||
|
{
|
||||||
|
SpriteSheet[] sheets = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<XElement> sheetElements = new List<XElement>();
|
||||||
|
|
||||||
|
foreach (var sheetElement in videoElement.Elements("Sheet"))
|
||||||
|
{
|
||||||
|
sheetElements.Add(sheetElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
sheets = new SpriteSheet[sheetElements.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < sheetElements.Count; i++)
|
||||||
|
{
|
||||||
|
sheets[i] = new SpriteSheet(sheetElements[i], contentPath, sheetElements[i].GetAttributeString("path", ""), sheetElements[i].GetAttributeInt("empty", 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error loading sprite sheet content " + contentPath + "!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSheetView(float deltaTime, GUICustomComponent viewContainer)
|
||||||
|
{
|
||||||
|
if (!isPlaying) return;
|
||||||
|
if (loopTimer > 0.0f)
|
||||||
|
{
|
||||||
|
loopTimer -= deltaTime;
|
||||||
|
|
||||||
|
if (loopTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
currentSheetIndex = 0;
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
currentSheet = playingSheets[currentSheetIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalElapsed += deltaTime;
|
||||||
|
if (totalElapsed > animationSpeed)
|
||||||
|
{
|
||||||
|
totalElapsed -= animationSpeed;
|
||||||
|
currentFrameIndex++;
|
||||||
|
|
||||||
|
if (currentFrameIndex > currentSheet.FrameCount - 1)
|
||||||
|
{
|
||||||
|
currentSheetIndex++;
|
||||||
|
|
||||||
|
if (currentSheetIndex > playingSheets.Length - 1)
|
||||||
|
{
|
||||||
|
if (loopDelay > 0.0f)
|
||||||
|
{
|
||||||
|
loopTimer = loopDelay;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSheetIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
currentSheet = playingSheets[currentSheetIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSheetView(SpriteBatch spriteBatch, Rectangle rect)
|
||||||
|
{
|
||||||
|
if (!isPlaying) return;
|
||||||
|
currentSheet.Draw(spriteBatch, currentFrameIndex, rect.Center.ToVector2(), Color.White, currentSheet.Origin, 0f, Vector2.One);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove()
|
||||||
|
{
|
||||||
|
if (playingSheets != null)
|
||||||
|
{
|
||||||
|
foreach (SpriteSheet existingSheet in playingSheets)
|
||||||
|
{
|
||||||
|
existingSheet.Remove();
|
||||||
|
}
|
||||||
|
playingSheets = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveAllPreloaded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
public class UISprite
|
||||||
|
{
|
||||||
|
public Sprite Sprite
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Tile
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Slice
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle[] Slices
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MaintainAspectRatio
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UISprite(XElement element)
|
||||||
|
{
|
||||||
|
Sprite = new Sprite(element);
|
||||||
|
MaintainAspectRatio = element.GetAttributeBool("maintainaspectratio", false);
|
||||||
|
Tile = element.GetAttributeBool("tile", true);
|
||||||
|
|
||||||
|
Vector4 sliceVec = element.GetAttributeVector4("slice", Vector4.Zero);
|
||||||
|
if (sliceVec != Vector4.Zero)
|
||||||
|
{
|
||||||
|
Rectangle slice = new Rectangle((int)sliceVec.X, (int)sliceVec.Y, (int)(sliceVec.Z - sliceVec.X), (int)(sliceVec.W - sliceVec.Y));
|
||||||
|
|
||||||
|
Slice = true;
|
||||||
|
Slices = new Rectangle[9];
|
||||||
|
|
||||||
|
//top-left
|
||||||
|
Slices[0] = new Rectangle(Sprite.SourceRect.Location, slice.Location - Sprite.SourceRect.Location);
|
||||||
|
//top-mid
|
||||||
|
Slices[1] = new Rectangle(slice.Location.X, Slices[0].Y, slice.Width, Slices[0].Height);
|
||||||
|
//top-right
|
||||||
|
Slices[2] = new Rectangle(slice.Right, Slices[0].Y, Sprite.SourceRect.Right - slice.Right, Slices[0].Height);
|
||||||
|
|
||||||
|
//mid-left
|
||||||
|
Slices[3] = new Rectangle(Slices[0].X, slice.Y, Slices[0].Width, slice.Height);
|
||||||
|
//center
|
||||||
|
Slices[4] = slice;
|
||||||
|
//mid-right
|
||||||
|
Slices[5] = new Rectangle(Slices[2].X, slice.Y, Slices[2].Width, slice.Height);
|
||||||
|
|
||||||
|
//bottom-left
|
||||||
|
Slices[6] = new Rectangle(Slices[0].X, slice.Bottom, Slices[0].Width, Sprite.SourceRect.Bottom - slice.Bottom);
|
||||||
|
//bottom-mid
|
||||||
|
Slices[7] = new Rectangle(Slices[1].X, slice.Bottom, Slices[1].Width, Sprite.SourceRect.Bottom - slice.Bottom);
|
||||||
|
//bottom-right
|
||||||
|
Slices[8] = new Rectangle(Slices[2].X, slice.Bottom, Slices[2].Width, Sprite.SourceRect.Bottom - slice.Bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||||
|
{
|
||||||
|
if (Sprite.Texture == null)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, Color.Magenta);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Slice)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < 3; x++)
|
||||||
|
{
|
||||||
|
float width = (x == 1 ? centerWidth : Slices[x].Width * scale.X);
|
||||||
|
for (int y = 0; y < 3; y++)
|
||||||
|
{
|
||||||
|
float height = (y == 1 ? centerHeight : Slices[x + y * 3].Height * scale.Y);
|
||||||
|
|
||||||
|
spriteBatch.Draw(Sprite.Texture,
|
||||||
|
new Rectangle((int)pos.X, (int)pos.Y, (int)width, (int)height),
|
||||||
|
Slices[x + y * 3],
|
||||||
|
color);
|
||||||
|
|
||||||
|
pos.Y += height;
|
||||||
|
}
|
||||||
|
pos.X += width;
|
||||||
|
pos.Y = rect.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tile)
|
||||||
|
{
|
||||||
|
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
||||||
|
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), null, color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (MaintainAspectRatio)
|
||||||
|
{
|
||||||
|
float scale = Math.Min((float)rect.Width / Sprite.SourceRect.Width, (float)rect.Height / Sprite.SourceRect.Height);
|
||||||
|
|
||||||
|
spriteBatch.Draw(Sprite.Texture, rect.Center.ToVector2(),
|
||||||
|
Sprite.SourceRect,
|
||||||
|
color,
|
||||||
|
rotation: 0.0f,
|
||||||
|
origin: Sprite.size / 2.0f,
|
||||||
|
scale: scale,
|
||||||
|
effects: spriteEffects, layerDepth: 0.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spriteBatch.Draw(Sprite.Texture, rect, Sprite.SourceRect, color, 0, Vector2.Zero, spriteEffects, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class Widget
|
||||||
|
{
|
||||||
|
public enum Shape
|
||||||
|
{
|
||||||
|
Rectangle,
|
||||||
|
Circle,
|
||||||
|
Cross
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shape shape;
|
||||||
|
public string tooltip;
|
||||||
|
public bool showTooltip = true;
|
||||||
|
public Rectangle DrawRect => new Rectangle((int)(DrawPos.X - (float)size / 2), (int)(DrawPos.Y - (float)size / 2), size, size);
|
||||||
|
public Rectangle InputRect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var inputRect = DrawRect;
|
||||||
|
inputRect.Inflate(inputAreaMargin, inputAreaMargin);
|
||||||
|
return inputRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 DrawPos { get; set; }
|
||||||
|
public int size = 10;
|
||||||
|
/// <summary>
|
||||||
|
/// Used only for circles.
|
||||||
|
/// </summary>
|
||||||
|
public int sides = 40;
|
||||||
|
/// <summary>
|
||||||
|
/// Currently used only for rectangles.
|
||||||
|
/// </summary>
|
||||||
|
public bool isFilled;
|
||||||
|
public int inputAreaMargin;
|
||||||
|
public Color color = Color.Red;
|
||||||
|
public Color? secondaryColor;
|
||||||
|
public Color textColor = Color.White;
|
||||||
|
public Color textBackgroundColor = Color.Black * 0.5f;
|
||||||
|
public readonly string id;
|
||||||
|
|
||||||
|
public event Action Selected;
|
||||||
|
public event Action Deselected;
|
||||||
|
public event Action Hovered;
|
||||||
|
public event Action MouseUp;
|
||||||
|
public event Action MouseDown;
|
||||||
|
public event Action<float> MouseHeld;
|
||||||
|
public event Action<float> PreUpdate;
|
||||||
|
public event Action<float> PostUpdate;
|
||||||
|
public event Action<SpriteBatch, float> PreDraw;
|
||||||
|
public event Action<SpriteBatch, float> PostDraw;
|
||||||
|
|
||||||
|
public Action refresh;
|
||||||
|
|
||||||
|
public object data;
|
||||||
|
|
||||||
|
public bool IsSelected => enabled && selectedWidgets.Contains(this);
|
||||||
|
public bool IsControlled => IsSelected && PlayerInput.LeftButtonHeld();
|
||||||
|
public bool IsMouseOver => GUI.MouseOn == null && InputRect.Contains(PlayerInput.MousePosition);
|
||||||
|
private bool enabled = true;
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
get { return enabled; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
enabled = value;
|
||||||
|
if (!enabled && selectedWidgets.Contains(this))
|
||||||
|
{
|
||||||
|
selectedWidgets.Remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool multiselect;
|
||||||
|
public static bool EnableMultiSelect
|
||||||
|
{
|
||||||
|
get { return multiselect; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
multiselect = value;
|
||||||
|
if (!multiselect && selectedWidgets.Multiple())
|
||||||
|
{
|
||||||
|
selectedWidgets = selectedWidgets.Take(1).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Vector2? tooltipOffset;
|
||||||
|
|
||||||
|
public Widget linkedWidget;
|
||||||
|
|
||||||
|
public static List<Widget> selectedWidgets = new List<Widget>();
|
||||||
|
|
||||||
|
public Widget(string id, int size, Shape shape)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.size = size;
|
||||||
|
this.shape = shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
PreUpdate?.Invoke(deltaTime);
|
||||||
|
if (!enabled) { return; }
|
||||||
|
if (IsMouseOver)
|
||||||
|
{
|
||||||
|
Hovered?.Invoke();
|
||||||
|
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())
|
||||||
|
{
|
||||||
|
selectedWidgets.Add(this);
|
||||||
|
Selected?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (selectedWidgets.Contains(this))
|
||||||
|
{
|
||||||
|
selectedWidgets.Remove(this);
|
||||||
|
Deselected?.Invoke();
|
||||||
|
}
|
||||||
|
if (IsSelected)
|
||||||
|
{
|
||||||
|
if (PlayerInput.LeftButtonDown())
|
||||||
|
{
|
||||||
|
MouseDown?.Invoke();
|
||||||
|
}
|
||||||
|
if (PlayerInput.LeftButtonHeld())
|
||||||
|
{
|
||||||
|
MouseHeld?.Invoke(deltaTime);
|
||||||
|
}
|
||||||
|
if (PlayerInput.LeftButtonClicked())
|
||||||
|
{
|
||||||
|
MouseUp?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PostUpdate?.Invoke(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Draw(SpriteBatch spriteBatch, float deltaTime)
|
||||||
|
{
|
||||||
|
PreDraw?.Invoke(spriteBatch, deltaTime);
|
||||||
|
var drawRect = DrawRect;
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case Shape.Rectangle:
|
||||||
|
if (secondaryColor.HasValue)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, drawRect, secondaryColor.Value, isFilled, thickness: 2);
|
||||||
|
}
|
||||||
|
GUI.DrawRectangle(spriteBatch, drawRect, color, isFilled, thickness: IsSelected ? 3 : 1);
|
||||||
|
break;
|
||||||
|
case Shape.Circle:
|
||||||
|
if (secondaryColor.HasValue)
|
||||||
|
{
|
||||||
|
ShapeExtensions.DrawCircle(spriteBatch, DrawPos, size / 2, sides, secondaryColor.Value, thickness: 2);
|
||||||
|
}
|
||||||
|
ShapeExtensions.DrawCircle(spriteBatch, DrawPos, size / 2, sides, color, thickness: IsSelected ? 3 : 1);
|
||||||
|
break;
|
||||||
|
case Shape.Cross:
|
||||||
|
float halfSize = size / 2;
|
||||||
|
if (secondaryColor.HasValue)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, DrawPos + Vector2.UnitY * halfSize, DrawPos - Vector2.UnitY * halfSize, secondaryColor.Value, width: 2);
|
||||||
|
GUI.DrawLine(spriteBatch, DrawPos + Vector2.UnitX * halfSize, DrawPos - Vector2.UnitX * halfSize, secondaryColor.Value, width: 2);
|
||||||
|
}
|
||||||
|
GUI.DrawLine(spriteBatch, DrawPos + Vector2.UnitY * halfSize, DrawPos - Vector2.UnitY * halfSize, color, width: IsSelected ? 3 : 1);
|
||||||
|
GUI.DrawLine(spriteBatch, DrawPos + Vector2.UnitX * halfSize, DrawPos - Vector2.UnitX * halfSize, color, width: IsSelected ? 3 : 1);
|
||||||
|
break;
|
||||||
|
default: throw new NotImplementedException(shape.ToString());
|
||||||
|
}
|
||||||
|
if (IsSelected)
|
||||||
|
{
|
||||||
|
if (showTooltip && !string.IsNullOrEmpty(tooltip))
|
||||||
|
{
|
||||||
|
var offset = tooltipOffset ?? new Vector2(size, -size / 2);
|
||||||
|
GUI.DrawString(spriteBatch, DrawPos + offset, tooltip, textColor, textBackgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PostDraw?.Invoke(spriteBatch, deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Barotrauma.Particles;
|
using Barotrauma.Particles;
|
||||||
|
using Barotrauma.Steam;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using FarseerPhysics.Dynamics;
|
using FarseerPhysics.Dynamics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
@@ -8,56 +9,83 @@ using Microsoft.Xna.Framework.Input;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using GameAnalyticsSDK.Net;
|
using GameAnalyticsSDK.Net;
|
||||||
using System.Threading;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using RestSharp;
|
using System.Threading;
|
||||||
using System.Net;
|
using Barotrauma.Tutorials;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class GameMain : Game
|
class GameMain : Game
|
||||||
{
|
{
|
||||||
public static bool ShowFPS = false;
|
public static bool ShowFPS = false;
|
||||||
|
public static bool ShowPerf = false;
|
||||||
public static bool DebugDraw;
|
public static bool DebugDraw;
|
||||||
|
public static bool IsMultiplayer => Client != null || Server != null;
|
||||||
public static FrameCounter FrameCounter;
|
|
||||||
|
public static PerformanceCounter PerformanceCounter;
|
||||||
|
|
||||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||||
|
|
||||||
public static string SteamVersionUrl
|
public static GameScreen GameScreen;
|
||||||
{
|
public static MainMenuScreen MainMenuScreen;
|
||||||
get;
|
public static LobbyScreen LobbyScreen;
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GameScreen GameScreen;
|
public static NetLobbyScreen NetLobbyScreen;
|
||||||
public static MainMenuScreen MainMenuScreen;
|
public static ServerListScreen ServerListScreen;
|
||||||
public static LobbyScreen LobbyScreen;
|
public static SteamWorkshopScreen SteamWorkshopScreen;
|
||||||
|
|
||||||
public static NetLobbyScreen NetLobbyScreen;
|
public static SubEditorScreen SubEditorScreen;
|
||||||
public static ServerListScreen ServerListScreen;
|
|
||||||
|
|
||||||
public static SubEditorScreen SubEditorScreen;
|
|
||||||
public static CharacterEditorScreen CharacterEditorScreen;
|
|
||||||
public static ParticleEditorScreen ParticleEditorScreen;
|
public static ParticleEditorScreen ParticleEditorScreen;
|
||||||
|
public static LevelEditorScreen LevelEditorScreen;
|
||||||
|
public static SpriteEditorScreen SpriteEditorScreen;
|
||||||
|
public static CharacterEditorScreen CharacterEditorScreen;
|
||||||
|
|
||||||
public static Lights.LightManager LightManager;
|
public static Lights.LightManager LightManager;
|
||||||
|
|
||||||
public static ContentPackage SelectedPackage
|
public static Sounds.SoundManager SoundManager;
|
||||||
|
|
||||||
|
public static HashSet<ContentPackage> SelectedPackages
|
||||||
{
|
{
|
||||||
get { return Config.SelectedContentPackage; }
|
get { return Config?.SelectedContentPackages; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ContentPackage vanillaContent;
|
||||||
|
public static ContentPackage VanillaContent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (vanillaContent == null)
|
||||||
|
{
|
||||||
|
// TODO: Dynamic method for defining and finding the vanilla content package.
|
||||||
|
vanillaContent = SelectedPackages.Single(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
|
||||||
|
}
|
||||||
|
return vanillaContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameSession gameSession;
|
||||||
|
public static GameSession GameSession
|
||||||
|
{
|
||||||
|
get { return gameSession; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (gameSession == value) { return; }
|
||||||
|
if (gameSession?.GameMode != null && gameSession.GameMode != value?.GameMode)
|
||||||
|
{
|
||||||
|
gameSession.GameMode.Remove();
|
||||||
|
}
|
||||||
|
gameSession = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameSession GameSession;
|
|
||||||
|
|
||||||
public static NetworkMember NetworkMember;
|
public static NetworkMember NetworkMember;
|
||||||
|
|
||||||
public static ParticleManager ParticleManager;
|
public static ParticleManager ParticleManager;
|
||||||
public static DecalManager DecalManager;
|
public static DecalManager DecalManager;
|
||||||
|
|
||||||
public static World World;
|
public static World World;
|
||||||
|
|
||||||
public static LoadingScreen TitleScreen;
|
public static LoadingScreen TitleScreen;
|
||||||
@@ -74,6 +102,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Viewport defaultViewport;
|
private Viewport defaultViewport;
|
||||||
|
|
||||||
|
public event Action OnResolutionChanged;
|
||||||
|
|
||||||
public static GameMain Instance
|
public static GameMain Instance
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -85,6 +115,7 @@ namespace Barotrauma
|
|||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool FullscreenOnTabIn;
|
private static bool FullscreenOnTabIn;
|
||||||
|
|
||||||
public static WindowMode WindowMode
|
public static WindowMode WindowMode
|
||||||
@@ -119,7 +150,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get { return NetworkMember as GameClient; }
|
get { return NetworkMember as GameClient; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RasterizerState ScissorTestEnable
|
public static RasterizerState ScissorTestEnable
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -130,13 +161,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get { return loadingScreenOpen; }
|
get { return loadingScreenOpen; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameMain()
|
public GameMain()
|
||||||
{
|
{
|
||||||
GraphicsDeviceManager = new GraphicsDeviceManager(this);
|
GraphicsDeviceManager = new GraphicsDeviceManager(this);
|
||||||
|
|
||||||
Window.Title = "Barotrauma";
|
Window.Title = "Barotrauma";
|
||||||
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
Config = new GameSettings("config.xml");
|
Config = new GameSettings("config.xml");
|
||||||
@@ -144,15 +175,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
UpdaterUtil.CleanOldFiles();
|
UpdaterUtil.CleanOldFiles();
|
||||||
Config.WasGameUpdated = false;
|
Config.WasGameUpdated = false;
|
||||||
Config.Save("config.xml");
|
Config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextManager.LoadTextPacks();
|
||||||
|
|
||||||
ApplyGraphicsSettings();
|
ApplyGraphicsSettings();
|
||||||
|
|
||||||
Content.RootDirectory = "Content";
|
Content.RootDirectory = "Content";
|
||||||
|
|
||||||
FrameCounter = new FrameCounter();
|
PerformanceCounter = new PerformanceCounter();
|
||||||
|
|
||||||
IsFixedTimeStep = false;
|
IsFixedTimeStep = false;
|
||||||
|
|
||||||
Timing.Accumulator = 0.0f;
|
Timing.Accumulator = 0.0f;
|
||||||
@@ -189,14 +222,22 @@ namespace Barotrauma
|
|||||||
SetWindowMode(Config.WindowMode);
|
SetWindowMode(Config.WindowMode);
|
||||||
|
|
||||||
defaultViewport = GraphicsDevice.Viewport;
|
defaultViewport = GraphicsDevice.Viewport;
|
||||||
|
|
||||||
|
OnResolutionChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWindowMode(WindowMode windowMode)
|
public void SetWindowMode(WindowMode windowMode)
|
||||||
{
|
{
|
||||||
WindowMode = windowMode;
|
WindowMode = windowMode;
|
||||||
|
#if !(OSX)
|
||||||
GraphicsDeviceManager.HardwareModeSwitch = Config.WindowMode != WindowMode.BorderlessWindowed;
|
GraphicsDeviceManager.HardwareModeSwitch = Config.WindowMode != WindowMode.BorderlessWindowed;
|
||||||
|
#else
|
||||||
|
// Force borderless on macOS.
|
||||||
|
GraphicsDeviceManager.HardwareModeSwitch = Config.WindowMode != WindowMode.BorderlessWindowed && Config.WindowMode != WindowMode.Fullscreen;
|
||||||
|
#endif
|
||||||
GraphicsDeviceManager.IsFullScreen = Config.WindowMode == WindowMode.Fullscreen || Config.WindowMode == WindowMode.BorderlessWindowed;
|
GraphicsDeviceManager.IsFullScreen = Config.WindowMode == WindowMode.Fullscreen || Config.WindowMode == WindowMode.BorderlessWindowed;
|
||||||
|
Window.IsBorderless = !GraphicsDeviceManager.HardwareModeSwitch;
|
||||||
|
|
||||||
GraphicsDeviceManager.ApplyChanges();
|
GraphicsDeviceManager.ApplyChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,9 +272,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GraphicsWidth = GraphicsDevice.Viewport.Width;
|
GraphicsWidth = GraphicsDevice.Viewport.Width;
|
||||||
GraphicsHeight = GraphicsDevice.Viewport.Height;
|
GraphicsHeight = GraphicsDevice.Viewport.Height;
|
||||||
|
|
||||||
Sound.Init();
|
|
||||||
|
|
||||||
ConvertUnits.SetDisplayUnitToSimUnitRatio(Physics.DisplayToSimRation);
|
ConvertUnits.SetDisplayUnitToSimUnitRatio(Physics.DisplayToSimRation);
|
||||||
|
|
||||||
spriteBatch = new SpriteBatch(GraphicsDevice);
|
spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||||
@@ -243,10 +282,11 @@ namespace Barotrauma
|
|||||||
TitleScreen = new LoadingScreen(GraphicsDevice);
|
TitleScreen = new LoadingScreen(GraphicsDevice);
|
||||||
|
|
||||||
loadingCoroutine = CoroutineManager.StartCoroutine(Load());
|
loadingCoroutine = CoroutineManager.StartCoroutine(Load());
|
||||||
|
#if WINDOWS
|
||||||
var myForm = (System.Windows.Forms.Form)System.Windows.Forms.Form.FromHandle(Window.Handle);
|
var myForm = (System.Windows.Forms.Form)System.Windows.Forms.Form.FromHandle(Window.Handle);
|
||||||
myForm.Deactivate += new EventHandler(HandleDefocus);
|
myForm.Deactivate += new EventHandler(HandleDefocus);
|
||||||
myForm.Activated += new EventHandler(HandleFocus);
|
myForm.Activated += new EventHandler(HandleFocus);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDefocus(object sender, EventArgs e)
|
private void HandleDefocus(object sender, EventArgs e)
|
||||||
@@ -311,19 +351,34 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
DebugConsole.NewMessage("LOADING COROUTINE", Color.Lime);
|
DebugConsole.NewMessage("LOADING COROUTINE", Color.Lime);
|
||||||
}
|
}
|
||||||
GUI.GraphicsDevice = base.GraphicsDevice;
|
|
||||||
GUI.Init(Content);
|
SoundManager = new Sounds.SoundManager();
|
||||||
|
SoundManager.SetCategoryGainMultiplier("default", Config.SoundVolume);
|
||||||
|
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume);
|
||||||
|
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume);
|
||||||
|
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume);
|
||||||
|
|
||||||
|
GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
|
||||||
|
DebugConsole.Init();
|
||||||
|
|
||||||
|
SteamManager.Initialize();
|
||||||
|
|
||||||
|
if (SelectedPackages.Count == 0)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("No content packages selected");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Selected content packages: " + string.Join(", ", SelectedPackages.Select(cp => cp.Name)));
|
||||||
|
}
|
||||||
|
|
||||||
InitUserStats();
|
InitUserStats();
|
||||||
|
|
||||||
GUIComponent.Init(Window);
|
|
||||||
DebugConsole.Init(Window);
|
|
||||||
DebugConsole.Log(SelectedPackage == null ? "No content package selected" : "Content package \"" + SelectedPackage.Name + "\" selected");
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
LightManager = new Lights.LightManager(base.GraphicsDevice, Content);
|
LightManager = new Lights.LightManager(base.GraphicsDevice, Content);
|
||||||
|
|
||||||
Hull.renderer = new WaterRenderer(base.GraphicsDevice, Content);
|
WaterRenderer.Instance = new WaterRenderer(base.GraphicsDevice, Content);
|
||||||
TitleScreen.LoadState = 1.0f;
|
TitleScreen.LoadState = 1.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
@@ -333,30 +388,46 @@ namespace Barotrauma
|
|||||||
|
|
||||||
MissionPrefab.Init();
|
MissionPrefab.Init();
|
||||||
MapEntityPrefab.Init();
|
MapEntityPrefab.Init();
|
||||||
|
Tutorials.Tutorial.Init();
|
||||||
|
MapGenerationParams.Init();
|
||||||
LevelGenerationParams.LoadPresets();
|
LevelGenerationParams.LoadPresets();
|
||||||
|
ScriptedEventSet.LoadPrefabs();
|
||||||
|
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||||
TitleScreen.LoadState = 10.0f;
|
TitleScreen.LoadState = 10.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
JobPrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Jobs));
|
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
|
||||||
|
TitleScreen.LoadState = 15.0f;
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
|
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||||
|
TitleScreen.LoadState = 25.0f;
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
|
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
|
||||||
// Add any missing jobs from the prefab into Config.JobNamePreferences.
|
// Add any missing jobs from the prefab into Config.JobNamePreferences.
|
||||||
foreach (JobPrefab job in JobPrefab.List)
|
foreach (JobPrefab job in JobPrefab.List)
|
||||||
{
|
{
|
||||||
if (!Config.JobNamePreferences.Contains(job.Name)) { Config.JobNamePreferences.Add(job.Name); }
|
if (!Config.JobPreferences.Contains(job.Identifier)) { Config.JobPreferences.Add(job.Identifier); }
|
||||||
}
|
}
|
||||||
StructurePrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Structure));
|
|
||||||
TitleScreen.LoadState = 20.0f;
|
|
||||||
yield return CoroutineStatus.Running;
|
|
||||||
|
|
||||||
ItemPrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Item));
|
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
|
||||||
|
|
||||||
|
ItemAssemblyPrefab.LoadAll();
|
||||||
TitleScreen.LoadState = 30.0f;
|
TitleScreen.LoadState = 30.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
Debug.WriteLine("sounds");
|
Debug.WriteLine("sounds");
|
||||||
CoroutineManager.StartCoroutine(SoundPlayer.Init());
|
var soundLoadingCoroutine = CoroutineManager.StartCoroutine(SoundPlayer.Init());
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (!SoundPlayer.Initialized)
|
while (!SoundPlayer.Initialized)
|
||||||
{
|
{
|
||||||
|
if (soundLoadingCoroutine.Exception != null)
|
||||||
|
{
|
||||||
|
throw soundLoadingCoroutine.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ?
|
TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ?
|
||||||
30.0f :
|
30.0f :
|
||||||
@@ -373,23 +444,30 @@ namespace Barotrauma
|
|||||||
TitleScreen.LoadState = 80.0f;
|
TitleScreen.LoadState = 80.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content);
|
GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content);
|
||||||
TitleScreen.LoadState = 90.0f;
|
TitleScreen.LoadState = 90.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
MainMenuScreen = new MainMenuScreen(this);
|
MainMenuScreen = new MainMenuScreen(this);
|
||||||
LobbyScreen = new LobbyScreen();
|
LobbyScreen = new LobbyScreen();
|
||||||
|
ServerListScreen = new ServerListScreen();
|
||||||
ServerListScreen = new ServerListScreen();
|
|
||||||
|
|
||||||
SubEditorScreen = new SubEditorScreen(Content);
|
if (SteamManager.USE_STEAM)
|
||||||
CharacterEditorScreen = new CharacterEditorScreen();
|
{
|
||||||
ParticleEditorScreen = new ParticleEditorScreen();
|
SteamWorkshopScreen = new SteamWorkshopScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
SubEditorScreen = new SubEditorScreen();
|
||||||
|
ParticleEditorScreen = new ParticleEditorScreen();
|
||||||
|
LevelEditorScreen = new LevelEditorScreen();
|
||||||
|
SpriteEditorScreen = new SpriteEditorScreen();
|
||||||
|
CharacterEditorScreen = new CharacterEditorScreen();
|
||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
ParticleManager = new ParticleManager(GameScreen.Cam);
|
ParticleManager = new ParticleManager(GameScreen.Cam);
|
||||||
ParticleManager.LoadPrefabs();
|
ParticleManager.LoadPrefabs();
|
||||||
|
LevelObjectPrefab.LoadAll();
|
||||||
DecalManager = new DecalManager();
|
DecalManager = new DecalManager();
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
@@ -410,22 +488,26 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CheckContentPackage()
|
private void CheckContentPackage()
|
||||||
{
|
{
|
||||||
var exePaths = Config.SelectedContentPackage.GetFilesOfType(ContentType.Executable);
|
foreach (ContentPackage contentPackage in Config.SelectedContentPackages)
|
||||||
if (exePaths.Count > 0 && AppDomain.CurrentDomain.FriendlyName != exePaths[0])
|
|
||||||
{
|
{
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("Error"),
|
var exePaths = contentPackage.GetFilesOfType(ContentType.Executable);
|
||||||
TextManager.Get("IncorrectExe")
|
if (exePaths.Count() > 0 && AppDomain.CurrentDomain.FriendlyName != exePaths.First())
|
||||||
.Replace("[selectedpackage]", Config.SelectedContentPackage.Name)
|
|
||||||
.Replace("[exename]", exePaths[0]),
|
|
||||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
|
||||||
msgBox.Buttons[0].OnClicked += (_, userdata) =>
|
|
||||||
{
|
{
|
||||||
string fullPath = Path.GetFullPath(exePaths[0]);
|
var msgBox = new GUIMessageBox(TextManager.Get("Error"),
|
||||||
Process.Start(fullPath);
|
TextManager.Get("IncorrectExe")
|
||||||
Exit();
|
.Replace("[selectedpackage]", contentPackage.Name)
|
||||||
return true;
|
.Replace("[exename]", exePaths.First()),
|
||||||
};
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
msgBox.Buttons[0].OnClicked += (_, userdata) =>
|
||||||
|
{
|
||||||
|
string fullPath = Path.GetFullPath(exePaths.First());
|
||||||
|
Process.Start(fullPath);
|
||||||
|
Exit();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +517,15 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void UnloadContent()
|
protected override void UnloadContent()
|
||||||
{
|
{
|
||||||
Sound.Dispose();
|
SoundManager.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the file paths of all files of the given type in the currently selected content packages.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<string> GetFilesOfType(ContentType type)
|
||||||
|
{
|
||||||
|
return ContentPackage.GetFilesOfType(SelectedPackages, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -447,23 +537,31 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Timing.TotalTime = gameTime.TotalGameTime.TotalSeconds;
|
Timing.TotalTime = gameTime.TotalGameTime.TotalSeconds;
|
||||||
Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds;
|
Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds;
|
||||||
|
int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step);
|
||||||
|
if (Timing.Accumulator > Timing.Step * 6.0)
|
||||||
|
{
|
||||||
|
//if the game's running too slowly then we have no choice
|
||||||
|
//but to skip a bunch of steps
|
||||||
|
//otherwise it snowballs and becomes unplayable
|
||||||
|
Timing.Accumulator = Timing.Step;
|
||||||
|
}
|
||||||
PlayerInput.UpdateVariable();
|
PlayerInput.UpdateVariable();
|
||||||
|
|
||||||
bool paused = true;
|
bool paused = true;
|
||||||
|
|
||||||
while (Timing.Accumulator >= Timing.Step)
|
while (Timing.Accumulator >= Timing.Step)
|
||||||
{
|
{
|
||||||
|
Stopwatch sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly;
|
fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly;
|
||||||
TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16);
|
TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16);
|
||||||
fixedTime.ElapsedGameTime = addTime;
|
fixedTime.ElapsedGameTime = addTime;
|
||||||
fixedTime.TotalGameTime.Add(addTime);
|
fixedTime.TotalGameTime.Add(addTime);
|
||||||
base.Update(fixedTime);
|
base.Update(fixedTime);
|
||||||
|
|
||||||
if (WindowActive)
|
PlayerInput.Update(Timing.Step);
|
||||||
{
|
|
||||||
PlayerInput.Update(Timing.Step);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadingScreenOpen)
|
if (loadingScreenOpen)
|
||||||
{
|
{
|
||||||
//reset accumulator if loading
|
//reset accumulator if loading
|
||||||
@@ -479,7 +577,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
|
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
|
||||||
{
|
{
|
||||||
throw new Exception("Loading was interrupted due to an error");
|
string errMsg = "Loading was interrupted due to an error";
|
||||||
|
if (loadingCoroutine.Exception != null)
|
||||||
|
{
|
||||||
|
errMsg += ": " + loadingCoroutine.Exception.Message + "\n" + loadingCoroutine.Exception.StackTrace;
|
||||||
|
}
|
||||||
|
throw new Exception(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hasLoaded)
|
else if (hasLoaded)
|
||||||
@@ -488,23 +591,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (PlayerInput.KeyHit(Keys.Escape)) GUI.TogglePauseMenu();
|
if (PlayerInput.KeyHit(Keys.Escape)) GUI.TogglePauseMenu();
|
||||||
|
|
||||||
GUIComponent.ClearUpdateList();
|
GUI.ClearUpdateList();
|
||||||
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen) &&
|
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || ContextualTutorial.ContentRunning) &&
|
||||||
(NetworkMember == null || !NetworkMember.GameStarted);
|
(NetworkMember == null || !NetworkMember.GameStarted);
|
||||||
|
|
||||||
if (!paused)
|
Screen.Selected.AddToGUIUpdateList();
|
||||||
{
|
|
||||||
Screen.Selected.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NetworkMember != null)
|
if (NetworkMember != null)
|
||||||
{
|
{
|
||||||
NetworkMember.AddToGUIUpdateList();
|
NetworkMember.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.AddToGUIUpdateList();
|
|
||||||
DebugConsole.AddToGUIUpdateList();
|
DebugConsole.AddToGUIUpdateList();
|
||||||
GUIComponent.UpdateMouseOn();
|
|
||||||
|
|
||||||
DebugConsole.Update(this, (float)Timing.Step);
|
DebugConsole.Update(this, (float)Timing.Step);
|
||||||
paused = paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted));
|
paused = paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted));
|
||||||
@@ -513,6 +611,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Screen.Selected.Update(Timing.Step);
|
Screen.Selected.Update(Timing.Step);
|
||||||
}
|
}
|
||||||
|
else if (ContextualTutorial.Initialized && ContextualTutorial.ContentRunning && GameSession.GameMode is SinglePlayerCampaign)
|
||||||
|
{
|
||||||
|
(GameSession.GameMode as SinglePlayerCampaign).ContextualTutorial.Update((float)Timing.Step);
|
||||||
|
}
|
||||||
|
|
||||||
if (NetworkMember != null)
|
if (NetworkMember != null)
|
||||||
{
|
{
|
||||||
@@ -524,7 +626,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
Timing.Accumulator -= Timing.Step;
|
Timing.Accumulator -= Timing.Step;
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
|
||||||
|
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks / (float)TimeSpan.TicksPerMillisecond);
|
||||||
|
PerformanceCounter.UpdateIterationsGraph.Update(updateIterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
|
if (!paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
|
||||||
@@ -536,9 +645,12 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Draw(GameTime gameTime)
|
protected override void Draw(GameTime gameTime)
|
||||||
{
|
{
|
||||||
|
Stopwatch sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds;
|
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds;
|
||||||
|
|
||||||
FrameCounter.Update(deltaTime);
|
PerformanceCounter.Update(deltaTime);
|
||||||
|
|
||||||
if (loadingScreenOpen)
|
if (loadingScreenOpen)
|
||||||
{
|
{
|
||||||
@@ -549,70 +661,16 @@ namespace Barotrauma
|
|||||||
Screen.Selected.Draw(deltaTime, base.GraphicsDevice, spriteBatch);
|
Screen.Selected.Draw(deltaTime, base.GraphicsDevice, spriteBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DebugDraw) return;
|
if (DebugDraw && GUI.MouseOn != null)
|
||||||
if (GUIComponent.MouseOn!=null)
|
|
||||||
{
|
{
|
||||||
spriteBatch.Begin();
|
spriteBatch.Begin();
|
||||||
GUI.DrawRectangle(spriteBatch, GUIComponent.MouseOn.MouseRect, Color.Lime);
|
GUI.DrawRectangle(spriteBatch, GUI.MouseOn.MouseRect, Color.Lime);
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
public void CheckSteamReleaseStatus()
|
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
|
||||||
{
|
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks / (float)TimeSpan.TicksPerMillisecond);
|
||||||
CoroutineManager.StartCoroutine(WaitForVersionInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<object> WaitForVersionInfo()
|
|
||||||
{
|
|
||||||
var client = new RestClient(Config.MasterServerUrl);
|
|
||||||
var request = new RestRequest("versioninfo.xml", Method.GET);
|
|
||||||
IRestResponse response = null;
|
|
||||||
client.ExecuteAsync(request,
|
|
||||||
(receivedResponse) =>
|
|
||||||
{
|
|
||||||
response = receivedResponse;
|
|
||||||
if (response.StatusCode != HttpStatusCode.OK) { return; }
|
|
||||||
|
|
||||||
string xml = response.Content;
|
|
||||||
XDocument doc = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
doc = XDocument.Parse(xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
int index = xml.IndexOf('<');
|
|
||||||
xml = xml.Substring(index, xml.Length - index);
|
|
||||||
doc = XDocument.Parse(xml);
|
|
||||||
}
|
|
||||||
if (doc?.Root != null)
|
|
||||||
{
|
|
||||||
SteamVersionUrl = doc.Root.GetAttributeString("steamversionurl", "");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
while (response == null)
|
|
||||||
{
|
|
||||||
yield return CoroutineStatus.Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(SteamVersionUrl))
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox("",
|
|
||||||
"This version of Barotrauma is no longer supported. You can get the latest version of Barotrauma on Steam. Do you want to open Barotrauma's Steam page on your web browser?",
|
|
||||||
new string[] { "Yes", "No" });
|
|
||||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
|
||||||
{
|
|
||||||
Process.Start(SteamVersionUrl);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
|
||||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool waitForKeyHit = true;
|
static bool waitForKeyHit = true;
|
||||||
@@ -627,6 +685,7 @@ namespace Barotrauma
|
|||||||
protected override void OnExiting(object sender, EventArgs args)
|
protected override void OnExiting(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
if (NetworkMember != null) NetworkMember.Disconnect();
|
if (NetworkMember != null) NetworkMember.Disconnect();
|
||||||
|
SteamManager.ShutDown();
|
||||||
if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
|
if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
|
||||||
base.OnExiting(sender, args);
|
base.OnExiting(sender, args);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,39 +10,57 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
public static GUIComponent StartCampaignSetup()
|
public static GUIComponent StartCampaignSetup()
|
||||||
{
|
{
|
||||||
GUIFrame background = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.5f, null);
|
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
||||||
|
|
||||||
GUIFrame setupBox = new GUIFrame(new Rectangle(0, 0, 500, 500), null, Alignment.Center, "", background);
|
GUIFrame setupBox = new GUIFrame(new RectTransform(new Vector2(0.25f, 0.45f), background.RectTransform, Anchor.Center) { MinSize = new Point(500, 500) });
|
||||||
setupBox.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f);
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), setupBox.RectTransform, Anchor.Center))
|
||||||
new GUITextBlock(new Rectangle(0, 0, 10, 10), "Campaign Setup", "", setupBox, GUI.LargeFont);
|
{
|
||||||
setupBox.Padding = new Vector4(20.0f, 80.0f, 20.0f, 20.0f);
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
var newCampaignContainer = new GUIFrame(new Rectangle(0, 40, 0, 0), null, setupBox);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform,Anchor.TopCenter),
|
||||||
var loadCampaignContainer = new GUIFrame(new Rectangle(0, 40, 0, 0), null, setupBox);
|
TextManager.Get("CampaignSetup"), font: GUI.LargeFont);
|
||||||
|
|
||||||
|
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.1f) }, isHorizontal: true)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
|
var campaignContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), paddedFrame.RectTransform, Anchor.BottomLeft), style: null);
|
||||||
|
|
||||||
|
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 campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer);
|
var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer);
|
||||||
|
|
||||||
var newCampaignButton = new GUIButton(new Rectangle(0, 0, 120, 20), "New campaign", "", setupBox);
|
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform),
|
||||||
newCampaignButton.OnClicked += (btn, obj) =>
|
TextManager.Get("NewCampaign"))
|
||||||
{
|
{
|
||||||
newCampaignContainer.Visible = true;
|
OnClicked = (btn, obj) =>
|
||||||
loadCampaignContainer.Visible = false;
|
{
|
||||||
return true;
|
newCampaignContainer.Visible = true;
|
||||||
|
loadCampaignContainer.Visible = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var loadCampaignButton = new GUIButton(new Rectangle(130, 0, 120, 20), "Load campaign", "", setupBox);
|
var loadCampaignButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.00f), buttonContainer.RectTransform),
|
||||||
loadCampaignButton.OnClicked += (btn, obj) =>
|
TextManager.Get("LoadCampaign"))
|
||||||
{
|
{
|
||||||
newCampaignContainer.Visible = false;
|
OnClicked = (btn, obj) =>
|
||||||
loadCampaignContainer.Visible = true;
|
{
|
||||||
return true;
|
newCampaignContainer.Visible = false;
|
||||||
|
loadCampaignContainer.Visible = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loadCampaignContainer.Visible = false;
|
loadCampaignContainer.Visible = false;
|
||||||
|
|
||||||
campaignSetupUI.StartNewGame = (Submarine sub, string saveName, string mapSeed) =>
|
campaignSetupUI.StartNewGame = (Submarine sub, string saveName, string mapSeed) =>
|
||||||
{
|
{
|
||||||
GameMain.GameSession = new GameSession(new Submarine(sub.FilePath, ""), saveName, GameModePreset.list.Find(g => g.Name == "Campaign"));
|
GameMain.GameSession = new GameSession(new Submarine(sub.FilePath, ""), saveName,
|
||||||
|
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
|
||||||
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
||||||
campaign.GenerateMap(mapSeed);
|
campaign.GenerateMap(mapSeed);
|
||||||
campaign.SetDelegates();
|
campaign.SetDelegates();
|
||||||
@@ -58,6 +76,12 @@ namespace Barotrauma
|
|||||||
campaignSetupUI.LoadGame = (string fileName) =>
|
campaignSetupUI.LoadGame = (string fileName) =>
|
||||||
{
|
{
|
||||||
SaveUtil.LoadGame(fileName);
|
SaveUtil.LoadGame(fileName);
|
||||||
|
if (!(GameMain.GameSession.GameMode is MultiPlayerCampaign))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Failed to load the campaign. The save file appears to be for a single player campaign.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
||||||
campaign.LastSaveID++;
|
campaign.LastSaveID++;
|
||||||
|
|
||||||
@@ -67,19 +91,22 @@ namespace Barotrauma
|
|||||||
campaign.Map.SelectRandomLocation(true);
|
campaign.Map.SelectRandomLocation(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
var cancelButton = new GUIButton(new Rectangle(0, 0, 120, 30), "Cancel", Alignment.BottomLeft, "", setupBox);
|
var cancelButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.05f), paddedFrame.RectTransform, Anchor.BottomLeft), TextManager.Get("Cancel"))
|
||||||
cancelButton.OnClicked += (btn, obj) =>
|
|
||||||
{
|
{
|
||||||
background.Visible = false;
|
OnClicked = (btn, obj) =>
|
||||||
int otherModeIndex = 0;
|
|
||||||
for (otherModeIndex = 0; otherModeIndex < GameMain.NetLobbyScreen.ModeList.children.Count; otherModeIndex++)
|
|
||||||
{
|
{
|
||||||
if (GameMain.NetLobbyScreen.ModeList.children[otherModeIndex].UserData is MultiPlayerCampaign) continue;
|
//find the first mode that's not multiplayer campaign and switch to that
|
||||||
break;
|
background.Visible = false;
|
||||||
}
|
int otherModeIndex = 0;
|
||||||
|
for (otherModeIndex = 0; otherModeIndex < GameMain.NetLobbyScreen.ModeList.Content.CountChildren; otherModeIndex++)
|
||||||
|
{
|
||||||
|
if (GameMain.NetLobbyScreen.ModeList.Content.GetChild(otherModeIndex).UserData is MultiPlayerCampaign) continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.SelectMode(otherModeIndex);
|
GameMain.NetLobbyScreen.SelectMode(otherModeIndex);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return background;
|
return background;
|
||||||
@@ -90,12 +117,13 @@ namespace Barotrauma
|
|||||||
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
|
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
|
||||||
|
|
||||||
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
||||||
|
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
||||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
||||||
{
|
{
|
||||||
msg.Write((UInt16)MapEntityPrefab.List.IndexOf(pi.itemPrefab));
|
msg.Write((UInt16)MapEntityPrefab.List.IndexOf(pi.ItemPrefab));
|
||||||
msg.Write((UInt16)pi.quantity);
|
msg.Write((UInt16)pi.Quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +136,7 @@ namespace Barotrauma
|
|||||||
string mapSeed = msg.ReadString();
|
string mapSeed = msg.ReadString();
|
||||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||||
|
byte selectedMissionIndex = msg.ReadByte();
|
||||||
|
|
||||||
int money = msg.ReadInt32();
|
int money = msg.ReadInt32();
|
||||||
|
|
||||||
@@ -120,12 +149,20 @@ namespace Barotrauma
|
|||||||
purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
|
purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasCharacterData = msg.ReadBoolean();
|
||||||
|
CharacterInfo myCharacterInfo = null;
|
||||||
|
if (hasCharacterData)
|
||||||
|
{
|
||||||
|
myCharacterInfo = CharacterInfo.ClientRead(Character.HumanConfigFile, msg);
|
||||||
|
}
|
||||||
|
|
||||||
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||||
if (campaign == null || campaignID != campaign.CampaignID)
|
if (campaign == null || campaignID != campaign.CampaignID)
|
||||||
{
|
{
|
||||||
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);
|
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);
|
||||||
|
|
||||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.list.Find(g => g.Name == "Campaign"));
|
GameMain.GameSession = new GameSession(null, savePath,
|
||||||
|
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
|
||||||
|
|
||||||
campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
||||||
campaign.CampaignID = campaignID;
|
campaign.CampaignID = campaignID;
|
||||||
@@ -155,10 +192,21 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
||||||
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||||
|
campaign.Map.SelectMission(selectedMissionIndex);
|
||||||
|
|
||||||
campaign.Money = money;
|
campaign.Money = money;
|
||||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||||
|
|
||||||
|
if (myCharacterInfo != null)
|
||||||
|
{
|
||||||
|
GameMain.NetworkMember.CharacterInfo = myCharacterInfo;
|
||||||
|
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
|
||||||
|
}
|
||||||
|
|
||||||
campaign.lastUpdateID = updateID;
|
campaign.lastUpdateID = updateID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Barotrauma.Tutorials;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -8,6 +9,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class SinglePlayerCampaign : CampaignMode
|
class SinglePlayerCampaign : CampaignMode
|
||||||
{
|
{
|
||||||
|
public ContextualTutorial ContextualTutorial;
|
||||||
|
|
||||||
private GUIButton endRoundButton;
|
private GUIButton endRoundButton;
|
||||||
|
|
||||||
private bool crewDead;
|
private bool crewDead;
|
||||||
@@ -20,17 +23,16 @@ namespace Barotrauma
|
|||||||
private Submarine leavingSub;
|
private Submarine leavingSub;
|
||||||
private bool atEndPosition;
|
private bool atEndPosition;
|
||||||
|
|
||||||
protected CrewManager CrewManager
|
|
||||||
{
|
|
||||||
get { return GameMain.GameSession?.CrewManager; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public SinglePlayerCampaign(GameModePreset preset, object param)
|
public SinglePlayerCampaign(GameModePreset preset, object param)
|
||||||
: base(preset, param)
|
: base(preset, param)
|
||||||
{
|
{
|
||||||
endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 220, 20, 200, 25), TextManager.Get("EndRound"), null, Alignment.TopLeft, Alignment.Center, "");
|
int buttonHeight = (int)(HUDLayoutSettings.ButtonAreaTop.Height * 0.7f);
|
||||||
endRoundButton.Font = GUI.SmallFont;
|
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(HUDLayoutSettings.ButtonAreaTop.Right - 200, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonHeight / 2, 200, buttonHeight), GUICanvas.Instance),
|
||||||
endRoundButton.OnClicked = TryEndRound;
|
TextManager.Get("EndRound"), textAlignment: Alignment.Center)
|
||||||
|
{
|
||||||
|
Font = GUI.SmallFont,
|
||||||
|
OnClicked = (btn, userdata) => { TryEndRound(GetLeavingSub()); return true; }
|
||||||
|
};
|
||||||
|
|
||||||
foreach (JobPrefab jobPrefab in JobPrefab.List)
|
foreach (JobPrefab jobPrefab in JobPrefab.List)
|
||||||
{
|
{
|
||||||
@@ -39,10 +41,18 @@ namespace Barotrauma
|
|||||||
CrewManager.AddCharacterInfo(new CharacterInfo(Character.HumanConfigFile, "", Gender.None, jobPrefab));
|
CrewManager.AddCharacterInfo(new CharacterInfo(Character.HumanConfigFile, "", Gender.None, jobPrefab));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial) as ContextualTutorial;
|
||||||
|
|
||||||
|
if (ContextualTutorial.Selected && !ContextualTutorial.Initialized) // Selected when starting a new game -> initialize
|
||||||
|
{
|
||||||
|
ContextualTutorial.Initialize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
|
base.Start();
|
||||||
CargoManager.CreateItems();
|
CargoManager.CreateItems();
|
||||||
|
|
||||||
if (!savedOnStart)
|
if (!savedOnStart)
|
||||||
@@ -51,54 +61,78 @@ namespace Barotrauma
|
|||||||
savedOnStart = true;
|
savedOnStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crewDead = false;
|
||||||
endTimer = 5.0f;
|
endTimer = 5.0f;
|
||||||
|
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
|
CrewManager.InitSinglePlayerRound();
|
||||||
|
|
||||||
CrewManager.StartRound();
|
if (ContextualTutorial.Initialized)
|
||||||
|
{
|
||||||
|
ContextualTutorial.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryHireCharacter(HireManager hireManager, CharacterInfo characterInfo)
|
public bool TryHireCharacter(Location location, CharacterInfo characterInfo)
|
||||||
{
|
{
|
||||||
if (Money < characterInfo.Salary) return false;
|
if (Money < characterInfo.Salary) { return false; }
|
||||||
|
|
||||||
hireManager.availableCharacters.Remove(characterInfo);
|
location.RemoveHireableCharacter(characterInfo);
|
||||||
CrewManager.AddCharacterInfo(characterInfo);
|
CrewManager.AddCharacterInfo(characterInfo);
|
||||||
Money -= characterInfo.Salary;
|
Money -= characterInfo.Salary;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FireCharacter(CharacterInfo characterInfo)
|
||||||
|
{
|
||||||
|
CrewManager.RemoveCharacterInfo(characterInfo);
|
||||||
|
}
|
||||||
|
|
||||||
private Submarine GetLeavingSub()
|
private Submarine GetLeavingSub()
|
||||||
{
|
{
|
||||||
if (Character.Controlled != null && Character.Controlled.Submarine != null)
|
if (Character.Controlled?.Submarine == null)
|
||||||
{
|
{
|
||||||
if (Character.Controlled.Submarine.AtEndPosition || Character.Controlled.Submarine.AtStartPosition)
|
|
||||||
{
|
|
||||||
return Character.Controlled.Submarine;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Submarine closestSub = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);
|
//allow leaving if inside an outpost, and the submarine is either docked to it or close enough
|
||||||
if (closestSub != null && (closestSub.AtEndPosition || closestSub.AtStartPosition))
|
return GetLeavingSubAtOutpost(Level.Loaded.StartOutpost) ?? GetLeavingSubAtOutpost(Level.Loaded.EndOutpost);
|
||||||
{
|
|
||||||
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
Submarine GetLeavingSubAtOutpost(Submarine outpost)
|
||||||
|
{
|
||||||
|
//controlled character has to be inside the outpost
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var dockedSub = outpost.DockedTo.FirstOrDefault();
|
||||||
|
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
//nothing docked, check if there's a sub close enough to the outpost
|
||||||
|
Submarine closestSub = Submarine.FindClosest(outpost.WorldPosition, ignoreOutposts: true);
|
||||||
|
if (closestSub == null) { return null; }
|
||||||
|
|
||||||
|
if (outpost == Level.Loaded.StartOutpost)
|
||||||
|
{
|
||||||
|
if (!closestSub.AtStartPosition) { return null; }
|
||||||
|
}
|
||||||
|
else if (outpost == Level.Loaded.EndOutpost)
|
||||||
|
{
|
||||||
|
if (!closestSub.AtEndPosition) { return null; }
|
||||||
|
}
|
||||||
|
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
public override void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (!isRunning|| GUI.DisableHUD) return;
|
if (!isRunning|| GUI.DisableHUD) return;
|
||||||
|
|
||||||
CrewManager.Draw(spriteBatch);
|
|
||||||
|
|
||||||
if (Submarine.MainSub == null) return;
|
if (Submarine.MainSub == null) return;
|
||||||
|
|
||||||
Submarine leavingSub = GetLeavingSub();
|
Submarine leavingSub = GetLeavingSub();
|
||||||
|
|
||||||
if (leavingSub == null)
|
if (leavingSub == null)
|
||||||
{
|
{
|
||||||
endRoundButton.Visible = false;
|
endRoundButton.Visible = false;
|
||||||
@@ -106,13 +140,11 @@ namespace Barotrauma
|
|||||||
else if (leavingSub.AtEndPosition)
|
else if (leavingSub.AtEndPosition)
|
||||||
{
|
{
|
||||||
endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.SelectedLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.SelectedLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
||||||
endRoundButton.UserData = leavingSub;
|
|
||||||
endRoundButton.Visible = true;
|
endRoundButton.Visible = true;
|
||||||
}
|
}
|
||||||
else if (leavingSub.AtStartPosition)
|
else if (leavingSub.AtStartPosition)
|
||||||
{
|
{
|
||||||
endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.CurrentLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.CurrentLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
||||||
endRoundButton.UserData = leavingSub;
|
|
||||||
endRoundButton.Visible = true;
|
endRoundButton.Visible = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -120,7 +152,7 @@ namespace Barotrauma
|
|||||||
endRoundButton.Visible = false;
|
endRoundButton.Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
endRoundButton.Draw(spriteBatch);
|
endRoundButton.DrawManually(spriteBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void AddToGUIUpdateList()
|
||||||
@@ -130,17 +162,28 @@ namespace Barotrauma
|
|||||||
base.AddToGUIUpdateList();
|
base.AddToGUIUpdateList();
|
||||||
CrewManager.AddToGUIUpdateList();
|
CrewManager.AddToGUIUpdateList();
|
||||||
endRoundButton.AddToGUIUpdateList();
|
endRoundButton.AddToGUIUpdateList();
|
||||||
|
|
||||||
|
if (ContextualTutorial.Initialized)
|
||||||
|
{
|
||||||
|
ContextualTutorial.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (!isRunning || GUI.DisableHUD) return;
|
if (!isRunning) { return; }
|
||||||
|
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
|
|
||||||
CrewManager.Update(deltaTime);
|
if (ContextualTutorial.Initialized)
|
||||||
|
{
|
||||||
|
ContextualTutorial.Update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
endRoundButton.Update(deltaTime);
|
if (!GUI.DisableHUD)
|
||||||
|
{
|
||||||
|
endRoundButton.UpdateManually(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (!crewDead)
|
if (!crewDead)
|
||||||
{
|
{
|
||||||
@@ -149,16 +192,41 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
endTimer -= deltaTime;
|
endTimer -= deltaTime;
|
||||||
|
if (endTimer <= 0.0f) { EndRound(leavingSub: null); }
|
||||||
if (endTimer <= 0.0f) EndRound(null, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void WatchmanInteract(Character watchman, Character interactor)
|
||||||
|
{
|
||||||
|
Submarine leavingSub = GetLeavingSub();
|
||||||
|
if (leavingSub == null)
|
||||||
|
{
|
||||||
|
CreateDialog(new List<Character> { watchman }, "WatchmanInteractNoLeavingSub", 5.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateDialog(new List<Character> { watchman }, "WatchmanInteract", 1.0f);
|
||||||
|
|
||||||
|
var msgBox = new GUIMessageBox("", TextManager.Get("CampaignEnterOutpostPrompt")
|
||||||
|
.Replace("[locationname]", leavingSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
|
||||||
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
|
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||||
|
{
|
||||||
|
if (!isRunning) { return true; }
|
||||||
|
TryEndRound(GetLeavingSub());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
|
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||||
|
}
|
||||||
|
|
||||||
public override void End(string endMessage = "")
|
public override void End(string endMessage = "")
|
||||||
{
|
{
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
|
|
||||||
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
||||||
|
crewDead = false;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@@ -193,32 +261,54 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Map.MoveToNextLocation();
|
Map.MoveToNextLocation();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Map.SelectLocation(-1);
|
||||||
|
}
|
||||||
|
Map.ProgressWorld();
|
||||||
|
|
||||||
|
//save and remove all items that are in someone's inventory
|
||||||
|
foreach (Character c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c.Info == null || c.Inventory == null) { continue; }
|
||||||
|
var inventoryElement = new XElement("inventory");
|
||||||
|
c.SaveInventory(c.Inventory, inventoryElement);
|
||||||
|
c.Info.InventoryData = inventoryElement;
|
||||||
|
c.Inventory?.DeleteAllItems();
|
||||||
|
}
|
||||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
var summaryScreen = GUIMessageBox.VisibleBox;
|
var summaryScreen = GUIMessageBox.VisibleBox;
|
||||||
|
|
||||||
if (summaryScreen != null)
|
if (summaryScreen != null)
|
||||||
{
|
{
|
||||||
summaryScreen = summaryScreen.children[0];
|
summaryScreen = summaryScreen.Children.First();
|
||||||
summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton));
|
var buttonArea = summaryScreen.Children.First().FindChild("buttonarea");
|
||||||
|
buttonArea.ClearChildren();
|
||||||
|
|
||||||
var okButton = new GUIButton(new Rectangle(-120, 0, 100, 30), TextManager.Get("LoadGameButton"), Alignment.BottomRight, "", summaryScreen);
|
|
||||||
okButton.OnClicked += (GUIButton button, object obj) =>
|
summaryScreen.RemoveChild(summaryScreen.Children.FirstOrDefault(c => c is GUIButton));
|
||||||
|
|
||||||
|
var okButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform),
|
||||||
|
TextManager.Get("LoadGameButton"))
|
||||||
{
|
{
|
||||||
GameMain.GameSession.LoadPrevious();
|
OnClicked = (GUIButton button, object obj) =>
|
||||||
GameMain.LobbyScreen.Select();
|
{
|
||||||
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
GameMain.GameSession.LoadPrevious();
|
||||||
return true;
|
GameMain.LobbyScreen.Select();
|
||||||
|
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var quitButton = new GUIButton(new Rectangle(0, 0, 100, 30), TextManager.Get("QuitButton"), Alignment.BottomRight, "", summaryScreen);
|
var quitButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform),
|
||||||
|
TextManager.Get("QuitButton"));
|
||||||
quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu;
|
quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu;
|
||||||
quitButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; };
|
quitButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; };
|
||||||
|
quitButton.OnClicked += (GUIButton button, object obj) => { if (ContextualTutorial.Initialized) ContextualTutorial.Stop(); return true; };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,14 +323,12 @@ namespace Barotrauma
|
|||||||
GameMain.LobbyScreen.Select();
|
GameMain.LobbyScreen.Select();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryEndRound(GUIButton button, object obj)
|
private bool TryEndRound(Submarine leavingSub)
|
||||||
{
|
{
|
||||||
leavingSub = obj as Submarine;
|
if (leavingSub == null) { return false; }
|
||||||
if (leavingSub != null)
|
|
||||||
{
|
|
||||||
subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.leavingSub = leavingSub;
|
||||||
|
subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||||
atEndPosition = leavingSub.AtEndPosition;
|
atEndPosition = leavingSub.AtEndPosition;
|
||||||
|
|
||||||
if (subsToLeaveBehind.Any())
|
if (subsToLeaveBehind.Any())
|
||||||
@@ -248,7 +336,7 @@ namespace Barotrauma
|
|||||||
string msg = TextManager.Get(subsToLeaveBehind.Count == 1 ? "LeaveSubBehind" : "LeaveSubsBehind");
|
string msg = TextManager.Get(subsToLeaveBehind.Count == 1 ? "LeaveSubBehind" : "LeaveSubsBehind");
|
||||||
|
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("Warning"), msg, new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
var msgBox = new GUIMessageBox(TextManager.Get("Warning"), msg, new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
msgBox.Buttons[0].OnClicked += EndRound;
|
msgBox.Buttons[0].OnClicked += (btn, userdata) => { EndRound(leavingSub); return true; } ;
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
msgBox.Buttons[0].UserData = Submarine.Loaded.FindAll(s => !subsToLeaveBehind.Contains(s));
|
msgBox.Buttons[0].UserData = Submarine.Loaded.FindAll(s => !subsToLeaveBehind.Contains(s));
|
||||||
|
|
||||||
@@ -256,30 +344,28 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EndRound(button, obj);
|
EndRound(leavingSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool EndRound(GUIButton button, object obj)
|
private bool EndRound(Submarine leavingSub)
|
||||||
{
|
{
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
|
|
||||||
List<Submarine> leavingSubs = obj as List<Submarine>;
|
//var cinematic = new RoundEndCinematic(leavingSub, GameMain.GameScreen.Cam, 5.0f);
|
||||||
if (leavingSubs == null) leavingSubs = new List<Submarine>() { GetLeavingSub() };
|
|
||||||
|
|
||||||
var cinematic = new TransitionCinematic(leavingSubs, GameMain.GameScreen.Cam, 5.0f);
|
|
||||||
|
|
||||||
SoundPlayer.OverrideMusicType = CrewManager.GetCharacters().Any(c => !c.IsDead) ? "endround" : "crewdead";
|
SoundPlayer.OverrideMusicType = CrewManager.GetCharacters().Any(c => !c.IsDead) ? "endround" : "crewdead";
|
||||||
SoundPlayer.OverrideMusicDuration = 18.0f;
|
SoundPlayer.OverrideMusicDuration = 18.0f;
|
||||||
|
|
||||||
CoroutineManager.StartCoroutine(EndCinematic(cinematic), "EndCinematic");
|
//CoroutineManager.StartCoroutine(EndCinematic(cinematic), "EndCinematic");
|
||||||
|
End("");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<object> EndCinematic(TransitionCinematic cinematic)
|
/*private IEnumerable<object> EndCinematic(RoundEndCinematic cinematic)
|
||||||
{
|
{
|
||||||
while (cinematic.Running)
|
while (cinematic.Running)
|
||||||
{
|
{
|
||||||
@@ -291,26 +377,40 @@ namespace Barotrauma
|
|||||||
if (Submarine.MainSub != null) End("");
|
if (Submarine.MainSub != null) End("");
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public static SinglePlayerCampaign Load(XElement element)
|
public static SinglePlayerCampaign Load(XElement element)
|
||||||
{
|
{
|
||||||
SinglePlayerCampaign campaign = new SinglePlayerCampaign(GameModePreset.list.Find(gm => gm.Name == "Single Player"), null);
|
SinglePlayerCampaign campaign = new SinglePlayerCampaign(GameModePreset.List.Find(gm => gm.Identifier == "singleplayercampaign"), null);
|
||||||
|
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "crew":
|
case "crew":
|
||||||
GameMain.GameSession.CrewManager = new CrewManager(subElement);
|
GameMain.GameSession.CrewManager = new CrewManager(subElement, true);
|
||||||
break;
|
break;
|
||||||
case "map":
|
case "map":
|
||||||
campaign.map = Map.LoadNew(subElement);
|
campaign.map = Map.LoadNew(subElement);
|
||||||
break;
|
break;
|
||||||
|
case "contextualtutorial":
|
||||||
|
campaign.ContextualTutorial.Initialize(); // Initialize when saved element found
|
||||||
|
campaign.ContextualTutorial.LoadPartiallyComplete(subElement);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
campaign.Money = element.GetAttributeInt("money", 0);
|
campaign.Money = element.GetAttributeInt("money", 0);
|
||||||
|
campaign.CheatsEnabled = element.GetAttributeBool("cheatsenabled", false);
|
||||||
|
if (campaign.CheatsEnabled)
|
||||||
|
{
|
||||||
|
DebugConsole.CheatsEnabled = true;
|
||||||
|
if (GameMain.Config.UseSteam && !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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//backwards compatibility with older save files
|
//backwards compatibility with older save files
|
||||||
if (campaign.map == null)
|
if (campaign.map == null)
|
||||||
@@ -327,13 +427,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override void Save(XElement element)
|
public override void Save(XElement element)
|
||||||
{
|
{
|
||||||
XElement modeElement = new XElement("SinglePlayerCampaign");
|
XElement modeElement = new XElement("SinglePlayerCampaign",
|
||||||
|
new XAttribute("money", Money),
|
||||||
modeElement.Add(new XAttribute("money", Money));
|
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||||
|
|
||||||
CrewManager.Save(modeElement);
|
CrewManager.Save(modeElement);
|
||||||
Map.Save(modeElement);
|
Map.Save(modeElement);
|
||||||
|
|
||||||
|
if (ContextualTutorial.Initialized)
|
||||||
|
{
|
||||||
|
ContextualTutorial.SavePartiallyComplete(modeElement);
|
||||||
|
}
|
||||||
|
|
||||||
element.Add(modeElement);
|
element.Add(modeElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-40
@@ -4,15 +4,15 @@ using Microsoft.Xna.Framework;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Tutorials
|
namespace Barotrauma.Tutorials
|
||||||
{
|
{
|
||||||
class BasicTutorial : TutorialType
|
class BasicTutorial : ScenarioTutorial
|
||||||
{
|
{
|
||||||
public BasicTutorial(string name)
|
public BasicTutorial(XElement element)
|
||||||
: base(name)
|
: base(element)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<object> UpdateState()
|
public override IEnumerable<object> UpdateState()
|
||||||
@@ -69,7 +69,7 @@ namespace Barotrauma.Tutorials
|
|||||||
infoBox = CreateInfoFrame("At the moment the submarine has no power, which means that crucial systems such as the oxygen generator or the engine aren't running. Let's fix this: go to the upper left corner of the submarine, where you'll find a nuclear reactor.");
|
infoBox = CreateInfoFrame("At the moment the submarine has no power, which means that crucial systems such as the oxygen generator or the engine aren't running. Let's fix this: go to the upper left corner of the submarine, where you'll find a nuclear reactor.");
|
||||||
|
|
||||||
Reactor reactor = Item.ItemList.Find(i => i.HasTag("tutorialreactor")).GetComponent<Reactor>();
|
Reactor reactor = Item.ItemList.Find(i => i.HasTag("tutorialreactor")).GetComponent<Reactor>();
|
||||||
reactor.MeltDownTemp = 20000.0f;
|
//reactor.MeltDownTemp = 20000.0f;
|
||||||
|
|
||||||
while (Vector2.Distance(Controlled.Position, reactor.Item.Position) > 200.0f)
|
while (Vector2.Distance(Controlled.Position, reactor.Item.Position) > 200.0f)
|
||||||
{
|
{
|
||||||
@@ -78,14 +78,14 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
infoBox = CreateInfoFrame("The reactor requires fuel rods to generate power. You can grab one from the steel cabinet by walking next to it and pressing E.");
|
infoBox = CreateInfoFrame("The reactor requires fuel rods to generate power. You can grab one from the steel cabinet by walking next to it and pressing E.");
|
||||||
|
|
||||||
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Name != "Steel Cabinet")
|
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Prefab.Identifier != "steelcabinet")
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
infoBox = CreateInfoFrame("Pick up one of the fuel rods either by double-clicking or dragging and dropping it into your inventory.");
|
infoBox = CreateInfoFrame("Pick up one of the fuel rods either by double-clicking or dragging and dropping it into your inventory.");
|
||||||
|
|
||||||
while (!HasItem("Fuel Rod"))
|
while (!HasItem("fuelrod"))
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,8 @@ namespace Barotrauma.Tutorials
|
|||||||
infoBox = CreateInfoFrame("The reactor core has started generating heat, which in turn generates power for the submarine. The power generation is very low at the moment,"
|
infoBox = CreateInfoFrame("The reactor core has started generating heat, which in turn generates power for the submarine. The power generation is very low at the moment,"
|
||||||
+ " because the reactor is set to shut itself down when the temperature rises above 500 degrees Celsius. You can adjust the temperature limit by changing the \"Shutdown Temperature\" in the control panel.", true);
|
+ " because the reactor is set to shut itself down when the temperature rises above 500 degrees Celsius. You can adjust the temperature limit by changing the \"Shutdown Temperature\" in the control panel.", true);
|
||||||
|
|
||||||
while (infoBox != null)
|
//TODO: reimplement
|
||||||
|
/*while (infoBox != null)
|
||||||
{
|
{
|
||||||
reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
|
reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
@@ -142,14 +143,14 @@ namespace Barotrauma.Tutorials
|
|||||||
while (!reactor.AutoTemp)
|
while (!reactor.AutoTemp)
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}*/
|
||||||
yield return new WaitForSeconds(0.5f);
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
|
||||||
infoBox = CreateInfoFrame("That's the basics of operating the reactor! Now that there's power available for the engines, it's time to get the submarine moving. "
|
infoBox = CreateInfoFrame("That's the basics of operating the reactor! Now that there's power available for the engines, it's time to get the submarine moving. "
|
||||||
+ "Deselect the reactor by pressing E and head to the command room at the right edge of the vessel.");
|
+ "Deselect the reactor by pressing E and head to the command room at the right edge of the vessel.");
|
||||||
|
|
||||||
Steering steering = Item.ItemList.Find(i => i.HasTag("tutorialsteering")).GetComponent<Steering>();
|
Steering steering = Item.ItemList.Find(i => i.HasTag("tutorialsteering")).GetComponent<Steering>();
|
||||||
Radar radar = steering.Item.GetComponent<Radar>();
|
Sonar sonar = steering.Item.GetComponent<Sonar>();
|
||||||
|
|
||||||
while (Vector2.Distance(Controlled.Position, steering.Item.Position) > 150.0f)
|
while (Vector2.Distance(Controlled.Position, steering.Item.Position) > 150.0f)
|
||||||
{
|
{
|
||||||
@@ -181,7 +182,7 @@ namespace Barotrauma.Tutorials
|
|||||||
+ " Equip a screwdriver by pulling it to either of the slots with a hand symbol, and then use it on the terminal by left clicking.");
|
+ " Equip a screwdriver by pulling it to either of the slots with a hand symbol, and then use it on the terminal by left clicking.");
|
||||||
|
|
||||||
while (Controlled.SelectedConstruction != steering.Item ||
|
while (Controlled.SelectedConstruction != steering.Item ||
|
||||||
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Name == "Screwdriver") == null)
|
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "screwdriver") == null)
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -191,7 +192,7 @@ namespace Barotrauma.Tutorials
|
|||||||
+ " going into the to the power connection - that's why the monitor isn't working."
|
+ " going into the to the power connection - that's why the monitor isn't working."
|
||||||
+ " You should find a piece of wire to connect it. Try searching some of the cabinets scattered around the sub.");
|
+ " You should find a piece of wire to connect it. Try searching some of the cabinets scattered around the sub.");
|
||||||
|
|
||||||
while (!HasItem("Wire"))
|
while (!HasItem("wire"))
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -202,7 +203,7 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
while ((Controlled.SelectedConstruction != junctionBox.Item &&
|
while ((Controlled.SelectedConstruction != junctionBox.Item &&
|
||||||
Controlled.SelectedConstruction != steering.Item) ||
|
Controlled.SelectedConstruction != steering.Item) ||
|
||||||
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Name == "Screwdriver") == null)
|
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "screwdriver") == null)
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -248,7 +249,7 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
infoBox = CreateInfoFrame("Connect the wire to the junction box by pulling it to the power connection, the same way you did with the navigation terminal.");
|
infoBox = CreateInfoFrame("Connect the wire to the junction box by pulling it to the power connection, the same way you did with the navigation terminal.");
|
||||||
|
|
||||||
while (radar.Voltage < 0.1f)
|
while (sonar.Voltage < 0.1f)
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -263,7 +264,7 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
infoBox = CreateInfoFrame("You can take a look at the area around the sub by selecting the \"Active Sonar\" checkbox.");
|
infoBox = CreateInfoFrame("You can take a look at the area around the sub by selecting the \"Active Sonar\" checkbox.");
|
||||||
|
|
||||||
while (!radar.IsActive)
|
while (!sonar.IsActive)
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -296,13 +297,13 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
var moloch = Character.Create(
|
var moloch = Character.Create(
|
||||||
"Content/Characters/Moloch/moloch.xml",
|
"Content/Characters/Moloch/moloch.xml",
|
||||||
steering.Item.WorldPosition + new Vector2(3000.0f, -500.0f));
|
steering.Item.WorldPosition + new Vector2(3000.0f, -500.0f), "");
|
||||||
|
|
||||||
moloch.PlaySound(CharacterSound.SoundType.Attack);
|
moloch.PlaySound(CharacterSound.SoundType.Attack);
|
||||||
|
|
||||||
yield return new WaitForSeconds(1.0f);
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
|
||||||
infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the radar.");
|
infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the sonar.");
|
||||||
|
|
||||||
List<Structure> windows = new List<Structure>();
|
List<Structure> windows = new List<Structure>();
|
||||||
foreach (Structure s in Structure.WallList)
|
foreach (Structure s in Structure.WallList)
|
||||||
@@ -389,10 +390,10 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
bool divingMaskSelected = false;
|
bool divingMaskSelected = false;
|
||||||
|
|
||||||
while (!HasItem("Diving Mask") && !HasItem("Diving Suit"))
|
while (!HasItem("divingmask") && !HasItem("divingsuit"))
|
||||||
{
|
{
|
||||||
if (!divingMaskSelected &&
|
if (!divingMaskSelected &&
|
||||||
Controlled.FocusedItem != null && Controlled.FocusedItem.Name == "Diving Suit")
|
Controlled.FocusedItem != null && Controlled.FocusedItem.Prefab.Identifier == "divingsuit")
|
||||||
{
|
{
|
||||||
infoBox = CreateInfoFrame("There can only be one item in each inventory slot, so you need to take off "
|
infoBox = CreateInfoFrame("There can only be one item in each inventory slot, so you need to take off "
|
||||||
+ "the jumpsuit if you wish to wear a diving suit.");
|
+ "the jumpsuit if you wish to wear a diving suit.");
|
||||||
@@ -403,20 +404,20 @@ namespace Barotrauma.Tutorials
|
|||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasItem("Diving Mask"))
|
if (HasItem("divingmask"))
|
||||||
{
|
{
|
||||||
infoBox = CreateInfoFrame("The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. " +
|
infoBox = CreateInfoFrame("The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. " +
|
||||||
"It should be fine for the situation at hand, but you still need to find an oxygen tank and drag it into the same slot as the mask." +
|
"It should be fine for the situation at hand, but you still need to find an oxygen tank and drag it into the same slot as the mask." +
|
||||||
"You should grab one or two from one of the cabinets.");
|
"You should grab one or two from one of the cabinets.");
|
||||||
}
|
}
|
||||||
else if (HasItem("Diving Suit"))
|
else if (HasItem("divingsuit"))
|
||||||
{
|
{
|
||||||
infoBox = CreateInfoFrame("In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " +
|
infoBox = CreateInfoFrame("In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " +
|
||||||
"(unlike the diving mask). However, you still need to drag an oxygen tank into the same slot as the suit to supply oxygen. " +
|
"(unlike the diving mask). However, you still need to drag an oxygen tank into the same slot as the suit to supply oxygen. " +
|
||||||
"You should grab one or two from one of the cabinets.");
|
"You should grab one or two from one of the cabinets.");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!HasItem("Oxygen Tank"))
|
while (!HasItem("oxygentank"))
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -444,7 +445,7 @@ namespace Barotrauma.Tutorials
|
|||||||
"time to head to the room below and load some shells for the railgun.");
|
"time to head to the room below and load some shells for the railgun.");
|
||||||
|
|
||||||
|
|
||||||
var loader = Item.ItemList.Find(i => i.Name == "Railgun Loader").GetComponent<ItemContainer>();
|
var loader = Item.ItemList.Find(i => i.Prefab.Identifier == "railgunloader").GetComponent<ItemContainer>();
|
||||||
|
|
||||||
while (Math.Abs(Controlled.Position.Y - loader.Item.Position.Y) > 80)
|
while (Math.Abs(Controlled.Position.Y - loader.Item.Position.Y) > 80)
|
||||||
{
|
{
|
||||||
@@ -454,9 +455,10 @@ namespace Barotrauma.Tutorials
|
|||||||
infoBox = CreateInfoFrame("Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. "
|
infoBox = CreateInfoFrame("Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. "
|
||||||
+ "one of the free slots. You need two hands to carry a shell, so make sure you don't have anything else in either hand.");
|
+ "one of the free slots. You need two hands to carry a shell, so make sure you don't have anything else in either hand.");
|
||||||
|
|
||||||
while (loader.Item.ContainedItems.FirstOrDefault(i => i != null && i.Name == "Railgun Shell") == null)
|
while (loader.Item.ContainedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "railgunshell") == null)
|
||||||
{
|
{
|
||||||
moloch.Health = 50.0f;
|
//TODO: reimplement
|
||||||
|
//moloch.Health = 50.0f;
|
||||||
|
|
||||||
capacitor1.Charge += 5.0f;
|
capacitor1.Charge += 5.0f;
|
||||||
capacitor2.Charge += 5.0f;
|
capacitor2.Charge += 5.0f;
|
||||||
@@ -465,7 +467,7 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
infoBox = CreateInfoFrame("Now we're ready to shoot! Select the railgun controller.");
|
infoBox = CreateInfoFrame("Now we're ready to shoot! Select the railgun controller.");
|
||||||
|
|
||||||
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Name != "Railgun Controller")
|
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Prefab.Identifier != "railguncontroller")
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -491,7 +493,7 @@ namespace Barotrauma.Tutorials
|
|||||||
infoBox = CreateInfoFrame("The creature has died. Now you should fix the damages in the control room: " +
|
infoBox = CreateInfoFrame("The creature has died. Now you should fix the damages in the control room: " +
|
||||||
"Grab a welding tool from the closet in the railgun room.");
|
"Grab a welding tool from the closet in the railgun room.");
|
||||||
|
|
||||||
while (!HasItem("Welding Tool"))
|
while (!HasItem("weldingtool"))
|
||||||
{
|
{
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -501,9 +503,9 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var weldingTool = Controlled.Inventory.Items.FirstOrDefault(i => i != null && i.Name == "Welding Tool");
|
var weldingTool = Controlled.Inventory.Items.FirstOrDefault(i => i != null && i.Prefab.Identifier == "weldingtool");
|
||||||
if (weldingTool != null &&
|
if (weldingTool != null &&
|
||||||
weldingTool.ContainedItems.FirstOrDefault(contained => contained != null && contained.Name == "Welding Fuel Tank") != null) break;
|
weldingTool.ContainedItems.FirstOrDefault(contained => contained != null && contained.Prefab.Identifier == "weldingfueltank") != null) break;
|
||||||
|
|
||||||
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
|
||||||
} while (true);
|
} while (true);
|
||||||
@@ -606,13 +608,15 @@ namespace Barotrauma.Tutorials
|
|||||||
infoBox = CreateInfoFrame("That was all there is to this tutorial! Now you should be able to handle " +
|
infoBox = CreateInfoFrame("That was all there is to this tutorial! Now you should be able to handle " +
|
||||||
"most of the basic tasks on board the submarine.");
|
"most of the basic tasks on board the submarine.");
|
||||||
|
|
||||||
|
Completed = true;
|
||||||
|
|
||||||
yield return new WaitForSeconds(4.0f);
|
yield return new WaitForSeconds(4.0f);
|
||||||
|
|
||||||
Controlled = null;
|
Controlled = null;
|
||||||
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
|
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
|
||||||
GameMain.LightManager.LosEnabled = false;
|
GameMain.LightManager.LosEnabled = false;
|
||||||
|
|
||||||
var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f);
|
var cinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f);
|
||||||
|
|
||||||
while (cinematic.Running)
|
while (cinematic.Running)
|
||||||
{
|
{
|
||||||
@@ -625,21 +629,20 @@ namespace Barotrauma.Tutorials
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HasItem(string itemName)
|
private bool HasItem(string itemIdentifier)
|
||||||
{
|
{
|
||||||
if (Character.Controlled == null) return false;
|
if (Character.Controlled == null) return false;
|
||||||
|
|
||||||
return Character.Controlled.Inventory.FindItem(itemName) != null;
|
return Character.Controlled.Inventory.FindItemByIdentifier(itemIdentifier) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected IEnumerable<object> KeepReactorRunning(Reactor reactor)
|
protected IEnumerable<object> KeepReactorRunning(Reactor reactor)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
reactor.AutoTemp = true;
|
//TODO: reimplement
|
||||||
reactor.ShutDownTemp = 5000.0f;
|
/*reactor.AutoTemp = true;
|
||||||
|
reactor.ShutDownTemp = 5000.0f;*/
|
||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
} while (Item.ItemList.Contains(reactor.Item));
|
} while (Item.ItemList.Contains(reactor.Item));
|
||||||
@@ -657,16 +660,17 @@ namespace Barotrauma.Tutorials
|
|||||||
{
|
{
|
||||||
if (enemy == null || Character.Controlled == null) break;
|
if (enemy == null || Character.Controlled == null) break;
|
||||||
|
|
||||||
enemy.Health = 50.0f;
|
//TODO: reimplement
|
||||||
|
//enemy.Health = 50.0f;
|
||||||
|
|
||||||
enemy.AIController.State = AIController.AIState.None;
|
enemy.AIController.State = AIController.AIState.Idle;
|
||||||
|
|
||||||
Vector2 targetPos = Character.Controlled.WorldPosition + new Vector2(0.0f, 3000.0f);
|
Vector2 targetPos = Character.Controlled.WorldPosition + new Vector2(0.0f, 3000.0f);
|
||||||
|
|
||||||
Vector2 steering = targetPos - enemy.WorldPosition;
|
Vector2 steering = targetPos - enemy.WorldPosition;
|
||||||
if (steering != Vector2.Zero) steering = Vector2.Normalize(steering);
|
if (steering != Vector2.Zero) steering = Vector2.Normalize(steering);
|
||||||
|
|
||||||
enemy.AIController.Steering = steering * 2.0f;
|
enemy.AIController.Steering = steering * enemy.AnimController.GetCurrentSpeed(true);
|
||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
} while (capacitors.FirstOrDefault(c => c.Charge > 0.4f) == null);
|
} while (capacitors.FirstOrDefault(c => c.Charge > 0.4f) == null);
|
||||||
|
|||||||
+512
@@ -0,0 +1,512 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Barotrauma.Items.Components;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Tutorials
|
||||||
|
{
|
||||||
|
class ContextualTutorial : Tutorial
|
||||||
|
{
|
||||||
|
public static bool Selected = false;
|
||||||
|
public static bool ContentRunning = false;
|
||||||
|
public static bool Initialized = false;
|
||||||
|
|
||||||
|
private enum ContentTypes { None = 0, Video = 1, Text = 2 };
|
||||||
|
|
||||||
|
private TutorialSegment activeSegment;
|
||||||
|
private List<TutorialSegment> segments;
|
||||||
|
|
||||||
|
private SpriteSheetPlayer spriteSheetPlayer;
|
||||||
|
private Steering navConsole;
|
||||||
|
private Reactor reactor;
|
||||||
|
private Sonar sonar;
|
||||||
|
private Vector2 subStartingPosition;
|
||||||
|
private List<Character> crew;
|
||||||
|
private List<Pair<Character, float>> characterTimeOnSonar;
|
||||||
|
private float requiredTimeOnSonar = 5f;
|
||||||
|
|
||||||
|
private bool started = false;
|
||||||
|
private string playableContentPath;
|
||||||
|
|
||||||
|
private float inputGracePeriodTimer;
|
||||||
|
private const float inputGracePeriod = .5f;
|
||||||
|
private float tutorialTimer;
|
||||||
|
private float degrading2ActivationCountdown;
|
||||||
|
|
||||||
|
private bool disableTutorialOnDeficiencyFound = true;
|
||||||
|
|
||||||
|
private class TutorialSegment
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public ContentTypes ContentType;
|
||||||
|
public XElement Content;
|
||||||
|
public bool IsTriggered;
|
||||||
|
|
||||||
|
public TutorialSegment(XElement config)
|
||||||
|
{
|
||||||
|
Name = config.GetAttributeString("name", "Missing Name");
|
||||||
|
Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType);
|
||||||
|
IsTriggered = config.GetAttributeBool("istriggered", false);
|
||||||
|
|
||||||
|
switch (ContentType)
|
||||||
|
{
|
||||||
|
case ContentTypes.None:
|
||||||
|
break;
|
||||||
|
case ContentTypes.Video:
|
||||||
|
Content = config.Element("Video");
|
||||||
|
break;
|
||||||
|
case ContentTypes.Text:
|
||||||
|
Content = config.Element("Text");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContextualTutorial(XElement element) : base(element)
|
||||||
|
{
|
||||||
|
playableContentPath = element.GetAttributeString("playablecontentpath", "");
|
||||||
|
segments = new List<TutorialSegment>();
|
||||||
|
|
||||||
|
foreach (var segment in element.Elements("Segment"))
|
||||||
|
{
|
||||||
|
segments.Add(new TutorialSegment(segment));
|
||||||
|
}
|
||||||
|
|
||||||
|
Name = "ContextualTutorial";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
if (Initialized) return;
|
||||||
|
Initialized = true;
|
||||||
|
|
||||||
|
base.Initialize();
|
||||||
|
spriteSheetPlayer = new SpriteSheetPlayer();
|
||||||
|
characterTimeOnSonar = new List<Pair<Character, float>>();
|
||||||
|
|
||||||
|
for (int i = 0; i < segments.Count; i++)
|
||||||
|
{
|
||||||
|
segments[i].IsTriggered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadPartiallyComplete(XElement element)
|
||||||
|
{
|
||||||
|
int[] completedSegments = element.GetAttributeIntArray("completedsegments", null);
|
||||||
|
|
||||||
|
if (completedSegments == null || completedSegments.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completedSegments.Length == segments.Count) // Completed all segments
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < completedSegments.Length; i++)
|
||||||
|
{
|
||||||
|
segments[completedSegments[i]].IsTriggered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PreloadVideoContent()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < segments.Count; i++)
|
||||||
|
{
|
||||||
|
if (segments[i].ContentType != ContentTypes.Video || segments[i].IsTriggered) continue;
|
||||||
|
spriteSheetPlayer.PreloadContent(playableContentPath, "tutorial", segments[i].Name, segments[i].Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SavePartiallyComplete(XElement element)
|
||||||
|
{
|
||||||
|
XElement tutorialElement = new XElement("contextualtutorial");
|
||||||
|
tutorialElement.Add(new XAttribute("completedsegments", GetCompletedSegments()));
|
||||||
|
element.Add(tutorialElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCompletedSegments()
|
||||||
|
{
|
||||||
|
string completedSegments = string.Empty;
|
||||||
|
|
||||||
|
for (int i = 0; i < segments.Count; i++)
|
||||||
|
{
|
||||||
|
if (segments[i].IsTriggered)
|
||||||
|
{
|
||||||
|
completedSegments += i + ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completedSegments.Length > 0)
|
||||||
|
{
|
||||||
|
completedSegments = completedSegments.TrimEnd(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
return completedSegments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
if (!Initialized) return;
|
||||||
|
|
||||||
|
PreloadVideoContent();
|
||||||
|
Completed = true; // Trigger completed at start to prevent the contextual tutorial from automatically activating on starting new campaigns after this one
|
||||||
|
|
||||||
|
base.Start();
|
||||||
|
|
||||||
|
activeSegment = null;
|
||||||
|
tutorialTimer = 0.0f;
|
||||||
|
inputGracePeriodTimer = 0.0f;
|
||||||
|
degrading2ActivationCountdown = -1;
|
||||||
|
subStartingPosition = Vector2.Zero;
|
||||||
|
characterTimeOnSonar.Clear();
|
||||||
|
|
||||||
|
subStartingPosition = Submarine.MainSub.WorldPosition;
|
||||||
|
navConsole = Item.ItemList.Find(i => i.HasTag("command"))?.GetComponent<Steering>();
|
||||||
|
sonar = navConsole?.Item.GetComponent<Sonar>();
|
||||||
|
reactor = Item.ItemList.Find(i => i.HasTag("reactor"))?.GetComponent<Reactor>();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (reactor == null || navConsole == null || sonar == null)
|
||||||
|
{
|
||||||
|
infoBox = CreateInfoFrame("Submarine not compatible with the tutorial:"
|
||||||
|
+ "\nReactor - " + (reactor != null ? "OK" : "Tag 'reactor' not found")
|
||||||
|
+ "\nNavigation Console - " + (navConsole != null ? "OK" : "Tag 'command' not found")
|
||||||
|
+ "\nSonar - " + (sonar != null ? "OK" : "Not found under Navigation Console"), true);
|
||||||
|
CoroutineManager.StartCoroutine(WaitForErrorClosed());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (disableTutorialOnDeficiencyFound)
|
||||||
|
{
|
||||||
|
if (reactor == null || navConsole == null || sonar == null)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (navConsole == null) segments[2].IsTriggered = true; // Disable navigation console usage tutorial
|
||||||
|
if (reactor == null) segments[5].IsTriggered = true; // Disable reactor usage tutorial
|
||||||
|
if (sonar == null) segments[6].IsTriggered = true; // Disable enemy on sonar tutorial
|
||||||
|
}
|
||||||
|
|
||||||
|
crew = GameMain.GameSession.CrewManager.GetCharacters().ToList();
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private IEnumerable<object> WaitForErrorClosed()
|
||||||
|
{
|
||||||
|
while (infoBox != null) yield return null;
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
started = ContentRunning = Initialized = false;
|
||||||
|
spriteSheetPlayer.Remove();
|
||||||
|
spriteSheetPlayer = null;
|
||||||
|
characterTimeOnSonar = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
base.AddToGUIUpdateList();
|
||||||
|
if (spriteSheetPlayer != null)
|
||||||
|
{
|
||||||
|
spriteSheetPlayer.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!started) return;
|
||||||
|
deltaTime *= 0.5f;
|
||||||
|
|
||||||
|
if (ContentRunning) // Content is running, wait until dismissed
|
||||||
|
{
|
||||||
|
if (inputGracePeriodTimer < inputGracePeriod)
|
||||||
|
{
|
||||||
|
inputGracePeriodTimer += deltaTime;
|
||||||
|
}
|
||||||
|
else if (Keyboard.GetState().GetPressedKeys().Length > 0 || Mouse.GetState().LeftButton == ButtonState.Pressed || Mouse.GetState().RightButton == ButtonState.Pressed)
|
||||||
|
{
|
||||||
|
switch (activeSegment.ContentType)
|
||||||
|
{
|
||||||
|
case ContentTypes.None:
|
||||||
|
break;
|
||||||
|
case ContentTypes.Video:
|
||||||
|
spriteSheetPlayer.Stop();
|
||||||
|
break;
|
||||||
|
case ContentTypes.Text:
|
||||||
|
infoBox = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSegment = null;
|
||||||
|
ContentRunning = false;
|
||||||
|
inputGracePeriodTimer = 0.0f;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < segments.Count; i++)
|
||||||
|
{
|
||||||
|
if (segments[i].IsTriggered) continue;
|
||||||
|
if (CheckContextualTutorials(i, deltaTime)) // Found a relevant tutorial, halt finding new ones
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckContextualTutorials(int index, float deltaTime)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0: // Welcome: Game Start [Text]
|
||||||
|
if (tutorialTimer < 0.5f)
|
||||||
|
{
|
||||||
|
tutorialTimer += deltaTime;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // Command Reactor: 10 seconds after 'Welcome' dismissed and only if no command given to start reactor [Video]
|
||||||
|
if (tutorialTimer < 10.5f)
|
||||||
|
{
|
||||||
|
tutorialTimer += deltaTime;
|
||||||
|
|
||||||
|
if (HasOrder("operatereactor"))
|
||||||
|
{
|
||||||
|
segments[index].IsTriggered = true;
|
||||||
|
tutorialTimer = 10.5f;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // Nav Console: 20 seconds after 'Command Reactor' dismissed or if nav console is activated [Video]
|
||||||
|
if (Character.Controlled?.SelectedConstruction != navConsole.Item)
|
||||||
|
{
|
||||||
|
if (!segments[1].IsTriggered) return false; // Do not advance tutorial timer based on this segment if reactor has not been powered up
|
||||||
|
if (tutorialTimer < 30.5f)
|
||||||
|
{
|
||||||
|
tutorialTimer += deltaTime;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!segments[1].IsTriggered || !HasOrder("operatereactor")) // If reactor has not been powered up or ordered to be, default to that one first
|
||||||
|
{
|
||||||
|
if (tutorialTimer < 10.5f)
|
||||||
|
{
|
||||||
|
tutorialTimer = 10.5f;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tutorialTimer = 30.5f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: // Objective: Travel ~150 meters and while sub is not flooding [Text]
|
||||||
|
if (Vector2.Distance(subStartingPosition, Submarine.MainSub.WorldPosition) < 12000f || IsFlooding())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else // Called earlier than others due to requiring specific args
|
||||||
|
{
|
||||||
|
TriggerTutorialSegment(index, GameMain.GameSession.EndLocation.Name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 4: // Flood: Hull is breached and sub is taking on water [Video]
|
||||||
|
if (!IsFlooding())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // Reactor: Player uses reactor for the first time [Video]
|
||||||
|
if (Character.Controlled?.SelectedConstruction != reactor.Item)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6: // Enemy on Sonar: Player witnesses creature signal on sonar for 5 seconds [Video]
|
||||||
|
if (!HasEnemyOnSonarForDuration(deltaTime))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7: // Degrading1: Any equipment degrades to 50% health or less and player has not assigned any crew to perform maintenance [Text]
|
||||||
|
bool degradedEquipmentFound = false;
|
||||||
|
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (!item.Repairables.Any() || item.Condition > 50.0f) continue;
|
||||||
|
degradedEquipmentFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (degradedEquipmentFound)
|
||||||
|
{
|
||||||
|
degrading2ActivationCountdown = 5f;
|
||||||
|
if (HasOrder("repairsystems"))
|
||||||
|
{
|
||||||
|
segments[index].IsTriggered = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8: // Degrading2: 5 seconds after 'Degrading1' dismissed, and only if player has not assigned any crew to perform maintenance [Video]
|
||||||
|
if (degrading2ActivationCountdown == -1f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (degrading2ActivationCountdown > 0.0f)
|
||||||
|
{
|
||||||
|
degrading2ActivationCountdown -= deltaTime;
|
||||||
|
if (HasOrder("repairsystems"))
|
||||||
|
{
|
||||||
|
segments[index].IsTriggered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9: // Medical: Crewmember is injured but not killed [Video]
|
||||||
|
bool injuredFound = false;
|
||||||
|
for (int i = 0; i < crew.Count; i++)
|
||||||
|
{
|
||||||
|
Character member = crew[i];
|
||||||
|
if (member.Vitality < member.MaxVitality && !member.IsDead)
|
||||||
|
{
|
||||||
|
injuredFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!injuredFound) return false;
|
||||||
|
break;
|
||||||
|
case 10: // Approach1: Destination is within ~100m [Video]
|
||||||
|
if (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 8000f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11: // Approach2: Sub is docked [Text]
|
||||||
|
if (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerTutorialSegment(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasOrder(string aiTag)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < crew.Count; i++)
|
||||||
|
{
|
||||||
|
if (crew[i].CurrentOrder?.AITag == aiTag) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsFlooding()
|
||||||
|
{
|
||||||
|
foreach (Gap gap in Gap.GapList)
|
||||||
|
{
|
||||||
|
if (gap.ConnectedWall == null) continue;
|
||||||
|
if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue;
|
||||||
|
if (gap.Submarine == null) continue;
|
||||||
|
if (gap.Submarine != Submarine.MainSub) continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasEnemyOnSonarForDuration(float deltaTime)
|
||||||
|
{
|
||||||
|
foreach (Character c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c.AnimController.CurrentHull != null || !c.Enabled || !(c.AIController is EnemyAIController)) continue;
|
||||||
|
if (sonar.DetectSubmarineWalls && c.AnimController.CurrentHull == null && sonar.Item.CurrentHull != null) continue;
|
||||||
|
if (Vector2.DistanceSquared(c.WorldPosition, sonar.Item.WorldPosition) > sonar.Range * sonar.Range)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < characterTimeOnSonar.Count; i++)
|
||||||
|
{
|
||||||
|
if (characterTimeOnSonar[i].First == c)
|
||||||
|
{
|
||||||
|
characterTimeOnSonar.RemoveAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair<Character, float> pair = characterTimeOnSonar.Find(ct => ct.First == c);
|
||||||
|
if (pair != null)
|
||||||
|
{
|
||||||
|
pair.Second += deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
characterTimeOnSonar.Add(new Pair<Character, float>(c, deltaTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return characterTimeOnSonar.Find(ct => ct.Second >= requiredTimeOnSonar) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TriggerTutorialSegment(int index, params object[] args)
|
||||||
|
{
|
||||||
|
ContentRunning = true;
|
||||||
|
activeSegment = segments[index];
|
||||||
|
activeSegment.IsTriggered = true;
|
||||||
|
|
||||||
|
switch (activeSegment.ContentType)
|
||||||
|
{
|
||||||
|
case ContentTypes.None:
|
||||||
|
break;
|
||||||
|
case ContentTypes.Video:
|
||||||
|
spriteSheetPlayer.LoadContent(playableContentPath, activeSegment.Content, activeSegment.Name, true);
|
||||||
|
break;
|
||||||
|
case ContentTypes.Text:
|
||||||
|
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Name), TextManager.Get(activeSegment.Content.GetAttributeString("tag", ""), false, args),
|
||||||
|
activeSegment.Content.GetAttributeInt("width", 300),
|
||||||
|
activeSegment.Content.GetAttributeInt("height", 80),
|
||||||
|
activeSegment.Content.GetAttributeString("anchor", "Center"), false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < segments.Count; i++)
|
||||||
|
{
|
||||||
|
if (!segments[i].IsTriggered) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineManager.StartCoroutine(WaitToStop()); // Completed
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> WaitToStop()
|
||||||
|
{
|
||||||
|
while (ContentRunning) yield return null;
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-6
@@ -1,19 +1,20 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Tutorials
|
namespace Barotrauma.Tutorials
|
||||||
{
|
{
|
||||||
class EditorTutorial : TutorialType
|
class EditorTutorial : Tutorial
|
||||||
{
|
{
|
||||||
public EditorTutorial(string name)
|
public EditorTutorial(XElement element)
|
||||||
: base (name)
|
: base (element)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<object> UpdateState()
|
public override IEnumerable<object> UpdateState()
|
||||||
{
|
{
|
||||||
infoBox = CreateInfoFrame("Use the mouse wheel to zoom in and out, and WASD to move the camera around.", true);
|
/*infoBox = CreateInfoFrame("Use the mouse wheel to zoom in and out, and WASD to move the camera around.", true);
|
||||||
|
|
||||||
while (infoBox!=null)
|
while (infoBox != null)
|
||||||
{
|
{
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -32,7 +33,7 @@ namespace Barotrauma.Tutorials
|
|||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
infoBox = CreateInfoFrame("You can now create a horizontal wall by clicking and dragging. When you're done, right click to stop creating walls.");
|
infoBox = CreateInfoFrame("You can now create a horizontal wall by clicking and dragging. When you're done, right click to stop creating walls.");*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Tutorials
|
||||||
|
{
|
||||||
|
class ScenarioTutorial : Tutorial
|
||||||
|
{
|
||||||
|
private Character character;
|
||||||
|
private SpawnType spawnPointType;
|
||||||
|
private string submarinePath;
|
||||||
|
private string levelSeed;
|
||||||
|
|
||||||
|
public ScenarioTutorial(XElement element) : base(element)
|
||||||
|
{
|
||||||
|
submarinePath = element.GetAttributeString("submarinepath", "");
|
||||||
|
levelSeed = element.GetAttributeString("levelseed", "tuto");
|
||||||
|
Enum.TryParse(element.GetAttributeString("spawnpointtype", "Human"), true, out spawnPointType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
GameMain.Instance.ShowLoading(Loading());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
base.Start();
|
||||||
|
|
||||||
|
WayPoint wayPoint = WayPoint.GetRandom(spawnPointType, null);
|
||||||
|
if (wayPoint == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("A waypoint with the spawntype \"" + spawnPointType + "\" is required for the tutorial event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterInfo charInfo = configElement.Element("Character") == null ?
|
||||||
|
new CharacterInfo(Character.HumanConfigFile, "", Gender.None, JobPrefab.List.Find(jp => jp.Identifier == "engineer")) :
|
||||||
|
new CharacterInfo(configElement.Element("Character"));
|
||||||
|
|
||||||
|
character = Character.Create(charInfo, wayPoint.WorldPosition, "", false, false);
|
||||||
|
Character.Controlled = character;
|
||||||
|
character.GiveJobItems(null);
|
||||||
|
|
||||||
|
var idCard = character.Inventory.FindItemByIdentifier("idcard");
|
||||||
|
if (idCard == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idCard.AddTag("com");
|
||||||
|
idCard.AddTag("eng");
|
||||||
|
|
||||||
|
CoroutineManager.StartCoroutine(UpdateState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> Loading()
|
||||||
|
{
|
||||||
|
Submarine.MainSub = Submarine.Load(submarinePath, "", true);
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
|
GameMain.GameSession = new GameSession(Submarine.MainSub, "",
|
||||||
|
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
|
||||||
|
(GameMain.GameSession.GameMode as TutorialMode).tutorial = this;
|
||||||
|
GameMain.GameSession.StartRound(levelSeed);
|
||||||
|
GameMain.GameSession.EventManager.Events.Clear();
|
||||||
|
GameMain.GameScreen.Select();
|
||||||
|
|
||||||
|
yield return CoroutineStatus.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
base.Update(deltaTime);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
if (Character.Controlled == null)
|
||||||
|
{
|
||||||
|
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
|
||||||
|
infoBox = null;
|
||||||
|
}
|
||||||
|
else if (Character.Controlled.IsDead)
|
||||||
|
{
|
||||||
|
Character.Controlled = null;
|
||||||
|
|
||||||
|
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
|
||||||
|
infoBox = null;
|
||||||
|
CoroutineManager.StartCoroutine(Dead());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> Dead()
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(3.0f);
|
||||||
|
|
||||||
|
var messageBox = new GUIMessageBox("You have died", "Do you want to try again?", new string[] { "Yes", "No" });
|
||||||
|
|
||||||
|
messageBox.Buttons[0].OnClicked += Restart;
|
||||||
|
messageBox.Buttons[0].OnClicked += messageBox.Close;
|
||||||
|
|
||||||
|
|
||||||
|
messageBox.Buttons[1].OnClicked = GameMain.MainMenuScreen.SelectTab;
|
||||||
|
messageBox.Buttons[1].OnClicked += messageBox.Close;
|
||||||
|
|
||||||
|
yield return CoroutineStatus.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Tutorials
|
||||||
|
{
|
||||||
|
abstract class Tutorial
|
||||||
|
{
|
||||||
|
public static List<Tutorial> Tutorials;
|
||||||
|
|
||||||
|
protected GUIComponent infoBox;
|
||||||
|
protected XElement configElement;
|
||||||
|
|
||||||
|
private enum TutorialType { None, Scenario, Contextual };
|
||||||
|
private TutorialType tutorialType = TutorialType.None;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool completed;
|
||||||
|
public bool Completed
|
||||||
|
{
|
||||||
|
get { return completed; }
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
if (completed == value) return;
|
||||||
|
completed = value;
|
||||||
|
GameMain.Config.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
Tutorials = new List<Tutorial>();
|
||||||
|
foreach (string file in GameMain.Instance.GetFilesOfType(ContentType.Tutorials))
|
||||||
|
{
|
||||||
|
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||||
|
if (doc?.Root == null) continue;
|
||||||
|
|
||||||
|
foreach (XElement element in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
Tutorial newTutorial = Load(element);
|
||||||
|
if (newTutorial != null) Tutorials.Add(newTutorial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Tutorial Load(XElement element)
|
||||||
|
{
|
||||||
|
Type t;
|
||||||
|
string type = element.Name.ToString().ToLowerInvariant();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the type of a specified class.
|
||||||
|
t = Type.GetType("Barotrauma.Tutorials." + type + "", false, true);
|
||||||
|
if (t == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Could not find tutorial type \"" + type + "\"");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Could not find tutorial type \"" + type + "\"", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstructorInfo constructor;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!t.IsSubclassOf(typeof(Tutorial))) return null;
|
||||||
|
constructor = t.GetConstructor(new Type[] { typeof(XElement) });
|
||||||
|
if (constructor == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Could not find the constructor of tutorial type \"" + type + "\"");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Could not find the constructor of tutorial type \"" + type + "\"", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Tutorial tutorial = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object component = constructor.Invoke(new object[] { element });
|
||||||
|
tutorial = (Tutorial)component;
|
||||||
|
}
|
||||||
|
catch (TargetInvocationException e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error while loading tutorial of the type " + t + ".", e.InnerException);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tutorial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tutorial(XElement element)
|
||||||
|
{
|
||||||
|
configElement = element;
|
||||||
|
Name = element.GetAttributeString("name", "Unnamed");
|
||||||
|
Completed = GameMain.Config.CompletedTutorialNames.Contains(Name);
|
||||||
|
Enum.TryParse(element.GetAttributeString("tutorialtype", "Scenario"), true, out tutorialType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Start()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
if (infoBox != null) infoBox.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerable<object> UpdateState()
|
||||||
|
{
|
||||||
|
yield return CoroutineStatus.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool CloseInfoFrame(GUIButton button, object userData)
|
||||||
|
{
|
||||||
|
infoBox = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GUIComponent CreateInfoFrame(string text, bool hasButton = false)
|
||||||
|
{
|
||||||
|
int width = 300;
|
||||||
|
int height = hasButton ? 110 : 80;
|
||||||
|
|
||||||
|
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
|
||||||
|
|
||||||
|
height += wrappedText.Split('\n').Length * 25;
|
||||||
|
|
||||||
|
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, Anchor.TopRight) { AbsoluteOffset = new Point(20) });
|
||||||
|
infoBlock.Flash(Color.Green);
|
||||||
|
|
||||||
|
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.7f), infoBlock.RectTransform, Anchor.Center),
|
||||||
|
text, wrap: true);
|
||||||
|
|
||||||
|
if (hasButton)
|
||||||
|
{
|
||||||
|
var okButton = new GUIButton(new RectTransform(new Point(80, 25), infoBlock.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 5) },
|
||||||
|
TextManager.Get("OK"))
|
||||||
|
{
|
||||||
|
OnClicked = CloseInfoFrame
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.PlayUISound(GUISoundType.Message);
|
||||||
|
|
||||||
|
return infoBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GUIComponent CreateInfoFrame(string title, string text, int width, int height, string anchorStr, bool hasButton = false)
|
||||||
|
{
|
||||||
|
if (hasButton) height += 30;
|
||||||
|
|
||||||
|
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
|
||||||
|
|
||||||
|
height += wrappedText.Split('\n').Length * 25;
|
||||||
|
|
||||||
|
if (title.Length > 0)
|
||||||
|
{
|
||||||
|
height += 35;
|
||||||
|
}
|
||||||
|
|
||||||
|
Anchor anchor = Anchor.TopRight;
|
||||||
|
Enum.TryParse(anchorStr, out anchor);
|
||||||
|
|
||||||
|
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, anchor) { AbsoluteOffset = new Point(20) });
|
||||||
|
infoBlock.Flash(Color.Green);
|
||||||
|
|
||||||
|
if (title.Length > 0)
|
||||||
|
{
|
||||||
|
var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1f, .35f), infoBlock.RectTransform, Anchor.TopCenter,
|
||||||
|
Pivot.TopCenter), title, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1f), infoBlock.RectTransform, Anchor.BottomCenter),
|
||||||
|
text, wrap: true);
|
||||||
|
|
||||||
|
if (hasButton)
|
||||||
|
{
|
||||||
|
var okButton = new GUIButton(new RectTransform(new Point(80, 25), infoBlock.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 5) },
|
||||||
|
TextManager.Get("OK"))
|
||||||
|
{
|
||||||
|
OnClicked = CloseInfoFrame
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.PlayUISound(GUISoundType.Message);
|
||||||
|
|
||||||
|
return infoBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool Restart(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
TutorialMode.StartTutorial(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,13 +5,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class TutorialMode : GameMode
|
class TutorialMode : GameMode
|
||||||
{
|
{
|
||||||
public TutorialType tutorialType;
|
public Tutorial tutorial;
|
||||||
|
|
||||||
public static void StartTutorial(TutorialType tutorialType)
|
public static void StartTutorial(Tutorial tutorial)
|
||||||
{
|
{
|
||||||
Submarine.MainSub = Submarine.Load("Content/Map/TutorialSub.sub", "", true);
|
tutorial.Initialize();
|
||||||
|
|
||||||
tutorialType.Initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TutorialMode(GameModePreset preset, object param)
|
public TutorialMode(GameModePreset preset, object param)
|
||||||
@@ -22,32 +20,18 @@ namespace Barotrauma
|
|||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
base.Start();
|
base.Start();
|
||||||
|
tutorial.Start();
|
||||||
tutorialType.Start();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void AddToGUIUpdateList()
|
||||||
{
|
{
|
||||||
tutorialType.AddToGUIUpdateList();
|
tutorial.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
|
tutorial.Update(deltaTime);
|
||||||
tutorialType.Update(deltaTime);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
base.Draw(spriteBatch);
|
|
||||||
|
|
||||||
//CrewManager.Draw(spriteBatch);
|
|
||||||
tutorialType.Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Barotrauma.Tutorials
|
|
||||||
{
|
|
||||||
class TutorialType
|
|
||||||
{
|
|
||||||
|
|
||||||
public static List<TutorialType> TutorialTypes;
|
|
||||||
|
|
||||||
protected GUIComponent infoBox;
|
|
||||||
|
|
||||||
Character character;
|
|
||||||
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TutorialType()
|
|
||||||
{
|
|
||||||
TutorialTypes = new List<TutorialType>();
|
|
||||||
|
|
||||||
TutorialTypes.Add(new BasicTutorial("Basic tutorial"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public TutorialType(string name)
|
|
||||||
{
|
|
||||||
this.Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Initialize()
|
|
||||||
{
|
|
||||||
|
|
||||||
GameMain.GameSession = new GameSession(Submarine.MainSub, "", GameModePreset.list.Find(gm => gm.Name.ToLowerInvariant() == "tutorial"));
|
|
||||||
(GameMain.GameSession.GameMode as TutorialMode).tutorialType = this;
|
|
||||||
|
|
||||||
GameMain.GameSession.StartRound("tuto");
|
|
||||||
|
|
||||||
GameMain.GameSession.EventManager.Events.Clear();
|
|
||||||
|
|
||||||
GameMain.GameScreen.Select();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Start()
|
|
||||||
{
|
|
||||||
|
|
||||||
WayPoint wayPoint = WayPoint.GetRandom(SpawnType.Cargo, null);
|
|
||||||
if (wayPoint == null)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("A waypoint with the spawntype \"cargo\" is required for the tutorial event");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CharacterInfo charInfo = new CharacterInfo(Character.HumanConfigFile, "", Gender.None, JobPrefab.List.Find(jp => jp.Name == "Engineer"));
|
|
||||||
|
|
||||||
character = Character.Create(charInfo, wayPoint.WorldPosition, false, false);
|
|
||||||
Character.Controlled = character;
|
|
||||||
character.GiveJobItems(null);
|
|
||||||
|
|
||||||
var idCard = character.Inventory.FindItem("ID Card");
|
|
||||||
if (idCard == null)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
idCard.AddTag("com");
|
|
||||||
idCard.AddTag("eng");
|
|
||||||
|
|
||||||
//CoroutineManager.StartCoroutine(QuitChecker());
|
|
||||||
CoroutineManager.StartCoroutine(UpdateState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void AddToGUIUpdateList()
|
|
||||||
{
|
|
||||||
if (infoBox != null) infoBox.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Update(float deltaTime)
|
|
||||||
{
|
|
||||||
if (character!=null)
|
|
||||||
{
|
|
||||||
if (Character.Controlled==null)
|
|
||||||
{
|
|
||||||
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
|
|
||||||
infoBox = null;
|
|
||||||
}
|
|
||||||
else if (Character.Controlled.IsDead)
|
|
||||||
{
|
|
||||||
Character.Controlled = null;
|
|
||||||
|
|
||||||
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
|
|
||||||
infoBox = null;
|
|
||||||
CoroutineManager.StartCoroutine(Dead());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//CrewManager.Update(deltaTime);
|
|
||||||
|
|
||||||
if (infoBox != null) infoBox.Update(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<object> UpdateState()
|
|
||||||
{
|
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Draw(SpriteBatch spriteBatch)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (infoBox != null) infoBox.Draw(spriteBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private IEnumerable<object> Dead()
|
|
||||||
{
|
|
||||||
yield return new WaitForSeconds(3.0f);
|
|
||||||
|
|
||||||
var messageBox = new GUIMessageBox("You have died", "Do you want to try again?", new string[] { "Yes", "No" });
|
|
||||||
|
|
||||||
messageBox.Buttons[0].OnClicked += Restart;
|
|
||||||
messageBox.Buttons[0].OnClicked += messageBox.Close;
|
|
||||||
|
|
||||||
|
|
||||||
messageBox.Buttons[1].OnClicked = GameMain.MainMenuScreen.SelectTab;
|
|
||||||
messageBox.Buttons[1].OnClicked += messageBox.Close;
|
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected bool CloseInfoFrame(GUIButton button, object userData)
|
|
||||||
{
|
|
||||||
infoBox = null;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected GUIComponent CreateInfoFrame(string text, bool hasButton = false)
|
|
||||||
{
|
|
||||||
int width = 300;
|
|
||||||
int height = hasButton ? 110 : 80;
|
|
||||||
|
|
||||||
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
|
|
||||||
|
|
||||||
height += wrappedText.Split('\n').Length * 25;
|
|
||||||
|
|
||||||
var infoBlock = new GUIFrame(new Rectangle(-20, 20, width, height), null, Alignment.TopRight, "");
|
|
||||||
//infoBlock.Color = infoBlock.Color * 0.8f;
|
|
||||||
infoBlock.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
|
|
||||||
infoBlock.Flash(Color.Green);
|
|
||||||
|
|
||||||
var textBlock = new GUITextBlock(new Rectangle(10, 10, width - 40, height), text, "", infoBlock, true);
|
|
||||||
|
|
||||||
if (hasButton)
|
|
||||||
{
|
|
||||||
var okButton = new GUIButton(new Rectangle(0, -40, 80, 25), "OK", Alignment.BottomCenter, "", textBlock);
|
|
||||||
okButton.OnClicked = CloseInfoFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GUI.PlayUISound(GUISoundType.Message);
|
|
||||||
|
|
||||||
return infoBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private bool Restart(GUIButton button, object obj)
|
|
||||||
{
|
|
||||||
TutorialMode.StartTutorial(this);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
private InfoFrameTab selectedTab;
|
private InfoFrameTab selectedTab;
|
||||||
private GUIButton infoButton;
|
private GUIButton infoButton;
|
||||||
private GUIFrame infoFrame;
|
private GUIButton infoFrame;
|
||||||
|
|
||||||
|
private GUIFrame infoFrameContent;
|
||||||
|
|
||||||
private RoundSummary roundSummary;
|
private RoundSummary roundSummary;
|
||||||
public RoundSummary RoundSummary
|
public RoundSummary RoundSummary
|
||||||
{
|
{
|
||||||
@@ -19,11 +21,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (infoFrame == null)
|
if (infoFrame == null)
|
||||||
{
|
{
|
||||||
if (CrewManager != null && CrewManager.CrewCommander != null && CrewManager.CrewCommander.IsOpen)
|
|
||||||
{
|
|
||||||
CrewManager.CrewCommander.ToggleGUIFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateInfoFrame();
|
CreateInfoFrame();
|
||||||
SelectInfoFrameTab(null, selectedTab);
|
SelectInfoFrameTab(null, selectedTab);
|
||||||
}
|
}
|
||||||
@@ -39,35 +36,46 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
int width = 600, height = 400;
|
int width = 600, height = 400;
|
||||||
|
|
||||||
|
infoFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
|
||||||
|
{
|
||||||
|
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ToggleInfoFrame(btn, userdata); return true; }
|
||||||
|
};
|
||||||
|
|
||||||
infoFrame = new GUIFrame(
|
|
||||||
Rectangle.Empty, Color.Black * 0.8f, null);
|
|
||||||
|
|
||||||
var innerFrame = new GUIFrame(
|
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.35f), infoFrame.RectTransform, Anchor.Center) { MinSize = new Point(width,height) });
|
||||||
new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), "", infoFrame);
|
|
||||||
|
|
||||||
innerFrame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
|
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center), style:null);
|
||||||
|
var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedFrame.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.01f
|
||||||
|
};
|
||||||
|
infoFrameContent = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.08f) }, style: "InnerFrame");
|
||||||
|
|
||||||
var crewButton = new GUIButton(new Rectangle(0, -30, 100, 20), TextManager.Get("Crew"), "", innerFrame);
|
var crewButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("Crew"))
|
||||||
crewButton.ClampMouseRectToParent = false;
|
{
|
||||||
crewButton.UserData = InfoFrameTab.Crew;
|
UserData = InfoFrameTab.Crew,
|
||||||
crewButton.OnClicked = SelectInfoFrameTab;
|
OnClicked = SelectInfoFrameTab
|
||||||
|
};
|
||||||
|
|
||||||
var missionButton = new GUIButton(new Rectangle(100, -30, 100, 20), TextManager.Get("Mission"), "", innerFrame);
|
var missionButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("Mission"))
|
||||||
missionButton.ClampMouseRectToParent = false;
|
{
|
||||||
missionButton.UserData = InfoFrameTab.Mission;
|
UserData = InfoFrameTab.Mission,
|
||||||
missionButton.OnClicked = SelectInfoFrameTab;
|
OnClicked = SelectInfoFrameTab
|
||||||
|
};
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
{
|
{
|
||||||
var manageButton = new GUIButton(new Rectangle(200, -30, 130, 20), TextManager.Get("ManagePlayers"), "", innerFrame);
|
var manageButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("ManagePlayers"))
|
||||||
manageButton.ClampMouseRectToParent = false;
|
{
|
||||||
manageButton.UserData = InfoFrameTab.ManagePlayers;
|
UserData = InfoFrameTab.ManagePlayers,
|
||||||
manageButton.OnClicked = SelectInfoFrameTab;
|
OnClicked = SelectInfoFrameTab
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var closeButton = new GUIButton(new Rectangle(0, 0, 80, 20), TextManager.Get("Close"), Alignment.BottomCenter, "", innerFrame);
|
var closeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.08f), paddedFrame.RectTransform, Anchor.BottomRight), TextManager.Get("Close"))
|
||||||
closeButton.OnClicked = ToggleInfoFrame;
|
{
|
||||||
|
OnClicked = ToggleInfoFrame
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,13 +88,13 @@ namespace Barotrauma
|
|||||||
switch (selectedTab)
|
switch (selectedTab)
|
||||||
{
|
{
|
||||||
case InfoFrameTab.Crew:
|
case InfoFrameTab.Crew:
|
||||||
CrewManager.CreateCrewFrame(CrewManager.GetCharacters(), infoFrame.children[0] as GUIFrame);
|
CrewManager.CreateCrewListFrame(CrewManager.GetCharacters(), infoFrameContent);
|
||||||
break;
|
break;
|
||||||
case InfoFrameTab.Mission:
|
case InfoFrameTab.Mission:
|
||||||
CreateMissionInfo(infoFrame.children[0] as GUIFrame);
|
CreateMissionInfo(infoFrameContent);
|
||||||
break;
|
break;
|
||||||
case InfoFrameTab.ManagePlayers:
|
case InfoFrameTab.ManagePlayers:
|
||||||
GameMain.Server.ManagePlayersFrame(infoFrame.children[0] as GUIFrame);
|
GameMain.Server.ManagePlayersFrame(infoFrameContent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,57 +103,49 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateMissionInfo(GUIFrame infoFrame)
|
private void CreateMissionInfo(GUIFrame infoFrame)
|
||||||
{
|
{
|
||||||
|
infoFrameContent.ClearChildren();
|
||||||
|
|
||||||
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), infoFrameContent.RectTransform))
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
if (Mission == null)
|
if (Mission == null)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new Rectangle(0, 0, 0, 50), TextManager.Get("NoMission"), "", infoFrame, true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform, Anchor.TopCenter), TextManager.Get("NoMission"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, 0, 0, 40), Mission.Name, "", infoFrame, GUI.LargeFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Mission.Name, font: GUI.LargeFont);
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, 50, 0, 20), TextManager.Get("MissionReward").Replace("[reward]", Mission.Reward.ToString()), "", infoFrame, true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), TextManager.Get("MissionReward").Replace("[reward]", Mission.Reward.ToString()));
|
||||||
new GUITextBlock(new Rectangle(0, 70, 0, 50), Mission.Description, "", infoFrame, true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), Mission.Description, wrap: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddToGUIUpdateList()
|
public void AddToGUIUpdateList()
|
||||||
{
|
{
|
||||||
infoButton.AddToGUIUpdateList();
|
|
||||||
|
|
||||||
if (GameMode != null) GameMode.AddToGUIUpdateList();
|
|
||||||
|
|
||||||
if (infoFrame != null) infoFrame.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
|
||||||
{
|
|
||||||
EventManager.Update(deltaTime);
|
|
||||||
|
|
||||||
if (GUI.DisableHUD) return;
|
if (GUI.DisableHUD) return;
|
||||||
|
infoButton.AddToGUIUpdateList();
|
||||||
//guiRoot.Update(deltaTime);
|
GameMode?.AddToGUIUpdateList();
|
||||||
infoButton.Update(deltaTime);
|
infoFrame?.AddToGUIUpdateList();
|
||||||
|
|
||||||
if (GameMode != null) GameMode.Update(deltaTime);
|
|
||||||
if (Mission != null) Mission.Update(deltaTime);
|
|
||||||
if (infoFrame != null)
|
|
||||||
{
|
|
||||||
infoFrame.Update(deltaTime);
|
|
||||||
|
|
||||||
if (CrewManager != null && CrewManager.CrewCommander != null && CrewManager.CrewCommander.IsOpen)
|
|
||||||
{
|
|
||||||
infoFrame = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
|
{
|
||||||
|
if (GUI.DisableHUD) return;
|
||||||
|
|
||||||
|
infoButton?.UpdateManually(deltaTime);
|
||||||
|
infoFrame?.UpdateManually(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch)
|
public void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (GUI.DisableHUD) return;
|
if (GUI.DisableHUD) return;
|
||||||
|
|
||||||
infoButton.Draw(spriteBatch);
|
infoButton.DrawManually(spriteBatch);
|
||||||
|
|
||||||
if (GameMode != null) GameMode.Draw(spriteBatch);
|
GameMode?.Draw(spriteBatch);
|
||||||
if (infoFrame != null) infoFrame.Draw(spriteBatch);
|
infoFrame?.DrawManually(spriteBatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class HireManager
|
class HireManager
|
||||||
{
|
{
|
||||||
public List<CharacterInfo> availableCharacters;
|
private List<CharacterInfo> availableCharacters;
|
||||||
|
public IEnumerable<CharacterInfo> AvailableCharacters
|
||||||
|
{
|
||||||
|
get { return availableCharacters; }
|
||||||
|
}
|
||||||
|
|
||||||
public const int MaxAvailableCharacters = 10;
|
public const int MaxAvailableCharacters = 10;
|
||||||
|
|
||||||
@@ -12,16 +16,29 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
availableCharacters = new List<CharacterInfo>();
|
availableCharacters = new List<CharacterInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveCharacter(CharacterInfo character)
|
||||||
|
{
|
||||||
|
availableCharacters.Remove(character);
|
||||||
|
}
|
||||||
|
|
||||||
public void GenerateCharacters(Location location, int amount)
|
public void GenerateCharacters(Location location, int amount)
|
||||||
{
|
{
|
||||||
for (int i = 0 ; i<amount ; i++)
|
availableCharacters.ForEach(c => c.Remove());
|
||||||
|
availableCharacters.Clear();
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
{
|
{
|
||||||
JobPrefab job = location.Type.GetRandomHireable();
|
JobPrefab job = location.Type.GetRandomHireable();
|
||||||
if (job == null) return;
|
if (job == null) { return; }
|
||||||
|
|
||||||
availableCharacters.Add(new CharacterInfo(Character.HumanConfigFile, "", Gender.None, job));
|
availableCharacters.Add(new CharacterInfo(Character.HumanConfigFile, "", Gender.None, job));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Remove()
|
||||||
|
{
|
||||||
|
availableCharacters.ForEach(c => c.Remove());
|
||||||
|
availableCharacters.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,31 +17,33 @@ namespace Barotrauma
|
|||||||
|
|
||||||
startLocation = gameSession.StartLocation;
|
startLocation = gameSession.StartLocation;
|
||||||
endLocation = gameSession.EndLocation;
|
endLocation = gameSession.EndLocation;
|
||||||
|
|
||||||
selectedMission = gameSession.Mission;
|
selectedMission = gameSession.Mission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public GUIFrame CreateSummaryFrame(string endMessage)
|
public GUIFrame CreateSummaryFrame(string endMessage)
|
||||||
{
|
{
|
||||||
bool singleplayer = GameMain.NetworkMember == null;
|
bool singleplayer = GameMain.NetworkMember == null;
|
||||||
|
|
||||||
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsUnconscious);
|
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsUnconscious);
|
||||||
bool progress = Submarine.MainSub.AtEndPosition;
|
bool progress = Submarine.MainSub.AtEndPosition;
|
||||||
|
|
||||||
GUIFrame frame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.8f, null);
|
|
||||||
|
|
||||||
int width = 760, height = 400;
|
|
||||||
GUIFrame innerFrame = new GUIFrame(new Rectangle(0, 0, width, height), null, Alignment.Center, "", frame);
|
|
||||||
|
|
||||||
GUIListBox listBox = new GUIListBox(new Rectangle(0, 0, 0, height - (int)(30 + innerFrame.Padding.Y + innerFrame.Padding.W)), "", innerFrame);
|
|
||||||
|
|
||||||
if (!singleplayer)
|
if (!singleplayer)
|
||||||
{
|
{
|
||||||
SoundPlayer.OverrideMusicType = gameOver ? "crewdead" : "endround";
|
SoundPlayer.OverrideMusicType = gameOver ? "crewdead" : "endround";
|
||||||
SoundPlayer.OverrideMusicDuration = 18.0f;
|
SoundPlayer.OverrideMusicDuration = 18.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
||||||
|
|
||||||
|
int width = 760, height = 400;
|
||||||
|
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.4f), frame.RectTransform, Anchor.Center, minSize: new Point(width, height)));
|
||||||
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.03f
|
||||||
|
};
|
||||||
|
|
||||||
|
GUIListBox infoTextBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), paddedFrame.RectTransform));
|
||||||
|
|
||||||
string summaryText = TextManager.Get(gameOver ? "RoundSummaryGameOver" :
|
string summaryText = TextManager.Get(gameOver ? "RoundSummaryGameOver" :
|
||||||
(progress ? "RoundSummaryProgress" : "RoundSummaryReturn"));
|
(progress ? "RoundSummaryProgress" : "RoundSummaryReturn"));
|
||||||
|
|
||||||
@@ -49,26 +51,26 @@ namespace Barotrauma
|
|||||||
.Replace("[sub]", Submarine.MainSub.Name)
|
.Replace("[sub]", Submarine.MainSub.Name)
|
||||||
.Replace("[location]", progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name);
|
.Replace("[location]", progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name);
|
||||||
|
|
||||||
var infoText = new GUITextBlock(new Rectangle(0, 0, listBox.Rect.Width - 20, 0), summaryText, "", null, true);
|
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||||
infoText.Rect = new Rectangle(0, 0, infoText.Rect.Width, infoText.Rect.Height + 20);
|
summaryText, wrap: true);
|
||||||
listBox.AddChild(infoText);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(endMessage))
|
if (!string.IsNullOrWhiteSpace(endMessage))
|
||||||
{
|
{
|
||||||
var endText = new GUITextBlock(new Rectangle(0, 0, listBox.Rect.Width - 20, 0), endMessage, "", null, true);
|
var endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||||
endText.Rect = new Rectangle(0, 0, endText.Rect.Width, endText.Rect.Height + 20);
|
endMessage, wrap: true);
|
||||||
listBox.AddChild(endText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.GameSession.Mission != null)
|
if (GameMain.GameSession.Mission != null)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new Rectangle(0, 0, 0, 40), TextManager.Get("Mission") + ": " + GameMain.GameSession.Mission.Name, "", listBox, GUI.LargeFont);
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform), style: null);
|
||||||
|
|
||||||
var missionInfo = new GUITextBlock(new Rectangle(0, 0, listBox.Rect.Width-20, 0),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||||
(GameMain.GameSession.Mission.Completed) ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage,
|
TextManager.Get("Mission") + ": " + GameMain.GameSession.Mission.Name, font: GUI.LargeFont);
|
||||||
"", null, true);
|
|
||||||
missionInfo.Rect = new Rectangle(0, 0, missionInfo.Rect.Width, missionInfo.Rect.Height + 20);
|
var missionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||||
listBox.AddChild(missionInfo);
|
GameMain.GameSession.Mission.Completed ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage,
|
||||||
|
wrap: true);
|
||||||
|
|
||||||
if (GameMain.GameSession.Mission.Completed)
|
if (GameMain.GameSession.Mission.Completed)
|
||||||
{
|
{
|
||||||
@@ -77,23 +79,24 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (GameMain.GameSession.Mission.Completed && singleplayer)
|
if (GameMain.GameSession.Mission.Completed && singleplayer)
|
||||||
{
|
{
|
||||||
var missionReward = new GUITextBlock(new Rectangle(0, 0, listBox.Rect.Width-20, 0), TextManager.Get("Reward") + ": " + GameMain.GameSession.Mission.Reward, "", Alignment.BottomLeft, Alignment.BottomLeft, null);
|
var missionReward = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||||
missionReward.Rect = new Rectangle(0, 0, missionReward.Rect.Width, missionReward.Rect.Height + 20);
|
TextManager.Get("MissionReward").Replace("[reward]", GameMain.GameSession.Mission.Reward.ToString()));
|
||||||
listBox.AddChild(missionReward);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameMain.Server?.ConnectedClients.ForEach(c => c.Karma += 0.1f);
|
GameMain.Server?.ConnectedClients.ForEach(c => c.Karma += 0.1f);
|
||||||
}
|
}
|
||||||
|
foreach (GUIComponent child in infoTextBox.Content.Children)
|
||||||
|
{
|
||||||
|
child.CanBeFocused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
|
TextManager.Get("RoundSummaryCrewStatus"), font: GUI.LargeFont);
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, 0, 0, 40), TextManager.Get("RoundSummaryCrewStatus"), "", listBox, GUI.LargeFont);
|
GUIListBox characterListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), paddedFrame.RectTransform, minSize: new Point(0, 75)), isHorizontal: true);
|
||||||
|
|
||||||
GUIListBox characterListBox = new GUIListBox(new Rectangle(0, 0, listBox.Rect.Width - 20, 90), null, Alignment.TopLeft, "", null, true);
|
|
||||||
listBox.AddChild(characterListBox);
|
|
||||||
|
|
||||||
int x = 0;
|
|
||||||
foreach (CharacterInfo characterInfo in gameSession.CrewManager.GetCharacterInfos())
|
foreach (CharacterInfo characterInfo in gameSession.CrewManager.GetCharacterInfos())
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession.Mission is CombatMission &&
|
if (GameMain.GameSession.Mission is CombatMission &&
|
||||||
@@ -102,10 +105,11 @@ namespace Barotrauma
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var characterFrame = new GUIFrame(new Rectangle(x, 0, 170, 70), Color.Transparent, "", characterListBox);
|
var characterFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), characterListBox.Content.RectTransform, minSize: new Point(170, 0)))
|
||||||
characterFrame.OutlineColor = Color.Transparent;
|
{
|
||||||
characterFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
CanBeFocused = false,
|
||||||
characterFrame.CanBeFocused = false;
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
characterInfo.CreateCharacterFrame(characterFrame,
|
characterInfo.CreateCharacterFrame(characterFrame,
|
||||||
characterInfo.Job != null ? (characterInfo.Name + '\n' + "(" + characterInfo.Job.Name + ")") : characterInfo.Name, null);
|
characterInfo.Job != null ? (characterInfo.Name + '\n' + "(" + characterInfo.Job.Name + ")") : characterInfo.Name, null);
|
||||||
@@ -116,7 +120,19 @@ namespace Barotrauma
|
|||||||
Character character = characterInfo.Character;
|
Character character = characterInfo.Character;
|
||||||
if (character == null || character.IsDead)
|
if (character == null || character.IsDead)
|
||||||
{
|
{
|
||||||
statusText = TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.ToString());
|
if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
|
||||||
|
{
|
||||||
|
string errorMsg = "Character \"" + character.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ?
|
||||||
|
characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
|
||||||
|
TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
|
||||||
|
}
|
||||||
statusColor = Color.DarkRed;
|
statusColor = Color.DarkRed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -126,21 +142,24 @@ namespace Barotrauma
|
|||||||
statusText = TextManager.Get("Unconscious");
|
statusText = TextManager.Get("Unconscious");
|
||||||
statusColor = Color.DarkOrange;
|
statusColor = Color.DarkOrange;
|
||||||
}
|
}
|
||||||
else if (character.Health / character.MaxHealth < 0.8f)
|
else if (character.Vitality / character.MaxVitality < 0.8f)
|
||||||
{
|
{
|
||||||
statusText = TextManager.Get("Injured");
|
statusText = TextManager.Get("Injured");
|
||||||
statusColor = Color.DarkOrange;
|
statusColor = Color.DarkOrange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new GUITextBlock(
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), characterFrame.RectTransform, Anchor.BottomCenter),
|
||||||
new Rectangle(0, 0, 0, 20), statusText, statusColor * 0.8f, Color.White,
|
statusText, Color.White,
|
||||||
Alignment.BottomLeft, Alignment.Center,
|
textAlignment: Alignment.Center,
|
||||||
null, characterFrame, true, GUI.SmallFont);
|
wrap: true, font: GUI.SmallFont, style: null, color: statusColor * 0.8f);
|
||||||
|
|
||||||
x += characterFrame.Rect.Width + 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.BottomRight)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.05f,
|
||||||
|
UserData = "buttonarea"
|
||||||
|
};
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,25 @@ using Microsoft.Xna.Framework.Input;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
public partial class GameSettings
|
public partial class GameSettings
|
||||||
{
|
{
|
||||||
|
private enum Tab
|
||||||
|
{
|
||||||
|
General,
|
||||||
|
Graphics,
|
||||||
|
}
|
||||||
|
|
||||||
private GUIFrame settingsFrame;
|
private GUIFrame settingsFrame;
|
||||||
private GUIButton applyButton;
|
private GUIButton applyButton;
|
||||||
|
|
||||||
|
private GUIFrame[] tabs;
|
||||||
|
private GUIButton[] tabButtons;
|
||||||
|
|
||||||
|
public Action OnHUDScaleChanged;
|
||||||
|
|
||||||
public GUIFrame SettingsFrame
|
public GUIFrame SettingsFrame
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -22,24 +32,26 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyOrMouse KeyBind(InputType inputType)
|
private bool ChangeSliderText(GUIScrollBar scrollBar, float barScroll)
|
||||||
{
|
|
||||||
return keyMapping[(int)inputType];
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ChangeSoundVolume(GUIScrollBar scrollBar, float barScroll)
|
|
||||||
{
|
{
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
SoundVolume = barScroll;
|
GUITextBlock text = scrollBar.UserData as GUITextBlock;
|
||||||
|
//search for percentage value
|
||||||
return true;
|
int index = text.Text.IndexOf("%");
|
||||||
}
|
string label = text.Text;
|
||||||
|
//if "%" is found
|
||||||
private bool ChangeMusicVolume(GUIScrollBar scrollBar, float barScroll)
|
if(index > 0)
|
||||||
{
|
{
|
||||||
UnsavedSettings = true;
|
while(true)
|
||||||
MusicVolume = barScroll;
|
{
|
||||||
|
//search for end of label
|
||||||
|
index -= 1;
|
||||||
|
if (text.Text[index] == ' ')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
label = text.Text.Substring(0, index);
|
||||||
|
}
|
||||||
|
text.Text = label + " " + barScroll * 100 + "%";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,24 +62,57 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateSettingsFrame()
|
private void CreateSettingsFrame()
|
||||||
{
|
{
|
||||||
settingsFrame = new GUIFrame(new Rectangle(0, 0, 500, 500), null, Alignment.Center, "");
|
settingsFrame = new GUIFrame(new RectTransform(new Point(500, 500), GUI.Canvas, Anchor.Center));
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, -30, 0, 30), TextManager.Get("Settings"), "", Alignment.TopCenter, Alignment.TopCenter, settingsFrame, false, GUI.LargeFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), settingsFrame.RectTransform),
|
||||||
|
TextManager.Get("Settings"), textAlignment: Alignment.Center, font: GUI.LargeFont);
|
||||||
|
|
||||||
|
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.8f), settingsFrame.RectTransform, Anchor.Center)
|
||||||
|
{ RelativeOffset = new Vector2(0.0f, 0.06f) }, style: null);
|
||||||
|
|
||||||
int x = 0, y = 10;
|
var tabButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.05f), settingsFrame.RectTransform, Anchor.TopCenter)
|
||||||
|
{ RelativeOffset = new Vector2(0.0f, 0.1f) }, isHorizontal: true);
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, y, 20, 20), TextManager.Get("Resolution"), "", Alignment.TopLeft, Alignment.TopLeft, settingsFrame);
|
tabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length];
|
||||||
var resolutionDD = new GUIDropDown(new Rectangle(0, y + 20, 180, 20), "", "", settingsFrame);
|
tabButtons = new GUIButton[tabs.Length];
|
||||||
resolutionDD.OnSelected = SelectResolution;
|
foreach (Tab tab in Enum.GetValues(typeof(Tab)))
|
||||||
|
{
|
||||||
|
tabs[(int)tab] = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.91f), paddedFrame.RectTransform), style: "InnerFrame")
|
||||||
|
{
|
||||||
|
UserData = tab
|
||||||
|
};
|
||||||
|
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform), tab.ToString())
|
||||||
|
{
|
||||||
|
UserData = tab,
|
||||||
|
OnClicked = (bt, userdata) => { SelectTab((Tab)userdata); return true; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var supportedModes = new List<DisplayMode>();
|
var buttonArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.08f), paddedFrame.RectTransform, Anchor.BottomCenter), style: null);
|
||||||
|
|
||||||
|
/// Graphics tab --------------------------------------------------------------
|
||||||
|
|
||||||
|
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.CenterLeft)
|
||||||
|
{ RelativeOffset = new Vector2(0.02f, 0.0f) }) { RelativeSpacing = 0.01f, Stretch = true };
|
||||||
|
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.CenterRight)
|
||||||
|
{ RelativeOffset = new Vector2(0.02f, 0.0f) }) { RelativeSpacing = 0.01f, Stretch = true };
|
||||||
|
|
||||||
|
var supportedDisplayModes = new List<DisplayMode>();
|
||||||
foreach (DisplayMode mode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
|
foreach (DisplayMode mode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
|
||||||
{
|
{
|
||||||
if (supportedModes.FirstOrDefault(m => m.Width == mode.Width && m.Height == mode.Height) != null) continue;
|
if (supportedDisplayModes.Any(m => m.Width == mode.Width && m.Height == mode.Height)) continue;
|
||||||
|
supportedDisplayModes.Add(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("Resolution"));
|
||||||
|
var resolutionDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), elementCount: supportedDisplayModes.Count)
|
||||||
|
{
|
||||||
|
OnSelected = SelectResolution
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (DisplayMode mode in supportedDisplayModes)
|
||||||
|
{
|
||||||
resolutionDD.AddItem(mode.Width + "x" + mode.Height, mode);
|
resolutionDD.AddItem(mode.Width + "x" + mode.Height, mode);
|
||||||
supportedModes.Add(mode);
|
|
||||||
|
|
||||||
if (GraphicsWidth == mode.Width && GraphicsHeight == mode.Height) resolutionDD.SelectItem(mode);
|
if (GraphicsWidth == mode.Width && GraphicsHeight == mode.Height) resolutionDD.SelectItem(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,21 +120,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
resolutionDD.SelectItem(GraphicsAdapter.DefaultAdapter.SupportedDisplayModes.Last());
|
resolutionDD.SelectItem(GraphicsAdapter.DefaultAdapter.SupportedDisplayModes.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
y += 50;
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("DisplayMode"));
|
||||||
|
var displayModeDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform));
|
||||||
//var fullScreenTick = new GUITickBox(new Rectangle(x, y, 20, 20), "Fullscreen", Alignment.TopLeft, settingsFrame);
|
|
||||||
//fullScreenTick.OnSelected = ToggleFullScreen;
|
|
||||||
//fullScreenTick.Selected = FullScreenEnabled;
|
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(x, y, 20, 20), TextManager.Get("DisplayMode"), "", Alignment.TopLeft, Alignment.TopLeft, settingsFrame);
|
|
||||||
var displayModeDD = new GUIDropDown(new Rectangle(x, y + 20, 180, 20), "", "", settingsFrame);
|
|
||||||
displayModeDD.AddItem(TextManager.Get("Fullscreen"), WindowMode.Fullscreen);
|
displayModeDD.AddItem(TextManager.Get("Fullscreen"), WindowMode.Fullscreen);
|
||||||
displayModeDD.AddItem(TextManager.Get("Windowed"), WindowMode.Windowed);
|
displayModeDD.AddItem(TextManager.Get("Windowed"), WindowMode.Windowed);
|
||||||
displayModeDD.AddItem(TextManager.Get("BorderlessWindowed"), WindowMode.BorderlessWindowed);
|
displayModeDD.AddItem(TextManager.Get("BorderlessWindowed"), WindowMode.BorderlessWindowed);
|
||||||
|
|
||||||
displayModeDD.SelectItem(GameMain.Config.WindowMode);
|
displayModeDD.SelectItem(GameMain.Config.WindowMode);
|
||||||
|
|
||||||
displayModeDD.OnSelected = (guiComponent, obj) =>
|
displayModeDD.OnSelected = (guiComponent, obj) =>
|
||||||
{
|
{
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
@@ -97,66 +134,318 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
y += 70;
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), style: null);
|
||||||
|
|
||||||
GUITickBox vsyncTickBox = new GUITickBox(new Rectangle(0, y, 20, 20), TextManager.Get("EnableVSync"), Alignment.CenterY | Alignment.Left, settingsFrame);
|
GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("EnableVSync"))
|
||||||
vsyncTickBox.OnSelected = (GUITickBox box) =>
|
{
|
||||||
|
OnSelected = (GUITickBox box) =>
|
||||||
|
{
|
||||||
|
VSyncEnabled = box.Selected;
|
||||||
|
GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = VSyncEnabled;
|
||||||
|
GameMain.GraphicsDeviceManager.ApplyChanges();
|
||||||
|
UnsavedSettings = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Selected = VSyncEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), leftColumn.RectTransform), style: null);
|
||||||
|
GUITextBlock particleLimitText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ParticleLimit"));
|
||||||
|
GUIScrollBar particleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
||||||
|
barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = particleLimitText,
|
||||||
|
BarScroll = (ParticleLimit - 200) / 1300.0f,
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
ParticleLimit = 200 + (int)(scroll * 1300.0f);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.1f
|
||||||
|
};
|
||||||
|
particleScrollBar.OnMoved(particleScrollBar, particleScrollBar.BarScroll);
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LosEffect"));
|
||||||
|
var losModeDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform));
|
||||||
|
losModeDD.AddItem(TextManager.Get("LosModeNone"), LosMode.None);
|
||||||
|
losModeDD.AddItem(TextManager.Get("LosModeTransparent"), LosMode.Transparent);
|
||||||
|
losModeDD.AddItem(TextManager.Get("LosModeOpaque"), LosMode.Opaque);
|
||||||
|
losModeDD.SelectItem(GameMain.Config.LosMode);
|
||||||
|
losModeDD.OnSelected = (guiComponent, obj) =>
|
||||||
{
|
{
|
||||||
VSyncEnabled = !VSyncEnabled;
|
|
||||||
GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = VSyncEnabled;
|
|
||||||
GameMain.GraphicsDeviceManager.ApplyChanges();
|
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
|
GameMain.Config.LosMode = (LosMode)guiComponent.UserData;
|
||||||
|
//don't allow changing los mode when playing as a client
|
||||||
|
if (GameMain.Client == null)
|
||||||
|
{
|
||||||
|
GameMain.LightManager.LosMode = GameMain.Config.LosMode;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
|
||||||
|
GUITextBlock LightText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LightMapScale"))
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("LightMapScaleToolTip")
|
||||||
|
};
|
||||||
|
GUIScrollBar lightScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
||||||
|
barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = LightText,
|
||||||
|
ToolTip = TextManager.Get("LightMapScaleToolTip"),
|
||||||
|
BarScroll = MathUtils.InverseLerp(0.2f, 1.0f, LightMapScale),
|
||||||
|
OnMoved = (scrollBar, barScroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, barScroll);
|
||||||
|
LightMapScale = MathHelper.Lerp(0.2f, 1.0f, barScroll);
|
||||||
|
UnsavedSettings = true; return true;
|
||||||
|
},
|
||||||
|
Step = 0.25f
|
||||||
|
};
|
||||||
|
lightScrollBar.OnMoved(lightScrollBar, lightScrollBar.BarScroll);
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
|
||||||
|
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("SpecularLighting"))
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("SpecularLightingToolTip"),
|
||||||
|
Selected = SpecularityEnabled,
|
||||||
|
OnSelected = (tickBox) =>
|
||||||
|
{
|
||||||
|
SpecularityEnabled = tickBox.Selected;
|
||||||
|
UnsavedSettings = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
|
||||||
|
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ChromaticAberration"))
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ChromaticAberrationToolTip"),
|
||||||
|
Selected = ChromaticAberrationEnabled,
|
||||||
|
OnSelected = (tickBox) =>
|
||||||
|
{
|
||||||
|
ChromaticAberrationEnabled = tickBox.Selected;
|
||||||
|
UnsavedSettings = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
|
||||||
|
|
||||||
|
GUITextBlock HUDScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("HUDScale"));
|
||||||
|
GUIScrollBar HUDScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
||||||
|
barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = HUDScaleText,
|
||||||
|
BarScroll = (HUDScale - MinHUDScale) / (MaxHUDScale - MinHUDScale),
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
HUDScale = MathHelper.Lerp(MinHUDScale, MaxHUDScale, scroll);
|
||||||
|
UnsavedSettings = true;
|
||||||
|
OnHUDScaleChanged?.Invoke();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.05f
|
||||||
|
};
|
||||||
|
HUDScaleScrollBar.OnMoved(HUDScaleScrollBar, HUDScaleScrollBar.BarScroll);
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
|
||||||
|
|
||||||
|
GUITextBlock inventoryScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("InventoryScale"));
|
||||||
|
GUIScrollBar inventoryScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = inventoryScaleText,
|
||||||
|
BarScroll = (InventoryScale - MinInventoryScale) / (MaxInventoryScale - MinInventoryScale),
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
InventoryScale = MathHelper.Lerp(MinInventoryScale, MaxInventoryScale, scroll);
|
||||||
|
UnsavedSettings = true;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.05f
|
||||||
|
};
|
||||||
|
inventoryScaleScrollBar.OnMoved(inventoryScaleScrollBar, inventoryScaleScrollBar.BarScroll);
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), rightColumn.RectTransform), style: null);
|
||||||
|
|
||||||
|
/// General tab --------------------------------------------------------------
|
||||||
|
|
||||||
|
leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.General].RectTransform, Anchor.CenterLeft)
|
||||||
|
{ RelativeOffset = new Vector2(0.02f, 0.0f) }) { RelativeSpacing = 0.01f, Stretch = true };
|
||||||
|
rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.General].RectTransform, Anchor.CenterRight)
|
||||||
|
{ RelativeOffset = new Vector2(0.02f, 0.0f) }) { RelativeSpacing = 0.01f, Stretch = true };
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("ContentPackages"));
|
||||||
|
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), leftColumn.RectTransform))
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (ContentPackage contentPackage in ContentPackage.List)
|
||||||
|
{
|
||||||
|
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), contentPackageList.Content.RectTransform, minSize: new Point(0, 15)), contentPackage.Name)
|
||||||
|
{
|
||||||
|
UserData = contentPackage,
|
||||||
|
OnSelected = SelectContentPackage,
|
||||||
|
Selected = SelectedContentPackages.Contains(contentPackage)
|
||||||
|
};
|
||||||
|
if (!contentPackage.IsCompatible())
|
||||||
|
{
|
||||||
|
tickBox.TextColor = Color.Red;
|
||||||
|
tickBox.Enabled = false;
|
||||||
|
tickBox.ToolTip = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
|
||||||
|
.Replace("[packagename]", contentPackage.Name)
|
||||||
|
.Replace("[packageversion]", contentPackage.GameVersion.ToString())
|
||||||
|
.Replace("[gameversion]", GameMain.Version.ToString());
|
||||||
|
}
|
||||||
|
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
|
||||||
|
{
|
||||||
|
tickBox.TextColor = Color.Red;
|
||||||
|
tickBox.Enabled = false;
|
||||||
|
tickBox.ToolTip = TextManager.Get("ContentPackageMissingCoreFiles")
|
||||||
|
.Replace("[packagename]", contentPackage.Name)
|
||||||
|
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), style: null);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("Language"));
|
||||||
|
var languageDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform));
|
||||||
|
foreach (string language in TextManager.AvailableLanguages)
|
||||||
|
{
|
||||||
|
languageDD.AddItem(language, language);
|
||||||
|
}
|
||||||
|
languageDD.SelectItem(TextManager.Language);
|
||||||
|
languageDD.OnSelected = (guiComponent, obj) =>
|
||||||
|
{
|
||||||
|
string newLanguage = obj as string;
|
||||||
|
if (newLanguage == Language) return true;
|
||||||
|
|
||||||
|
UnsavedSettings = true;
|
||||||
|
Language = newLanguage;
|
||||||
|
|
||||||
|
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
vsyncTickBox.Selected = VSyncEnabled;
|
|
||||||
|
|
||||||
y += 70;
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), style: null);
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, y, 100, 20), TextManager.Get("SoundVolume"), "", settingsFrame);
|
GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("SoundVolume"));
|
||||||
GUIScrollBar soundScrollBar = new GUIScrollBar(new Rectangle(0, y + 20, 150, 20), "", 0.1f, settingsFrame);
|
GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform),
|
||||||
soundScrollBar.BarScroll = SoundVolume;
|
barSize: 0.1f)
|
||||||
soundScrollBar.OnMoved = ChangeSoundVolume;
|
|
||||||
soundScrollBar.Step = 0.05f;
|
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(0, y + 40, 100, 20), TextManager.Get("MusicVolume"), "", settingsFrame);
|
|
||||||
GUIScrollBar musicScrollBar = new GUIScrollBar(new Rectangle(0, y + 60, 150, 20), "", 0.1f, settingsFrame);
|
|
||||||
musicScrollBar.BarScroll = MusicVolume;
|
|
||||||
musicScrollBar.OnMoved = ChangeMusicVolume;
|
|
||||||
musicScrollBar.Step = 0.05f;
|
|
||||||
|
|
||||||
x = 200;
|
|
||||||
y = 10;
|
|
||||||
|
|
||||||
new GUITextBlock(new Rectangle(x, y, 20, 20), TextManager.Get("ContentPackage"), "", Alignment.TopLeft, Alignment.TopLeft, settingsFrame);
|
|
||||||
var contentPackageDD = new GUIDropDown(new Rectangle(x, y + 20, 200, 20), "", "", settingsFrame);
|
|
||||||
contentPackageDD.OnSelected = SelectContentPackage;
|
|
||||||
|
|
||||||
foreach (ContentPackage contentPackage in ContentPackage.list)
|
|
||||||
{
|
{
|
||||||
contentPackageDD.AddItem(contentPackage.Name, contentPackage);
|
UserData = soundVolumeText,
|
||||||
if (SelectedContentPackage == contentPackage) contentPackageDD.SelectItem(contentPackage);
|
BarScroll = SoundVolume,
|
||||||
}
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
SoundVolume = scroll;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.05f
|
||||||
|
};
|
||||||
|
soundScrollBar.OnMoved(soundScrollBar, soundScrollBar.BarScroll);
|
||||||
|
|
||||||
y += 50;
|
GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("MusicVolume"));
|
||||||
new GUITextBlock(new Rectangle(x, y, 100, 20), TextManager.Get("Controls"), "", settingsFrame);
|
GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform),
|
||||||
y += 30;
|
barSize: 0.1f)
|
||||||
var inputNames = Enum.GetNames(typeof(InputType));
|
{
|
||||||
|
UserData = musicVolumeText,
|
||||||
|
BarScroll = MusicVolume,
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
MusicVolume = scroll;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.05f
|
||||||
|
};
|
||||||
|
musicScrollBar.OnMoved(musicScrollBar, musicScrollBar.BarScroll);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("Controls"));
|
||||||
|
|
||||||
|
var inputFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform))
|
||||||
|
{
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
var inputNames = Enum.GetValues(typeof(InputType));
|
||||||
for (int i = 0; i < inputNames.Length; i++)
|
for (int i = 0; i < inputNames.Length; i++)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new Rectangle(x, y, 100, 18), inputNames[i] + ": ", "", Alignment.TopLeft, Alignment.CenterLeft, settingsFrame);
|
var inputContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), inputFrame.RectTransform), style: null);
|
||||||
var keyBox = new GUITextBox(new Rectangle(x + 100, y, 120, 18), null, null, Alignment.TopLeft, Alignment.CenterLeft, "", settingsFrame);
|
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), inputContainer.RectTransform), TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont);
|
||||||
|
var keyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), inputContainer.RectTransform, Anchor.TopRight),
|
||||||
keyBox.Text = keyMapping[i].ToString();
|
text: keyMapping[i].ToString(), font: GUI.SmallFont)
|
||||||
keyBox.UserData = i;
|
{
|
||||||
|
UserData = i
|
||||||
|
};
|
||||||
keyBox.OnSelected += KeyBoxSelected;
|
keyBox.OnSelected += KeyBoxSelected;
|
||||||
keyBox.SelectedColor = Color.Gold * 0.3f;
|
keyBox.SelectedColor = Color.Gold * 0.3f;
|
||||||
|
|
||||||
y += 20;
|
|
||||||
}
|
}
|
||||||
|
GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("AimAssist"));
|
||||||
|
GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
||||||
|
barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = aimAssistText,
|
||||||
|
BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount),
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
ChangeSliderText(scrollBar, scroll);
|
||||||
|
AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.1f
|
||||||
|
};
|
||||||
|
aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll);
|
||||||
|
|
||||||
applyButton = new GUIButton(new Rectangle(0, 0, 100, 20), TextManager.Get("ApplySettingsButton"), Alignment.BottomRight, "", settingsFrame);
|
new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft),
|
||||||
|
TextManager.Get("Cancel"))
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
OnClicked = (x, y) =>
|
||||||
|
{
|
||||||
|
if (GameMain.Config.UnsavedSettings) GameMain.Config.Load("config.xml");
|
||||||
|
if (Screen.Selected == GameMain.MainMenuScreen) GameMain.MainMenuScreen.SelectTab(0);
|
||||||
|
GUI.SettingsMenuOpen = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
applyButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomRight),
|
||||||
|
TextManager.Get("ApplySettingsButton"))
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
applyButton.OnClicked = ApplyClicked;
|
applyButton.OnClicked = ApplyClicked;
|
||||||
|
|
||||||
|
SelectTab(Tab.General);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectTab(Tab tab)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tabs.Length; i++)
|
||||||
|
{
|
||||||
|
tabs[i].Visible = (Tab)tabs[i].UserData == tab;
|
||||||
|
tabButtons[i].Selected = tabs[i].Visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void KeyBoxSelected(GUITextBox textBox, Keys key)
|
private void KeyBoxSelected(GUITextBox textBox, Keys key)
|
||||||
@@ -174,15 +463,48 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GraphicsWidth = mode.Width;
|
GraphicsWidth = mode.Width;
|
||||||
GraphicsHeight = mode.Height;
|
GraphicsHeight = mode.Height;
|
||||||
|
GameMain.Instance.ApplyGraphicsSettings();
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectContentPackage(GUIComponent select, object userData)
|
private bool SelectContentPackage(GUITickBox tickBox)
|
||||||
{
|
{
|
||||||
GameMain.Config.SelectedContentPackage = (ContentPackage)userData;
|
var contentPackage = tickBox.UserData as ContentPackage;
|
||||||
|
if (contentPackage.CorePackage)
|
||||||
|
{
|
||||||
|
if (tickBox.Selected)
|
||||||
|
{
|
||||||
|
//make sure no other core packages are selected
|
||||||
|
SelectedContentPackages.RemoveWhere(cp => cp.CorePackage && cp != contentPackage);
|
||||||
|
SelectedContentPackages.Add(contentPackage);
|
||||||
|
foreach (GUITickBox otherTickBox in tickBox.Parent.Children)
|
||||||
|
{
|
||||||
|
ContentPackage otherContentPackage = otherTickBox.UserData as ContentPackage;
|
||||||
|
if (otherContentPackage == contentPackage) continue;
|
||||||
|
otherTickBox.Selected = SelectedContentPackages.Contains(otherContentPackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (SelectedContentPackages.Contains(contentPackage))
|
||||||
|
{
|
||||||
|
//core packages cannot be deselected, only switched by selecting another core package
|
||||||
|
new GUIMessageBox(TextManager.Get("Warning"), TextManager.Get("CorePackageRequiredWarning"));
|
||||||
|
tickBox.Selected = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tickBox.Selected)
|
||||||
|
{
|
||||||
|
SelectedContentPackages.Add(contentPackage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedContentPackages.Remove(contentPackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -190,9 +512,14 @@ namespace Barotrauma
|
|||||||
private IEnumerable<object> WaitForKeyPress(GUITextBox keyBox)
|
private IEnumerable<object> WaitForKeyPress(GUITextBox keyBox)
|
||||||
{
|
{
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
while (keyBox.Selected && PlayerInput.GetKeyboardState.GetPressedKeys().Length == 0
|
while (PlayerInput.LeftButtonHeld() || PlayerInput.LeftButtonClicked())
|
||||||
&& !PlayerInput.LeftButtonClicked() && !PlayerInput.RightButtonClicked())
|
{
|
||||||
|
//wait for the mouse to be released, so that we don't interpret clicking on the textbox as the keybinding
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
}
|
||||||
|
while (keyBox.Selected && PlayerInput.GetKeyboardState.GetPressedKeys().Length == 0 &&
|
||||||
|
!PlayerInput.LeftButtonClicked() && !PlayerInput.RightButtonClicked() && !PlayerInput.MidButtonClicked())
|
||||||
{
|
{
|
||||||
if (Screen.Selected != GameMain.MainMenuScreen && !GUI.SettingsMenuOpen) yield return CoroutineStatus.Success;
|
if (Screen.Selected != GameMain.MainMenuScreen && !GUI.SettingsMenuOpen) yield return CoroutineStatus.Success;
|
||||||
|
|
||||||
@@ -213,6 +540,11 @@ namespace Barotrauma
|
|||||||
keyMapping[keyIndex] = new KeyOrMouse(1);
|
keyMapping[keyIndex] = new KeyOrMouse(1);
|
||||||
keyBox.Text = "Mouse2";
|
keyBox.Text = "Mouse2";
|
||||||
}
|
}
|
||||||
|
else if (PlayerInput.MidButtonClicked())
|
||||||
|
{
|
||||||
|
keyMapping[keyIndex] = new KeyOrMouse(2);
|
||||||
|
keyBox.Text = "Mouse3";
|
||||||
|
}
|
||||||
else if (PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0)
|
else if (PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0)
|
||||||
{
|
{
|
||||||
Keys key = PlayerInput.GetKeyboardState.GetPressedKeys()[0];
|
Keys key = PlayerInput.GetKeyboardState.GetPressedKeys()[0];
|
||||||
@@ -231,7 +563,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool ApplyClicked(GUIButton button, object userData)
|
private bool ApplyClicked(GUIButton button, object userData)
|
||||||
{
|
{
|
||||||
Save("config.xml");
|
Save();
|
||||||
|
|
||||||
settingsFrame.Flash(Color.Green);
|
settingsFrame.Flash(Color.Green);
|
||||||
|
|
||||||
@@ -242,9 +574,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (GameMain.GraphicsWidth != GameMain.Config.GraphicsWidth || GameMain.GraphicsHeight != GameMain.Config.GraphicsHeight)
|
if (GameMain.GraphicsWidth != GameMain.Config.GraphicsWidth || GameMain.GraphicsHeight != GameMain.Config.GraphicsHeight)
|
||||||
{
|
{
|
||||||
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredText"));
|
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredResolution"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Screen.Selected != GameMain.MainMenuScreen) GUI.SettingsMenuOpen = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,78 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class CharacterInventory : Inventory
|
partial class CharacterInventory : Inventory
|
||||||
{
|
{
|
||||||
private static Texture2D icons;
|
public enum Layout
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Center
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum QuickUseAction
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Equip,
|
||||||
|
Unequip,
|
||||||
|
Drop,
|
||||||
|
TakeFromContainer,
|
||||||
|
TakeFromCharacter,
|
||||||
|
PutToContainer,
|
||||||
|
PutToCharacter,
|
||||||
|
UseTreatment
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
|
||||||
|
|
||||||
|
private Point screenResolution;
|
||||||
|
|
||||||
public Vector2[] SlotPositions;
|
public Vector2[] SlotPositions;
|
||||||
|
|
||||||
private GUIButton[] useOnSelfButton;
|
private Layout layout;
|
||||||
|
public Layout CurrentLayout
|
||||||
partial void InitProjSpecific()
|
|
||||||
{
|
{
|
||||||
useOnSelfButton = new GUIButton[2];
|
get { return layout; }
|
||||||
|
set
|
||||||
if (icons == null) icons = TextureLoader.FromFile("Content/UI/inventoryIcons.png");
|
|
||||||
|
|
||||||
SlotPositions = new Vector2[limbSlots.Length];
|
|
||||||
|
|
||||||
int rectWidth = 40, rectHeight = 40;
|
|
||||||
int spacing = 10;
|
|
||||||
for (int i = 0; i < SlotPositions.Length; i++)
|
|
||||||
{
|
{
|
||||||
switch (i)
|
if (layout == value) return;
|
||||||
{
|
layout = value;
|
||||||
//head, torso, legs
|
SetSlotPositions(layout);
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
SlotPositions[i] = new Vector2(
|
|
||||||
spacing,
|
|
||||||
GameMain.GraphicsHeight - (spacing + rectHeight) * (3 - i));
|
|
||||||
break;
|
|
||||||
//lefthand, righthand
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
SlotPositions[i] = new Vector2(
|
|
||||||
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 1),
|
|
||||||
GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
|
|
||||||
|
|
||||||
useOnSelfButton[i - 3] = new GUIButton(
|
|
||||||
new Rectangle((int)SlotPositions[i].X, (int)(SlotPositions[i].Y - spacing - rectHeight),
|
|
||||||
rectWidth, rectHeight), TextManager.Get("UseItemButton"), "")
|
|
||||||
{
|
|
||||||
UserData = i,
|
|
||||||
OnClicked = UseItemOnSelf
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
//face
|
|
||||||
case 5:
|
|
||||||
SlotPositions[i] = new Vector2(
|
|
||||||
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 5),
|
|
||||||
GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
|
|
||||||
|
|
||||||
break;
|
|
||||||
//id card
|
|
||||||
case 6:
|
|
||||||
SlotPositions[i] = new Vector2(
|
|
||||||
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 5),
|
|
||||||
GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SlotPositions[i] = new Vector2(
|
|
||||||
spacing * 2 + rectWidth + (spacing + rectWidth) * ((i - 7) % 5),
|
|
||||||
GameMain.GraphicsHeight - (spacing + rectHeight) * ((i > 11) ? 2 : 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public bool Hidden { get; set; }
|
||||||
|
|
||||||
private bool UseItemOnSelf(GUIButton button, object obj)
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
if (!(obj is int)) return false;
|
Hidden = true;
|
||||||
|
|
||||||
int slotIndex = (int)obj;
|
if (limbSlotIcons == null)
|
||||||
|
{
|
||||||
|
limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
|
||||||
|
|
||||||
return UseItemOnSelf(slotIndex);
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotPositions = new Vector2[SlotTypes.Length];
|
||||||
|
CurrentLayout = Layout.Default;
|
||||||
|
SetSlotPositions(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
|
protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
|
||||||
{
|
{
|
||||||
base.PutItem(item, i, user, removeItem, createNetworkEvent);
|
base.PutItem(item, i, user, removeItem, createNetworkEvent);
|
||||||
@@ -98,127 +85,400 @@ namespace Barotrauma
|
|||||||
CreateSlots();
|
CreateSlots();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateSlots()
|
public override void CreateSlots()
|
||||||
{
|
{
|
||||||
if (slots == null) slots = new InventorySlot[capacity];
|
if (slots == null) slots = new InventorySlot[capacity];
|
||||||
|
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
InventorySlot prevSlot = slots[i];
|
||||||
|
|
||||||
|
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 rectWidth = 40, rectHeight = 40;
|
if (Items[i] != null)
|
||||||
|
{
|
||||||
|
ItemContainer itemContainer = Items[i].GetComponent<ItemContainer>();
|
||||||
|
if (itemContainer != null)
|
||||||
|
{
|
||||||
|
if (itemContainer.InventoryTopSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryTopSprite.size.X * UIScale));
|
||||||
|
if (itemContainer.InventoryBottomSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryBottomSprite.size.X * UIScale));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slots[i] = new InventorySlot(slotRect)
|
||||||
|
{
|
||||||
|
SubInventoryDir = Math.Sign(HUDLayoutSettings.InventoryAreaUpper.Bottom - slotRect.Center.Y),
|
||||||
|
Disabled = false,
|
||||||
|
SlotSprite = slotSprite,
|
||||||
|
Color = SlotTypes[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f
|
||||||
|
};
|
||||||
|
if (prevSlot != null)
|
||||||
|
{
|
||||||
|
slots[i].DrawOffset = prevSlot.DrawOffset;
|
||||||
|
slots[i].Color = prevSlot.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSlot?.ParentInventory == this && selectedSlot.SlotIndex == i)
|
||||||
|
{
|
||||||
|
selectedSlot = new SlotReference(this, slots[i], i, selectedSlot.IsSubSlot, selectedSlot.Inventory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssignQuickUseNumKeys();
|
||||||
|
|
||||||
|
highlightedSubInventorySlots.Clear();
|
||||||
|
|
||||||
|
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
CalculateBackgroundFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CalculateBackgroundFrame()
|
||||||
|
{
|
||||||
|
Rectangle frame = Rectangle.Empty;
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
if (frame == Rectangle.Empty)
|
||||||
|
{
|
||||||
|
frame = slots[i].Rect;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
frame = Rectangle.Union(frame, slots[i].Rect);
|
||||||
|
}
|
||||||
|
frame.Inflate(10, 30);
|
||||||
|
frame.Location -= new Point(0, 25);
|
||||||
|
BackgroundFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool HideSlot(int i)
|
||||||
|
{
|
||||||
|
if (slots[i].Disabled || (hideEmptySlot[i] && Items[i] == null)) return true;
|
||||||
|
|
||||||
|
//no need to draw the right hand slot if the item is in both hands
|
||||||
|
if (Items[i] != null && SlotTypes[i] == InvSlotType.RightHand && IsInLimbSlot(Items[i], InvSlotType.LeftHand))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't show the equip slot if the item is also in the default inventory
|
||||||
|
if (SlotTypes[i] != InvSlotType.Any && Items[i] != null)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < capacity; j++)
|
||||||
|
{
|
||||||
|
if (SlotTypes[j] == InvSlotType.Any && Items[j] == Items[i]) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSlotPositions(Layout layout)
|
||||||
|
{
|
||||||
|
int spacing = (int)(10 * UIScale);
|
||||||
|
Point slotSize = (slotSpriteSmall.size * UIScale).ToPoint();
|
||||||
|
int bottomOffset = slotSize.Y + spacing * 2 + ContainedIndicatorHeight;
|
||||||
|
|
||||||
|
if (slots == null) CreateSlots();
|
||||||
|
|
||||||
|
var upperSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.Head;
|
||||||
|
|
||||||
|
switch (layout)
|
||||||
|
{
|
||||||
|
case Layout.Default:
|
||||||
|
{
|
||||||
|
int personalSlotCount = SlotTypes.Count(s => upperSlots.HasFlag(s));
|
||||||
|
int normalSlotCount = SlotTypes.Count(s => !upperSlots.HasFlag(s));
|
||||||
|
|
||||||
|
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (slotSize.X + spacing) / 2;
|
||||||
|
int upperX = HUDLayoutSettings.PortraitArea.X - slotSize.X;
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (upperSlots.HasFlag(SlotTypes[i]))
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset);
|
||||||
|
upperX -= slotSize.X + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||||
|
x += slotSize.X + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Layout.Right:
|
||||||
|
{
|
||||||
|
int extraOffset = 0;
|
||||||
|
int x = HUDLayoutSettings.InventoryAreaLower.Right;
|
||||||
|
int upperX = HUDLayoutSettings.InventoryAreaLower.Right;
|
||||||
|
for (int i = 0; i < slots.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
if (upperSlots.HasFlag(SlotTypes[i]))
|
||||||
|
{
|
||||||
|
upperX -= slotSize.X + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x -= slotSize.X + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int lowerX = x;
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
if (upperSlots.HasFlag(SlotTypes[i]))
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - spacing * 2);
|
||||||
|
upperX += slots[i].Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
|
||||||
|
x += slots[i].Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x = lowerX;
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (!HideSlot(i)) continue;
|
||||||
|
x -= slots[i].Rect.Width + spacing;
|
||||||
|
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Layout.Left:
|
||||||
|
{
|
||||||
|
int x = HUDLayoutSettings.InventoryAreaLower.X;
|
||||||
|
int upperX = x;
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
if (upperSlots.HasFlag(SlotTypes[i]))
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset * 2 - spacing * 2);
|
||||||
|
upperX += slots[i].Rect.Width + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 x = startX, y = startY;
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y += slots[0].Rect.Height + spacing + ContainedIndicatorHeight + slots[0].EquipButtonRect.Height;
|
||||||
|
x = startX;
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < SlotPositions.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i)) continue;
|
||||||
|
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;
|
||||||
|
n++;
|
||||||
|
if (n >= columns)
|
||||||
|
{
|
||||||
|
x = startX;
|
||||||
|
y += slots[i].Rect.Height + spacing + ContainedIndicatorHeight + slots[i].EquipButtonRect.Height;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateSlots();
|
||||||
|
if (layout == Layout.Default)
|
||||||
|
{
|
||||||
|
HUDLayoutSettings.InventoryTopY = slots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ControlInput(Camera cam)
|
||||||
|
{
|
||||||
|
base.ControlInput(cam);
|
||||||
|
// Ignore the background frame of this object in purpose, because it encompasses half of the screen.
|
||||||
|
if (highlightedSubInventorySlots.Any(i => i.Inventory != null && i.Inventory.BackgroundFrame.Contains(PlayerInput.MousePosition)))
|
||||||
|
{
|
||||||
|
cam.Freeze = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float deltaTime, Camera cam, bool isSubInventory = false)
|
||||||
|
{
|
||||||
|
if (!AccessibleWhenAlive && !character.IsDead)
|
||||||
|
{
|
||||||
|
syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Update(deltaTime, cam);
|
||||||
|
|
||||||
|
bool hoverOnInventory = GUI.MouseOn == null &&
|
||||||
|
((selectedSlot != null && selectedSlot.IsSubSlot) || (draggingItem != null && (draggingSlot == null || !draggingSlot.MouseOn())));
|
||||||
|
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
|
||||||
|
|
||||||
|
if (hoverOnInventory) HideTimer = 0.5f;
|
||||||
|
if (HideTimer > 0.0f) HideTimer -= deltaTime;
|
||||||
|
|
||||||
for (int i = 0; i < capacity; i++)
|
for (int i = 0; i < capacity; i++)
|
||||||
{
|
{
|
||||||
Rectangle slotRect = new Rectangle(
|
if (Items[i] != null && Items[i] != draggingItem && Character.Controlled?.Inventory == this &&
|
||||||
(int)(SlotPositions[i].X + DrawOffset.X),
|
GUI.KeyboardDispatcher.Subscriber == null &&
|
||||||
(int)(SlotPositions[i].Y + DrawOffset.Y),
|
slots[i].QuickUseKey != Keys.None && PlayerInput.KeyHit(slots[i].QuickUseKey))
|
||||||
rectWidth, rectHeight);
|
|
||||||
|
|
||||||
slots[i] = new InventorySlot(slotRect);
|
|
||||||
slots[i].Disabled = false;
|
|
||||||
slots[i].Color = limbSlots[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
MergeSlots();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void Update(float deltaTime, bool isSubInventory = false)
|
|
||||||
{
|
|
||||||
base.Update(deltaTime);
|
|
||||||
|
|
||||||
if (doubleClickedItem != null)
|
|
||||||
{
|
|
||||||
bool wasPut = false;
|
|
||||||
if (doubleClickedItem.ParentInventory != this)
|
|
||||||
{
|
{
|
||||||
wasPut = TryPutItem(doubleClickedItem, Character.Controlled, doubleClickedItem.AllowedSlots, true);
|
QuickUseItem(Items[i], true, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SlotReference> hideSubInventories = new List<SlotReference>();
|
||||||
|
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||||
|
{
|
||||||
|
if (highlightedSubInventorySlot.ParentInventory == this)
|
||||||
|
{
|
||||||
|
UpdateSubInventory(deltaTime, highlightedSubInventorySlot.SlotIndex, cam);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle hoverArea = GetSubInventoryHoverArea(highlightedSubInventorySlot);
|
||||||
|
if (highlightedSubInventorySlot.Inventory?.slots == null || (!hoverArea.Contains(PlayerInput.MousePosition)))
|
||||||
|
{
|
||||||
|
hideSubInventories.Add(highlightedSubInventorySlot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
|
highlightedSubInventorySlot.Inventory.HideTimer = 1.0f;
|
||||||
if (selectedContainer != null && selectedContainer.Inventory != null)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doubleClickedItem != null)
|
||||||
|
{
|
||||||
|
QuickUseItem(doubleClickedItem, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//activate the subinventory of the currently selected slot
|
||||||
|
if (selectedSlot?.ParentInventory == this)
|
||||||
|
{
|
||||||
|
var subInventory = GetSubInventory(selectedSlot.SlotIndex);
|
||||||
|
if (subInventory != null)
|
||||||
|
{
|
||||||
|
selectedSlot.Inventory = subInventory;
|
||||||
|
if (!highlightedSubInventorySlots.Any(s => s.Inventory == subInventory))
|
||||||
{
|
{
|
||||||
wasPut = selectedContainer.Inventory.TryPutItem(doubleClickedItem, Character.Controlled, doubleClickedItem.AllowedSlots, true);
|
var slot = selectedSlot;
|
||||||
}
|
highlightedSubInventorySlots.Add(selectedSlot);
|
||||||
else if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
UpdateSubInventory(deltaTime, selectedSlot.SlotIndex, cam);
|
||||||
{
|
|
||||||
wasPut = character.SelectedCharacter.Inventory.TryPutItem(doubleClickedItem, Character.Controlled, doubleClickedItem.AllowedSlots, true);
|
//hide previously opened subinventories if this one overlaps with them
|
||||||
}
|
Rectangle hoverArea = GetSubInventoryHoverArea(slot);
|
||||||
else if (character.SelectedBy != null && Character.Controlled == character.SelectedBy && character.SelectedBy.Inventory != null)
|
foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||||
{
|
|
||||||
wasPut = character.SelectedBy.Inventory.TryPutItem(doubleClickedItem, Character.Controlled, doubleClickedItem.AllowedSlots, true);
|
|
||||||
}
|
|
||||||
else //doubleclicked and no other inventory is selected
|
|
||||||
{
|
|
||||||
//not equipped -> attempt to equip
|
|
||||||
if (IsInLimbSlot(doubleClickedItem, InvSlotType.Any))
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < capacity; i++)
|
if (highlightedSubInventorySlot == slot) continue;
|
||||||
|
if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
|
||||||
{
|
{
|
||||||
if (limbSlots[i] == InvSlotType.Any || !doubleClickedItem.AllowedSlots.Any(a => a.HasFlag(limbSlots[i]))) continue;
|
hideSubInventories.Add(highlightedSubInventorySlot);
|
||||||
wasPut = TryPutItem(doubleClickedItem, i, true, false, Character.Controlled, true);
|
highlightedSubInventorySlot.Inventory.HideTimer = 0.0f;
|
||||||
if (wasPut) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//equipped -> attempt to unequip
|
}
|
||||||
else if (doubleClickedItem.AllowedSlots.Contains(InvSlotType.Any))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var subInventorySlot in hideSubInventories)
|
||||||
|
{
|
||||||
|
if (subInventorySlot.Inventory == null) continue;
|
||||||
|
subInventorySlot.Inventory.HideTimer -= deltaTime;
|
||||||
|
if (subInventorySlot.Inventory.HideTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
highlightedSubInventorySlots.Remove(subInventorySlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
if (Items[i] != null && Items[i].AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||||
|
{
|
||||||
|
slots[i].EquipButtonState = slots[i].EquipButtonRect.Contains(PlayerInput.MousePosition) ?
|
||||||
|
GUIComponent.ComponentState.Hover : GUIComponent.ComponentState.None;
|
||||||
|
if (PlayerInput.LeftButtonHeld() && PlayerInput.RightButtonHeld())
|
||||||
|
{
|
||||||
|
slots[i].EquipButtonState = GUIComponent.ComponentState.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slots[i].EquipButtonState != GUIComponent.ComponentState.Hover)
|
||||||
|
{
|
||||||
|
slots[i].QuickUseTimer = Math.Max(0.0f, slots[i].QuickUseTimer - deltaTime * 5.0f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var quickUseAction = GetQuickUseAction(Items[i], allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||||
|
slots[i].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)
|
||||||
|
{
|
||||||
|
slots[i].QuickUseButtonToolTip = "Hold to unequip";
|
||||||
|
if (PlayerInput.LeftButtonHeld())
|
||||||
{
|
{
|
||||||
wasPut = TryPutItem(doubleClickedItem, Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
|
slots[i].QuickUseTimer = Math.Max(0.1f, slots[i].QuickUseTimer + deltaTime);
|
||||||
|
if (slots[i].QuickUseTimer >= 1.0f)
|
||||||
|
{
|
||||||
|
CreateNetworkEvent();
|
||||||
|
Items[i].Drop(Character.Controlled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slots[i].QuickUseTimer = Math.Max(0.0f, slots[i].QuickUseTimer - deltaTime * 5.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
if (wasPut)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < capacity; i++)
|
|
||||||
{
|
{
|
||||||
if (Items[i] == doubleClickedItem) slots[i].ShowBorderHighlight(Color.Green, 0.1f, 0.9f);
|
if (PlayerInput.LeftButtonDown()) slots[i].EquipButtonState = GUIComponent.ComponentState.Pressed;
|
||||||
}
|
if (PlayerInput.LeftButtonClicked())
|
||||||
}
|
{
|
||||||
|
QuickUseItem(Items[i], allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||||
draggingItem = null;
|
}
|
||||||
GUI.PlayUISound(wasPut ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (highlightedSubInventorySlot != null)
|
|
||||||
{
|
|
||||||
if (highlightedSubInventorySlot.Inventory == this)
|
|
||||||
{
|
|
||||||
UpdateSubInventory(deltaTime, highlightedSubInventorySlot.SlotIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlightedSubInventory.slots == null ||
|
|
||||||
(!highlightedSubInventorySlot.Slot.InteractRect.Contains(PlayerInput.MousePosition) && !highlightedSubInventory.slots.Any(s => s.InteractRect.Contains(PlayerInput.MousePosition))))
|
|
||||||
{
|
|
||||||
highlightedSubInventory = null;
|
|
||||||
highlightedSubInventorySlot = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (selectedSlot?.Inventory == this)
|
|
||||||
{
|
|
||||||
var subInventory = GetSubInventory(selectedSlot.SlotIndex);
|
|
||||||
if (subInventory != null)
|
|
||||||
{
|
|
||||||
highlightedSubInventory = subInventory;
|
|
||||||
highlightedSubInventorySlot = selectedSlot;
|
|
||||||
UpdateSubInventory(deltaTime, highlightedSubInventorySlot.SlotIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (character == Character.Controlled)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < capacity; i++)
|
|
||||||
{
|
|
||||||
if ((selectedSlot == null || selectedSlot.SlotIndex != i) &&
|
|
||||||
Items[i] != null && Items[i].CanUseOnSelf && character.HasSelectedItem(Items[i]))
|
|
||||||
{
|
|
||||||
//-3 because selected items are in slots 3 and 4 (hands)
|
|
||||||
useOnSelfButton[i - 3].Update(deltaTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//cancel dragging if too far away from the container of the dragged item
|
//cancel dragging if too far away from the container of the dragged item
|
||||||
if (draggingItem != null)
|
if (draggingItem != null)
|
||||||
@@ -228,8 +488,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (rootContainer != null)
|
if (rootContainer != null)
|
||||||
{
|
{
|
||||||
rootInventory = rootContainer.ParentInventory != null ?
|
rootInventory = rootContainer.ParentInventory ?? rootContainer.GetComponent<ItemContainer>().Inventory;
|
||||||
rootContainer.ParentInventory : rootContainer.GetComponent<ItemContainer>().Inventory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rootInventory != null &&
|
if (rootInventory != null &&
|
||||||
@@ -237,98 +496,268 @@ namespace Barotrauma
|
|||||||
rootInventory.Owner != Character.Controlled.SelectedConstruction &&
|
rootInventory.Owner != Character.Controlled.SelectedConstruction &&
|
||||||
rootInventory.Owner != Character.Controlled.SelectedCharacter)
|
rootInventory.Owner != Character.Controlled.SelectedCharacter)
|
||||||
{
|
{
|
||||||
draggingItem = null;
|
//allow interacting if the container is linked to the item the character is interacting with
|
||||||
}
|
if (!(rootContainer != null &&
|
||||||
}
|
rootContainer.DisplaySideBySideWhenLinked &&
|
||||||
|
Character.Controlled.SelectedConstruction != null &&
|
||||||
|
rootContainer.linkedTo.Contains(Character.Controlled.SelectedConstruction)))
|
||||||
doubleClickedItem = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MergeSlots()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < capacity - 1; i++)
|
|
||||||
{
|
|
||||||
slots[i].State = GUIComponent.ComponentState.None;
|
|
||||||
if (slots[i].Disabled || Items[i] == null) continue;
|
|
||||||
|
|
||||||
for (int n = i + 1; n < capacity; n++)
|
|
||||||
{
|
|
||||||
if (Items[n] == Items[i])
|
|
||||||
{
|
{
|
||||||
slots[i].Rect = Rectangle.Union(slots[i].Rect, slots[n].Rect);
|
draggingItem = null;
|
||||||
slots[i].InteractRect = Rectangle.Union(slots[i].InteractRect, slots[n].InteractRect);
|
|
||||||
slots[n].Disabled = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightedSubInventory = null;
|
doubleClickedItem = null;
|
||||||
highlightedSubInventorySlot = null;
|
}
|
||||||
selectedSlot = null;
|
|
||||||
|
private void AssignQuickUseNumKeys()
|
||||||
|
{
|
||||||
|
int num = 1;
|
||||||
|
for (int i = 0; i < slots.Length; i++)
|
||||||
|
{
|
||||||
|
if (HideSlot(i))
|
||||||
|
{
|
||||||
|
slots[i].QuickUseKey = Keys.None;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SlotTypes[i] == InvSlotType.Any)
|
||||||
|
{
|
||||||
|
slots[i].QuickUseKey = Keys.D0 + num % 10;
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private QuickUseAction GetQuickUseAction(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
|
||||||
|
{
|
||||||
|
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null)
|
||||||
|
{
|
||||||
|
return QuickUseAction.UseTreatment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ParentInventory != this)
|
||||||
|
{
|
||||||
|
//in another inventory -> attempt to place in the character's inventory
|
||||||
|
if (allowInventorySwap)
|
||||||
|
{
|
||||||
|
return item.ParentInventory is CharacterInventory ?
|
||||||
|
QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
|
||||||
|
if (selectedContainer != null && selectedContainer.Inventory != null && allowInventorySwap)
|
||||||
|
{
|
||||||
|
//player has selected the inventory of another item -> attempt to move the item there
|
||||||
|
return QuickUseAction.PutToContainer;
|
||||||
|
}
|
||||||
|
else if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null && allowInventorySwap)
|
||||||
|
{
|
||||||
|
//player has selected the inventory of another character -> attempt to move the item there
|
||||||
|
return QuickUseAction.PutToCharacter;
|
||||||
|
}
|
||||||
|
else if (character.SelectedBy != null && Character.Controlled == character.SelectedBy &&
|
||||||
|
character.SelectedBy.Inventory != null && allowInventorySwap)
|
||||||
|
{
|
||||||
|
return QuickUseAction.TakeFromCharacter;
|
||||||
|
}
|
||||||
|
else if (allowEquip) //doubleclicked and no other inventory is selected
|
||||||
|
{
|
||||||
|
//not equipped -> attempt to equip
|
||||||
|
if (!character.HasEquippedItem(item))
|
||||||
|
{
|
||||||
|
return QuickUseAction.Equip;
|
||||||
|
}
|
||||||
|
//equipped -> attempt to unequip
|
||||||
|
else if (item.AllowedSlots.Contains(InvSlotType.Any))
|
||||||
|
{
|
||||||
|
return QuickUseAction.Unequip;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QuickUseAction.Drop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QuickUseAction.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void QuickUseItem(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
|
||||||
|
{
|
||||||
|
var quickUseAction = GetQuickUseAction(item, allowEquip, allowInventorySwap, allowApplyTreatment);
|
||||||
|
bool success = false;
|
||||||
|
switch (quickUseAction)
|
||||||
|
{
|
||||||
|
case QuickUseAction.Equip:
|
||||||
|
//attempt to put in a free slot first
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
if (Items[i] != null) continue;
|
||||||
|
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) continue;
|
||||||
|
success = TryPutItem(item, i, true, false, Character.Controlled, true);
|
||||||
|
if (success) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) continue;
|
||||||
|
//something else already equipped in the slot, attempt to unequip it
|
||||||
|
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any))
|
||||||
|
{
|
||||||
|
TryPutItem(Items[i], Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
|
||||||
|
}
|
||||||
|
success = TryPutItem(item, i, true, false, Character.Controlled, true);
|
||||||
|
if (success) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QuickUseAction.Unequip:
|
||||||
|
if (item.AllowedSlots.Contains(InvSlotType.Any))
|
||||||
|
{
|
||||||
|
success = TryPutItem(item, Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QuickUseAction.UseTreatment:
|
||||||
|
CharacterHealth.OpenHealthWindow?.OnItemDropped(item, ignoreMousePos: true);
|
||||||
|
return;
|
||||||
|
case QuickUseAction.Drop:
|
||||||
|
//do nothing, the item is dropped after a delay
|
||||||
|
return;
|
||||||
|
case QuickUseAction.PutToCharacter:
|
||||||
|
if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||||
|
{
|
||||||
|
//player has selected the inventory of another character -> attempt to move the item there
|
||||||
|
success = character.SelectedCharacter.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QuickUseAction.PutToContainer:
|
||||||
|
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
|
||||||
|
if (selectedContainer != null && selectedContainer.Inventory != null)
|
||||||
|
{
|
||||||
|
//player has selected the inventory of another item -> attempt to move the item there
|
||||||
|
success = selectedContainer.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QuickUseAction.TakeFromCharacter:
|
||||||
|
if (character.SelectedBy != null && Character.Controlled == character.SelectedBy &&
|
||||||
|
character.SelectedBy.Inventory != null)
|
||||||
|
{
|
||||||
|
//item is in the inventory of another character -> attempt to get the item from there
|
||||||
|
success = character.SelectedBy.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QuickUseAction.TakeFromContainer:
|
||||||
|
success = TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
|
{
|
||||||
|
if (Items[i] == item) slots[i].ShowBorderHighlight(Color.Green, 0.1f, 0.4f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draggingItem = null;
|
||||||
|
GUI.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||||
|
}
|
||||||
|
|
||||||
public void DrawOwn(SpriteBatch spriteBatch)
|
public void DrawOwn(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
|
if (!AccessibleWhenAlive && !character.IsDead) return;
|
||||||
if (slots == null) CreateSlots();
|
if (slots == null) CreateSlots();
|
||||||
|
if (GameMain.GraphicsWidth != screenResolution.X ||
|
||||||
Rectangle slotRect = new Rectangle(0, 0, 40, 40);
|
GameMain.GraphicsHeight != screenResolution.Y ||
|
||||||
|
prevUIScale != UIScale ||
|
||||||
for (int i = 0; i < capacity; i++)
|
prevHUDScale != GUI.Scale)
|
||||||
{
|
{
|
||||||
slotRect.X = (int)(SlotPositions[i].X + DrawOffset.X);
|
SetSlotPositions(layout);
|
||||||
slotRect.Y = (int)(SlotPositions[i].Y + DrawOffset.Y);
|
prevUIScale = UIScale;
|
||||||
|
prevHUDScale = GUI.Scale;
|
||||||
|
}
|
||||||
|
|
||||||
if (i == 1) //head
|
if (layout == Layout.Center)
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y),
|
CalculateBackgroundFrame();
|
||||||
new Rectangle(0, 0, 56, 128), Color.White * 0.7f, 0.0f,
|
GUI.DrawRectangle(spriteBatch, BackgroundFrame, Color.Black * 0.8f, true);
|
||||||
new Vector2(28.0f, 64.0f), Vector2.One,
|
GUI.DrawString(spriteBatch,
|
||||||
SpriteEffects.None, 0.1f);
|
new Vector2((int)(BackgroundFrame.Center.X - GUI.Font.MeasureString(character.Name).X / 2), (int)BackgroundFrame.Y + 5),
|
||||||
}
|
character.Name, Color.White * 0.9f);
|
||||||
else if (i == 3 || i == 4)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y),
|
|
||||||
new Rectangle(92, 41 * (4 - i), 36, 40), Color.White * 0.7f, 0.0f,
|
|
||||||
new Vector2(18.0f, 20.0f), Vector2.One,
|
|
||||||
SpriteEffects.None, 0.1f);
|
|
||||||
}
|
|
||||||
else if (i == 5)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y),
|
|
||||||
new Rectangle(57, 0, 31, 32), Color.White * 0.7f, 0.0f,
|
|
||||||
new Vector2(15.0f, 16.0f), Vector2.One,
|
|
||||||
SpriteEffects.None, 0.1f);
|
|
||||||
}
|
|
||||||
else if (i == 6)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y),
|
|
||||||
new Rectangle(62, 36, 22, 18), Color.White * 0.7f, 0.0f,
|
|
||||||
new Vector2(11.0f, 9.0f), Vector2.One,
|
|
||||||
SpriteEffects.None, 0.1f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Draw(spriteBatch);
|
base.Draw(spriteBatch);
|
||||||
|
|
||||||
if (character == Character.Controlled)
|
InventorySlot highlightedQuickUseSlot = null;
|
||||||
|
for (int i = 0; i < capacity; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < capacity; i++)
|
if (HideSlot(i)) continue;
|
||||||
|
|
||||||
|
if (Items[i] == null ||
|
||||||
|
(draggingItem == Items[i] && !slots[i].InteractRect.Contains(PlayerInput.MousePosition)) ||
|
||||||
|
!Items[i].AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||||
{
|
{
|
||||||
if ((selectedSlot == null || selectedSlot.SlotIndex != i) &&
|
//draw limb icons on empty slots
|
||||||
Items[i] != null && Items[i].CanUseOnSelf && character.HasSelectedItem(Items[i]))
|
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
|
||||||
{
|
{
|
||||||
useOnSelfButton[i - 3].Draw(spriteBatch);
|
var icon = limbSlotIcons[SlotTypes[i]];
|
||||||
|
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2(), Color.White * 0.3f, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (draggingItem == Items[i] && !slots[i].IsHighlighted) continue;
|
||||||
|
|
||||||
|
//draw hand icons if the item is equipped in a hand slot
|
||||||
|
if (IsInLimbSlot(Items[i], InvSlotType.LeftHand))
|
||||||
|
{
|
||||||
|
var icon = limbSlotIcons[InvSlotType.LeftHand];
|
||||||
|
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.X, slots[i].Rect.Bottom), Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
|
||||||
|
}
|
||||||
|
if (IsInLimbSlot(Items[i], InvSlotType.RightHand))
|
||||||
|
{
|
||||||
|
var icon = limbSlotIcons[InvSlotType.RightHand];
|
||||||
|
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.Right, slots[i].Rect.Bottom), 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;
|
||||||
|
highlightedQuickUseSlot = slots[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else if (character.HasEquippedItem(Items[i]))
|
||||||
|
{
|
||||||
|
quickUseHighlight.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color * 0.9f, quickUseHighlight.Origin, 0, UIScale * 0.85f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < capacity; i++)
|
if (highlightedQuickUseSlot != null && !string.IsNullOrEmpty(highlightedQuickUseSlot.QuickUseButtonToolTip))
|
||||||
{
|
{
|
||||||
if (slots[i].IsHighlighted)
|
GUIComponent.DrawToolTip(spriteBatch, highlightedQuickUseSlot.QuickUseButtonToolTip, highlightedQuickUseSlot.EquipButtonRect);
|
||||||
{
|
|
||||||
DrawSubInventory(spriteBatch, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ namespace Barotrauma.Items.Components
|
|||||||
private Vector2[] GetConvexHullCorners(Rectangle rect)
|
private Vector2[] GetConvexHullCorners(Rectangle rect)
|
||||||
{
|
{
|
||||||
Vector2[] corners = new Vector2[4];
|
Vector2[] corners = new Vector2[4];
|
||||||
corners[0] = new Vector2(rect.X, rect.Y - rect.Height);
|
corners[0] = new Vector2(rect.X - 1, rect.Y - rect.Height - 1);
|
||||||
corners[1] = new Vector2(rect.X, rect.Y);
|
corners[1] = new Vector2(rect.X - 1, rect.Y + 1);
|
||||||
corners[2] = new Vector2(rect.Right, rect.Y);
|
corners[2] = new Vector2(rect.Right + 1, rect.Y + 1);
|
||||||
corners[3] = new Vector2(rect.Right, rect.Y - rect.Height);
|
corners[3] = new Vector2(rect.Right + 1, rect.Y - rect.Height - 1);
|
||||||
|
|
||||||
return corners;
|
return corners;
|
||||||
}
|
}
|
||||||
@@ -26,10 +26,10 @@ namespace Barotrauma.Items.Components
|
|||||||
private void UpdateConvexHulls()
|
private void UpdateConvexHulls()
|
||||||
{
|
{
|
||||||
doorRect = new Rectangle(
|
doorRect = new Rectangle(
|
||||||
item.Rect.Center.X - (int)(doorSprite.size.X / 2),
|
item.Rect.Center.X - (int)(doorSprite.size.X / 2 * item.Scale),
|
||||||
item.Rect.Y - item.Rect.Height / 2 + (int)(doorSprite.size.Y / 2.0f),
|
item.Rect.Y - item.Rect.Height / 2 + (int)(doorSprite.size.Y / 2.0f * item.Scale),
|
||||||
(int)doorSprite.size.X,
|
(int)(doorSprite.size.X * item.Scale),
|
||||||
(int)doorSprite.size.Y);
|
(int)(doorSprite.size.Y * item.Scale));
|
||||||
|
|
||||||
Rectangle rect = doorRect;
|
Rectangle rect = doorRect;
|
||||||
if (isHorizontal)
|
if (isHorizontal)
|
||||||
@@ -43,7 +43,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (window.Height > 0 && window.Width > 0)
|
if (window.Height > 0 && window.Width > 0)
|
||||||
{
|
{
|
||||||
rect.Height = -window.Y;
|
rect.Height = -(int)(window.Y * item.Scale);
|
||||||
|
|
||||||
rect.Y += (int)(doorRect.Height * openState);
|
rect.Y += (int)(doorRect.Height * openState);
|
||||||
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
|
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
|
||||||
@@ -52,12 +52,11 @@ namespace Barotrauma.Items.Components
|
|||||||
if (convexHull2 != null)
|
if (convexHull2 != null)
|
||||||
{
|
{
|
||||||
Rectangle rect2 = doorRect;
|
Rectangle rect2 = doorRect;
|
||||||
rect2.Y = rect2.Y + window.Y - window.Height;
|
rect2.Y = rect2.Y + (int)((window.Y * item.Scale - window.Height * item.Scale));
|
||||||
|
|
||||||
rect2.Y += (int)(doorRect.Height * openState);
|
rect2.Y += (int)(doorRect.Height * openState);
|
||||||
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
|
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
|
||||||
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
|
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
|
||||||
//convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
|
||||||
|
|
||||||
if (rect2.Height == 0)
|
if (rect2.Height == 0)
|
||||||
{
|
{
|
||||||
@@ -86,7 +85,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing)
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
{
|
{
|
||||||
Color color = (item.IsSelected) ? Color.Green : Color.White;
|
Color color = Color.White;
|
||||||
if (brokenSprite == null)
|
if (brokenSprite == null)
|
||||||
{
|
{
|
||||||
//broken doors turn black if no broken sprite has been configured
|
//broken doors turn black if no broken sprite has been configured
|
||||||
@@ -101,7 +100,7 @@ namespace Barotrauma.Items.Components
|
|||||||
weldSpritePos.Y = -weldSpritePos.Y;
|
weldSpritePos.Y = -weldSpritePos.Y;
|
||||||
|
|
||||||
weldedSprite.Draw(spriteBatch,
|
weldedSprite.Draw(spriteBatch,
|
||||||
weldSpritePos, Color.White * (stuck / 100.0f), 0.0f, 1.0f);
|
weldSpritePos, Color.White * (stuck / 100.0f), scale: item.Scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openState == 1.0f)
|
if (openState == 1.0f)
|
||||||
@@ -122,7 +121,7 @@ namespace Barotrauma.Items.Components
|
|||||||
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
|
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
|
||||||
(int) doorSprite.SourceRect.Y,
|
(int) doorSprite.SourceRect.Y,
|
||||||
(int) (doorSprite.size.X * (1.0f - openState)), (int) doorSprite.size.Y),
|
(int) (doorSprite.size.X * (1.0f - openState)), (int) doorSprite.size.Y),
|
||||||
color, 0.0f, doorSprite.Origin, 1.0f, SpriteEffects.None, doorSprite.Depth);
|
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
||||||
@@ -132,7 +131,7 @@ namespace Barotrauma.Items.Components
|
|||||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||||
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
|
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
|
||||||
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
|
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
|
||||||
color * alpha, 0.0f, brokenSprite.Origin, scale, SpriteEffects.None,
|
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None,
|
||||||
brokenSprite.Depth);
|
brokenSprite.Depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +147,7 @@ namespace Barotrauma.Items.Components
|
|||||||
new Rectangle(doorSprite.SourceRect.X,
|
new Rectangle(doorSprite.SourceRect.X,
|
||||||
(int) (doorSprite.SourceRect.Y + doorSprite.size.Y * openState),
|
(int) (doorSprite.SourceRect.Y + doorSprite.size.Y * openState),
|
||||||
(int) doorSprite.size.X, (int) (doorSprite.size.Y * (1.0f - openState))),
|
(int) doorSprite.size.X, (int) (doorSprite.size.Y * (1.0f - openState))),
|
||||||
color, 0.0f, doorSprite.Origin, 1.0f, SpriteEffects.None, doorSprite.Depth);
|
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
||||||
@@ -158,7 +157,7 @@ namespace Barotrauma.Items.Components
|
|||||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||||
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
|
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
|
||||||
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
|
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
|
||||||
color * alpha, 0.0f, brokenSprite.Origin, scale, SpriteEffects.None, brokenSprite.Depth);
|
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None, brokenSprite.Depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class ElectricalDischarger : Powered
|
||||||
|
{
|
||||||
|
private static SpriteSheet electricitySprite;
|
||||||
|
|
||||||
|
private int frameOffset;
|
||||||
|
|
||||||
|
partial void InitProjSpecific()
|
||||||
|
{
|
||||||
|
if (electricitySprite == null)
|
||||||
|
{
|
||||||
|
electricitySprite = new SpriteSheet("Content/Lights/Electricity.png", 4, 4, new Vector2(0.5f, 0.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DischargeProjSpecific()
|
||||||
|
{
|
||||||
|
PlaySound(ActionType.OnUse, item.WorldPosition);
|
||||||
|
foreach (Node node in nodes)
|
||||||
|
{
|
||||||
|
GameMain.ParticleManager.CreateParticle("swirlysmoke", node.WorldPosition, Vector2.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawElectricity(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (nodes[i].Length <= 1.0f) continue;
|
||||||
|
var node = nodes[i];
|
||||||
|
electricitySprite.Draw(spriteBatch,
|
||||||
|
(i + frameOffset) % electricitySprite.FrameCount,
|
||||||
|
new Vector2(node.WorldPosition.X, -node.WorldPosition.Y),
|
||||||
|
Color.Lerp(Color.LightBlue, Color.White, Rand.Range(0.0f, 1.0f)),
|
||||||
|
electricitySprite.Origin, -node.Angle - MathHelper.PiOver2,
|
||||||
|
new Vector2(
|
||||||
|
Math.Min(node.Length / electricitySprite.FrameSize.X, 1.0f) * Rand.Range(0.5f, 2.0f),
|
||||||
|
node.Length / electricitySprite.FrameSize.Y) * Rand.Range(1.0f, 1.2f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameMain.DebugDraw)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (nodes[i].Length <= 1.0f) continue;
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Vector2(nodes[i].WorldPosition.X, -nodes[i].WorldPosition.Y), Vector2.One * 5, Color.LightCyan, isFilled: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
|
using Barotrauma.Sounds;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
@@ -10,25 +11,38 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
|
enum SoundSelectionMode
|
||||||
|
{
|
||||||
|
Random,
|
||||||
|
CharacterSpecific,
|
||||||
|
ItemSpecific,
|
||||||
|
All
|
||||||
|
}
|
||||||
|
|
||||||
class ItemSound
|
class ItemSound
|
||||||
{
|
{
|
||||||
public readonly Sound Sound;
|
public readonly RoundSound RoundSound;
|
||||||
public readonly ActionType Type;
|
public readonly ActionType Type;
|
||||||
|
|
||||||
public string VolumeProperty;
|
public string VolumeProperty;
|
||||||
|
public float VolumeMultiplier
|
||||||
|
{
|
||||||
|
get { return RoundSound.Volume; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Range
|
||||||
|
{
|
||||||
|
get { return RoundSound.Range; }
|
||||||
|
}
|
||||||
|
|
||||||
public float VolumeMultiplier;
|
|
||||||
|
|
||||||
public readonly float Range;
|
|
||||||
|
|
||||||
public readonly bool Loop;
|
public readonly bool Loop;
|
||||||
|
|
||||||
public ItemSound(Sound sound, ActionType type, float range, bool loop = false)
|
public ItemSound(RoundSound sound, ActionType type, bool loop = false)
|
||||||
{
|
{
|
||||||
this.Sound = sound;
|
this.RoundSound = sound;
|
||||||
this.Type = type;
|
this.Type = type;
|
||||||
this.Range = range;
|
|
||||||
|
|
||||||
this.Loop = loop;
|
this.Loop = loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,71 +50,260 @@ namespace Barotrauma.Items.Components
|
|||||||
partial class ItemComponent : ISerializableEntity
|
partial class ItemComponent : ISerializableEntity
|
||||||
{
|
{
|
||||||
private Dictionary<ActionType, List<ItemSound>> sounds;
|
private Dictionary<ActionType, List<ItemSound>> sounds;
|
||||||
|
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
|
||||||
|
|
||||||
private GUIFrame guiFrame;
|
public GUILayoutSettings DefaultLayout { get; protected set; }
|
||||||
|
public GUILayoutSettings AlternativeLayout { get; protected set; }
|
||||||
|
|
||||||
protected GUIFrame GuiFrame
|
public class GUILayoutSettings
|
||||||
{
|
{
|
||||||
get
|
public Vector2? RelativeSize { get; private set; }
|
||||||
|
public Point? AbsoluteSize { get; private set; }
|
||||||
|
public Vector2? RelativeOffset { get; private set; }
|
||||||
|
public Point? AbsoluteOffset { get; private set; }
|
||||||
|
public Anchor? Anchor { get; private set; }
|
||||||
|
public Pivot? Pivot { get; private set; }
|
||||||
|
|
||||||
|
public static GUILayoutSettings Load(XElement element)
|
||||||
{
|
{
|
||||||
if (guiFrame == null)
|
var layout = new GUILayoutSettings();
|
||||||
|
var relativeSize = XMLExtensions.GetAttributeVector2(element, "relativesize", Vector2.Zero);
|
||||||
|
var absoluteSize = XMLExtensions.GetAttributePoint(element, "absolutesize", new Point(-1000, -1000));
|
||||||
|
var relativeOffset = XMLExtensions.GetAttributeVector2(element, "relativeoffset", Vector2.Zero);
|
||||||
|
var absoluteOffset = XMLExtensions.GetAttributePoint(element, "absoluteoffset", new Point(-1000, -1000));
|
||||||
|
if (relativeSize.Length() > 0)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error: the component " + name + " in " + item.Name + " doesn't have a GuiFrame component");
|
layout.RelativeSize = relativeSize;
|
||||||
guiFrame = new GUIFrame(new Rectangle(0, 0, 100, 100), Color.Black);
|
|
||||||
}
|
}
|
||||||
return guiFrame;
|
if (absoluteSize.X > 0 && absoluteSize.Y > 0)
|
||||||
|
{
|
||||||
|
layout.AbsoluteSize = absoluteSize;
|
||||||
|
}
|
||||||
|
if (relativeOffset.Length() > 0)
|
||||||
|
{
|
||||||
|
layout.RelativeOffset = relativeOffset;
|
||||||
|
}
|
||||||
|
if (absoluteOffset.X > -1000 && absoluteOffset.Y > -1000)
|
||||||
|
{
|
||||||
|
layout.AbsoluteOffset = absoluteOffset;
|
||||||
|
}
|
||||||
|
if (Enum.TryParse(XMLExtensions.GetAttributeString(element, "anchor", ""), out Anchor a))
|
||||||
|
{
|
||||||
|
layout.Anchor = a;
|
||||||
|
}
|
||||||
|
if (Enum.TryParse(XMLExtensions.GetAttributeString(element, "pivot", ""), out Pivot p))
|
||||||
|
{
|
||||||
|
layout.Pivot = p;
|
||||||
|
}
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTo(RectTransform target)
|
||||||
|
{
|
||||||
|
if (RelativeOffset.HasValue)
|
||||||
|
{
|
||||||
|
target.RelativeOffset = RelativeOffset.Value;
|
||||||
|
}
|
||||||
|
else if (AbsoluteOffset.HasValue)
|
||||||
|
{
|
||||||
|
target.AbsoluteOffset = AbsoluteOffset.Value;
|
||||||
|
}
|
||||||
|
if (RelativeSize.HasValue)
|
||||||
|
{
|
||||||
|
target.RelativeSize = RelativeSize.Value;
|
||||||
|
}
|
||||||
|
else if (AbsoluteSize.HasValue)
|
||||||
|
{
|
||||||
|
target.NonScaledSize = AbsoluteSize.Value;
|
||||||
|
}
|
||||||
|
if (Anchor.HasValue)
|
||||||
|
{
|
||||||
|
target.Anchor = Anchor.Value;
|
||||||
|
}
|
||||||
|
if (Pivot.HasValue)
|
||||||
|
{
|
||||||
|
target.Pivot = Pivot.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor);
|
||||||
|
}
|
||||||
|
target.RecalculateChildren(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GUIFrame GuiFrame { get; protected set; }
|
||||||
|
|
||||||
|
[Serialize(false, false)]
|
||||||
|
public bool AllowUIOverlap
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemComponent linkToUIComponent;
|
||||||
|
[Serialize("", false)]
|
||||||
|
public string LinkUIToComponent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serialize(0, false)]
|
||||||
|
public int HudPriority
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool useAlternativeLayout;
|
||||||
|
public bool UseAlternativeLayout
|
||||||
|
{
|
||||||
|
get { return useAlternativeLayout; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (AlternativeLayout != null)
|
||||||
|
{
|
||||||
|
if (value == useAlternativeLayout) { return; }
|
||||||
|
useAlternativeLayout = value;
|
||||||
|
if (useAlternativeLayout)
|
||||||
|
{
|
||||||
|
AlternativeLayout?.ApplyTo(GuiFrame.RectTransform);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DefaultLayout?.ApplyTo(GuiFrame.RectTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool shouldMuffleLooping;
|
||||||
|
private float lastMuffleCheckTime;
|
||||||
private ItemSound loopingSound;
|
private ItemSound loopingSound;
|
||||||
private int loopingSoundIndex;
|
private SoundChannel loopingSoundChannel;
|
||||||
public void PlaySound(ActionType type, Vector2 position)
|
public void PlaySound(ActionType type, Vector2 position, Character user = null)
|
||||||
{
|
{
|
||||||
if (loopingSound != null)
|
if (loopingSound != null)
|
||||||
{
|
{
|
||||||
loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range);
|
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range)
|
||||||
|
{
|
||||||
|
if (loopingSoundChannel != null)
|
||||||
|
{
|
||||||
|
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
|
||||||
|
{
|
||||||
|
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
|
||||||
|
}
|
||||||
|
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||||
|
{
|
||||||
|
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
|
||||||
|
new Vector3(position.X, position.Y, 0.0f),
|
||||||
|
GetSoundVolume(loopingSound),
|
||||||
|
SoundPlayer.ShouldMuffleSound(Character.Controlled, position, 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;
|
||||||
|
loopingSoundChannel.Gain = GetSoundVolume(loopingSound);
|
||||||
|
loopingSoundChannel.Position = new Vector3(position.X, position.Y, 0.0f);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ItemSound> matchingSounds;
|
if (!sounds.TryGetValue(type, out List<ItemSound> matchingSounds)) return;
|
||||||
if (!sounds.TryGetValue(type, out matchingSounds)) return;
|
|
||||||
|
|
||||||
ItemSound itemSound = null;
|
ItemSound itemSound = null;
|
||||||
if (!Sounds.SoundManager.IsPlaying(loopingSoundIndex))
|
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||||
{
|
{
|
||||||
int index = Rand.Int(matchingSounds.Count);
|
SoundSelectionMode soundSelectionMode = soundSelectionModes[type];
|
||||||
|
int index;
|
||||||
|
if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && user != null)
|
||||||
|
{
|
||||||
|
index = user.ID % matchingSounds.Count;
|
||||||
|
}
|
||||||
|
else if (soundSelectionMode == SoundSelectionMode.ItemSpecific)
|
||||||
|
{
|
||||||
|
index = item.ID % matchingSounds.Count;
|
||||||
|
}
|
||||||
|
else if (soundSelectionMode == SoundSelectionMode.All)
|
||||||
|
{
|
||||||
|
foreach (ItemSound sound in matchingSounds)
|
||||||
|
{
|
||||||
|
PlaySound(sound, position, user);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = Rand.Int(matchingSounds.Count);
|
||||||
|
}
|
||||||
|
|
||||||
itemSound = matchingSounds[index];
|
itemSound = matchingSounds[index];
|
||||||
|
PlaySound(matchingSounds[index], position, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSound == null) return;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void PlaySound(ItemSound itemSound, Vector2 position, Character user = null)
|
||||||
|
{
|
||||||
|
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > itemSound.Range * itemSound.Range)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (itemSound.Loop)
|
if (itemSound.Loop)
|
||||||
{
|
{
|
||||||
loopingSound = itemSound;
|
loopingSound = itemSound;
|
||||||
|
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
|
||||||
loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range);
|
{
|
||||||
|
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
|
||||||
|
}
|
||||||
|
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||||
|
{
|
||||||
|
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
|
||||||
|
new Vector3(position.X, position.Y, 0.0f),
|
||||||
|
GetSoundVolume(loopingSound),
|
||||||
|
muffle: SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull));
|
||||||
|
loopingSoundChannel.Looping = true;
|
||||||
|
//TODO: tweak
|
||||||
|
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
|
||||||
|
loopingSoundChannel.Far = loopingSound.Range;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float volume = GetSoundVolume(itemSound);
|
float volume = GetSoundVolume(itemSound);
|
||||||
if (volume == 0.0f) return;
|
if (volume <= 0.0f) return;
|
||||||
itemSound.Sound.Play(volume, itemSound.Range, position);
|
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, volume, itemSound.Range, position, item.CurrentHull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopSounds(ActionType type)
|
public void StopSounds(ActionType type)
|
||||||
{
|
{
|
||||||
if (loopingSoundIndex <= 0) return;
|
|
||||||
|
|
||||||
if (loopingSound == null) return;
|
if (loopingSound == null) return;
|
||||||
|
|
||||||
if (loopingSound.Type != type) return;
|
if (loopingSound.Type != type) return;
|
||||||
|
|
||||||
if (Sounds.SoundManager.IsPlaying(loopingSoundIndex))
|
if (loopingSoundChannel != null)
|
||||||
{
|
{
|
||||||
Sounds.SoundManager.Stop(loopingSoundIndex);
|
loopingSoundChannel.Dispose();
|
||||||
|
loopingSoundChannel = null;
|
||||||
loopingSound = null;
|
loopingSound = null;
|
||||||
loopingSoundIndex = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,8 +312,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (sound == null) return 0.0f;
|
if (sound == null) return 0.0f;
|
||||||
if (sound.VolumeProperty == "") return 1.0f;
|
if (sound.VolumeProperty == "") return 1.0f;
|
||||||
|
|
||||||
SerializableProperty property = null;
|
if (properties.TryGetValue(sound.VolumeProperty.ToLowerInvariant(), out SerializableProperty property))
|
||||||
if (properties.TryGetValue(sound.VolumeProperty.ToLowerInvariant(), out property))
|
|
||||||
{
|
{
|
||||||
float newVolume = 0.0f;
|
float newVolume = 0.0f;
|
||||||
try
|
try
|
||||||
@@ -123,55 +325,80 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
newVolume *= sound.VolumeMultiplier;
|
newVolume *= sound.VolumeMultiplier;
|
||||||
|
|
||||||
|
if (!MathUtils.IsValid(newVolume))
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce(
|
||||||
|
"ItemComponent.PlaySound:" + item.Name + GetType().ToString(),
|
||||||
|
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||||
|
"Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
return MathHelper.Clamp(newVolume, 0.0f, 1.0f);
|
return MathHelper.Clamp(newVolume, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool ShouldDrawHUD(Character character)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ItemComponent GetLinkUIToComponent()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(LinkUIToComponent))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach (ItemComponent component in item.components)
|
||||||
|
{
|
||||||
|
if (component.name.ToLower() == LinkUIToComponent.ToLower())
|
||||||
|
{
|
||||||
|
linkToUIComponent = component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (linkToUIComponent == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Failed to link the component \"" + Name + "\" to \"" + LinkUIToComponent + "\" in the item \"" + item.Name + "\" - component with a matching name not found.");
|
||||||
|
}
|
||||||
|
return linkToUIComponent;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
|
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
|
||||||
|
|
||||||
public virtual void AddToGUIUpdateList() { }
|
public virtual void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
GuiFrame?.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void UpdateHUD(Character character) { }
|
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
|
||||||
|
|
||||||
private bool LoadElemProjSpecific(XElement subElement)
|
private bool LoadElemProjSpecific(XElement subElement)
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "guiframe":
|
case "guiframe":
|
||||||
string rectStr = subElement.GetAttributeString("rect", "0.0,0.0,0.5,0.5");
|
if (subElement.Attribute("rect") != null)
|
||||||
|
|
||||||
string[] components = rectStr.Split(',');
|
|
||||||
if (components.Length < 4) break;
|
|
||||||
|
|
||||||
Vector4 rect = subElement.GetAttributeVector4("rect", Vector4.One);
|
|
||||||
if (components[0].Contains(".")) rect.X *= GameMain.GraphicsWidth;
|
|
||||||
if (components[1].Contains(".")) rect.Y *= GameMain.GraphicsHeight;
|
|
||||||
if (components[2].Contains(".")) rect.Z *= GameMain.GraphicsWidth;
|
|
||||||
if (components[3].Contains(".")) rect.W *= GameMain.GraphicsHeight;
|
|
||||||
|
|
||||||
string style = subElement.GetAttributeString("style", "");
|
|
||||||
|
|
||||||
Vector4 color = subElement.GetAttributeVector4("color", Vector4.One);
|
|
||||||
|
|
||||||
Alignment alignment = Alignment.Center;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
alignment = (Alignment)Enum.Parse(typeof(Alignment),
|
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - GUIFrame defined as rect, use RectTransform instead.");
|
||||||
subElement.GetAttributeString("alignment", "Center"), true);
|
break;
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Error in " + subElement.Parent + "! \"" + subElement.Parent.Attribute("type").Value + "\" is not a valid alignment");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guiFrame = new GUIFrame(
|
Color? color = null;
|
||||||
new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Z, (int)rect.W),
|
if (subElement.Attribute("color") != null) color = subElement.GetAttributeColor("color", Color.White);
|
||||||
new Color(color.X, color.Y, color.Z) * color.W,
|
string style = subElement.Attribute("style") == null ?
|
||||||
alignment, style);
|
null : subElement.GetAttributeString("style", "");
|
||||||
|
|
||||||
|
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas), style, color);
|
||||||
|
DefaultLayout = GUILayoutSettings.Load(subElement);
|
||||||
break;
|
break;
|
||||||
|
case "alternativelayout":
|
||||||
|
AlternativeLayout = GUILayoutSettings.Load(subElement);
|
||||||
|
break;
|
||||||
|
case "itemsound":
|
||||||
case "sound":
|
case "sound":
|
||||||
string filePath = subElement.GetAttributeString("file", "");
|
string filePath = subElement.GetAttributeString("file", "");
|
||||||
|
|
||||||
@@ -189,7 +416,6 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
ActionType type;
|
ActionType type;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
type = (ActionType)Enum.Parse(typeof(ActionType), subElement.GetAttributeString("type", ""), true);
|
type = (ActionType)Enum.Parse(typeof(ActionType), subElement.GetAttributeString("type", ""), true);
|
||||||
@@ -199,14 +425,20 @@ namespace Barotrauma.Items.Components
|
|||||||
DebugConsole.ThrowError("Invalid sound type in " + subElement + "!", e);
|
DebugConsole.ThrowError("Invalid sound type in " + subElement + "!", e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoundSound sound = Submarine.LoadRoundSound(subElement);
|
||||||
|
ItemSound itemSound = new ItemSound(sound, type, subElement.GetAttributeBool("loop", false))
|
||||||
|
{
|
||||||
|
VolumeProperty = subElement.GetAttributeString("volumeproperty", "")
|
||||||
|
};
|
||||||
|
|
||||||
Sound sound = Sound.Load(filePath);
|
if (soundSelectionModes == null) soundSelectionModes = new Dictionary<ActionType, SoundSelectionMode>();
|
||||||
|
if (!soundSelectionModes.ContainsKey(type) || soundSelectionModes[type] == SoundSelectionMode.Random)
|
||||||
float range = subElement.GetAttributeFloat("range", 800.0f);
|
{
|
||||||
bool loop = subElement.GetAttributeBool("loop", false);
|
SoundSelectionMode selectionMode = SoundSelectionMode.Random;
|
||||||
ItemSound itemSound = new ItemSound(sound, type, range, loop);
|
Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out selectionMode);
|
||||||
itemSound.VolumeProperty = subElement.GetAttributeString("volume", "");
|
soundSelectionModes[type] = selectionMode;
|
||||||
itemSound.VolumeMultiplier = subElement.GetAttributeFloat("volumemultiplier", 1.0f);
|
}
|
||||||
|
|
||||||
List<ItemSound> soundList = null;
|
List<ItemSound> soundList = null;
|
||||||
if (!sounds.TryGetValue(itemSound.Type, out soundList))
|
if (!sounds.TryGetValue(itemSound.Type, out soundList))
|
||||||
|
|||||||
@@ -1,29 +1,146 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using System;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class ItemContainer : ItemComponent, IDrawableComponent
|
partial class ItemContainer : ItemComponent, IDrawableComponent
|
||||||
{
|
{
|
||||||
//TODO: shouldn't this be overriding the base method?
|
private Sprite inventoryTopSprite;
|
||||||
|
private Sprite inventoryBackSprite;
|
||||||
|
private Sprite inventoryBottomSprite;
|
||||||
|
|
||||||
|
private GUICustomComponent guiCustomComponent;
|
||||||
|
|
||||||
|
public Sprite InventoryTopSprite
|
||||||
|
{
|
||||||
|
get { return inventoryTopSprite; }
|
||||||
|
}
|
||||||
|
public Sprite InventoryBackSprite
|
||||||
|
{
|
||||||
|
get { return inventoryBackSprite; }
|
||||||
|
}
|
||||||
|
public Sprite InventoryBottomSprite
|
||||||
|
{
|
||||||
|
get { return inventoryBottomSprite; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sprite ContainedStateIndicator
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[Serialize("0.0,0.0", false), Editable]
|
||||||
|
#else
|
||||||
|
[Serialize("0.0,0.0", false)]
|
||||||
|
#endif
|
||||||
|
public Vector2 ItemPos { get; set; }
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[Serialize("0.0,0.0", false), Editable]
|
||||||
|
#else
|
||||||
|
[Serialize("0.0,0.0", false)]
|
||||||
|
#endif
|
||||||
|
public Vector2 ItemInterval { get; set; }
|
||||||
|
[Serialize(100, false)]
|
||||||
|
public int ItemsPerRow { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.
|
||||||
|
/// </summary>
|
||||||
|
[Serialize(-1.0f, false)]
|
||||||
|
public float ContainedSpriteDepth { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private float itemRotation;
|
||||||
|
[Serialize(0.0f, false)]
|
||||||
|
public float ItemRotation
|
||||||
|
{
|
||||||
|
get { return MathHelper.ToDegrees(itemRotation); }
|
||||||
|
set { itemRotation = MathHelper.ToRadians(value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serialize(null, false)]
|
||||||
|
public string UILabel { get; set; }
|
||||||
|
|
||||||
|
[Serialize(false, false)]
|
||||||
|
public bool ShowConditionInContainedStateIndicator
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "topsprite":
|
||||||
|
inventoryTopSprite = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "backsprite":
|
||||||
|
inventoryBackSprite = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "bottomsprite":
|
||||||
|
inventoryBottomSprite = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "containedstateindicator":
|
||||||
|
ContainedStateIndicator = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GuiFrame == null)
|
||||||
|
{
|
||||||
|
//if a GUIFrame is not defined in the xml,
|
||||||
|
//we create a full-screen frame and let the inventory position itself on it
|
||||||
|
GuiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
guiCustomComponent = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform),
|
||||||
|
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
|
||||||
|
onUpdate: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||||
{
|
{
|
||||||
if (hideItems || (item.body != null && !item.body.Enabled)) return;
|
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
|
||||||
|
DrawContainedItems(spriteBatch);
|
||||||
|
}
|
||||||
|
|
||||||
Vector2 transformedItemPos = itemPos;
|
public void DrawContainedItems(SpriteBatch spriteBatch)
|
||||||
Vector2 transformedItemInterval = itemInterval;
|
{
|
||||||
|
Vector2 transformedItemPos = ItemPos * item.Scale;
|
||||||
|
Vector2 transformedItemInterval = ItemInterval * item.Scale;
|
||||||
float currentRotation = itemRotation;
|
float currentRotation = itemRotation;
|
||||||
|
|
||||||
if (item.body == null)
|
if (item.body == null)
|
||||||
{
|
{
|
||||||
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
|
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
|
||||||
if (item.Submarine != null) transformedItemPos += item.Submarine.DrawPosition;
|
if (item.Submarine != null) transformedItemPos += item.Submarine.DrawPosition;
|
||||||
transformedItemPos = transformedItemPos + itemPos;
|
transformedItemPos = transformedItemPos + ItemPos * item.Scale;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//item.body.Enabled = true;
|
|
||||||
|
|
||||||
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||||
|
|
||||||
if (item.body.Dir == -1.0f)
|
if (item.body.Dir == -1.0f)
|
||||||
@@ -39,30 +156,80 @@ namespace Barotrauma.Items.Components
|
|||||||
currentRotation += item.body.Rotation;
|
currentRotation += item.body.Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 currentItemPos = transformedItemPos;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
foreach (Item containedItem in Inventory.Items)
|
foreach (Item containedItem in Inventory.Items)
|
||||||
{
|
{
|
||||||
if (containedItem == null) continue;
|
if (containedItem == null) continue;
|
||||||
|
|
||||||
|
if (AutoInteractWithContained)
|
||||||
|
{
|
||||||
|
containedItem.IsHighlighted = item.IsHighlighted;
|
||||||
|
item.IsHighlighted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containedItem.body != null)
|
||||||
|
{
|
||||||
|
containedItem.body.FarseerBody.Rotation = currentRotation;
|
||||||
|
}
|
||||||
|
|
||||||
containedItem.Sprite.Draw(
|
containedItem.Sprite.Draw(
|
||||||
spriteBatch,
|
spriteBatch,
|
||||||
new Vector2(transformedItemPos.X, -transformedItemPos.Y),
|
new Vector2(currentItemPos.X, -currentItemPos.Y),
|
||||||
containedItem.GetSpriteColor(),
|
containedItem.GetSpriteColor(),
|
||||||
-currentRotation,
|
-currentRotation,
|
||||||
1.0f,
|
containedItem.Scale,
|
||||||
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None,
|
||||||
|
depth: ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth);
|
||||||
|
|
||||||
transformedItemPos += transformedItemInterval;
|
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())
|
||||||
|
{
|
||||||
|
if (ic.hideItems) continue;
|
||||||
|
ic.DrawContainedItems(spriteBatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (Math.Abs(transformedItemInterval.X) > 0.001f && Math.Abs(transformedItemInterval.Y) > 0.001f)
|
||||||
|
{
|
||||||
|
//interval set on both axes -> use a grid layout
|
||||||
|
currentItemPos.X += transformedItemInterval.X;
|
||||||
|
if (i % ItemsPerRow == 0)
|
||||||
|
{
|
||||||
|
currentItemPos.X = transformedItemPos.X;
|
||||||
|
currentItemPos.Y += transformedItemInterval.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentItemPos += transformedItemInterval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
Inventory.Update((float)Timing.Step);
|
if (Inventory.RectTransform != null)
|
||||||
|
{
|
||||||
|
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the item is in the character's inventory, no need to update the item's inventory
|
||||||
|
//because the player can see it by hovering the cursor over the item
|
||||||
|
guiCustomComponent.Visible = item.ParentInventory?.Owner != character && DrawInventory;
|
||||||
|
if (!guiCustomComponent.Visible) return;
|
||||||
|
|
||||||
|
Inventory.Update(deltaTime, cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
/*public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||||
{
|
{
|
||||||
Inventory.Draw(spriteBatch);
|
//if the item is in the character's inventory, no need to draw the item's inventory
|
||||||
}
|
//because the player can see it by hovering the cursor over the item
|
||||||
|
if (item.ParentInventory?.Owner == character || !DrawInventory) return;
|
||||||
|
|
||||||
|
Inventory.Draw(spriteBatch);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
@@ -10,20 +12,38 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private Color textColor;
|
private Color textColor;
|
||||||
|
|
||||||
|
private float scrollAmount;
|
||||||
|
private string scrollingText;
|
||||||
|
private float scrollPadding;
|
||||||
|
private int scrollIndex;
|
||||||
|
private bool needsScrolling;
|
||||||
|
|
||||||
|
private float[] charWidths;
|
||||||
|
|
||||||
|
[Serialize("0,0,0,0", true)]
|
||||||
|
public Vector4 Padding
|
||||||
|
{
|
||||||
|
get { return TextBlock.Padding; }
|
||||||
|
set { TextBlock.Padding = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string text;
|
||||||
[Serialize("", true), Editable(100)]
|
[Serialize("", true), Editable(100)]
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get { return textBlock.Text.Replace("\n", ""); }
|
get { return text; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == TextBlock.Text || item.Rect.Width < 5) return;
|
if (value == text || item.Rect.Width < 5) return;
|
||||||
|
|
||||||
if (textBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
|
if (TextBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
|
||||||
{
|
{
|
||||||
textBlock = null;
|
textBlock = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text = value;
|
||||||
TextBlock.Text = value;
|
TextBlock.Text = value;
|
||||||
|
SetScrollingText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,42 +68,149 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool scrollable;
|
||||||
|
[Serialize(false, true)]
|
||||||
|
public bool Scrollable
|
||||||
|
{
|
||||||
|
get { return scrollable; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
scrollable = value;
|
||||||
|
IsActive = value;
|
||||||
|
TextBlock.Wrap = !scrollable;
|
||||||
|
TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serialize(20.0f, true)]
|
||||||
|
public float ScrollSpeed
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
private GUITextBlock TextBlock
|
private GUITextBlock TextBlock
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (textBlock == null)
|
if (textBlock == null)
|
||||||
{
|
{
|
||||||
textBlock = new GUITextBlock(new Rectangle(item.Rect.X, -item.Rect.Y, item.Rect.Width, item.Rect.Height), "",
|
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
|
||||||
Color.Transparent, textColor,
|
textColor: textColor, font: GUI.SmallFont, textAlignment: Alignment.Center, wrap: true, style: null)
|
||||||
Alignment.TopLeft, Alignment.Center,
|
{
|
||||||
null, null, true);
|
TextDepth = item.SpriteDepth - 0.0001f,
|
||||||
textBlock.Font = GUI.SmallFont;
|
TextScale = TextScale
|
||||||
textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
};
|
||||||
textBlock.TextDepth = item.Sprite.Depth - 0.0001f;
|
|
||||||
textBlock.TextScale = TextScale;
|
|
||||||
}
|
}
|
||||||
return textBlock;
|
return textBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Move(Vector2 amount)
|
|
||||||
{
|
|
||||||
textBlock.Rect = new Rectangle(item.Rect.X, -item.Rect.Y, item.Rect.Width, item.Rect.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemLabel(Item item, XElement element)
|
public ItemLabel(Item item, XElement element)
|
||||||
: base(item, element)
|
: base(item, element)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetScrollingText()
|
||||||
|
{
|
||||||
|
if (!scrollable) return;
|
||||||
|
|
||||||
|
float totalWidth = textBlock.Font.MeasureString(text).X;
|
||||||
|
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
|
||||||
|
if (totalWidth >= textAreaWidth)
|
||||||
|
{
|
||||||
|
//add enough spaces to fill the rect
|
||||||
|
//(so the text can scroll entirely out of view before we reset it back to start)
|
||||||
|
needsScrolling = true;
|
||||||
|
float spaceWidth = textBlock.Font.MeasureChar(' ').X;
|
||||||
|
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//whole text can fit in the textblock, no need to scroll
|
||||||
|
needsScrolling = false;
|
||||||
|
scrollingText = text;
|
||||||
|
scrollAmount = 0.0f;
|
||||||
|
scrollIndex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate character widths
|
||||||
|
scrollPadding = 0;
|
||||||
|
charWidths = new float[scrollingText.Length];
|
||||||
|
for (int i = 0; i < scrollingText.Length; i++)
|
||||||
|
{
|
||||||
|
float charWidth = TextBlock.Font.MeasureChar(scrollingText[i]).X;
|
||||||
|
scrollPadding = Math.Max(charWidth, scrollPadding);
|
||||||
|
charWidths[i] = charWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollIndex = MathHelper.Clamp(scrollIndex, 0, text.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float deltaTime, Camera cam)
|
||||||
|
{
|
||||||
|
if (!scrollable) return;
|
||||||
|
|
||||||
|
if (scrollingText == null)
|
||||||
|
{
|
||||||
|
SetScrollingText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needsScrolling) return;
|
||||||
|
|
||||||
|
scrollAmount -= deltaTime * ScrollSpeed;
|
||||||
|
|
||||||
|
float currLength = 0;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
float textAreaWidth = textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z;
|
||||||
|
for (int i = scrollIndex; i < scrollingText.Length; i++)
|
||||||
|
{
|
||||||
|
//first character is out of view -> skip to next character
|
||||||
|
if (i == scrollIndex && scrollAmount < -charWidths[i])
|
||||||
|
{
|
||||||
|
scrollIndex++;
|
||||||
|
scrollAmount = 0;
|
||||||
|
if (scrollIndex >= scrollingText.Length) //reached the last character, reset
|
||||||
|
{
|
||||||
|
scrollIndex = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reached the right edge, stop adding more character
|
||||||
|
if (scrollAmount + (currLength + charWidths[i] + scrollPadding) >= textAreaWidth)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currLength += charWidths[i];
|
||||||
|
sb.Append(scrollingText[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextBlock.Text = sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||||
{
|
{
|
||||||
var drawPos = new Vector2(
|
var drawPos = new Vector2(
|
||||||
item.DrawPosition.X - item.Rect.Width / 2.0f,
|
item.DrawPosition.X - item.Rect.Width / 2.0f,
|
||||||
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
|
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
|
||||||
|
|
||||||
|
Rectangle worldRect = item.WorldRect;
|
||||||
|
if (worldRect.X > Screen.Selected.Cam.WorldView.Right ||
|
||||||
|
worldRect.Right < Screen.Selected.Cam.WorldView.X ||
|
||||||
|
worldRect.Y < Screen.Selected.Cam.WorldView.Y - Screen.Selected.Cam.WorldView.Height ||
|
||||||
|
worldRect.Y - worldRect.Height > Screen.Selected.Cam.WorldView.Y)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
textBlock.Draw(spriteBatch, drawPos - textBlock.Rect.Location.ToVector2());
|
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + new Vector2(scrollAmount + scrollPadding, 0.0f);
|
||||||
|
textBlock.DrawManually(spriteBatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class LevelResource : ItemComponent, IServerSerializable
|
||||||
|
{
|
||||||
|
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||||
|
{
|
||||||
|
DeattachTimer = msg.ReadSingle();
|
||||||
|
if (deattachTimer >= DeattachDuration)
|
||||||
|
{
|
||||||
|
holdable.DeattachFromWall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,16 +9,20 @@ namespace Barotrauma.Items.Components
|
|||||||
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
|
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
|
||||||
{
|
{
|
||||||
private LightSource light;
|
private LightSource light;
|
||||||
|
public LightSource Light
|
||||||
|
{
|
||||||
|
get { return light; }
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||||
{
|
{
|
||||||
if (light.LightSprite != null && (item.body == null || item.body.Enabled))
|
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f)
|
||||||
{
|
{
|
||||||
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.Sprite.Depth - 0.0001f);
|
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.SpriteDepth - 0.0001f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FlipX()
|
public override void FlipX(bool relativeToSub)
|
||||||
{
|
{
|
||||||
if (light?.LightSprite != null)
|
if (light?.LightSprite != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,27 +1,77 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Deconstructor : Powered, IServerSerializable, IClientSerializable
|
partial class Deconstructor : Powered, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
GUIProgressBar progressBar;
|
private GUIButton activateButton;
|
||||||
GUIButton activateButton;
|
private GUIComponent inputInventoryHolder, outputInventoryHolder;
|
||||||
|
private GUICustomComponent inputInventoryOverlay;
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private GUIComponent inSufficientPowerWarning;
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
GuiFrame.Draw(spriteBatch);
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
|
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.7f), paddedFrame.RectTransform), style: null);
|
||||||
|
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.1f), paddedFrame.RectTransform),
|
||||||
|
TextManager.Get("DeconstructorDeconstruct"))
|
||||||
|
{
|
||||||
|
OnClicked = ToggleActive
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("DeconstructorNoPower"),
|
||||||
|
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
|
||||||
|
{
|
||||||
|
HoverColor = Color.Black,
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
Visible = false,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), paddedFrame.RectTransform), style: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
partial void OnItemLoadedProjSpecific()
|
||||||
{
|
{
|
||||||
GuiFrame.AddToGUIUpdateList();
|
inputContainer.AllowUIOverlap = true;
|
||||||
|
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
|
||||||
|
outputContainer.AllowUIOverlap = true;
|
||||||
|
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||||
{
|
{
|
||||||
GuiFrame.Update((float)Timing.Step);
|
overlayComponent.RectTransform.SetAsLastChild();
|
||||||
|
var lastSlot = inputContainer.Inventory.slots.Last();
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Rectangle(
|
||||||
|
lastSlot.Rect.X, lastSlot.Rect.Y + (int)(lastSlot.Rect.Height * (1.0f - progressState)),
|
||||||
|
lastSlot.Rect.Width, (int)(lastSlot.Rect.Height * progressState)),
|
||||||
|
Color.Green * 0.5f, isFilled: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
|
{
|
||||||
|
inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage;
|
||||||
|
activateButton.Enabled = !inSufficientPowerWarning.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ToggleActive(GUIButton button, object obj)
|
private bool ToggleActive(GUIButton button, object obj)
|
||||||
|
|||||||
@@ -1,25 +1,142 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Barotrauma.Networking;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Engine : Powered
|
partial class Engine : Powered, IDrawableComponent
|
||||||
{
|
{
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private float spriteIndex;
|
||||||
{
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("Force") + ": " + (int)(targetForce) + " %", new Vector2(GuiFrame.Rect.X + 30, GuiFrame.Rect.Y + 30), Color.White);
|
private SpriteSheet propellerSprite;
|
||||||
|
|
||||||
|
private GUITickBox powerIndicator;
|
||||||
|
private GUIScrollBar forceSlider;
|
||||||
|
|
||||||
|
public float AnimSpeed
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
GuiFrame.AddToGUIUpdateList();
|
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), GuiFrame.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.15f) },
|
||||||
|
TextManager.Get("EnginePowered"), style: "IndicatorLightGreen")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
string powerLabel = TextManager.Get("EngineForce");
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.3f), GuiFrame.RectTransform, Anchor.BottomCenter)
|
||||||
|
{ RelativeOffset = new Vector2(0.0f, 0.4f) }, "", textAlignment: Alignment.Center)
|
||||||
|
{
|
||||||
|
TextGetter = () => { return powerLabel + ": " + (int)(targetForce) + " %"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.25f), GuiFrame.RectTransform, Anchor.BottomCenter)
|
||||||
|
{ RelativeOffset = new Vector2(0.0f, 0.2f) }, isHorizontal: true);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), sliderArea.RectTransform), TextManager.Get("EngineBackwards"),
|
||||||
|
font: GUI.SmallFont, textAlignment: Alignment.Center);
|
||||||
|
forceSlider = new GUIScrollBar(new RectTransform(new Vector2(0.6f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
|
||||||
|
{
|
||||||
|
Step = 0.05f,
|
||||||
|
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
float newTargetForce = barScroll * 200.0f - 100.0f;
|
||||||
|
if (Math.Abs(newTargetForce - targetForce) < 0.01) return false;
|
||||||
|
|
||||||
|
targetForce = newTargetForce;
|
||||||
|
if (GameMain.Server != null)
|
||||||
|
{
|
||||||
|
item.CreateServerEvent(this);
|
||||||
|
GameServer.Log(Character.Controlled.LogName + " set the force speed of " + item.Name + " to " + (int)(targetForce) + " %", ServerLog.MessageType.ItemInteraction);
|
||||||
|
}
|
||||||
|
else if (GameMain.Client != null)
|
||||||
|
{
|
||||||
|
correctionTimer = CorrectionDelay;
|
||||||
|
item.CreateClientEvent(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), sliderArea.RectTransform), TextManager.Get("EngineForwards"),
|
||||||
|
font: GUI.SmallFont, textAlignment: Alignment.Center);
|
||||||
|
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "propellersprite":
|
||||||
|
propellerSprite = new SpriteSheet(subElement);
|
||||||
|
AnimSpeed = subElement.GetAttributeFloat("animspeed", 1.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
powerIndicator.Selected = hasPower && IsActive;
|
||||||
|
|
||||||
|
if (!PlayerInput.LeftButtonHeld())
|
||||||
|
{
|
||||||
|
float newScroll = (targetForce + 100.0f) / 200.0f;
|
||||||
|
if (Math.Abs(newScroll - forceSlider.BarScroll) > 0.01f)
|
||||||
|
{
|
||||||
|
forceSlider.BarScroll = newScroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void UpdateAnimation(float deltaTime)
|
||||||
|
{
|
||||||
|
if (propellerSprite == null) return;
|
||||||
|
|
||||||
|
spriteIndex += (force / 100.0f) * AnimSpeed * deltaTime;
|
||||||
|
if (spriteIndex < 0) spriteIndex = propellerSprite.FrameCount;
|
||||||
|
if (spriteIndex >= propellerSprite.FrameCount) spriteIndex = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
|
{
|
||||||
|
if (propellerSprite != null)
|
||||||
|
{
|
||||||
|
Vector2 drawPos = item.DrawPosition;
|
||||||
|
drawPos += PropellerPos;
|
||||||
|
drawPos.Y = -drawPos.Y;
|
||||||
|
|
||||||
|
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editing)
|
||||||
|
{
|
||||||
|
Vector2 drawPos = item.DrawPosition;
|
||||||
|
drawPos += PropellerPos;
|
||||||
|
drawPos.Y = -drawPos.Y;
|
||||||
|
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||||
|
{
|
||||||
|
//targetForce can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||||
|
msg.WriteRangedInteger(-10, 10, (int)(targetForce / 10.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||||
|
{
|
||||||
|
if (correctionTimer > 0.0f)
|
||||||
|
{
|
||||||
|
StartDelayedCorrection(type, msg.ExtractBits(5), sendingTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetForce = msg.ReadRangedInteger(-10, 10) * 10.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Networking;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
@@ -13,148 +14,309 @@ namespace Barotrauma.Items.Components
|
|||||||
private GUIListBox itemList;
|
private GUIListBox itemList;
|
||||||
|
|
||||||
private GUIFrame selectedItemFrame;
|
private GUIFrame selectedItemFrame;
|
||||||
|
|
||||||
private GUIProgressBar progressBar;
|
|
||||||
private GUIButton activateButton;
|
private GUIButton activateButton;
|
||||||
|
|
||||||
|
private GUIComponent inputInventoryHolder, outputInventoryHolder;
|
||||||
|
private GUICustomComponent inputInventoryOverlay, outputInventoryOverlay;
|
||||||
|
|
||||||
|
private FabricableItem selectedItem;
|
||||||
|
|
||||||
|
private GUIComponent inSufficientPowerWarning;
|
||||||
|
|
||||||
|
private Pair<Rectangle, string> tooltip;
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
partial void InitProjSpecific()
|
||||||
{
|
{
|
||||||
GuiFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f);
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
itemList = new GUIListBox(new Rectangle(0, 0, GuiFrame.Rect.Width / 2 - 20, 0), "", GuiFrame);
|
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
|
||||||
itemList.OnSelected = SelectItem;
|
{
|
||||||
|
OnSelected = SelectItem
|
||||||
|
};
|
||||||
|
|
||||||
|
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.15f), paddedFrame.RectTransform), style: null);
|
||||||
|
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay, null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.3f), paddedFrame.RectTransform), isHorizontal: true);
|
||||||
|
|
||||||
|
selectedItemFrame = new GUIFrame(new RectTransform(new Vector2(0.75f, 1.0f), outputArea.RectTransform), style: "InnerFrame");
|
||||||
|
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), outputArea.RectTransform), style: null);
|
||||||
|
outputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, outputArea.RectTransform), DrawOutputOverLay, null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
foreach (FabricableItem fi in fabricableItems)
|
foreach (FabricableItem fi in fabricableItems)
|
||||||
{
|
{
|
||||||
GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 50), Color.Transparent, null, itemList)
|
GUIFrame frame = new GUIFrame(new RectTransform(new Point(itemList.Rect.Width, 50), itemList.Content.RectTransform), style: null)
|
||||||
{
|
{
|
||||||
UserData = fi,
|
UserData = fi,
|
||||||
Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f),
|
|
||||||
HoverColor = Color.Gold * 0.2f,
|
HoverColor = Color.Gold * 0.2f,
|
||||||
SelectedColor = Color.Gold * 0.5f,
|
SelectedColor = Color.Gold * 0.5f,
|
||||||
ToolTip = fi.TargetItem.Description
|
ToolTip = fi.TargetItem.Description
|
||||||
};
|
};
|
||||||
|
|
||||||
GUITextBlock textBlock = new GUITextBlock(
|
GUITextBlock textBlock = new GUITextBlock(new RectTransform(Vector2.Zero, frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(50, 0) },
|
||||||
new Rectangle(40, 0, 0, 25),
|
fi.DisplayName)
|
||||||
fi.TargetItem.Name,
|
|
||||||
Color.Transparent, Color.White,
|
|
||||||
Alignment.Left, Alignment.Left,
|
|
||||||
null, frame);
|
|
||||||
textBlock.ToolTip = fi.TargetItem.Description;
|
|
||||||
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
|
|
||||||
|
|
||||||
if (fi.TargetItem.sprite != null)
|
|
||||||
{
|
{
|
||||||
GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), fi.TargetItem.sprite, Alignment.Left, frame);
|
ToolTip = fi.TargetItem.Description
|
||||||
img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
|
};
|
||||||
img.Color = fi.TargetItem.SpriteColor;
|
|
||||||
img.ToolTip = fi.TargetItem.Description;
|
var itemIcon = fi.TargetItem.InventoryIcon ?? fi.TargetItem.sprite;
|
||||||
|
if (itemIcon != null)
|
||||||
|
{
|
||||||
|
GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(3, 0) },
|
||||||
|
itemIcon, scaleToFit: true)
|
||||||
|
{
|
||||||
|
Color = fi.TargetItem.InventoryIconColor,
|
||||||
|
ToolTip = fi.TargetItem.Description
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform),
|
||||||
|
TextManager.Get("FabricatorCreate"))
|
||||||
|
{
|
||||||
|
OnClicked = StartButtonClicked,
|
||||||
|
UserData = selectedItem,
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
|
||||||
|
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("FabricatorNoPower"),
|
||||||
|
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
|
||||||
|
{
|
||||||
|
HoverColor = Color.Black,
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
Visible = false,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnItemLoadedProjSpecific()
|
||||||
|
{
|
||||||
|
inputContainer.AllowUIOverlap = true;
|
||||||
|
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
|
||||||
|
outputContainer.AllowUIOverlap = true;
|
||||||
|
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void SelectProjSpecific(Character character)
|
||||||
|
{
|
||||||
|
var nonItems = itemList.Content.Children.Where(c => !(c.UserData is FabricableItem)).ToList();
|
||||||
|
nonItems.ForEach(i => itemList.Content.RemoveChild(i));
|
||||||
|
|
||||||
|
itemList.Content.RectTransform.SortChildren((c1, c2) =>
|
||||||
|
{
|
||||||
|
var item1 = c1.GUIComponent.UserData as FabricableItem;
|
||||||
|
var item2 = c2.GUIComponent.UserData as FabricableItem;
|
||||||
|
|
||||||
|
bool hasSkills1 = DegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
|
||||||
|
bool hasSkills2 = DegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
|
||||||
|
|
||||||
|
if (hasSkills1 != hasSkills2)
|
||||||
|
{
|
||||||
|
return hasSkills1 ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(item1.DisplayName, item2.DisplayName);
|
||||||
|
});
|
||||||
|
|
||||||
|
var sufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform), "Sufficient skills to fabricate:", textColor: Color.LightGreen)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
sufficientSkillsText.RectTransform.SetAsFirstChild();
|
||||||
|
|
||||||
|
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform), "Insufficient skills to fabricate:", textColor: Color.Orange)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricableItem fabricableItem && DegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f);
|
||||||
|
if (firstinSufficient != null)
|
||||||
|
{
|
||||||
|
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||||
|
{
|
||||||
|
overlayComponent.RectTransform.SetAsLastChild();
|
||||||
|
|
||||||
|
FabricableItem targetItem = fabricatedItem ?? selectedItem;
|
||||||
|
if (targetItem != null)
|
||||||
|
{
|
||||||
|
int slotIndex = 0;
|
||||||
|
|
||||||
|
var missingItems = new List<FabricableItem.RequiredItem>();
|
||||||
|
foreach (FabricableItem.RequiredItem requiredItem in targetItem.RequiredItems)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < requiredItem.Amount; i++)
|
||||||
|
{
|
||||||
|
missingItems.Add(requiredItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (Item item in inputContainer.Inventory.Items)
|
||||||
|
{
|
||||||
|
if (item == null) { continue; }
|
||||||
|
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefab == item.prefab));
|
||||||
|
}
|
||||||
|
|
||||||
|
var availableIngredients = GetAvailableIngredients();
|
||||||
|
|
||||||
|
foreach (FabricableItem.RequiredItem requiredItem in missingItems)
|
||||||
|
{
|
||||||
|
//highlight suitable ingredients in linked inventories
|
||||||
|
foreach (Item item in availableIngredients)
|
||||||
|
{
|
||||||
|
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
|
||||||
|
{
|
||||||
|
int availableSlotIndex = Array.IndexOf(item.ParentInventory.Items, item);
|
||||||
|
if (item.ParentInventory.slots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
item.ParentInventory.slots[availableSlotIndex].ShowBorderHighlight(Color.LightGreen * 0.5f, 0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (slotIndex < inputContainer.Capacity && inputContainer.Inventory.Items[slotIndex] != null)
|
||||||
|
{
|
||||||
|
slotIndex++;
|
||||||
|
}
|
||||||
|
if (slotIndex >= inputContainer.Capacity) { break; }
|
||||||
|
|
||||||
|
var itemIcon = requiredItem.ItemPrefab.InventoryIcon ?? requiredItem.ItemPrefab.sprite;
|
||||||
|
|
||||||
|
Rectangle slotRect = inputContainer.Inventory.slots[slotIndex].Rect;
|
||||||
|
|
||||||
|
itemIcon.Draw(
|
||||||
|
spriteBatch,
|
||||||
|
slotRect.Center.ToVector2(),
|
||||||
|
color: requiredItem.ItemPrefab.InventoryIconColor * 0.3f,
|
||||||
|
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
|
||||||
|
|
||||||
|
if (slotRect.Contains(PlayerInput.MousePosition))
|
||||||
|
{
|
||||||
|
string toolTipText = requiredItem.ItemPrefab.Name;
|
||||||
|
if (!string.IsNullOrEmpty(requiredItem.ItemPrefab.Description))
|
||||||
|
{
|
||||||
|
toolTipText += '\n' + requiredItem.ItemPrefab.Description;
|
||||||
|
}
|
||||||
|
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
|
||||||
|
}
|
||||||
|
|
||||||
|
slotIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||||
|
{
|
||||||
|
overlayComponent.RectTransform.SetAsLastChild();
|
||||||
|
|
||||||
|
FabricableItem targetItem = fabricatedItem ?? selectedItem;
|
||||||
|
if (targetItem != null)
|
||||||
|
{
|
||||||
|
var itemIcon = targetItem.TargetItem.InventoryIcon ?? targetItem.TargetItem.sprite;
|
||||||
|
|
||||||
|
Rectangle slotRect = outputContainer.Inventory.slots[0].Rect;
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Rectangle(
|
||||||
|
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - progressState)),
|
||||||
|
slotRect.Width, (int)(slotRect.Height * progressState)),
|
||||||
|
Color.Green * 0.5f, isFilled: true);
|
||||||
|
|
||||||
|
itemIcon.Draw(
|
||||||
|
spriteBatch,
|
||||||
|
slotRect.Center.ToVector2(),
|
||||||
|
color: targetItem.TargetItem.InventoryIconColor * 0.4f,
|
||||||
|
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y) * 0.9f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltip != null)
|
||||||
|
{
|
||||||
|
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
|
||||||
|
tooltip = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool SelectItem(GUIComponent component, object obj)
|
private bool SelectItem(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
FabricableItem targetItem = obj as FabricableItem;
|
selectedItem = obj as FabricableItem;
|
||||||
if (targetItem == null) return false;
|
if (selectedItem == null) return false;
|
||||||
|
|
||||||
if (selectedItemFrame != null) GuiFrame.RemoveChild(selectedItemFrame);
|
selectedItemFrame.ClearChildren();
|
||||||
|
|
||||||
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f, Stretch = true };
|
||||||
|
|
||||||
//int width = 200, height = 150;
|
/*var itemIcon = selectedItem.TargetItem.InventoryIcon ?? selectedItem.TargetItem.sprite;
|
||||||
selectedItemFrame = new GUIFrame(new Rectangle(0, 0, (int)(GuiFrame.Rect.Width * 0.4f), 350), Color.Black * 0.8f, Alignment.CenterY | Alignment.Right, null, GuiFrame);
|
if (itemIcon != null)
|
||||||
|
|
||||||
selectedItemFrame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
|
|
||||||
|
|
||||||
progressBar = new GUIProgressBar(new Rectangle(0, 0, 0, 20), Color.Green, "", 0.0f, Alignment.BottomCenter, selectedItemFrame);
|
|
||||||
progressBar.IsHorizontal = true;
|
|
||||||
|
|
||||||
if (targetItem.TargetItem.sprite != null)
|
|
||||||
{
|
{
|
||||||
int y = 0;
|
GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), paddedFrame.RectTransform),
|
||||||
|
itemIcon, scaleToFit: true)
|
||||||
GUIImage img = new GUIImage(new Rectangle(10, 0, 40, 40), targetItem.TargetItem.sprite, Alignment.TopLeft, selectedItemFrame);
|
|
||||||
img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
|
|
||||||
img.Color = targetItem.TargetItem.SpriteColor;
|
|
||||||
|
|
||||||
new GUITextBlock(
|
|
||||||
new Rectangle(60, 0, 0, 25),
|
|
||||||
targetItem.TargetItem.Name,
|
|
||||||
Color.Transparent, Color.White,
|
|
||||||
Alignment.TopLeft,
|
|
||||||
Alignment.TopLeft, null,
|
|
||||||
selectedItemFrame, true);
|
|
||||||
|
|
||||||
y += 40;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(targetItem.TargetItem.Description))
|
|
||||||
{
|
{
|
||||||
var description = new GUITextBlock(
|
Color = selectedItem.TargetItem.InventoryIconColor
|
||||||
new Rectangle(0, y, 0, 0),
|
};
|
||||||
targetItem.TargetItem.Description,
|
}*/
|
||||||
"", Alignment.TopLeft, Alignment.TopLeft,
|
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
selectedItemFrame, true, GUI.SmallFont);
|
selectedItem.TargetItem.Name, textAlignment: Alignment.CenterLeft);
|
||||||
|
|
||||||
y += description.Rect.Height + 10;
|
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
|
||||||
}
|
{
|
||||||
|
var description = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
|
selectedItem.TargetItem.Description,
|
||||||
List<Skill> inadequateSkills = new List<Skill>();
|
font: GUI.SmallFont, wrap: true);
|
||||||
|
if (description.Rect.Height > paddedFrame.Rect.Height * 0.4f)
|
||||||
if (Character.Controlled != null)
|
|
||||||
{
|
{
|
||||||
inadequateSkills = targetItem.RequiredSkills.FindAll(skill => Character.Controlled.GetSkillLevel(skill.Name) < skill.Level);
|
description.Wrap = false;
|
||||||
|
description.Text = description.WrappedText.Split('\n').First()+"...";
|
||||||
|
nameBlock.ToolTip = description.ToolTip = selectedItem.TargetItem.Description;
|
||||||
|
description.RectTransform.MaxSize = new Point(int.MaxValue, (int)description.Font.MeasureString(description.Text).Y);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
string text = TextManager.Get("FabricatorRequiredItems")+ ":\n";
|
|
||||||
foreach (Tuple<ItemPrefab, int, float, bool> ip in targetItem.RequiredItems)
|
List<Skill> inadequateSkills = new List<Skill>();
|
||||||
|
if (Character.Controlled != null)
|
||||||
|
{
|
||||||
|
inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => Character.Controlled.GetSkillLevel(skill.Identifier) < skill.Level);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem.RequiredSkills.Any())
|
||||||
|
{
|
||||||
|
string text = TextManager.Get("FabricatorRequiredSkills") + ":\n";
|
||||||
|
foreach (Skill skill in selectedItem.RequiredSkills)
|
||||||
{
|
{
|
||||||
text += " - " + ip.Item1.Name + " x" + ip.Item2 + (ip.Item3 < 1.0f ? ", " + ip.Item3 * 100 + "% " + TextManager.Get("FabricatorRequiredCondition") + "\n" : "\n");
|
text += " - " + TextManager.Get("SkillName." + skill.Identifier) + " " + TextManager.Get("Lvl").ToLower() + " " + skill.Level;
|
||||||
|
if (skill != selectedItem.RequiredSkills.Last()) { text += "\n"; }
|
||||||
}
|
}
|
||||||
text += TextManager.Get("FabricatorRequiredTime") + ": " + targetItem.RequiredTime + " s\n";
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), text,
|
||||||
|
textColor: inadequateSkills.Any() ? Color.Red : Color.LightGreen, font: GUI.SmallFont);
|
||||||
var requiredItemsText = new GUITextBlock(
|
|
||||||
new Rectangle(0, y, 0, 0),
|
|
||||||
text,
|
|
||||||
Color.Transparent, Color.White,
|
|
||||||
Alignment.TopLeft,
|
|
||||||
Alignment.TopLeft, null,
|
|
||||||
selectedItemFrame,
|
|
||||||
font: GUI.SmallFont);
|
|
||||||
|
|
||||||
|
|
||||||
if (targetItem.RequiredSkills.Any())
|
|
||||||
{
|
|
||||||
text = TextManager.Get("FabricatorRequiredSkills") + ":\n";
|
|
||||||
foreach (Skill skill in inadequateSkills)
|
|
||||||
{
|
|
||||||
text += " - " + skill.Name + " " + TextManager.Get("Lvl").ToLower() + " " + skill.Level + "\n";
|
|
||||||
}
|
|
||||||
new GUITextBlock(
|
|
||||||
new Rectangle(0, y + requiredItemsText.Rect.Height, 0, 0),
|
|
||||||
text,
|
|
||||||
Color.Transparent, inadequateSkills.Any() ? Color.Red : Color.White,
|
|
||||||
Alignment.TopLeft,
|
|
||||||
Alignment.TopLeft, null,
|
|
||||||
selectedItemFrame,
|
|
||||||
font: GUI.SmallFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
activateButton = new GUIButton(new Rectangle(0, -30, 100, 20), TextManager.Get("FabricatorCreate"), Color.White, Alignment.CenterX | Alignment.Bottom, "", selectedItemFrame);
|
|
||||||
activateButton.OnClicked = StartButtonClicked;
|
|
||||||
activateButton.UserData = targetItem;
|
|
||||||
activateButton.Enabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float degreeOfSuccess = DegreeOfSuccess(Character.Controlled, selectedItem.RequiredSkills);
|
||||||
|
if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; }
|
||||||
|
|
||||||
|
float requiredTime = GetRequiredTime(selectedItem, Character.Controlled);
|
||||||
|
string requiredTimeText = TextManager.Get("FabricatorRequiredTime") + ": " + ToolBox.SecondsToReadableTime(requiredTime);
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
|
requiredTimeText, textColor: ToolBox.GradientLerp(degreeOfSuccess, Color.Red, Color.Yellow, Color.LightGreen), font: GUI.SmallFont);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool StartButtonClicked(GUIButton button, object obj)
|
private bool StartButtonClicked(GUIButton button, object obj)
|
||||||
{
|
{
|
||||||
|
if (selectedItem == null) { return false; }
|
||||||
if (fabricatedItem == null)
|
if (fabricatedItem == null)
|
||||||
{
|
{
|
||||||
StartFabricating(obj as FabricableItem, Character.Controlled);
|
StartFabricating(selectedItem, Character.Controlled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -173,49 +335,29 @@ namespace Barotrauma.Items.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
GuiFrame.Draw(spriteBatch);
|
activateButton.Enabled = false;
|
||||||
}
|
inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage;
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
|
||||||
{
|
|
||||||
GuiFrame.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
|
||||||
{
|
|
||||||
FabricableItem targetItem = itemList.SelectedData as FabricableItem;
|
|
||||||
if (targetItem != null)
|
|
||||||
{
|
|
||||||
activateButton.Enabled = CanBeFabricated(targetItem, character);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var availableIngredients = GetAvailableIngredients();
|
||||||
if (character != null)
|
if (character != null)
|
||||||
{
|
{
|
||||||
bool itemsChanged = false;
|
foreach (GUIComponent child in itemList.Content.Children)
|
||||||
if (prevContainedItems == null)
|
|
||||||
{
|
{
|
||||||
itemsChanged = true;
|
var itemPrefab = child.UserData as FabricableItem;
|
||||||
}
|
if (itemPrefab == null) continue;
|
||||||
else
|
|
||||||
{
|
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients);
|
||||||
var itemContainer = item.GetComponent<ItemContainer>();
|
if (itemPrefab == selectedItem)
|
||||||
for (int i = 0; i < itemContainer.Inventory.Items.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (prevContainedItems[i] != itemContainer.Inventory.Items[i])
|
activateButton.Enabled = canBeFabricated;
|
||||||
{
|
|
||||||
itemsChanged = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child.GetChild<GUITextBlock>().TextColor = Color.White * (canBeFabricated ? 1.0f : 0.5f);
|
||||||
|
child.GetChild<GUIImage>().Color = itemPrefab.TargetItem.InventoryIconColor * (canBeFabricated ? 1.0f : 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemsChanged) CheckFabricableItems(character);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GuiFrame.Update((float)Timing.Step);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||||
@@ -227,8 +369,10 @@ namespace Barotrauma.Items.Components
|
|||||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||||
{
|
{
|
||||||
int itemIndex = msg.ReadRangedInteger(-1, fabricableItems.Count - 1);
|
int itemIndex = msg.ReadRangedInteger(-1, fabricableItems.Count - 1);
|
||||||
|
UInt16 userID = msg.ReadUInt16();
|
||||||
|
Character user = Entity.FindEntityByID(userID) as Character;
|
||||||
|
|
||||||
if (itemIndex == -1)
|
if (itemIndex == -1 || user == null)
|
||||||
{
|
{
|
||||||
CancelFabricating();
|
CancelFabricating();
|
||||||
}
|
}
|
||||||
@@ -239,7 +383,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return;
|
if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return;
|
||||||
|
|
||||||
SelectItem(null, fabricableItems[itemIndex]);
|
SelectItem(null, fabricableItems[itemIndex]);
|
||||||
StartFabricating(fabricableItems[itemIndex]);
|
StartFabricating(fabricableItems[itemIndex], user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +1,225 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Barotrauma.Extensions;
|
||||||
|
using FarseerPhysics;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class MiniMap : Powered
|
partial class MiniMap : Powered
|
||||||
{
|
{
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private GUIFrame submarineContainer;
|
||||||
|
|
||||||
|
private GUIFrame hullInfoFrame;
|
||||||
|
|
||||||
|
private GUITextBlock hullNameText, hullBreachText, hullAirQualityText, hullWaterText;
|
||||||
|
|
||||||
|
private List<Submarine> displayedSubs = new List<Submarine>();
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
|
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center),
|
||||||
|
DrawHUDBack, null);
|
||||||
|
submarineContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
|
hullInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.13f), GUI.Canvas, minSize: new Point(250, 150)),
|
||||||
|
style: "InnerFrame")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
var hullInfoContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), hullInfoFrame.RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
hullNameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), hullInfoContainer.RectTransform), "");
|
||||||
|
hullBreachText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
|
||||||
|
hullAirQualityText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
|
||||||
|
hullWaterText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
|
||||||
|
|
||||||
|
hullInfoFrame.Children.ForEach(c => { c.CanBeFocused = false; c.Children.ForEach(c2 => c2.CanBeFocused = false); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
base.AddToGUIUpdateList();
|
||||||
|
if (hasPower) hullInfoFrame.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMapLoaded()
|
||||||
|
{
|
||||||
|
base.OnMapLoaded();
|
||||||
|
CreateHUD();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateHUD()
|
||||||
|
{
|
||||||
|
submarineContainer.ClearChildren();
|
||||||
|
|
||||||
if (item.Submarine == null) return;
|
if (item.Submarine == null) return;
|
||||||
|
|
||||||
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
|
item.Submarine.CreateMiniMap(submarineContainer);
|
||||||
int x = GuiFrame.Rect.X;
|
displayedSubs.Clear();
|
||||||
int y = GuiFrame.Rect.Y;
|
displayedSubs.Add(item.Submarine);
|
||||||
|
displayedSubs.AddRange(item.Submarine.DockedTo);
|
||||||
|
}
|
||||||
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
|
{
|
||||||
|
//recreate HUD if the subs we should display have changed
|
||||||
|
if ((item.Submarine == null && displayedSubs.Count > 0) || //item not inside a sub anymore, but display is still showing subs
|
||||||
|
!displayedSubs.Contains(item.Submarine) || //current sub not displayer
|
||||||
|
item.Submarine.DockedTo.Any(s => !displayedSubs.Contains(s)) || //some of the docked subs not diplayed
|
||||||
|
displayedSubs.Any(s => s != item.Submarine && !item.Submarine.DockedTo.Contains(s))) //displaying a sub that shouldn't be displayed
|
||||||
|
{
|
||||||
|
CreateHUD();
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasPower) return;
|
float distort = 1.0f - item.Condition / 100.0f;
|
||||||
|
foreach (HullData hullData in hullDatas.Values)
|
||||||
|
{
|
||||||
|
hullData.DistortionTimer -= deltaTime;
|
||||||
|
if (hullData.DistortionTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
hullData.Distort = Rand.Range(0.0f, 1.0f) < distort * distort;
|
||||||
|
if (hullData.Distort)
|
||||||
|
{
|
||||||
|
hullData.Oxygen = Rand.Range(0.0f, 100.0f);
|
||||||
|
hullData.Water = Rand.Range(0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
hullData.DistortionTimer = Rand.Range(1.0f, 10.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60);
|
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||||
|
{
|
||||||
|
hullInfoFrame.Visible = false;
|
||||||
|
if (item.Submarine == null || !hasPower)
|
||||||
|
{
|
||||||
|
foreach (Hull hull in Hull.hullList)
|
||||||
|
{
|
||||||
|
var hullFrame = submarineContainer.Children.First().FindChild(hull);
|
||||||
|
if (hullFrame == null) continue;
|
||||||
|
|
||||||
float size = Math.Min((float)miniMap.Width / (float)item.Submarine.Borders.Width, (float)miniMap.Height / (float)item.Submarine.Borders.Height);
|
hullFrame.Color = Color.DarkCyan * 0.3f;
|
||||||
|
hullFrame.Children.First().Color = Color.DarkCyan * 0.3f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = 1.0f;
|
||||||
|
HashSet<Submarine> subs = new HashSet<Submarine>();
|
||||||
foreach (Hull hull in Hull.hullList)
|
foreach (Hull hull in Hull.hullList)
|
||||||
{
|
{
|
||||||
Point topLeft = new Point(
|
if (hull.Submarine == null) continue;
|
||||||
miniMap.X + (int)((hull.Rect.X - item.Submarine.HiddenSubPosition.X - item.Submarine.Borders.X) * size),
|
var hullFrame = submarineContainer.Children.First().FindChild(hull);
|
||||||
miniMap.Y - (int)((hull.Rect.Y - item.Submarine.HiddenSubPosition.Y - item.Submarine.Borders.Y) * size));
|
if (hullFrame == null) continue;
|
||||||
|
|
||||||
Point bottomRight = new Point(
|
hullDatas.TryGetValue(hull, out HullData hullData);
|
||||||
topLeft.X + (int)(hull.Rect.Width * size),
|
if (hullData == null)
|
||||||
topLeft.Y + (int)(hull.Rect.Height * size));
|
{
|
||||||
|
hullData = new HullData();
|
||||||
topLeft.X = (int)MathUtils.RoundTowardsClosest(topLeft.X, 4);
|
hullDatas.Add(hull, hullData);
|
||||||
topLeft.Y = (int)MathUtils.RoundTowardsClosest(topLeft.Y, 4);
|
}
|
||||||
bottomRight.X = (int)MathUtils.RoundTowardsClosest(bottomRight.X, 4);
|
|
||||||
bottomRight.Y = (int)MathUtils.RoundTowardsClosest(bottomRight.Y, 4);
|
|
||||||
|
|
||||||
Rectangle hullRect = new Rectangle(
|
|
||||||
topLeft, bottomRight - topLeft);
|
|
||||||
|
|
||||||
HullData hullData;
|
|
||||||
hullDatas.TryGetValue(hull, out hullData);
|
|
||||||
|
|
||||||
Color borderColor = Color.Green;
|
|
||||||
|
|
||||||
|
|
||||||
//hull integrity -----------------------------------
|
|
||||||
|
|
||||||
|
if (hullData.Distort)
|
||||||
|
{
|
||||||
|
hullFrame.Children.First().Color = Color.Lerp(Color.Black, Color.DarkGray * 0.5f, Rand.Range(0.0f, 1.0f));
|
||||||
|
hullFrame.Color = Color.DarkGray * 0.5f;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
subs.Add(hull.Submarine);
|
||||||
|
scale = Math.Min(
|
||||||
|
hullFrame.Parent.Rect.Width / (float)hull.Submarine.Borders.Width,
|
||||||
|
hullFrame.Parent.Rect.Height / (float)hull.Submarine.Borders.Height);
|
||||||
|
|
||||||
|
Color borderColor = Color.DarkCyan;
|
||||||
|
|
||||||
float? gapOpenSum = 0.0f;
|
float? gapOpenSum = 0.0f;
|
||||||
if (ShowHullIntegrity)
|
if (ShowHullIntegrity)
|
||||||
{
|
{
|
||||||
gapOpenSum = hull.ConnectedGaps.Where(g => !g.IsRoomToRoom).Sum(g => g.Open);
|
gapOpenSum = hull.ConnectedGaps.Where(g => !g.IsRoomToRoom).Sum(g => g.Open);
|
||||||
borderColor = Color.Lerp(borderColor, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
|
borderColor = Color.Lerp(Color.DarkCyan, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
//oxygen -----------------------------------
|
|
||||||
|
|
||||||
float? oxygenAmount = null;
|
float? oxygenAmount = null;
|
||||||
if (RequireOxygenDetectors && (hullData == null || hullData.Oxygen == null))
|
if (!RequireOxygenDetectors || hullData?.Oxygen != null)
|
||||||
{
|
{
|
||||||
borderColor *= 0.5f;
|
oxygenAmount = RequireOxygenDetectors ? hullData.Oxygen : hull.OxygenPercentage;
|
||||||
|
GUI.DrawRectangle(spriteBatch, hullFrame.Rect, Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f), true);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
oxygenAmount = hullData != null && hullData.Oxygen != null ? (float)hullData.Oxygen : hull.OxygenPercentage;
|
|
||||||
GUI.DrawRectangle(spriteBatch, hullRect, Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//water -----------------------------------
|
|
||||||
|
|
||||||
float? waterAmount = null;
|
float? waterAmount = null;
|
||||||
if (RequireWaterDetectors && (hullData == null || hullData.Water == null))
|
if (!RequireWaterDetectors || hullData.Water != null)
|
||||||
{
|
{
|
||||||
borderColor *= 0.5f;
|
waterAmount = RequireWaterDetectors ? hullData.Water : Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
|
||||||
}
|
if (hullFrame.Rect.Height * waterAmount > 3.0f)
|
||||||
else
|
|
||||||
{
|
|
||||||
waterAmount = hullData != null && hullData.Water != null ?
|
|
||||||
(float)hullData.Water :
|
|
||||||
Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
|
|
||||||
|
|
||||||
if (hullRect.Height * waterAmount > 3.0f)
|
|
||||||
{
|
{
|
||||||
Rectangle waterRect = new Rectangle(
|
Rectangle waterRect = new Rectangle(
|
||||||
hullRect.X,
|
hullFrame.Rect.X, (int)(hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount)),
|
||||||
(int)(hullRect.Y + hullRect.Height * (1.0f - waterAmount)),
|
hullFrame.Rect.Width, (int)(hullFrame.Rect.Height * waterAmount));
|
||||||
hullRect.Width,
|
|
||||||
(int)(hullRect.Height * waterAmount));
|
|
||||||
|
|
||||||
waterRect.Inflate(-3, -3);
|
waterRect.Inflate(-3, -3);
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, waterRect, Color.DarkBlue, true);
|
GUI.DrawRectangle(spriteBatch, waterRect, new Color(85, 136, 147), true);
|
||||||
GUI.DrawLine(spriteBatch, new Vector2(waterRect.X, waterRect.Y), new Vector2(waterRect.Right, waterRect.Y), Color.LightBlue);
|
GUI.DrawLine(spriteBatch, new Vector2(waterRect.X, waterRect.Y), new Vector2(waterRect.Right, waterRect.Y), Color.LightBlue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hullRect.Contains(PlayerInput.MousePosition))
|
if (GUI.MouseOn == hullFrame || hullFrame.IsParentOf(GUI.MouseOn))
|
||||||
{
|
{
|
||||||
borderColor = Color.White;
|
hullInfoFrame.RectTransform.ScreenSpaceOffset = hullFrame.Rect.Center;
|
||||||
|
|
||||||
if (gapOpenSum > 0.1f)
|
hullInfoFrame.Visible = true;
|
||||||
{
|
hullNameText.Text = hull.RoomName;
|
||||||
GUI.DrawString(spriteBatch,
|
|
||||||
new Vector2(x + 10, y + height - 60),
|
|
||||||
TextManager.Get("MiniMapHullBreach"), Color.Red, Color.Black * 0.5f, 2, GUI.SmallFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch,
|
hullBreachText.Text = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : "";
|
||||||
new Vector2(x + 10, y + height - 60),
|
hullBreachText.TextColor = Color.Red;
|
||||||
oxygenAmount == null ? TextManager.Get("MiniMapAirQualityUnavailable") : TextManager.Get("MiniMapAirQuality") + ": " + (int)oxygenAmount + " %",
|
|
||||||
oxygenAmount == null ? Color.Red : Color.Lerp(Color.Red, Color.LightGreen, (float)oxygenAmount / 100.0f),
|
|
||||||
Color.Black * 0.5f, 2, GUI.SmallFont);
|
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch,
|
hullAirQualityText.Text = oxygenAmount == null ? TextManager.Get("MiniMapAirQualityUnavailable") : TextManager.Get("MiniMapAirQuality") + ": " + (int)oxygenAmount + " %";
|
||||||
new Vector2(x + 10, y + height - 40),
|
hullAirQualityText.TextColor = oxygenAmount == null ? Color.Red : Color.Lerp(Color.Red, Color.LightGreen, (float)oxygenAmount / 100.0f);
|
||||||
waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.Get("MiniMapWaterLevel") + ": " + (int)(waterAmount * 100.0f) + " %",
|
|
||||||
waterAmount == null ? Color.Red : Color.Lerp(Color.LightGreen, Color.Red, (float)waterAmount),
|
hullWaterText.Text = waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.Get("MiniMapWaterLevel") + ": " + (int)(waterAmount * 100.0f) + " %";
|
||||||
Color.Black * 0.5f, 2, GUI.SmallFont);
|
hullWaterText.TextColor = waterAmount == null ? Color.Red : Color.Lerp(Color.LightGreen, Color.Red, (float)waterAmount);
|
||||||
|
|
||||||
|
borderColor = Color.Lerp(borderColor, Color.White, 0.5f);
|
||||||
|
hullFrame.Children.First().Color = Color.White;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hullFrame.Children.First().Color = Color.DarkCyan * 0.8f;
|
||||||
|
}
|
||||||
|
hullFrame.Color = borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, hullRect, borderColor, false, 0.0f, 2);
|
foreach (Submarine sub in subs)
|
||||||
|
{
|
||||||
|
if (sub.HullVertices == null) { continue; }
|
||||||
|
|
||||||
|
Rectangle worldBorders = sub.GetDockedBorders();
|
||||||
|
worldBorders.Location += sub.WorldPosition.ToPoint();
|
||||||
|
|
||||||
|
scale = Math.Min(
|
||||||
|
submarineContainer.Rect.Width / (float)worldBorders.Width,
|
||||||
|
submarineContainer.Rect.Height / (float)worldBorders.Height) * 0.9f;
|
||||||
|
|
||||||
|
float displayScale = ConvertUnits.ToDisplayUnits(scale);
|
||||||
|
Vector2 offset = ConvertUnits.ToSimUnits(sub.WorldPosition - new Vector2(worldBorders.Center.X, worldBorders.Y - worldBorders.Height / 2));
|
||||||
|
Vector2 center = container.Rect.Center.ToVector2();
|
||||||
|
|
||||||
|
for (int i = 0; i < sub.HullVertices.Count; i++)
|
||||||
|
{
|
||||||
|
Vector2 start = (sub.HullVertices[i] + offset) * displayScale;
|
||||||
|
start.Y = -start.Y;
|
||||||
|
Vector2 end = (sub.HullVertices[(i + 1) % sub.HullVertices.Count] + offset) * displayScale;
|
||||||
|
end.Y = -end.Y;
|
||||||
|
GUI.DrawLine(spriteBatch, center + start, center + end, Color.DarkCyan * Rand.Range(0.3f, 0.35f), width: 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,62 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
|
using Barotrauma.Particles;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Pump : Powered, IServerSerializable, IClientSerializable
|
partial class Pump : Powered, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
private GUITickBox isActiveTickBox;
|
private GUIScrollBar isActiveSlider;
|
||||||
|
private GUIScrollBar pumpSpeedSlider;
|
||||||
|
private GUITickBox powerIndicator;
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
private List<Pair<Vector2, ParticleEmitter>> pumpOutEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||||
|
private List<Pair<Vector2, ParticleEmitter>> pumpInEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
isActiveTickBox = new GUITickBox(new Rectangle(0, 0, 20, 20), TextManager.Get("PumpRunning"), Alignment.TopLeft, GuiFrame);
|
foreach (XElement subElement in element.Elements())
|
||||||
isActiveTickBox.OnSelected = (GUITickBox box) =>
|
|
||||||
{
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "pumpoutemitter":
|
||||||
|
pumpOutEmitters.Add(new Pair<Vector2, ParticleEmitter>(
|
||||||
|
subElement.GetAttributeVector2("position", Vector2.Zero),
|
||||||
|
new ParticleEmitter(subElement)));
|
||||||
|
break;
|
||||||
|
case "pumpinemitter":
|
||||||
|
pumpInEmitters.Add(new Pair<Vector2, ParticleEmitter>(
|
||||||
|
subElement.GetAttributeVector2("position", Vector2.Zero),
|
||||||
|
new ParticleEmitter(subElement)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GuiFrame == null) { return; }
|
||||||
|
|
||||||
|
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
|
isActiveSlider = new GUIScrollBar(new RectTransform(new Point(50, 100), paddedFrame.RectTransform, Anchor.CenterLeft),
|
||||||
|
barSize: 0.2f, style: "OnOffLever")
|
||||||
|
{
|
||||||
|
IsBooleanSwitch = true,
|
||||||
|
MinValue = 0.25f,
|
||||||
|
MaxValue = 0.75f
|
||||||
|
};
|
||||||
|
var sliderHandle = isActiveSlider.GetChild<GUIButton>();
|
||||||
|
sliderHandle.RectTransform.NonScaledSize = new Point(84, sliderHandle.Rect.Height);
|
||||||
|
|
||||||
|
isActiveSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
bool active = scrollBar.BarScroll < 0.5f;
|
||||||
|
if (active == IsActive) return false;
|
||||||
|
|
||||||
targetLevel = null;
|
targetLevel = null;
|
||||||
IsActive = !IsActive;
|
IsActive = active;
|
||||||
if (!IsActive) currPowerConsumption = 0.0f;
|
if (!IsActive) currPowerConsumption = 0.0f;
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
@@ -31,66 +73,102 @@ namespace Barotrauma.Items.Components
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var button = new GUIButton(new Rectangle(160, 40, 35, 30), TextManager.Get("PumpOut"), "", GuiFrame);
|
var rightArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), paddedFrame.RectTransform, Anchor.CenterRight)) { RelativeSpacing = 0.1f };
|
||||||
button.OnClicked = (GUIButton btn, object obj) =>
|
|
||||||
|
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), rightArea.RectTransform), TextManager.Get("PumpPowered"), style: "IndicatorLightGreen")
|
||||||
{
|
{
|
||||||
FlowPercentage -= 10.0f;
|
CanBeFocused = false
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
item.CreateServerEvent(this);
|
|
||||||
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
|
|
||||||
}
|
|
||||||
else if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
correctionTimer = CorrectionDelay;
|
|
||||||
item.CreateClientEvent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
button = new GUIButton(new Rectangle(210, 40, 35, 30), TextManager.Get("PumpIn"), "", GuiFrame);
|
var pumpSpeedText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), rightArea.RectTransform) { RelativeOffset = new Vector2(0.25f, 0.0f) },
|
||||||
button.OnClicked = (GUIButton btn, object obj) =>
|
"", textAlignment: Alignment.BottomLeft);
|
||||||
|
string pumpSpeedStr = TextManager.Get("PumpSpeed");
|
||||||
|
pumpSpeedText.TextGetter = () => { return pumpSpeedStr + ": " + (int)flowPercentage + " %"; };
|
||||||
|
|
||||||
|
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), rightArea.RectTransform, Anchor.CenterLeft), isHorizontal: true)
|
||||||
{
|
{
|
||||||
FlowPercentage += 10.0f;
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
item.CreateServerEvent(this);
|
|
||||||
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
|
|
||||||
}
|
|
||||||
else if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
correctionTimer = CorrectionDelay;
|
|
||||||
item.CreateClientEvent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
|
||||||
|
TextManager.Get("PumpOut"), textAlignment: Alignment.Center);
|
||||||
|
pumpSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.8f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
|
||||||
|
{
|
||||||
|
Step = 0.05f,
|
||||||
|
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
float newValue = barScroll * 200.0f - 100.0f;
|
||||||
|
if (Math.Abs(newValue - FlowPercentage) < 0.1f) return false;
|
||||||
|
|
||||||
|
FlowPercentage = newValue;
|
||||||
|
if (GameMain.Server != null)
|
||||||
|
{
|
||||||
|
item.CreateServerEvent(this);
|
||||||
|
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
|
||||||
|
}
|
||||||
|
else if (GameMain.Client != null)
|
||||||
|
{
|
||||||
|
correctionTimer = CorrectionDelay;
|
||||||
|
item.CreateClientEvent(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
|
||||||
|
TextManager.Get("PumpIn"), textAlignment: Alignment.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnItemLoaded()
|
||||||
|
{
|
||||||
|
if (pumpSpeedSlider != null)
|
||||||
|
{
|
||||||
|
pumpSpeedSlider.BarScroll = (flowPercentage + 100.0f) / 200.0f;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
{
|
{
|
||||||
int x = GuiFrame.Rect.X;
|
if (FlowPercentage < 0.0f)
|
||||||
int y = GuiFrame.Rect.Y;
|
{
|
||||||
|
foreach (Pair<Vector2, ParticleEmitter> pumpOutEmitter in pumpOutEmitters)
|
||||||
GuiFrame.Draw(spriteBatch);
|
{
|
||||||
|
//only emit "pump out" particles when underwater
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("PumpSpeed") + ": " + (int)flowPercentage + " %", new Vector2(x + 40, y + 85), Color.White);
|
Vector2 particlePos = item.Rect.Location.ToVector2() + pumpOutEmitter.First;
|
||||||
|
if (item.CurrentHull != null && item.CurrentHull.Surface < particlePos.Y) continue;
|
||||||
|
|
||||||
|
pumpOutEmitter.Second.Emit(deltaTime, item.WorldRect.Location.ToVector2() + pumpOutEmitter.First * item.Scale, item.CurrentHull,
|
||||||
|
velocityMultiplier: MathHelper.Lerp(0.5f, 1.0f, -FlowPercentage / 100.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (FlowPercentage > 0.0f)
|
||||||
|
{
|
||||||
|
foreach (Pair<Vector2, ParticleEmitter> pumpInEmitter in pumpInEmitters)
|
||||||
|
{
|
||||||
|
pumpInEmitter.Second.Emit(deltaTime, item.WorldRect.Location.ToVector2() + pumpInEmitter.First * item.Scale, item.CurrentHull,
|
||||||
|
velocityMultiplier: MathHelper.Lerp(0.5f, 1.0f, FlowPercentage / 100.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
GuiFrame.AddToGUIUpdateList();
|
powerIndicator.Selected = hasPower && IsActive;
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
if (!PlayerInput.LeftButtonHeld())
|
||||||
{
|
{
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
isActiveSlider.BarScroll += (IsActive ? -10.0f : 10.0f) * deltaTime;
|
||||||
}
|
|
||||||
|
|
||||||
|
float pumpSpeedScroll = (FlowPercentage + 100.0f) / 200.0f;
|
||||||
|
if (Math.Abs(pumpSpeedScroll - pumpSpeedSlider.BarScroll) > 0.01f)
|
||||||
|
{
|
||||||
|
pumpSpeedSlider.BarScroll = pumpSpeedScroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
||||||
{
|
{
|
||||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||||
|
|||||||
@@ -1,468 +0,0 @@
|
|||||||
using Barotrauma.Networking;
|
|
||||||
using FarseerPhysics;
|
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Voronoi2;
|
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
|
||||||
{
|
|
||||||
partial class Radar : Powered, IServerSerializable, IClientSerializable
|
|
||||||
{
|
|
||||||
private GUITickBox isActiveTickBox;
|
|
||||||
|
|
||||||
private List<RadarBlip> radarBlips;
|
|
||||||
|
|
||||||
private static Color[] blipColorGradient =
|
|
||||||
{
|
|
||||||
Color.TransparentBlack,
|
|
||||||
new Color(0, 50, 160),
|
|
||||||
new Color(0, 133, 166),
|
|
||||||
new Color(2, 159, 30),
|
|
||||||
new Color(255, 255, 255)
|
|
||||||
};
|
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
|
||||||
{
|
|
||||||
GuiFrame.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
|
||||||
{
|
|
||||||
GuiFrame.Update((float)Timing.Step);
|
|
||||||
|
|
||||||
for (int i = radarBlips.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
radarBlips[i].FadeTimer -= (float)Timing.Step * 0.5f;
|
|
||||||
if (radarBlips[i].FadeTimer <= 0.0f) radarBlips.RemoveAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsActive)
|
|
||||||
{
|
|
||||||
float pingRadius = displayRadius * pingState;
|
|
||||||
Ping(item.WorldPosition, pingRadius, prevPingRadius, displayScale, range, 2.0f);
|
|
||||||
prevPingRadius = pingRadius;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float passivePingRadius = (float)Math.Sin(Timing.TotalTime * 10);
|
|
||||||
if (passivePingRadius > 0.0f)
|
|
||||||
{
|
|
||||||
foreach (AITarget t in AITarget.List)
|
|
||||||
{
|
|
||||||
if (t.SoundRange <= 0.0f) continue;
|
|
||||||
|
|
||||||
if (Vector2.Distance(t.WorldPosition, item.WorldPosition) < t.SoundRange)
|
|
||||||
{
|
|
||||||
Ping(t.WorldPosition, t.SoundRange * passivePingRadius * 0.2f, t.SoundRange * prevPassivePingRadius * 0.2f, displayScale, t.SoundRange, 0.5f);
|
|
||||||
|
|
||||||
radarBlips.Add(new RadarBlip(t.WorldPosition, 1.0f, 1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevPassivePingRadius = passivePingRadius;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
|
||||||
{
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
int radius = GuiFrame.Rect.Height / 2 - 10;
|
|
||||||
DrawRadar(spriteBatch, new Rectangle((int)GuiFrame.Center.X - radius, (int)GuiFrame.Center.Y - radius, radius * 2, radius * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawRadar(SpriteBatch spriteBatch, Rectangle rect)
|
|
||||||
{
|
|
||||||
center = new Vector2(rect.X + rect.Width * 0.5f, rect.Center.Y);
|
|
||||||
displayRadius = (rect.Width / 2.0f) * (1.0f - displayBorderSize);
|
|
||||||
displayScale = displayRadius / range;
|
|
||||||
|
|
||||||
if (IsActive)
|
|
||||||
{
|
|
||||||
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState), 0.0f, (displayRadius * 2 / pingCircle.size.X) * pingState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Submarine != null && !DetectSubmarineWalls)
|
|
||||||
{
|
|
||||||
float simScale = displayScale * Physics.DisplayToSimRation;
|
|
||||||
|
|
||||||
foreach (Submarine submarine in Submarine.Loaded)
|
|
||||||
{
|
|
||||||
if (submarine != item.Submarine && !submarine.DockedTo.Contains(item.Submarine)) continue;
|
|
||||||
if (submarine.HullVertices == null) continue;
|
|
||||||
|
|
||||||
Vector2 offset = ConvertUnits.ToSimUnits(submarine.WorldPosition - item.WorldPosition);
|
|
||||||
|
|
||||||
for (int i = 0; i < submarine.HullVertices.Count; i++)
|
|
||||||
{
|
|
||||||
Vector2 start = (submarine.HullVertices[i] + offset) * simScale;
|
|
||||||
start.Y = -start.Y;
|
|
||||||
Vector2 end = (submarine.HullVertices[(i + 1) % submarine.HullVertices.Count] + offset) * simScale;
|
|
||||||
end.Y = -end.Y;
|
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch, center + start, center + end, Color.LightBlue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radarBlips.Count > 0)
|
|
||||||
{
|
|
||||||
spriteBatch.End();
|
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
|
|
||||||
|
|
||||||
foreach (RadarBlip radarBlip in radarBlips)
|
|
||||||
{
|
|
||||||
DrawBlip(spriteBatch, radarBlip, center, radarBlip.FadeTimer / 2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
spriteBatch.End();
|
|
||||||
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, GameMain.ScissorTestEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameMain.DebugDraw)
|
|
||||||
{
|
|
||||||
GUI.DrawString(spriteBatch, rect.Location.ToVector2(), radarBlips.Count.ToString(), Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screenOverlay != null)
|
|
||||||
{
|
|
||||||
screenOverlay.Draw(spriteBatch, center, 0.0f, rect.Width / screenOverlay.size.X);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameMain.GameSession == null) return;
|
|
||||||
|
|
||||||
DrawMarker(spriteBatch,
|
|
||||||
GameMain.GameSession.StartLocation.Name,
|
|
||||||
(Level.Loaded.StartPosition - item.WorldPosition), displayScale, center, (rect.Width * 0.5f));
|
|
||||||
|
|
||||||
DrawMarker(spriteBatch,
|
|
||||||
GameMain.GameSession.EndLocation.Name,
|
|
||||||
(Level.Loaded.EndPosition - item.WorldPosition), displayScale, center, (rect.Width * 0.5f));
|
|
||||||
|
|
||||||
if (GameMain.GameSession.Mission != null)
|
|
||||||
{
|
|
||||||
var mission = GameMain.GameSession.Mission;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(mission.RadarLabel) && mission.RadarPosition != Vector2.Zero)
|
|
||||||
{
|
|
||||||
DrawMarker(spriteBatch,
|
|
||||||
mission.RadarLabel,
|
|
||||||
mission.RadarPosition - item.WorldPosition, displayScale, center, (rect.Width * 0.55f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Submarine sub in Submarine.Loaded)
|
|
||||||
{
|
|
||||||
if (!sub.OnRadar) continue;
|
|
||||||
if (item.Submarine == sub || sub.DockedTo.Contains(item.Submarine)) continue;
|
|
||||||
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) continue;
|
|
||||||
|
|
||||||
DrawMarker(spriteBatch, sub.Name, sub.WorldPosition - item.WorldPosition, displayScale, center, (rect.Width * 0.45f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GameMain.DebugDraw) return;
|
|
||||||
|
|
||||||
var steering = item.GetComponent<Steering>();
|
|
||||||
if (steering == null || steering.SteeringPath == null) return;
|
|
||||||
|
|
||||||
Vector2 prevPos = Vector2.Zero;
|
|
||||||
|
|
||||||
foreach (WayPoint wp in steering.SteeringPath.Nodes)
|
|
||||||
{
|
|
||||||
Vector2 pos = (wp.Position - item.WorldPosition) * displayScale;
|
|
||||||
if (pos.Length() > displayRadius) continue;
|
|
||||||
|
|
||||||
pos.Y = -pos.Y;
|
|
||||||
pos += center;
|
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 3 / 2, (int)pos.Y - 3, 6, 6), (steering.SteeringPath.CurrentNode == wp) ? Color.LightGreen : Color.Green, false);
|
|
||||||
|
|
||||||
if (prevPos != Vector2.Zero)
|
|
||||||
{
|
|
||||||
GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green);
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void Ping(Vector2 pingSource, float pingRadius, float prevPingRadius, float displayScale, float range, float pingStrength = 1.0f)
|
|
||||||
{
|
|
||||||
//inside a hull -> only show the edges of the hull
|
|
||||||
if (item.CurrentHull != null && DetectSubmarineWalls)
|
|
||||||
{
|
|
||||||
CreateBlipsForLine(
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y),
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y),
|
|
||||||
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
||||||
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y),
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
||||||
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y),
|
|
||||||
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
||||||
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Submarine submarine in Submarine.Loaded)
|
|
||||||
{
|
|
||||||
if (item.Submarine == submarine && !DetectSubmarineWalls) continue;
|
|
||||||
if (item.Submarine != null && item.Submarine.DockedTo.Contains(submarine)) continue;
|
|
||||||
if (submarine.HullVertices == null) continue;
|
|
||||||
|
|
||||||
for (int i = 0; i < submarine.HullVertices.Count; i++)
|
|
||||||
{
|
|
||||||
Vector2 start = ConvertUnits.ToDisplayUnits(submarine.HullVertices[i]);
|
|
||||||
Vector2 end = ConvertUnits.ToDisplayUnits(submarine.HullVertices[(i + 1) % submarine.HullVertices.Count]);
|
|
||||||
|
|
||||||
if (item.Submarine == submarine)
|
|
||||||
{
|
|
||||||
start += Rand.Vector(500.0f);
|
|
||||||
end += Rand.Vector(500.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
start + submarine.WorldPosition,
|
|
||||||
end + submarine.WorldPosition,
|
|
||||||
pingRadius, prevPingRadius,
|
|
||||||
200.0f, 2.0f, range, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Level.Loaded != null && (item.CurrentHull == null || !DetectSubmarineWalls))
|
|
||||||
{
|
|
||||||
if (Level.Loaded.Size.Y - pingSource.Y < range)
|
|
||||||
{
|
|
||||||
CreateBlipsForLine(
|
|
||||||
new Vector2(pingSource.X - range, Level.Loaded.Size.Y),
|
|
||||||
new Vector2(pingSource.X + range, Level.Loaded.Size.Y),
|
|
||||||
pingRadius, prevPingRadius,
|
|
||||||
250.0f, 150.0f, range, pingStrength);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
|
|
||||||
foreach (VoronoiCell cell in cells)
|
|
||||||
{
|
|
||||||
foreach (GraphEdge edge in cell.edges)
|
|
||||||
{
|
|
||||||
if (!edge.isSolid) continue;
|
|
||||||
float cellDot = Vector2.Dot(cell.Center - pingSource, (edge.Center + cell.Translation) - cell.Center);
|
|
||||||
if (cellDot > 0) continue;
|
|
||||||
|
|
||||||
float facingDot = Vector2.Dot(
|
|
||||||
Vector2.Normalize(edge.point1 - edge.point2),
|
|
||||||
Vector2.Normalize(cell.Center - pingSource));
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
edge.point1 + cell.Translation,
|
|
||||||
edge.point2 + cell.Translation,
|
|
||||||
pingRadius, prevPingRadius,
|
|
||||||
350.0f, 3.0f * (Math.Abs(facingDot) + 1.0f), range, pingStrength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
|
|
||||||
{
|
|
||||||
if (!MathUtils.CircleIntersectsRectangle(pingSource, range, ruin.Area)) continue;
|
|
||||||
|
|
||||||
foreach (var ruinShape in ruin.RuinShapes)
|
|
||||||
{
|
|
||||||
foreach (RuinGeneration.Line wall in ruinShape.Walls)
|
|
||||||
{
|
|
||||||
float cellDot = Vector2.Dot(
|
|
||||||
Vector2.Normalize(ruinShape.Center - pingSource),
|
|
||||||
Vector2.Normalize((wall.A + wall.B) / 2.0f - ruinShape.Center));
|
|
||||||
if (cellDot > 0) continue;
|
|
||||||
|
|
||||||
CreateBlipsForLine(
|
|
||||||
wall.A, wall.B,
|
|
||||||
pingRadius, prevPingRadius,
|
|
||||||
100.0f, 1000.0f, range, pingStrength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Character c in Character.CharacterList)
|
|
||||||
{
|
|
||||||
if (c.AnimController.CurrentHull != null || !c.Enabled) continue;
|
|
||||||
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) continue;
|
|
||||||
|
|
||||||
foreach (Limb limb in c.AnimController.Limbs)
|
|
||||||
{
|
|
||||||
float pointDist = (limb.WorldPosition - pingSource).Length() * displayScale;
|
|
||||||
|
|
||||||
if (limb.SimPosition == Vector2.Zero || pointDist > displayRadius) continue;
|
|
||||||
|
|
||||||
if (pointDist > prevPingRadius && pointDist < pingRadius)
|
|
||||||
{
|
|
||||||
var blip = new RadarBlip(
|
|
||||||
limb.WorldPosition + Rand.Vector(limb.Mass / 10.0f),
|
|
||||||
MathHelper.Clamp(limb.Mass, 0.1f, pingStrength),
|
|
||||||
MathHelper.Clamp(limb.Mass * 0.1f, 0.1f, 2.0f));
|
|
||||||
radarBlips.Add(blip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateBlipsForLine(Vector2 point1, Vector2 point2, float pingRadius, float prevPingRadius,
|
|
||||||
float lineStep, float zStep, float range, float pingStrength)
|
|
||||||
{
|
|
||||||
float length = (point1 - point2).Length();
|
|
||||||
|
|
||||||
Vector2 lineDir = (point2 - point1) / length;
|
|
||||||
|
|
||||||
range *= displayScale;
|
|
||||||
|
|
||||||
for (float x = 0; x < length; x += lineStep * Rand.Range(0.8f, 1.2f))
|
|
||||||
{
|
|
||||||
Vector2 point = point1 + lineDir * x;
|
|
||||||
//point += cell.Translation;
|
|
||||||
|
|
||||||
float pointDist = Vector2.Distance(item.WorldPosition, point) * displayScale;
|
|
||||||
|
|
||||||
if (pointDist > displayRadius) continue;
|
|
||||||
if (pointDist < prevPingRadius || pointDist > pingRadius) continue;
|
|
||||||
|
|
||||||
float alpha = pingStrength * Rand.Range(1.5f, 2.0f);
|
|
||||||
for (float z = 0; z < displayRadius - pointDist * displayScale; z += zStep)
|
|
||||||
{
|
|
||||||
Vector2 pos = point + Rand.Vector(150.0f) + Vector2.Normalize(point - item.WorldPosition) * z / displayScale;
|
|
||||||
float fadeTimer = alpha * (1.0f - pointDist / range);
|
|
||||||
|
|
||||||
int minDist = 200;
|
|
||||||
radarBlips.RemoveAll(b => b.FadeTimer < fadeTimer && Math.Abs(pos.X - b.Position.X) < minDist && Math.Abs(pos.Y - b.Position.Y) < minDist);
|
|
||||||
|
|
||||||
var blip = new RadarBlip(pos, fadeTimer, 1.0f + ((pointDist+z) / displayRadius));
|
|
||||||
|
|
||||||
radarBlips.Add(blip);
|
|
||||||
zStep += 0.5f;
|
|
||||||
|
|
||||||
if (z == 0)
|
|
||||||
{
|
|
||||||
alpha = Math.Min(alpha - 0.5f, 1.5f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alpha -= 0.1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alpha < 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawBlip(SpriteBatch spriteBatch, RadarBlip blip, Vector2 center, float strength)
|
|
||||||
{
|
|
||||||
strength = MathHelper.Clamp(strength, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
float scaledT = strength * (blipColorGradient.Length - 1);
|
|
||||||
Color color = Color.Lerp(blipColorGradient[(int)scaledT], blipColorGradient[(int)Math.Min(scaledT + 1, blipColorGradient.Length - 1)], (scaledT - (int)scaledT));
|
|
||||||
|
|
||||||
Vector2 pos = (blip.Position - item.WorldPosition) * displayScale;
|
|
||||||
pos.Y = -pos.Y;
|
|
||||||
|
|
||||||
float posDist = pos.Length();
|
|
||||||
if (posDist > displayRadius)
|
|
||||||
{
|
|
||||||
blip.FadeTimer = 0.0f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radarBlip == null)
|
|
||||||
{
|
|
||||||
GUI.DrawRectangle(spriteBatch, center + pos, Vector2.One * 4, Color.Magenta, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 dir = pos / posDist;
|
|
||||||
|
|
||||||
Vector2 normal = new Vector2(dir.Y, -dir.X);
|
|
||||||
float scale = (strength + 3.0f) * blip.Scale;
|
|
||||||
|
|
||||||
radarBlip.Draw(spriteBatch, center + pos, color, radarBlip.Origin, MathUtils.VectorToAngle(pos),
|
|
||||||
new Vector2(scale * 0.5f, scale) * 0.04f, SpriteEffects.None, 0);
|
|
||||||
|
|
||||||
pos += Rand.Range(0.0f, 1.0f) * dir + Rand.Range(-scale, scale) * normal;
|
|
||||||
|
|
||||||
radarBlip.Draw(spriteBatch, center + pos, color * 0.5f, radarBlip.Origin, 0, scale * 0.08f, SpriteEffects.None, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawMarker(SpriteBatch spriteBatch, string label, Vector2 position, float scale, Vector2 center, float radius)
|
|
||||||
{
|
|
||||||
float dist = position.Length();
|
|
||||||
|
|
||||||
position *= scale;
|
|
||||||
position.Y = -position.Y;
|
|
||||||
|
|
||||||
float textAlpha = MathHelper.Clamp(1.5f - dist / 50000.0f, 0.5f, 1.0f);
|
|
||||||
|
|
||||||
Vector2 dir = Vector2.Normalize(position);
|
|
||||||
|
|
||||||
Vector2 markerPos = (dist * scale > radius) ? dir * radius : position;
|
|
||||||
markerPos += center;
|
|
||||||
|
|
||||||
markerPos.X = (int)markerPos.X;
|
|
||||||
markerPos.Y = (int)markerPos.Y;
|
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X, (int)markerPos.Y, 5, 5), Color.LightBlue);
|
|
||||||
|
|
||||||
if (dir.X < 0.0f) markerPos.X -= GUI.SmallFont.MeasureString(label).X + 10;
|
|
||||||
|
|
||||||
string wrappedLabel = ToolBox.WrapText(label, 150, GUI.SmallFont);
|
|
||||||
wrappedLabel += "\n" + ((int)(dist * Physics.DisplayToRealWorldRatio) + " m");
|
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch,
|
|
||||||
new Vector2(markerPos.X + 10, markerPos.Y),
|
|
||||||
wrappedLabel,
|
|
||||||
Color.LightBlue * textAlpha, Color.Black * textAlpha * 0.5f,
|
|
||||||
2, GUI.SmallFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
|
||||||
{
|
|
||||||
msg.Write(IsActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
|
||||||
{
|
|
||||||
if (correctionTimer > 0.0f)
|
|
||||||
{
|
|
||||||
StartDelayedCorrection(type, msg.ExtractBits(1), sendingTime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsActive = msg.ReadBoolean();
|
|
||||||
isActiveTickBox.Selected = IsActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RadarBlip
|
|
||||||
{
|
|
||||||
public float FadeTimer;
|
|
||||||
public Vector2 Position;
|
|
||||||
public float Scale;
|
|
||||||
|
|
||||||
public RadarBlip(Vector2 pos, float fadeTimer, float scale)
|
|
||||||
{
|
|
||||||
Position = pos;
|
|
||||||
FadeTimer = Math.Max(fadeTimer, 0.0f);
|
|
||||||
Scale = scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,200 +4,458 @@ using Microsoft.Xna.Framework;
|
|||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Reactor : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
|
partial class Reactor : Powered, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
private GUITickBox autoTempTickBox;
|
private GUIScrollBar autoTempSlider;
|
||||||
|
private GUIScrollBar onOffSwitch;
|
||||||
|
|
||||||
private const int GraphSize = 25;
|
private const int GraphSize = 25;
|
||||||
private float graphTimer;
|
private float graphTimer;
|
||||||
private int updateGraphInterval = 500;
|
private int updateGraphInterval = 500;
|
||||||
|
|
||||||
|
private Sprite fissionRateMeter, turbineOutputMeter;
|
||||||
|
private Sprite meterPointer;
|
||||||
|
private Sprite sectorSprite;
|
||||||
|
|
||||||
private float[] fissionRateGraph = new float[GraphSize];
|
private Sprite tempMeterFrame, tempMeterBar;
|
||||||
private float[] coolingRateGraph = new float[GraphSize];
|
private Sprite tempRangeIndicator;
|
||||||
private float[] tempGraph = new float[GraphSize];
|
|
||||||
|
private Sprite graphLine;
|
||||||
|
|
||||||
|
private GUIScrollBar fissionRateScrollBar;
|
||||||
|
private GUIScrollBar turbineOutputScrollBar;
|
||||||
|
|
||||||
|
private float[] outputGraph = new float[GraphSize];
|
||||||
private float[] loadGraph = new float[GraphSize];
|
private float[] loadGraph = new float[GraphSize];
|
||||||
|
|
||||||
|
private GUITickBox criticalHeatWarning;
|
||||||
|
private GUITickBox lowTemperatureWarning;
|
||||||
|
private GUITickBox criticalOutputWarning;
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
private GUIFrame inventoryContainer;
|
||||||
|
|
||||||
|
private GUIComponent leftHUDColumn;
|
||||||
|
|
||||||
|
private Dictionary<string, GUIButton> warningButtons = new Dictionary<string, GUIButton>();
|
||||||
|
|
||||||
|
private static string[] warningTexts = new string[]
|
||||||
{
|
{
|
||||||
var button = new GUIButton(new Rectangle(410, 70, 40, 40), "-", "", GuiFrame);
|
"ReactorWarningLowTemp","ReactorWarningOverheating",
|
||||||
button.OnPressed = () =>
|
"ReactorWarningLowOutput", "ReactorWarningHighOutput",
|
||||||
{
|
"ReactorWarningLowFuel", "ReactorWarningFuelOut",
|
||||||
lastUser = Character.Controlled;
|
"ReactorWarningMeltdown","ReactorWarningSCRAM"
|
||||||
if (nextServerLogWriteTime == null)
|
};
|
||||||
{
|
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
|
||||||
}
|
|
||||||
unsentChanges = true;
|
|
||||||
ShutDownTemp -= 100.0f;
|
|
||||||
|
|
||||||
return false;
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "fissionratemeter":
|
||||||
|
fissionRateMeter = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "turbineoutputmeter":
|
||||||
|
turbineOutputMeter = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "meterpointer":
|
||||||
|
meterPointer = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "sectorsprite":
|
||||||
|
sectorSprite = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "tempmeterframe":
|
||||||
|
tempMeterFrame = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "tempmeterbar":
|
||||||
|
tempMeterBar = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "temprangeindicator":
|
||||||
|
tempRangeIndicator = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
case "graphline":
|
||||||
|
graphLine = new Sprite(subElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.85f), GuiFrame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.015f,
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
|
GUIFrame columnLeft = new GUIFrame(new RectTransform(new Vector2(0.2f, 1.0f), paddedFrame.RectTransform), style: null);
|
||||||
|
leftHUDColumn = columnLeft;
|
||||||
|
GUIFrame columnMid = new GUIFrame(new RectTransform(new Vector2(0.45f, 1.0f), paddedFrame.RectTransform), style: null);
|
||||||
|
GUIFrame columnRight = new GUIFrame(new RectTransform(new Vector2(0.35f, 1.0f), paddedFrame.RectTransform), style: null);
|
||||||
|
|
||||||
|
//----------------------------------------------------------
|
||||||
|
//left column
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
|
int buttonsPerRow = 2;
|
||||||
|
int spacing = 5;
|
||||||
|
int buttonWidth = columnLeft.Rect.Width / buttonsPerRow - (spacing * (buttonsPerRow - 1));
|
||||||
|
int buttonHeight = (int)(columnLeft.Rect.Height * 0.5f) / 4;
|
||||||
|
for (int i = 0; i < warningTexts.Length; i++)
|
||||||
|
{
|
||||||
|
var warningBtn = new GUIButton(new RectTransform(new Point(buttonWidth, buttonHeight), columnLeft.RectTransform)
|
||||||
|
{ AbsoluteOffset = new Point((i % buttonsPerRow) * (buttonWidth + spacing), (int)Math.Floor(i / (float)buttonsPerRow) * (buttonHeight + spacing)) },
|
||||||
|
TextManager.Get(warningTexts[i]), style: "IndicatorButton");
|
||||||
|
|
||||||
|
var btnText = warningBtn.GetChild<GUITextBlock>();
|
||||||
|
btnText.Font = GUI.SmallFont;
|
||||||
|
btnText.Wrap = true;
|
||||||
|
btnText.SetTextPos();
|
||||||
|
warningButtons.Add(warningTexts[i], warningBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
inventoryContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.45f), columnLeft.RectTransform, Anchor.BottomLeft), style: null);
|
||||||
|
|
||||||
|
//----------------------------------------------------------
|
||||||
|
//mid column
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
|
criticalHeatWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform),
|
||||||
|
TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SmallFont, style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
lowTemperatureWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform) { RelativeOffset = new Vector2(0.3f, 0.0f) },
|
||||||
|
TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SmallFont, style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
criticalOutputWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform) { RelativeOffset = new Vector2(0.75f, 0.0f) },
|
||||||
|
TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SmallFont, style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.05f), columnMid.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.25f) },
|
||||||
|
TextManager.Get("ReactorFissionRate"));
|
||||||
|
new GUICustomComponent(new RectTransform(new Vector2(0.5f, 0.5f), columnMid.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.3f) },
|
||||||
|
DrawFissionRateMeter, null)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ReactorTipFissionRate")
|
||||||
};
|
};
|
||||||
|
|
||||||
button = new GUIButton(new Rectangle(460, 70, 40, 40), "+", "", GuiFrame);
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.05f), columnMid.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.25f) },
|
||||||
button.OnPressed = () =>
|
TextManager.Get("ReactorTurbineOutput"));
|
||||||
|
new GUICustomComponent(new RectTransform(new Vector2(0.5f, 0.5f), columnMid.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.3f) },
|
||||||
|
DrawTurbineOutputMeter, null)
|
||||||
{
|
{
|
||||||
lastUser = Character.Controlled;
|
ToolTip = TextManager.Get("ReactorTipTurbineOutput")
|
||||||
if (nextServerLogWriteTime == null)
|
|
||||||
{
|
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
|
||||||
}
|
|
||||||
unsentChanges = true;
|
|
||||||
ShutDownTemp += 100.0f;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
autoTempTickBox = new GUITickBox(new Rectangle(410, 170, 20, 20), TextManager.Get("ReactorAutoTemp"), Alignment.TopLeft, GuiFrame);
|
new GUITextBlock(new RectTransform(new Point(0, 20), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, 90) },
|
||||||
autoTempTickBox.OnSelected = ToggleAutoTemp;
|
TextManager.Get("ReactorFissionRate"));
|
||||||
|
fissionRateScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, 30), columnMid.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 60) },
|
||||||
button = new GUIButton(new Rectangle(210, 290, 40, 40), "+", "", GuiFrame);
|
style: "GUISlider", barSize: 0.1f)
|
||||||
button.OnPressed = () =>
|
|
||||||
{
|
{
|
||||||
lastUser = Character.Controlled;
|
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
|
||||||
if (nextServerLogWriteTime == null)
|
|
||||||
{
|
{
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
LastUser = Character.Controlled;
|
||||||
}
|
if (nextServerLogWriteTime == null)
|
||||||
unsentChanges = true;
|
{
|
||||||
FissionRate += 1.0f;
|
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
targetFissionRate = scrollAmount * 100.0f;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
button = new GUIButton(new Rectangle(210, 340, 40, 40), "-", "", GuiFrame);
|
new GUITextBlock(new RectTransform(new Point(0, 20), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, 30) },
|
||||||
button.OnPressed = () =>
|
TextManager.Get("ReactorTurbineOutput"));
|
||||||
|
turbineOutputScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, 30), columnMid.RectTransform, Anchor.BottomCenter),
|
||||||
|
style: "GUISlider", barSize: 0.1f, isHorizontal: true)
|
||||||
{
|
{
|
||||||
lastUser = Character.Controlled;
|
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
|
||||||
if (nextServerLogWriteTime == null)
|
|
||||||
{
|
{
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
LastUser = Character.Controlled;
|
||||||
}
|
if (nextServerLogWriteTime == null)
|
||||||
unsentChanges = true;
|
{
|
||||||
FissionRate -= 1.0f;
|
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
targetTurbineOutput = scrollAmount * 100.0f;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
button = new GUIButton(new Rectangle(500, 290, 40, 40), "+", "", GuiFrame);
|
//----------------------------------------------------------
|
||||||
button.OnPressed = () =>
|
//right column
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Point(100, 20), columnRight.RectTransform), TextManager.Get("ReactorAutoTemp"))
|
||||||
{
|
{
|
||||||
lastUser = Character.Controlled;
|
ToolTip = TextManager.Get("ReactorTipAutoTemp")
|
||||||
if (nextServerLogWriteTime == null)
|
|
||||||
{
|
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
|
||||||
}
|
|
||||||
unsentChanges = true;
|
|
||||||
CoolingRate += 1.0f;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
autoTempSlider = new GUIScrollBar(new RectTransform(new Point(100, 30), columnRight.RectTransform) { AbsoluteOffset = new Point(0, 30) },
|
||||||
button = new GUIButton(new Rectangle(500, 340, 40, 40), "-", "", GuiFrame);
|
barSize: 0.5f, style: "OnOffSlider")
|
||||||
button.OnPressed = () =>
|
|
||||||
{
|
{
|
||||||
lastUser = Character.Controlled;
|
ToolTip = TextManager.Get("ReactorTipAutoTemp"),
|
||||||
if (nextServerLogWriteTime == null)
|
IsBooleanSwitch = true,
|
||||||
|
BarScroll = 1.0f,
|
||||||
|
OnMoved = (scrollBar, scrollAmount) =>
|
||||||
{
|
{
|
||||||
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
LastUser = Character.Controlled;
|
||||||
|
if (nextServerLogWriteTime == null)
|
||||||
|
{
|
||||||
|
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
unsentChanges = true;
|
|
||||||
CoolingRate -= 1.0f;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onOffSwitch = new GUIScrollBar(new RectTransform(new Point(50, 80), columnRight.RectTransform, Anchor.TopRight),
|
||||||
|
barSize: 0.2f, style: "OnOffLever")
|
||||||
|
{
|
||||||
|
IsBooleanSwitch = true,
|
||||||
|
MinValue = 0.25f,
|
||||||
|
MaxValue = 0.75f,
|
||||||
|
OnMoved = (scrollBar, scrollAmount) =>
|
||||||
|
{
|
||||||
|
LastUser = Character.Controlled;
|
||||||
|
if (nextServerLogWriteTime == null)
|
||||||
|
{
|
||||||
|
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var lever = onOffSwitch.GetChild<GUIButton>();
|
||||||
|
lever.RectTransform.NonScaledSize = new Point(lever.Rect.Width + 30, lever.Rect.Height);
|
||||||
|
|
||||||
|
var graphArea = new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.5f), columnRight.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 30) },
|
||||||
|
DrawGraph, null);
|
||||||
|
|
||||||
|
var loadText = new GUITextBlock(new RectTransform(new Point(100, 30), graphArea.RectTransform, Anchor.TopLeft, Pivot.BottomLeft),
|
||||||
|
"Load", textColor: Color.LightBlue, textAlignment: Alignment.CenterLeft)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ReactorTipLoad")
|
||||||
|
};
|
||||||
|
string loadStr = TextManager.Get("ReactorLoad");
|
||||||
|
loadText.TextGetter += () => { return loadStr.Replace("[kw]", ((int)load).ToString()); };
|
||||||
|
|
||||||
|
var outputText = new GUITextBlock(new RectTransform(new Point(100, 30), graphArea.RectTransform, Anchor.BottomLeft, Pivot.TopLeft),
|
||||||
|
"Output", textColor: Color.LightGreen, textAlignment: Alignment.CenterLeft)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ReactorTipPower")
|
||||||
|
};
|
||||||
|
string outputStr = TextManager.Get("ReactorOutput");
|
||||||
|
outputText.TextGetter += () => { return outputStr.Replace("[kw]", ((int)-currPowerConsumption).ToString()); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnItemLoaded()
|
||||||
|
{
|
||||||
|
turbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
|
||||||
|
fissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
|
||||||
|
var itemContainer = item.GetComponent<ItemContainer>();
|
||||||
|
if (itemContainer != null)
|
||||||
|
{
|
||||||
|
itemContainer.AllowUIOverlap = true;
|
||||||
|
itemContainer.Inventory.RectTransform = inventoryContainer.RectTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawGraph(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||||
|
{
|
||||||
|
Rectangle graphArea = new Rectangle(container.Rect.X + 30, container.Rect.Y, container.Rect.Width - 30, container.Rect.Height);
|
||||||
|
|
||||||
|
float maxLoad = loadGraph.Max();
|
||||||
|
|
||||||
|
float xOffset = graphTimer / updateGraphInterval;
|
||||||
|
DrawGraph(outputGraph, spriteBatch,
|
||||||
|
graphArea, Math.Max(10000.0f, maxLoad), xOffset, Color.LightGreen);
|
||||||
|
|
||||||
|
DrawGraph(loadGraph, spriteBatch,
|
||||||
|
graphArea, Math.Max(10000.0f, maxLoad), xOffset, Color.LightBlue);
|
||||||
|
|
||||||
|
tempMeterFrame.Draw(spriteBatch, new Vector2(graphArea.X - 30, graphArea.Y), Color.White, Vector2.Zero, 0.0f, new Vector2(1.0f, graphArea.Height / tempMeterFrame.size.Y));
|
||||||
|
float tempFill = temperature / 100.0f;
|
||||||
|
|
||||||
|
int barPadding = 5;
|
||||||
|
Vector2 meterBarPos = new Vector2(graphArea.X - 30 + tempMeterFrame.size.X / 2, graphArea.Bottom - tempMeterBar.size.Y);
|
||||||
|
while (meterBarPos.Y > graphArea.Bottom - graphArea.Height * tempFill)
|
||||||
|
{
|
||||||
|
float tempRatio = 1.0f - ((meterBarPos.Y - graphArea.Y) / graphArea.Height);
|
||||||
|
Color color = tempRatio < 0.5f ?
|
||||||
|
Color.Lerp(Color.Green, Color.Orange, tempRatio * 2.0f) :
|
||||||
|
Color.Lerp(Color.Orange, Color.Red, (tempRatio - 0.5f) * 2.0f);
|
||||||
|
|
||||||
|
tempMeterBar.Draw(spriteBatch, meterBarPos, color);
|
||||||
|
meterBarPos.Y -= (tempMeterBar.size.Y + barPadding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temperature > optimalTemperature.Y)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Vector2(graphArea.X - 30, graphArea.Y),
|
||||||
|
new Vector2(tempMeterFrame.SourceRect.Width, (graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f) - graphArea.Y),
|
||||||
|
Color.Red * (float)Math.Sin(Timing.TotalTime * 5.0f) * 0.7f, isFilled: true);
|
||||||
|
}
|
||||||
|
if (temperature < optimalTemperature.X)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Vector2(graphArea.X - 30, graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f),
|
||||||
|
new Vector2(tempMeterFrame.SourceRect.Width, graphArea.Bottom - (graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f)),
|
||||||
|
Color.Red * (float)Math.Sin(Timing.TotalTime * 5.0f) * 0.7f, isFilled: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempRangeIndicator.Draw(spriteBatch, new Vector2(meterBarPos.X, graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f));
|
||||||
|
tempRangeIndicator.Draw(spriteBatch, new Vector2(meterBarPos.X, graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void UpdateGraph(float deltaTime)
|
private void UpdateGraph(float deltaTime)
|
||||||
{
|
{
|
||||||
graphTimer += deltaTime * 1000.0f;
|
graphTimer += deltaTime * 1000.0f;
|
||||||
|
|
||||||
if (graphTimer > updateGraphInterval)
|
if (graphTimer > updateGraphInterval)
|
||||||
{
|
{
|
||||||
UpdateGraph(fissionRateGraph, fissionRate);
|
UpdateGraph(outputGraph, -currPowerConsumption);
|
||||||
UpdateGraph(coolingRateGraph, coolingRate);
|
|
||||||
UpdateGraph(tempGraph, temperature);
|
|
||||||
|
|
||||||
UpdateGraph(loadGraph, load);
|
UpdateGraph(loadGraph, load);
|
||||||
|
|
||||||
graphTimer = 0.0f;
|
graphTimer = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (autoTemp)
|
||||||
|
{
|
||||||
|
fissionRateScrollBar.BarScroll = FissionRate / 100.0f;
|
||||||
|
turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
private void DrawFissionRateMeter(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch,
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 6, -item.Rect.Y + 29),
|
spriteBatch.End();
|
||||||
new Vector2(12, 42), Color.Black);
|
spriteBatch.GraphicsDevice.ScissorRectangle = container.Rect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
|
||||||
if (temperature > 0)
|
DrawMeter(spriteBatch, container.Rect,
|
||||||
GUI.DrawRectangle(spriteBatch,
|
fissionRateMeter, FissionRate, new Vector2(0.0f, 100.0f), optimalFissionRate, allowedFissionRate);
|
||||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 5, -item.Rect.Y + 30 + (40.0f * (1.0f - temperature / 10000.0f))),
|
|
||||||
new Vector2(10, 40 * (temperature / 10000.0f)), new Color(temperature / 10000.0f, 1.0f - (temperature / 10000.0f), 0.0f, 1.0f), true);
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private void DrawTurbineOutputMeter(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||||
|
{
|
||||||
|
DrawMeter(spriteBatch, container.Rect,
|
||||||
|
turbineOutputMeter, TurbineOutput, new Vector2(0.0f, 100.0f), optimalTurbineOutput, allowedTurbineOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
|
|
||||||
int x = GuiFrame.Rect.X;
|
|
||||||
int y = GuiFrame.Rect.Y;
|
|
||||||
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
float xOffset = graphTimer / updateGraphInterval;
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorOutput") + ": " + (int)temperature + " kW",
|
bool lightOn = Timing.TotalTime % 0.5f < 0.25f && onOffSwitch.BarScroll < 0.5f;
|
||||||
new Vector2(x + 450, y + 30), Color.Red);
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorGridLoad") + ": " + (int)load + " kW",
|
|
||||||
new Vector2(x + 600, y + 30), Color.Yellow);
|
|
||||||
|
|
||||||
float maxLoad = 0.0f;
|
fissionRateScrollBar.Enabled = !autoTemp;
|
||||||
foreach (float loadVal in loadGraph)
|
turbineOutputScrollBar.Enabled = !autoTemp;
|
||||||
|
|
||||||
|
criticalHeatWarning.Selected = temperature > allowedTemperature.Y && lightOn;
|
||||||
|
lowTemperatureWarning.Selected = temperature < allowedTemperature.X && lightOn;
|
||||||
|
criticalOutputWarning.Selected = -currPowerConsumption > load * 1.5f && lightOn;
|
||||||
|
|
||||||
|
warningButtons["ReactorWarningOverheating"].Selected = temperature > optimalTemperature.Y && lightOn;
|
||||||
|
warningButtons["ReactorWarningHighOutput"].Selected = -currPowerConsumption > load * 1.1f && lightOn;
|
||||||
|
warningButtons["ReactorWarningLowTemp"].Selected = temperature < optimalTemperature.X && lightOn;
|
||||||
|
warningButtons["ReactorWarningLowOutput"].Selected = -currPowerConsumption < load * 0.9f && lightOn;
|
||||||
|
warningButtons["ReactorWarningFuelOut"].Selected = prevAvailableFuel < fissionRate * 0.01f && lightOn;
|
||||||
|
warningButtons["ReactorWarningLowFuel"].Selected = prevAvailableFuel < fissionRate && lightOn;
|
||||||
|
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
|
||||||
|
warningButtons["ReactorWarningSCRAM"].Selected = temperature > 0.1f && onOffSwitch.BarScroll > 0.5f;
|
||||||
|
|
||||||
|
AutoTemp = autoTempSlider.BarScroll < 0.5f;
|
||||||
|
shutDown = onOffSwitch.BarScroll > 0.5f;
|
||||||
|
|
||||||
|
if (shutDown)
|
||||||
{
|
{
|
||||||
maxLoad = Math.Max(maxLoad, loadVal);
|
fissionRateScrollBar.BarScroll = FissionRate / 100.0f;
|
||||||
}
|
turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
|
||||||
|
}
|
||||||
DrawGraph(tempGraph, spriteBatch,
|
|
||||||
new Rectangle(x + 30, y + 30, 400, 250), Math.Max(10000.0f, maxLoad), xOffset, Color.Red);
|
|
||||||
|
|
||||||
DrawGraph(loadGraph, spriteBatch,
|
|
||||||
new Rectangle(x + 30, y + 30, 400, 250), Math.Max(10000.0f, maxLoad), xOffset, Color.Yellow);
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorShutdownTemp") + ": " + (int)shutDownTemp, new Vector2(x + 450, y + 80), Color.White);
|
|
||||||
|
|
||||||
y += 300;
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorFissionRate") + ": " + (int)fissionRate + " %", new Vector2(x + 30, y), Color.White);
|
|
||||||
DrawGraph(fissionRateGraph, spriteBatch,
|
|
||||||
new Rectangle(x + 30, y + 30, 200, 100), 100.0f, xOffset, Color.Orange);
|
|
||||||
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorCoolingRate") + ": " + (int)coolingRate + " %", new Vector2(x + 320, y), Color.White);
|
|
||||||
DrawGraph(coolingRateGraph, spriteBatch,
|
|
||||||
new Rectangle(x + 320, y + 30, 200, 100), 100.0f, xOffset, Color.LightBlue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
|
||||||
{
|
|
||||||
GuiFrame.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
|
||||||
{
|
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ToggleAutoTemp(GUITickBox tickBox)
|
private bool ToggleAutoTemp(GUITickBox tickBox)
|
||||||
{
|
{
|
||||||
unsentChanges = true;
|
unsentChanges = true;
|
||||||
autoTemp = tickBox.Selected;
|
autoTemp = tickBox.Selected;
|
||||||
|
LastUser = Character.Controlled;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawMeter(SpriteBatch spriteBatch, Rectangle rect, Sprite meterSprite, float value, Vector2 range, Vector2 optimalRange, Vector2 allowedRange)
|
||||||
|
{
|
||||||
|
float scale = Math.Min(rect.Width / meterSprite.size.X, rect.Height / meterSprite.size.Y);
|
||||||
|
Vector2 pos = new Vector2(rect.Center.X, rect.Y + meterSprite.Origin.Y * scale);
|
||||||
|
|
||||||
|
Vector2 optimalRangeNormalized = new Vector2(
|
||||||
|
(optimalRange.X - range.X) / (range.Y - range.X),
|
||||||
|
(optimalRange.Y - range.X) / (range.Y - range.X));
|
||||||
|
|
||||||
|
Vector2 allowedRangeNormalized = new Vector2(
|
||||||
|
(allowedRange.X - range.X) / (range.Y - range.X),
|
||||||
|
(allowedRange.Y - range.X) / (range.Y - range.X));
|
||||||
|
|
||||||
|
Vector2 sectorRad = new Vector2(-1.57f, 1.57f);
|
||||||
|
|
||||||
|
Vector2 optimalSectorRad = new Vector2(
|
||||||
|
MathHelper.Lerp(sectorRad.X, sectorRad.Y, optimalRangeNormalized.X),
|
||||||
|
MathHelper.Lerp(sectorRad.X, sectorRad.Y, optimalRangeNormalized.Y));
|
||||||
|
|
||||||
|
Vector2 allowedSectorRad = new Vector2(
|
||||||
|
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.X),
|
||||||
|
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.Y));
|
||||||
|
|
||||||
|
if (optimalRangeNormalized.X == optimalRangeNormalized.Y)
|
||||||
|
{
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.Red, MathHelper.PiOver2, scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spriteBatch.End();
|
||||||
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0,0,GameMain.GraphicsWidth, (int)(pos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale));
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.LightGreen, MathHelper.PiOver2, scale);
|
||||||
|
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.Orange, optimalSectorRad.X, scale);
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.Red, allowedSectorRad.X, scale);
|
||||||
|
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.Orange, MathHelper.Pi + optimalSectorRad.Y, scale);
|
||||||
|
sectorSprite.Draw(spriteBatch, pos, Color.Red, MathHelper.Pi + allowedSectorRad.Y, scale);
|
||||||
|
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
meterSprite.Draw(spriteBatch, pos, 0, scale);
|
||||||
|
|
||||||
|
float normalizedValue = (value - range.X) / (range.Y - range.X);
|
||||||
|
float valueRad = MathHelper.Lerp(sectorRad.X, sectorRad.Y, normalizedValue);
|
||||||
|
meterPointer.Draw(spriteBatch, pos, valueRad, scale);
|
||||||
|
}
|
||||||
|
|
||||||
static void UpdateGraph<T>(IList<T> graph, T newValue)
|
static void UpdateGraph<T>(IList<T> graph, T newValue)
|
||||||
{
|
{
|
||||||
for (int i = graph.Count - 1; i > 0; i--)
|
for (int i = graph.Count - 1; i > 0; i--)
|
||||||
@@ -207,8 +465,13 @@ namespace Barotrauma.Items.Components
|
|||||||
graph[0] = newValue;
|
graph[0] = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawGraph(IList<float> graph, SpriteBatch spriteBatch, Rectangle rect, float maxVal, float xOffset, Color color)
|
private void DrawGraph(IList<float> graph, SpriteBatch spriteBatch, Rectangle rect, float maxVal, float xOffset, Color color)
|
||||||
{
|
{
|
||||||
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = rect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
|
||||||
float lineWidth = (float)rect.Width / (float)(graph.Count - 2);
|
float lineWidth = (float)rect.Width / (float)(graph.Count - 2);
|
||||||
float yScale = (float)rect.Height / maxVal;
|
float yScale = (float)rect.Height / maxVal;
|
||||||
|
|
||||||
@@ -223,8 +486,16 @@ namespace Barotrauma.Items.Components
|
|||||||
currX -= lineWidth;
|
currX -= lineWidth;
|
||||||
|
|
||||||
Vector2 newPoint = new Vector2(currX, rect.Bottom - graph[i] * yScale);
|
Vector2 newPoint = new Vector2(currX, rect.Bottom - graph[i] * yScale);
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
|
if (graphLine == null)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector2 dir = Vector2.Normalize(newPoint - prevPoint);
|
||||||
|
GUI.DrawLine(spriteBatch, graphLine.Texture, prevPoint - dir, newPoint + dir, color, 0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
prevPoint = newPoint;
|
prevPoint = newPoint;
|
||||||
}
|
}
|
||||||
@@ -232,16 +503,38 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 lastPoint = new Vector2(rect.X,
|
Vector2 lastPoint = new Vector2(rect.X,
|
||||||
rect.Bottom - (graph[graph.Count - 1] + (graph[graph.Count - 2] - graph[graph.Count - 1]) * xOffset) * yScale);
|
rect.Bottom - (graph[graph.Count - 1] + (graph[graph.Count - 2] - graph[graph.Count - 1]) * xOffset) * yScale);
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
|
if (graphLine == null)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, graphLine.Texture, prevPoint, lastPoint + (lastPoint - prevPoint), color, 0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
spriteBatch.End();
|
||||||
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveComponentSpecific()
|
||||||
|
{
|
||||||
|
graphLine.Remove();
|
||||||
|
fissionRateMeter.Remove();
|
||||||
|
turbineOutputMeter.Remove();
|
||||||
|
meterPointer.Remove();
|
||||||
|
sectorSprite.Remove();
|
||||||
|
tempMeterFrame.Remove();
|
||||||
|
tempMeterBar.Remove();
|
||||||
|
tempRangeIndicator.Remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||||
{
|
{
|
||||||
msg.Write(autoTemp);
|
msg.Write(autoTemp);
|
||||||
msg.WriteRangedSingle(shutDownTemp, 0.0f, 10000.0f, 15);
|
msg.Write(shutDown);
|
||||||
|
msg.WriteRangedSingle(targetFissionRate, 0.0f, 100.0f, 8);
|
||||||
msg.WriteRangedSingle(coolingRate, 0.0f, 100.0f, 8);
|
msg.WriteRangedSingle(targetTurbineOutput, 0.0f, 100.0f, 8);
|
||||||
msg.WriteRangedSingle(fissionRate, 0.0f, 100.0f, 8);
|
|
||||||
|
|
||||||
correctionTimer = CorrectionDelay;
|
correctionTimer = CorrectionDelay;
|
||||||
}
|
}
|
||||||
@@ -250,17 +543,20 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (correctionTimer > 0.0f)
|
if (correctionTimer > 0.0f)
|
||||||
{
|
{
|
||||||
StartDelayedCorrection(type, msg.ExtractBits(16 + 1 + 15 + 8 + 8), sendingTime);
|
StartDelayedCorrection(type, msg.ExtractBits(1 + 1 + 8 + 8 + 8 + 8), sendingTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Temperature = msg.ReadRangedSingle(0.0f, 10000.0f, 16);
|
|
||||||
|
|
||||||
AutoTemp = msg.ReadBoolean();
|
AutoTemp = msg.ReadBoolean();
|
||||||
ShutDownTemp = msg.ReadRangedSingle(0.0f, 10000.0f, 15);
|
shutDown = msg.ReadBoolean();
|
||||||
|
Temperature = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||||
|
targetFissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||||
|
targetTurbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||||
|
degreeOfSuccess = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||||
|
|
||||||
CoolingRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
fissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
|
||||||
FissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
turbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
|
||||||
|
onOffSwitch.BarScroll = shutDown ? Math.Max(onOffSwitch.BarScroll, 0.55f) : Math.Min(onOffSwitch.BarScroll, 0.45f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,176 +1,565 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Steering : Powered, IServerSerializable, IClientSerializable
|
partial class Steering : Powered, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
private GUITickBox autopilotTickBox, maintainPosTickBox;
|
private GUITickBox autopilotTickBox, manualTickBox;
|
||||||
private GUITickBox levelEndTickBox, levelStartTickBox;
|
private GUITickBox maintainPosTickBox, levelEndTickBox, levelStartTickBox;
|
||||||
|
|
||||||
|
private GUIFrame autoPilotControlsDisabler;
|
||||||
|
|
||||||
|
private GUIComponent steerArea;
|
||||||
|
|
||||||
|
private GUITextBlock pressureWarningText;
|
||||||
|
|
||||||
|
private GUITextBlock tipContainer;
|
||||||
|
|
||||||
|
private string noPowerTip, autoPilotMaintainPosTip, autoPilotLevelStartTip, autoPilotLevelEndTip;
|
||||||
|
|
||||||
|
private Vector2 keyboardInput = Vector2.Zero;
|
||||||
|
private float inputCumulation;
|
||||||
|
|
||||||
|
private bool levelStartSelected;
|
||||||
public bool LevelStartSelected
|
public bool LevelStartSelected
|
||||||
{
|
{
|
||||||
get { return levelStartTickBox.Selected; }
|
get { return levelStartTickBox.Selected; }
|
||||||
set { levelStartTickBox.Selected = value; }
|
set { levelStartTickBox.Selected = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool levelEndSelected;
|
||||||
public bool LevelEndSelected
|
public bool LevelEndSelected
|
||||||
{
|
{
|
||||||
get { return levelEndTickBox.Selected; }
|
get { return levelEndTickBox.Selected; }
|
||||||
set { levelEndTickBox.Selected = value; }
|
set { levelEndTickBox.Selected = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool maintainPos;
|
||||||
public bool MaintainPos
|
public bool MaintainPos
|
||||||
{
|
{
|
||||||
get { return maintainPosTickBox.Selected; }
|
get { return maintainPosTickBox.Selected; }
|
||||||
set { maintainPosTickBox.Selected = value; }
|
set { maintainPosTickBox.Selected = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DockingModeEnabled
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DockingPort DockingSource, DockingTarget;
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
partial void InitProjSpecific()
|
||||||
{
|
{
|
||||||
autopilotTickBox = new GUITickBox(new Rectangle(0, 25, 20, 20), TextManager.Get("SteeringAutoPilot"), Alignment.TopLeft, GuiFrame);
|
int viewSize = (int)Math.Min(GuiFrame.Rect.Width - 150, GuiFrame.Rect.Height * 0.9f);
|
||||||
autopilotTickBox.OnSelected = (GUITickBox box) =>
|
var controlContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.35f), GuiFrame.RectTransform, Anchor.CenterLeft)
|
||||||
|
{ MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.99f), (int)(viewSize * 0.05f)) }, "SonarFrame");
|
||||||
|
var paddedControlContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), controlContainer.RectTransform, Anchor.Center))
|
||||||
{
|
{
|
||||||
AutoPilot = box.Selected;
|
RelativeSpacing = 0.03f,
|
||||||
unsentChanges = true;
|
Stretch = true
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
maintainPosTickBox = new GUITickBox(new Rectangle(5, 50, 15, 15), TextManager.Get("SteeringMaintainPos"), Alignment.TopLeft, GUI.SmallFont, GuiFrame);
|
var statusContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft)
|
||||||
maintainPosTickBox.Enabled = false;
|
{ MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0) }, "SonarFrame");
|
||||||
maintainPosTickBox.OnSelected = ToggleMaintainPosition;
|
var paddedStatusContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), statusContainer.RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.03f,
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
levelStartTickBox = new GUITickBox(
|
manualTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), paddedControlContainer.RectTransform),
|
||||||
new Rectangle(5, 70, 15, 15),
|
TextManager.Get("SteeringManual"), style: "GUIRadioButton")
|
||||||
|
{
|
||||||
|
Selected = true,
|
||||||
|
OnSelected = (GUITickBox box) =>
|
||||||
|
{
|
||||||
|
AutoPilot = !box.Selected;
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
autopilotTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), paddedControlContainer.RectTransform),
|
||||||
|
TextManager.Get("SteeringAutoPilot"), style: "GUIRadioButton")
|
||||||
|
{
|
||||||
|
OnSelected = (GUITickBox box) =>
|
||||||
|
{
|
||||||
|
AutoPilot = box.Selected;
|
||||||
|
if (AutoPilot && MaintainPos)
|
||||||
|
{
|
||||||
|
posToMaintain = controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition;
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GUITickBox.CreateRadioButtonGroup(new List<GUITickBox> { manualTickBox, autopilotTickBox });
|
||||||
|
|
||||||
|
var autoPilotControls = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f), paddedControlContainer.RectTransform), "InnerFrame");
|
||||||
|
var paddedAutoPilotControls = new GUILayoutGroup(new RectTransform(new Vector2(0.8f), autoPilotControls.RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.03f
|
||||||
|
};
|
||||||
|
|
||||||
|
maintainPosTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
||||||
|
TextManager.Get("SteeringMaintainPos"), font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
Enabled = false,
|
||||||
|
Selected = maintainPos,
|
||||||
|
OnSelected = tickBox =>
|
||||||
|
{
|
||||||
|
if (maintainPos != tickBox.Selected)
|
||||||
|
{
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
maintainPos = tickBox.Selected;
|
||||||
|
if (maintainPos)
|
||||||
|
{
|
||||||
|
if (controlledSub == null)
|
||||||
|
{
|
||||||
|
posToMaintain = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
posToMaintain = controlledSub.WorldPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!LevelEndSelected && !LevelStartSelected)
|
||||||
|
{
|
||||||
|
AutoPilot = false;
|
||||||
|
}
|
||||||
|
if (!maintainPos)
|
||||||
|
{
|
||||||
|
posToMaintain = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
levelStartTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
||||||
GameMain.GameSession?.StartLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.StartLocation.Name, 20),
|
GameMain.GameSession?.StartLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.StartLocation.Name, 20),
|
||||||
Alignment.TopLeft, GUI.SmallFont, GuiFrame);
|
font: GUI.SmallFont)
|
||||||
levelStartTickBox.Enabled = false;
|
{
|
||||||
levelStartTickBox.OnSelected = SelectDestination;
|
Enabled = false,
|
||||||
|
Selected = levelStartSelected,
|
||||||
|
OnSelected = tickBox =>
|
||||||
|
{
|
||||||
|
if (levelStartSelected != tickBox.Selected)
|
||||||
|
{
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
levelStartSelected = tickBox.Selected;
|
||||||
|
levelEndSelected = !levelStartSelected;
|
||||||
|
if (levelStartSelected)
|
||||||
|
{
|
||||||
|
UpdatePath();
|
||||||
|
}
|
||||||
|
else if (!MaintainPos && !LevelEndSelected)
|
||||||
|
{
|
||||||
|
AutoPilot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
levelEndTickBox = new GUITickBox(
|
levelEndTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
||||||
new Rectangle(5, 90, 15, 15),
|
|
||||||
GameMain.GameSession?.EndLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, 20),
|
GameMain.GameSession?.EndLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, 20),
|
||||||
Alignment.TopLeft, GUI.SmallFont, GuiFrame);
|
font: GUI.SmallFont)
|
||||||
levelEndTickBox.Enabled = false;
|
{
|
||||||
levelEndTickBox.OnSelected = SelectDestination;
|
Enabled = false,
|
||||||
|
Selected = levelEndSelected,
|
||||||
|
OnSelected = tickBox =>
|
||||||
|
{
|
||||||
|
if (levelEndSelected != tickBox.Selected)
|
||||||
|
{
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
levelEndSelected = tickBox.Selected;
|
||||||
|
levelStartSelected = !levelEndSelected;
|
||||||
|
if (levelEndSelected)
|
||||||
|
{
|
||||||
|
UpdatePath();
|
||||||
|
}
|
||||||
|
else if (!MaintainPos && !LevelStartSelected)
|
||||||
|
{
|
||||||
|
AutoPilot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
autoPilotControlsDisabler = new GUIFrame(new RectTransform(Vector2.One, autoPilotControls.RectTransform), "InnerFrame");
|
||||||
|
|
||||||
|
GUITickBox.CreateRadioButtonGroup(new List<GUITickBox> { maintainPosTickBox, levelStartTickBox, levelEndTickBox });
|
||||||
|
|
||||||
|
string steeringVelX = TextManager.Get("SteeringVelocityX");
|
||||||
|
string steeringVelY = TextManager.Get("SteeringVelocityY");
|
||||||
|
string steeringDepth = TextManager.Get("SteeringDepth");
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
||||||
|
{
|
||||||
|
TextGetter = () =>
|
||||||
|
{
|
||||||
|
Vector2 vel = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
|
||||||
|
var realWorldVel = ConvertUnits.ToDisplayUnits(vel.Y * Physics.DisplayToRealWorldRatio) * 3.6f;
|
||||||
|
return steeringVelY.Replace("[kph]", ((int)-realWorldVel).ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
||||||
|
{
|
||||||
|
TextGetter = () =>
|
||||||
|
{
|
||||||
|
Vector2 vel = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
|
||||||
|
var realWorldVel = ConvertUnits.ToDisplayUnits(vel.X * Physics.DisplayToRealWorldRatio) * 3.6f;
|
||||||
|
return steeringVelX.Replace("[kph]", ((int)realWorldVel).ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
||||||
|
{
|
||||||
|
TextGetter = () =>
|
||||||
|
{
|
||||||
|
Vector2 pos = controlledSub == null ? Vector2.Zero : controlledSub.Position;
|
||||||
|
float realWorldDepth = Level.Loaded == null ? 0.0f : Math.Abs(pos.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio;
|
||||||
|
return steeringDepth.Replace("[m]", ((int)realWorldDepth).ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pressureWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), TextManager.Get("SteeringDepthWarning"), Color.Red)
|
||||||
|
{
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
|
||||||
|
tipContainer = new GUITextBlock(new RectTransform(new Vector2(0.25f, 0.12f), GuiFrame.RectTransform, Anchor.BottomLeft)
|
||||||
|
{ MinSize = new Point(150, 0), RelativeOffset = new Vector2(0.0f, -0.05f) }, "", wrap: true, style: "GUIToolTip")
|
||||||
|
{
|
||||||
|
AutoScale = true
|
||||||
|
};
|
||||||
|
|
||||||
|
noPowerTip = TextManager.Get("SteeringNoPowerTip");
|
||||||
|
autoPilotMaintainPosTip = TextManager.Get("SteeringAutoPilotMaintainPosTip");
|
||||||
|
autoPilotLevelStartTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
|
||||||
|
GameMain.GameSession?.StartLocation == null ? "Start" : GameMain.GameSession.StartLocation.Name);
|
||||||
|
autoPilotLevelEndTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
|
||||||
|
GameMain.GameSession?.EndLocation == null ? "End" : GameMain.GameSession.EndLocation.Name);
|
||||||
|
|
||||||
|
steerArea = new GUICustomComponent(new RectTransform(new Point(viewSize), GuiFrame.RectTransform, Anchor.CenterLeft),
|
||||||
|
(spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ToggleMaintainPosition(GUITickBox tickBox)
|
/// <summary>
|
||||||
|
/// Makes the sonar view CustomComponent render the steering HUD, preventing it from being drawn behing the sonar
|
||||||
|
/// </summary>
|
||||||
|
public void AttachToSonarHUD(GUICustomComponent sonarView)
|
||||||
{
|
{
|
||||||
unsentChanges = true;
|
steerArea.Visible = false;
|
||||||
|
sonarView.OnDraw += (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); };
|
||||||
levelStartTickBox.Selected = false;
|
|
||||||
levelEndTickBox.Selected = false;
|
|
||||||
|
|
||||||
if (item.Submarine == null)
|
|
||||||
{
|
|
||||||
posToMaintain = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
posToMaintain = item.Submarine.WorldPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
tickBox.Selected = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
|
||||||
{
|
{
|
||||||
//if (voltage < minVoltage) return;
|
int width = rect.Width, height = rect.Height;
|
||||||
|
int x = rect.X;
|
||||||
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
|
int y = rect.Y;
|
||||||
int x = GuiFrame.Rect.X;
|
|
||||||
int y = GuiFrame.Rect.Y;
|
|
||||||
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
|
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
|
||||||
|
|
||||||
Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40);
|
Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40);
|
||||||
//GUI.DrawRectangle(spriteBatch, velRect, Color.White, false);
|
|
||||||
|
|
||||||
if (item.Submarine != null && Level.Loaded != null)
|
|
||||||
{
|
|
||||||
Vector2 realWorldVelocity = ConvertUnits.ToDisplayUnits(item.Submarine.Velocity * Physics.DisplayToRealWorldRatio) * 3.6f;
|
|
||||||
float realWorldDepth = Math.Abs(item.Submarine.Position.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio;
|
|
||||||
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 65),
|
|
||||||
TextManager.Get("SteeringVelocityX").Replace("[kph]", ((int)realWorldVelocity.X).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
|
|
||||||
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 50),
|
|
||||||
TextManager.Get("SteeringVelocityY").Replace("[kph]", ((int)-realWorldVelocity.Y).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
|
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 30),
|
|
||||||
TextManager.Get("SteeringDepth").Replace("[m]", ((int)realWorldDepth).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(velRect.Center.X, velRect.Center.Y),
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
||||||
new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y),
|
new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y),
|
||||||
Color.Gray);
|
Color.Gray);
|
||||||
|
|
||||||
Vector2 targetVelPos = new Vector2(velRect.Center.X + targetVelocity.X, velRect.Center.Y - targetVelocity.Y);
|
if (!AutoPilot)
|
||||||
|
{
|
||||||
|
Vector2 unitSteeringInput = steeringInput / 100.0f;
|
||||||
|
//map input from rectangle to circle
|
||||||
|
Vector2 steeringInputPos = new Vector2(
|
||||||
|
steeringInput.X * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.Y * unitSteeringInput.Y),
|
||||||
|
-steeringInput.Y * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.X * unitSteeringInput.X));
|
||||||
|
steeringInputPos.X += velRect.Center.X;
|
||||||
|
steeringInputPos.Y += velRect.Center.Y;
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
||||||
|
steeringInputPos,
|
||||||
|
Color.LightGray);
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 5, (int)steeringInputPos.Y - 5, 10, 10), Color.White);
|
||||||
|
|
||||||
|
//if (keyboardInput.Length() > 0 || Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f)
|
||||||
|
if (velRect.Contains(PlayerInput.MousePosition))
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 10, (int)steeringInputPos.Y - 10, 20, 20), Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (posToMaintain.HasValue && !LevelStartSelected && !LevelEndSelected)
|
||||||
|
{
|
||||||
|
Sonar sonar = item.GetComponent<Sonar>();
|
||||||
|
if (sonar != null && controlledSub != null)
|
||||||
|
{
|
||||||
|
Vector2 displayPosToMaintain = ((posToMaintain.Value - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
|
||||||
|
displayPosToMaintain.Y = -displayPosToMaintain.Y;
|
||||||
|
displayPosToMaintain = displayPosToMaintain.ClampLength(velRect.Width / 2);
|
||||||
|
displayPosToMaintain = velRect.Center.ToVector2() + displayPosToMaintain;
|
||||||
|
|
||||||
|
float crossHairSize = 8.0f;
|
||||||
|
Color crosshairColor = Color.Orange * (0.5f + ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) / 4.0f);
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitY * crossHairSize, displayPosToMaintain - Vector2.UnitY * crossHairSize, crosshairColor, width: 3);
|
||||||
|
GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitX * crossHairSize, displayPosToMaintain - Vector2.UnitX * crossHairSize, crosshairColor, width: 3);
|
||||||
|
|
||||||
|
Vector2 neutralPos = ((controlledSub.WorldPosition - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
|
||||||
|
|
||||||
|
neutralPos.Y = -neutralPos.Y;
|
||||||
|
neutralPos = neutralPos.ClampLength(velRect.Width / 2);
|
||||||
|
neutralPos = velRect.Center.ToVector2() + neutralPos;
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)neutralPos.X - 5, (int)neutralPos.Y - 5, 10, 10), Color.Orange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//map velocity from rectangle to circle
|
||||||
|
Vector2 unitTargetVel = targetVelocity / 100.0f;
|
||||||
|
Vector2 steeringPos = new Vector2(
|
||||||
|
targetVelocity.X * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.Y * unitTargetVel.Y),
|
||||||
|
-targetVelocity.Y * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.X * unitTargetVel.X));
|
||||||
|
steeringPos.X += velRect.Center.X;
|
||||||
|
steeringPos.Y += velRect.Center.Y;
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch,
|
GUI.DrawLine(spriteBatch,
|
||||||
new Vector2(velRect.Center.X, velRect.Center.Y),
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
||||||
targetVelPos,
|
steeringPos,
|
||||||
Color.LightGray);
|
Color.CadetBlue, 0, 2);
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 5, (int)targetVelPos.Y - 5, 10, 10), Color.White);
|
|
||||||
|
|
||||||
if (Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f)
|
|
||||||
{
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 10, (int)targetVelPos.Y - 10, 20, 20), Color.Red);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter, float displayScale, float displayRadius, Vector2 center)
|
||||||
{
|
{
|
||||||
GuiFrame.AddToGUIUpdateList();
|
if (SteeringPath == null) return;
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
Vector2 prevPos = Vector2.Zero;
|
||||||
{
|
foreach (WayPoint wp in SteeringPath.Nodes)
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
|
||||||
|
|
||||||
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
|
|
||||||
|
|
||||||
if (Vector2.Distance(PlayerInput.MousePosition, new Vector2(GuiFrame.Rect.Center.X, GuiFrame.Rect.Center.Y)) < 200.0f)
|
|
||||||
{
|
{
|
||||||
if (PlayerInput.LeftButtonHeld())
|
Vector2 pos = (wp.Position - transducerCenter) * displayScale;
|
||||||
|
if (pos.Length() > displayRadius) continue;
|
||||||
|
|
||||||
|
pos.Y = -pos.Y;
|
||||||
|
pos += center;
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 3 / 2, (int)pos.Y - 3, 6, 6), (SteeringPath.CurrentNode == wp) ? Color.LightGreen : Color.Green, false);
|
||||||
|
|
||||||
|
if (prevPos != Vector2.Zero)
|
||||||
{
|
{
|
||||||
TargetVelocity = PlayerInput.MousePosition - new Vector2(GuiFrame.Rect.Center.X, GuiFrame.Rect.Center.Y);
|
GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green);
|
||||||
targetVelocity.Y = -targetVelocity.Y;
|
}
|
||||||
|
|
||||||
unsentChanges = true;
|
prevPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ObstacleDebugInfo obstacle in debugDrawObstacles)
|
||||||
|
{
|
||||||
|
Vector2 pos1 = (obstacle.Point1 - transducerCenter) * displayScale;
|
||||||
|
pos1.Y = -pos1.Y;
|
||||||
|
pos1 += center;
|
||||||
|
Vector2 pos2 = (obstacle.Point2 - transducerCenter) * displayScale;
|
||||||
|
pos2.Y = -pos2.Y;
|
||||||
|
pos2 += center;
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
pos1,
|
||||||
|
pos2,
|
||||||
|
Color.Red * 0.6f, width: 3);
|
||||||
|
|
||||||
|
if (obstacle.Intersection.HasValue)
|
||||||
|
{
|
||||||
|
Vector2 intersectionPos = (obstacle.Intersection.Value - transducerCenter) *displayScale;
|
||||||
|
intersectionPos.Y = -intersectionPos.Y;
|
||||||
|
intersectionPos += center;
|
||||||
|
GUI.DrawRectangle(spriteBatch, intersectionPos - Vector2.One * 2, Vector2.One * 4, Color.Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 obstacleCenter = (pos1 + pos2) / 2;
|
||||||
|
if (obstacle.AvoidStrength.LengthSquared() > 0.01f)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
obstacleCenter,
|
||||||
|
obstacleCenter + new Vector2(obstacle.AvoidStrength.X, -obstacle.AvoidStrength.Y) * 100,
|
||||||
|
Color.Lerp(Color.Green, Color.Orange, obstacle.Dot), width: 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectDestination(GUITickBox tickBox)
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
unsentChanges = true;
|
if (steerArea.Rect.Contains(PlayerInput.MousePosition))
|
||||||
|
|
||||||
if (tickBox == levelStartTickBox)
|
|
||||||
{
|
{
|
||||||
levelEndTickBox.Selected = false;
|
if (!PlayerInput.KeyDown(InputType.Select) && !PlayerInput.KeyHit(InputType.Select))
|
||||||
|
{
|
||||||
|
Character.DisableControls = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoPilotControlsDisabler.Visible = !AutoPilot;
|
||||||
|
|
||||||
|
if (voltage < minVoltage && currPowerConsumption > 0.0f)
|
||||||
|
{
|
||||||
|
tipContainer.Visible = true;
|
||||||
|
tipContainer.Text = noPowerTip;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tipContainer.Visible = AutoPilot;
|
||||||
|
if (AutoPilot)
|
||||||
|
{
|
||||||
|
if (maintainPos)
|
||||||
|
{
|
||||||
|
tipContainer.Text = autoPilotMaintainPosTip;
|
||||||
|
}
|
||||||
|
else if (LevelStartSelected)
|
||||||
|
{
|
||||||
|
tipContainer.Text = autoPilotLevelStartTip;
|
||||||
|
}
|
||||||
|
else if (LevelEndSelected)
|
||||||
|
{
|
||||||
|
tipContainer.Text = autoPilotLevelEndTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DockingModeEnabled && DockingTarget != null)
|
||||||
|
{
|
||||||
|
posToMaintain += ConvertUnits.ToDisplayUnits(DockingTarget.Item.Submarine.Velocity) * deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.5f;
|
||||||
|
|
||||||
|
if (Vector2.Distance(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerArea.Rect.Width / 2)
|
||||||
|
{
|
||||||
|
if (PlayerInput.LeftButtonHeld())
|
||||||
|
{
|
||||||
|
Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2();
|
||||||
|
inputPos.Y = -inputPos.Y;
|
||||||
|
if (AutoPilot && !LevelStartSelected && !LevelEndSelected)
|
||||||
|
{
|
||||||
|
posToMaintain = controlledSub == null ?
|
||||||
|
item.WorldPosition :
|
||||||
|
controlledSub.WorldPosition + (sonar.DisplayOffset * sonar.Zoom) + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SteeringInput = inputPos;
|
||||||
|
}
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!AutoPilot && Character.DisableControls)
|
||||||
|
{
|
||||||
|
steeringAdjustSpeed = character == null ? 0.2f : MathHelper.Lerp(0.2f, 1.0f, character.GetSkillLevel("helm") / 100.0f);
|
||||||
|
Vector2 input = Vector2.Zero;
|
||||||
|
if (PlayerInput.KeyDown(InputType.Left))
|
||||||
|
{
|
||||||
|
input -= Vector2.UnitX;
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyDown(InputType.Right))
|
||||||
|
{
|
||||||
|
input += Vector2.UnitX;
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyDown(InputType.Up))
|
||||||
|
{
|
||||||
|
input += Vector2.UnitY;
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyDown(InputType.Down))
|
||||||
|
{
|
||||||
|
input -= Vector2.UnitY;
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyDown(Keys.LeftShift))
|
||||||
|
{
|
||||||
|
SteeringInput += input * deltaTime * 200;
|
||||||
|
inputCumulation = 0;
|
||||||
|
keyboardInput = Vector2.Zero;
|
||||||
|
unsentChanges = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float step = deltaTime * 5;
|
||||||
|
if (input.Length() > 0)
|
||||||
|
{
|
||||||
|
inputCumulation += step;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputCumulation -= step;
|
||||||
|
}
|
||||||
|
float maxCumulation = 1;
|
||||||
|
inputCumulation = MathHelper.Clamp(inputCumulation, 0, maxCumulation);
|
||||||
|
float length = MathHelper.Lerp(0, 0.2f, MathUtils.InverseLerp(0, maxCumulation, inputCumulation));
|
||||||
|
var normalizedInput = Vector2.Normalize(input);
|
||||||
|
if (MathUtils.IsValid(normalizedInput))
|
||||||
|
{
|
||||||
|
keyboardInput += normalizedInput * length;
|
||||||
|
}
|
||||||
|
if (keyboardInput.LengthSquared() > 0.01f)
|
||||||
|
{
|
||||||
|
SteeringInput += keyboardInput;
|
||||||
|
unsentChanges = true;
|
||||||
|
user = Character.Controlled;
|
||||||
|
keyboardInput *= MathHelper.Clamp(1 - step, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
levelStartTickBox.Selected = false;
|
inputCumulation = 0;
|
||||||
|
keyboardInput = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
maintainPosTickBox.Selected = false;
|
|
||||||
posToMaintain = null;
|
|
||||||
tickBox.Selected = true;
|
|
||||||
|
|
||||||
UpdatePath();
|
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
|
||||||
|
DockingModeEnabled = false;
|
||||||
|
DockingSource = null;
|
||||||
|
DockingTarget = null;
|
||||||
|
foreach (DockingPort sourcePort in DockingPort.List)
|
||||||
|
{
|
||||||
|
if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; }
|
||||||
|
if (sourcePort.Item.Submarine != controlledSub) { continue; }
|
||||||
|
|
||||||
return true;
|
int sourceDir = sourcePort.IsHorizontal ?
|
||||||
|
Math.Sign(sourcePort.Item.WorldPosition.X - sourcePort.Item.Submarine.WorldPosition.X) :
|
||||||
|
Math.Sign(sourcePort.Item.WorldPosition.Y - sourcePort.Item.Submarine.WorldPosition.Y);
|
||||||
|
|
||||||
|
foreach (DockingPort targetPort in DockingPort.List)
|
||||||
|
{
|
||||||
|
if (targetPort.Docked || targetPort.Item.Submarine == null) { continue; }
|
||||||
|
if (targetPort.Item.Submarine == controlledSub || targetPort.IsHorizontal != sourcePort.IsHorizontal) { continue; }
|
||||||
|
if (Level.Loaded != null && targetPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||||
|
|
||||||
|
int targetDir = targetPort.IsHorizontal ?
|
||||||
|
Math.Sign(targetPort.Item.WorldPosition.X - targetPort.Item.Submarine.WorldPosition.X) :
|
||||||
|
Math.Sign(targetPort.Item.WorldPosition.Y - targetPort.Item.Submarine.WorldPosition.Y);
|
||||||
|
|
||||||
|
if (sourceDir == targetDir) { continue; }
|
||||||
|
|
||||||
|
float dist = Vector2.DistanceSquared(sourcePort.Item.WorldPosition, targetPort.Item.WorldPosition);
|
||||||
|
if (dist < closestDist)
|
||||||
|
{
|
||||||
|
DockingModeEnabled = true;
|
||||||
|
DockingSource = sourcePort;
|
||||||
|
DockingTarget = targetPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
||||||
@@ -180,8 +569,8 @@ namespace Barotrauma.Items.Components
|
|||||||
if (!autoPilot)
|
if (!autoPilot)
|
||||||
{
|
{
|
||||||
//no need to write steering info if autopilot is controlling
|
//no need to write steering info if autopilot is controlling
|
||||||
msg.Write(targetVelocity.X);
|
msg.Write(steeringInput.X);
|
||||||
msg.Write(targetVelocity.Y);
|
msg.Write(steeringInput.Y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -202,11 +591,13 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
long msgStartPos = msg.Position;
|
long msgStartPos = msg.Position;
|
||||||
|
|
||||||
bool autoPilot = msg.ReadBoolean();
|
bool autoPilot = msg.ReadBoolean();
|
||||||
Vector2 newTargetVelocity = targetVelocity;
|
Vector2 newSteeringInput = steeringInput;
|
||||||
bool maintainPos = false;
|
Vector2 newTargetVelocity = targetVelocity;
|
||||||
Vector2? newPosToMaintain = null;
|
float newSteeringAdjustSpeed = steeringAdjustSpeed;
|
||||||
bool headingToStart = false;
|
bool maintainPos = false;
|
||||||
|
Vector2? newPosToMaintain = null;
|
||||||
|
bool headingToStart = false;
|
||||||
|
|
||||||
if (autoPilot)
|
if (autoPilot)
|
||||||
{
|
{
|
||||||
@@ -224,7 +615,9 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
newSteeringInput = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||||
newTargetVelocity = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
newTargetVelocity = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||||
|
newSteeringAdjustSpeed = msg.ReadFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (correctionTimer > 0.0f)
|
if (correctionTimer > 0.0f)
|
||||||
@@ -239,11 +632,12 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (!AutoPilot)
|
if (!AutoPilot)
|
||||||
{
|
{
|
||||||
targetVelocity = newTargetVelocity;
|
SteeringInput = newSteeringInput;
|
||||||
|
TargetVelocity = newTargetVelocity;
|
||||||
|
steeringAdjustSpeed = newSteeringAdjustSpeed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
MaintainPos = newPosToMaintain != null;
|
MaintainPos = newPosToMaintain != null;
|
||||||
posToMaintain = newPosToMaintain;
|
posToMaintain = newPosToMaintain;
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,48 @@
|
|||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
|
partial class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
|
private GUIProgressBar chargeIndicator;
|
||||||
|
private GUIScrollBar rechargeSpeedSlider;
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
partial void InitProjSpecific()
|
||||||
{
|
{
|
||||||
if (canBeSelected)
|
if (GuiFrame == null) return;
|
||||||
|
|
||||||
|
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.7f), GuiFrame.RectTransform, Anchor.Center))
|
||||||
|
{ RelativeSpacing = 0.1f, Stretch = true };
|
||||||
|
|
||||||
|
string rechargeStr = TextManager.Get("PowerContainerRechargeRate");
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), "RechargeRate", textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
var button = new GUIButton(new Rectangle(160, 50, 30, 30), "-", "", GuiFrame);
|
TextGetter = () =>
|
||||||
button.OnClicked = (GUIButton btn, object obj) =>
|
|
||||||
{
|
{
|
||||||
RechargeSpeed = rechargeSpeed - maxRechargeSpeed * 0.1f;
|
return rechargeStr.Replace("[rate]", ((int)((rechargeSpeed / maxRechargeSpeed) * 100.0f)).ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
|
||||||
|
"0 %", textAlignment: Alignment.Center);
|
||||||
|
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.8f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
|
||||||
|
{
|
||||||
|
Step = 0.1f,
|
||||||
|
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
float newRechargeSpeed = maxRechargeSpeed * barScroll;
|
||||||
|
if (Math.Abs(newRechargeSpeed - rechargeSpeed) < 0.1f) return false;
|
||||||
|
|
||||||
|
RechargeSpeed = newRechargeSpeed;
|
||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
{
|
{
|
||||||
item.CreateServerEvent(this);
|
item.CreateServerEvent(this);
|
||||||
@@ -26,68 +54,79 @@ namespace Barotrauma.Items.Components
|
|||||||
item.CreateClientEvent(this);
|
item.CreateClientEvent(this);
|
||||||
correctionTimer = CorrectionDelay;
|
correctionTimer = CorrectionDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
|
||||||
|
"100 %", textAlignment: Alignment.Center);
|
||||||
|
|
||||||
button = new GUIButton(new Rectangle(200, 50, 30, 30), "+", "", GuiFrame);
|
string chargeStr = TextManager.Get("PowerContainerCharge");
|
||||||
button.OnClicked = (GUIButton btn, object obj) =>
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), "Charge", textAlignment: Alignment.Center)
|
||||||
|
{
|
||||||
|
TextGetter = () =>
|
||||||
{
|
{
|
||||||
RechargeSpeed = rechargeSpeed + maxRechargeSpeed * 0.1f;
|
return chargeStr.Replace("[charge]", (int)charge + "/" + (int)capacity).Replace("[percentage]", ((int)((charge / capacity) * 100.0f)).ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
chargeIndicator = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), barSize: 0.0f)
|
||||||
{
|
{
|
||||||
item.CreateServerEvent(this);
|
ProgressGetter = () =>
|
||||||
GameServer.Log(Character.Controlled.LogName + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
|
{
|
||||||
}
|
return charge / capacity;
|
||||||
else if (GameMain.Client != null)
|
}
|
||||||
{
|
};
|
||||||
item.CreateClientEvent(this);
|
}
|
||||||
correctionTimer = CorrectionDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
public override void OnItemLoaded()
|
||||||
};
|
{
|
||||||
|
if (rechargeSpeedSlider != null)
|
||||||
|
{
|
||||||
|
rechargeSpeedSlider.BarScroll = rechargeSpeed / MaxRechargeSpeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
|
{
|
||||||
|
float chargeRatio = charge / capacity;
|
||||||
|
chargeIndicator.Color = ToolBox.GradientLerp(chargeRatio, Color.Red, Color.Orange, Color.Green);
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||||
{
|
{
|
||||||
|
if (indicatorSize.X <= 1.0f || indicatorSize.Y <= 1.0f) return;
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch,
|
GUI.DrawRectangle(spriteBatch,
|
||||||
new Vector2(item.DrawPosition.X - 4, -item.DrawPosition.Y),
|
new Vector2(
|
||||||
new Vector2(8, 22), Color.Black);
|
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale,
|
||||||
|
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale),
|
||||||
|
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.00001f);
|
||||||
|
|
||||||
if (charge > 0)
|
if (charge > 0)
|
||||||
GUI.DrawRectangle(spriteBatch,
|
{
|
||||||
new Vector2(item.DrawPosition.X - 3, -item.DrawPosition.Y + 1 + (20.0f * (1.0f - charge / capacity))),
|
Color indicatorColor = ToolBox.GradientLerp(charge / capacity, Color.Red, Color.Orange, Color.Green);
|
||||||
new Vector2(6, 20 * (charge / capacity)), Color.Green, true);
|
if (!isHorizontal)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Vector2(
|
||||||
|
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1,
|
||||||
|
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1 + ((indicatorSize.Y * item.Scale) * (1.0f - charge / capacity))),
|
||||||
|
new Vector2(indicatorSize.X * item.Scale - 2, (indicatorSize.Y * item.Scale - 2) * (charge / capacity)), indicatorColor, true,
|
||||||
|
depth: item.SpriteDepth - 0.00001f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch,
|
||||||
|
new Vector2(
|
||||||
|
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1 ,
|
||||||
|
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1),
|
||||||
|
new Vector2((indicatorSize.X * item.Scale - 2) * (charge / capacity), indicatorSize.Y * item.Scale - 2), indicatorColor, true,
|
||||||
|
depth: item.SpriteDepth - 0.00001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
|
||||||
{
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
|
||||||
|
|
||||||
int x = GuiFrame.Rect.X;
|
|
||||||
int y = GuiFrame.Rect.Y;
|
|
||||||
//GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch,
|
|
||||||
TextManager.Get("PowerContainerCharge").Replace("[charge]", (int)charge + "/" + (int)capacity).Replace("[percentage]", ((int)((charge / capacity) * 100.0f)).ToString()),
|
|
||||||
new Vector2(x + 30, y + 30), Color.White);
|
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch, TextManager.Get("PowerContainerRechargeRate") + ": " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", new Vector2(x + 30, y + 95), Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
|
||||||
{
|
|
||||||
GuiFrame.AddToGUIUpdateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
|
||||||
{
|
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClientWrite(NetBuffer msg, object[] extraData)
|
public void ClientWrite(NetBuffer msg, object[] extraData)
|
||||||
{
|
{
|
||||||
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
||||||
|
|||||||
@@ -1,36 +1,73 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class PowerTransfer : Powered
|
partial class PowerTransfer : Powered
|
||||||
{
|
{
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private GUITickBox powerIndicator;
|
||||||
|
private GUITickBox highVoltageIndicator;
|
||||||
|
private GUITickBox lowVoltageIndicator;
|
||||||
|
|
||||||
|
partial void InitProjectSpecific(XElement element)
|
||||||
{
|
{
|
||||||
if (!canBeSelected) return;
|
if (GuiFrame == null) return;
|
||||||
|
|
||||||
int x = GuiFrame.Rect.X;
|
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), GuiFrame.RectTransform, Anchor.Center), style: null);
|
||||||
int y = GuiFrame.Rect.Y;
|
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform),
|
||||||
|
TextManager.Get("PowerTransferPowered"), style: "IndicatorLightGreen")
|
||||||
|
{
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
highVoltageIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform) { AbsoluteOffset = new Point(0, 40) },
|
||||||
|
TextManager.Get("PowerTransferHighVoltage"), style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipOvervoltage"),
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
lowVoltageIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform) { AbsoluteOffset = new Point(0, 80) },
|
||||||
|
TextManager.Get("PowerTransferLowVoltage"), style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipLowvoltage"),
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
|
||||||
GuiFrame.Draw(spriteBatch);
|
var textContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), paddedFrame.RectTransform, Anchor.TopRight));
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch,
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContainer.RectTransform),
|
||||||
TextManager.Get("PowerTransferPower").Replace("[power]", ((int)(-currPowerConsumption)).ToString()),
|
TextManager.Get("PowerTransferPowerLabel"), font: GUI.LargeFont)
|
||||||
new Vector2(x + 30, y + 30), Color.White);
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipPower")
|
||||||
|
};
|
||||||
|
string powerStr = TextManager.Get("PowerTransferPower");
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), textContainer.RectTransform), "", textColor: Color.LightGreen)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipPower"),
|
||||||
|
TextGetter = () => { return powerStr.Replace("[power]", ((int)(-currPowerConsumption)).ToString()); }
|
||||||
|
};
|
||||||
|
|
||||||
GUI.Font.DrawString(spriteBatch,
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContainer.RectTransform),
|
||||||
TextManager.Get("PowerTransferLoad").Replace("[load]", ((int)powerLoad).ToString()),
|
TextManager.Get("PowerTransferLoadLabel"), font: GUI.LargeFont)
|
||||||
new Vector2(x + 30, y + 100), Color.White);
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipLoad")
|
||||||
|
};
|
||||||
|
string loadStr = TextManager.Get("PowerTransferLoad");
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), textContainer.RectTransform), "", textColor: Color.LightBlue)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("PowerTransferTipLoad"),
|
||||||
|
TextGetter = () => { return loadStr.Replace("[load]", ((int)(powerLoad)).ToString()); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
GuiFrame.AddToGUIUpdateList();
|
if (GuiFrame == null) return;
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateHUD(Character character)
|
float voltage = powerLoad <= 0.0f ? 1.0f : -currPowerConsumption / powerLoad;
|
||||||
{
|
powerIndicator.Selected = IsActive && currPowerConsumption < -0.1f;
|
||||||
GuiFrame.Update(1.0f / 60.0f);
|
highVoltageIndicator.Selected = Timing.TotalTime % 0.5f < 0.25f && powerIndicator.Selected && voltage > 1.2f;
|
||||||
|
lowVoltageIndicator.Selected = Timing.TotalTime % 0.5f < 0.25f && powerIndicator.Selected && voltage < 0.8f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,31 @@
|
|||||||
namespace Barotrauma.Items.Components
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Barotrauma.Sounds;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Powered : ItemComponent
|
partial class Powered : ItemComponent
|
||||||
{
|
{
|
||||||
protected static Sound[] sparkSounds;
|
protected List<RoundSound> sparkSounds;
|
||||||
|
|
||||||
|
private RoundSound powerOnSound;
|
||||||
private bool powerOnSoundPlayed;
|
private bool powerOnSoundPlayed;
|
||||||
|
|
||||||
private static Sound powerOnSound;
|
partial void InitProjectSpecific(XElement element)
|
||||||
|
{
|
||||||
|
sparkSounds = new List<RoundSound>();
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "poweronsound":
|
||||||
|
powerOnSound = Submarine.LoadRoundSound(subElement, false);
|
||||||
|
break;
|
||||||
|
case "sparksound":
|
||||||
|
sparkSounds.Add(Submarine.LoadRoundSound(subElement, false));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using Barotrauma.Particles;
|
||||||
|
using FarseerPhysics;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class RepairTool
|
||||||
|
{
|
||||||
|
public ParticleEmitter ParticleEmitter
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
|
||||||
|
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
|
||||||
|
private List<Pair<RelatedItem, ParticleEmitter>> ParticleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "particleemitter":
|
||||||
|
ParticleEmitter = new ParticleEmitter(subElement);
|
||||||
|
break;
|
||||||
|
case "particleemitterhititem":
|
||||||
|
string[] identifiers = subElement.GetAttributeStringArray("identifiers", new string[0]);
|
||||||
|
if (identifiers.Length == 0) identifiers = subElement.GetAttributeStringArray("identifier", new string[0]);
|
||||||
|
string[] excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifiers", new string[0]);
|
||||||
|
if (excludedIdentifiers.Length == 0) excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifier", new string[0]);
|
||||||
|
|
||||||
|
ParticleEmitterHitItem.Add(
|
||||||
|
new Pair<RelatedItem, ParticleEmitter>(
|
||||||
|
new RelatedItem(identifiers, excludedIdentifiers),
|
||||||
|
new ParticleEmitter(subElement)));
|
||||||
|
break;
|
||||||
|
case "particleemitterhitstructure":
|
||||||
|
ParticleEmitterHitStructure.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
case "particleemitterhitcharacter":
|
||||||
|
ParticleEmitterHitCharacter.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
partial void UseProjSpecific(float deltaTime)
|
||||||
|
{
|
||||||
|
if (ParticleEmitter != null)
|
||||||
|
{
|
||||||
|
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||||
|
ParticleEmitter.Emit(
|
||||||
|
deltaTime, item.WorldPosition + TransformedBarrelPos,
|
||||||
|
item.CurrentHull, particleAngle, -particleAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex)
|
||||||
|
{
|
||||||
|
Vector2 progressBarPos = targetStructure.SectionPosition(sectionIndex);
|
||||||
|
if (targetStructure.Submarine != null)
|
||||||
|
{
|
||||||
|
progressBarPos += targetStructure.Submarine.DrawPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressBar = user.UpdateHUDProgressBar(
|
||||||
|
targetStructure,
|
||||||
|
progressBarPos,
|
||||||
|
1.0f - targetStructure.SectionDamage(sectionIndex) / targetStructure.Health,
|
||||||
|
Color.Red, Color.Green);
|
||||||
|
|
||||||
|
if (progressBar != null) progressBar.Size = new Vector2(60.0f, 20.0f);
|
||||||
|
|
||||||
|
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||||
|
if (targetStructure.Submarine != null) particlePos += targetStructure.Submarine.DrawPosition;
|
||||||
|
foreach (var emitter in ParticleEmitterHitStructure)
|
||||||
|
{
|
||||||
|
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||||
|
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter)
|
||||||
|
{
|
||||||
|
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||||
|
if (targetCharacter.Submarine != null) particlePos += targetCharacter.Submarine.DrawPosition;
|
||||||
|
foreach (var emitter in ParticleEmitterHitCharacter)
|
||||||
|
{
|
||||||
|
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||||
|
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition)
|
||||||
|
{
|
||||||
|
if (prevCondition != targetItem.Condition)
|
||||||
|
{
|
||||||
|
Vector2 progressBarPos = targetItem.DrawPosition;
|
||||||
|
var progressBar = user.UpdateHUDProgressBar(
|
||||||
|
targetItem,
|
||||||
|
progressBarPos,
|
||||||
|
targetItem.Condition / 100.0f,
|
||||||
|
Color.Red, Color.Green);
|
||||||
|
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||||
|
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
||||||
|
foreach (var emitter in ParticleEmitterHitItem)
|
||||||
|
{
|
||||||
|
if (!emitter.First.MatchesItem(targetItem)) continue;
|
||||||
|
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||||
|
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
using Barotrauma.Particles;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class Repairable : ItemComponent
|
||||||
|
{
|
||||||
|
private GUIButton repairButton;
|
||||||
|
private GUIProgressBar progressBar;
|
||||||
|
|
||||||
|
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||||
|
//the corresponding particle emitter is active when the condition is within this range
|
||||||
|
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||||
|
|
||||||
|
private string repairButtonText, repairingText;
|
||||||
|
|
||||||
|
[Serialize("", false)]
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldDrawHUD(Character character)
|
||||||
|
{
|
||||||
|
if (!HasRequiredItems(character, false)) return false;
|
||||||
|
return (item.Condition < ShowRepairUIThreshold || (currentFixer == character && item.Condition < item.Prefab.Health));
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||||
|
header, textAlignment: Alignment.TopCenter, font: GUI.LargeFont);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
|
Description, font: GUI.SmallFont, wrap: true);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||||
|
TextManager.Get("RequiredRepairSkills"));
|
||||||
|
for (int i = 0; i < requiredSkills.Count; i++)
|
||||||
|
{
|
||||||
|
var skillText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||||
|
" - " + TextManager.Get("SkillName." + requiredSkills[i].Identifier) + ": " + ((int)requiredSkills[i].Level), font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
UserData = requiredSkills[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
progressBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||||
|
color: Color.Green, barSize: 0.0f);
|
||||||
|
|
||||||
|
repairButtonText = TextManager.Get("RepairButton");
|
||||||
|
repairingText = TextManager.Get("Repairing");
|
||||||
|
repairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter),
|
||||||
|
repairButtonText)
|
||||||
|
{
|
||||||
|
OnClicked = (btn, obj) =>
|
||||||
|
{
|
||||||
|
currentFixer = Character.Controlled;
|
||||||
|
item.CreateClientEvent(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "emitter":
|
||||||
|
case "particleemitter":
|
||||||
|
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||||
|
particleEmitterConditionRanges.Add(new Vector2(
|
||||||
|
subElement.GetAttributeFloat("mincondition", 0.0f),
|
||||||
|
subElement.GetAttributeFloat("maxcondition", 100.0f)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < particleEmitters.Count; i++)
|
||||||
|
{
|
||||||
|
if (item.Condition >= particleEmitterConditionRanges[i].X && item.Condition <= particleEmitterConditionRanges[i].Y)
|
||||||
|
{
|
||||||
|
particleEmitters[i].Emit(deltaTime, item.WorldPosition, item.CurrentHull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||||
|
{
|
||||||
|
IsActive = true;
|
||||||
|
|
||||||
|
progressBar.BarSize = item.Condition / item.Prefab.Health;
|
||||||
|
progressBar.Color = ToolBox.GradientLerp(item.Condition / item.Prefab.Health, Color.Red, Color.Orange, Color.Green);
|
||||||
|
|
||||||
|
repairButton.Enabled = currentFixer == null;
|
||||||
|
repairButton.Text = currentFixer == null ?
|
||||||
|
repairButtonText :
|
||||||
|
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
||||||
|
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
||||||
|
{
|
||||||
|
Skill skill = c.UserData as Skill;
|
||||||
|
if (skill == null) continue;
|
||||||
|
|
||||||
|
GUITextBlock textBlock = (GUITextBlock)c;
|
||||||
|
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
|
||||||
|
{
|
||||||
|
textBlock.TextColor = Color.Red;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textBlock.TextColor = Color.White;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,27 +2,27 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Connection
|
partial class Connection
|
||||||
{
|
{
|
||||||
private static Texture2D panelTexture;
|
//private static Texture2D panelTexture;
|
||||||
private static Sprite connector;
|
private static Sprite connector;
|
||||||
private static Sprite wireVertical;
|
private static Sprite wireVertical;
|
||||||
|
private static Sprite connectionSprite;
|
||||||
|
private static Sprite connectionSpriteHighlight;
|
||||||
|
private static List<Sprite> screwSprites;
|
||||||
|
|
||||||
|
private static Wire draggingConnected;
|
||||||
|
|
||||||
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
|
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
|
||||||
{
|
{
|
||||||
|
Rectangle panelRect = panel.GuiFrame.Rect;
|
||||||
int width = 400, height = 200;
|
int x = panelRect.X, y = panelRect.Y;
|
||||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = GameMain.GraphicsHeight - height;
|
int width = panelRect.Width, height = panelRect.Height;
|
||||||
|
|
||||||
Rectangle panelRect = new Rectangle(x, y, width, height);
|
|
||||||
|
|
||||||
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 512 - height, width, height), Color.White);
|
|
||||||
|
|
||||||
//GUI.DrawRectangle(spriteBatch, panelRect, Color.Black, true);
|
|
||||||
|
|
||||||
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
|
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
|
||||||
|
|
||||||
@@ -49,14 +49,15 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 rightPos = new Vector2(x + width - 130, y + 50);
|
Vector2 rightPos = new Vector2(x + width - 130, y + 80);
|
||||||
Vector2 leftPos = new Vector2(x + 130, y + 50);
|
Vector2 leftPos = new Vector2(x + 130, y + 80);
|
||||||
|
|
||||||
Vector2 rightWirePos = new Vector2(x + width - 5, y + 30);
|
Vector2 rightWirePos = new Vector2(x + width - 5, y + 30);
|
||||||
|
|
||||||
Vector2 leftWirePos = new Vector2(x + 5, y + 30);
|
Vector2 leftWirePos = new Vector2(x + 5, y + 30);
|
||||||
|
|
||||||
int wireInterval = (height - 20) / Math.Max(totalWireCount, 1);
|
int wireInterval = (height - 20) / Math.Max(totalWireCount, 1);
|
||||||
|
int connectorIntervalLeft = (height - 100) / Math.Max(panel.Connections.Count(c => c.IsOutput), 1);
|
||||||
|
int connectorIntervalRight = (height - 100) / Math.Max(panel.Connections.Count(c => !c.IsOutput), 1);
|
||||||
|
|
||||||
foreach (Connection c in panel.Connections)
|
foreach (Connection c in panel.Connections)
|
||||||
{
|
{
|
||||||
@@ -67,7 +68,7 @@ namespace Barotrauma.Items.Components
|
|||||||
int linkIndex = c.FindWireIndex(draggingConnected.Item);
|
int linkIndex = c.FindWireIndex(draggingConnected.Item);
|
||||||
if (linkIndex > -1)
|
if (linkIndex > -1)
|
||||||
{
|
{
|
||||||
Inventory.draggingItem = c.Wires[linkIndex].Item;
|
Inventory.draggingItem = c.wires[linkIndex].Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ namespace Barotrauma.Items.Components
|
|||||||
mouseInRect, equippedWire,
|
mouseInRect, equippedWire,
|
||||||
wireInterval);
|
wireInterval);
|
||||||
|
|
||||||
rightPos.Y += 30;
|
rightPos.Y += connectorIntervalLeft;
|
||||||
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -91,7 +92,7 @@ namespace Barotrauma.Items.Components
|
|||||||
mouseInRect, equippedWire,
|
mouseInRect, equippedWire,
|
||||||
wireInterval);
|
wireInterval);
|
||||||
|
|
||||||
leftPos.Y += 30;
|
leftPos.Y += connectorIntervalRight;
|
||||||
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
||||||
//leftWireX -= wireInterval;
|
//leftWireX -= wireInterval;
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (draggingConnected != null)
|
if (draggingConnected != null)
|
||||||
{
|
{
|
||||||
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height), mouseInRect, null, panel);
|
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height - 10), mouseInRect, null, panel, "");
|
||||||
|
|
||||||
if (!PlayerInput.LeftButtonHeld())
|
if (!PlayerInput.LeftButtonHeld())
|
||||||
{
|
{
|
||||||
@@ -124,48 +125,45 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
DrawWire(spriteBatch, equippedWire, equippedWire.Item,
|
DrawWire(spriteBatch, equippedWire, equippedWire.Item,
|
||||||
new Vector2(x + width / 2, y + height - 100),
|
new Vector2(x + width / 2, y + height - 100),
|
||||||
new Vector2(x + width / 2, y + height), mouseInRect, null, panel);
|
new Vector2(x + width / 2, y + height), mouseInRect, null, panel, "");
|
||||||
|
|
||||||
if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item;
|
if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop dragging a wire item if cursor is outside the panel
|
//stop dragging a wire item if the cursor is within any connection panel
|
||||||
if (mouseInRect) Inventory.draggingItem = null;
|
//(so we don't drop the item when dropping the wire on a connection)
|
||||||
|
if (mouseInRect || GUI.MouseOn?.UserData is ConnectionPanel) Inventory.draggingItem = null;
|
||||||
|
|
||||||
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 0, width, height), Color.White);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Draw(SpriteBatch spriteBatch, ConnectionPanel panel, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval)
|
private void Draw(SpriteBatch spriteBatch, ConnectionPanel panel, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval)
|
||||||
{
|
{
|
||||||
//spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
|
//spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
|
||||||
GUI.DrawString(spriteBatch, labelPos, Name, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont);
|
GUI.DrawString(spriteBatch, labelPos, Name, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont);
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)position.X - 10, (int)position.Y - 10, 20, 20), Color.White);
|
connectionSprite.Draw(spriteBatch, position);
|
||||||
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(64, 256, 32, 32), Color.White);
|
|
||||||
|
|
||||||
for (int i = 0; i < MaxLinked; i++)
|
for (int i = 0; i < MaxLinked; i++)
|
||||||
{
|
{
|
||||||
if (Wires[i] == null || Wires[i].Hidden || draggingConnected == Wires[i]) continue;
|
if (wires[i] == null || wires[i].Hidden || draggingConnected == wires[i]) continue;
|
||||||
|
|
||||||
Connection recipient = Wires[i].OtherConnection(this);
|
Connection recipient = wires[i].OtherConnection(this);
|
||||||
|
|
||||||
DrawWire(spriteBatch, Wires[i], (recipient == null) ? Wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire, panel);
|
string label = recipient == null ? "" :
|
||||||
|
wires[i].Locked ? recipient.item.Name + "\n" + TextManager.Get("ConnectionLocked") : recipient.item.Name;
|
||||||
|
DrawWire(spriteBatch, wires[i], (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire, panel, label);
|
||||||
|
|
||||||
wirePosition.Y += wireInterval;
|
wirePosition.Y += wireInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f)
|
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f)
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(panelTexture, position - new Vector2(21.5f, 21.5f), new Rectangle(106, 250, 43, 43), Color.White);
|
connectionSpriteHighlight.Draw(spriteBatch, position);
|
||||||
|
|
||||||
if (!PlayerInput.LeftButtonHeld())
|
if (!PlayerInput.LeftButtonHeld())
|
||||||
{
|
{
|
||||||
//find an empty cell for the new connection
|
//find an empty cell for the new connection
|
||||||
int index = FindWireIndex(null);
|
int index = FindEmptyIndex();
|
||||||
|
|
||||||
if (index > -1 && !Wires.Contains(draggingConnected))
|
if (index > -1 && !Wires.Contains(draggingConnected))
|
||||||
{
|
{
|
||||||
bool alreadyConnected = draggingConnected.IsConnectedTo(panel.Item);
|
bool alreadyConnected = draggingConnected.IsConnectedTo(panel.Item);
|
||||||
@@ -186,22 +184,20 @@ namespace Barotrauma.Items.Components
|
|||||||
Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction);
|
Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLink(index, draggingConnected);
|
SetWire(index, draggingConnected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int screwIndex = (position.Y % 60 < 30) ? 0 : 1;
|
|
||||||
|
|
||||||
if (Wires.Any(w => w != null && w != draggingConnected))
|
if (Wires.Any(w => w != null && w != draggingConnected))
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(screwIndex * 32, 256, 32, 32), Color.White);
|
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
||||||
|
screwSprites[screwIndex].Draw(spriteBatch, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel)
|
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel, string label)
|
||||||
{
|
{
|
||||||
if (draggingConnected == wire)
|
if (draggingConnected == wire)
|
||||||
{
|
{
|
||||||
@@ -228,13 +224,14 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f ||
|
Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f ||
|
||||||
new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition));
|
new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition));
|
||||||
|
|
||||||
string label = wire.Locked || panel.Locked ? item.Name + "\n" + TextManager.Get("ConnectionLocked") : item.Name;
|
if (!string.IsNullOrEmpty(label))
|
||||||
|
{
|
||||||
GUI.DrawString(spriteBatch,
|
GUI.DrawString(spriteBatch,
|
||||||
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
|
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
|
||||||
label,
|
label,
|
||||||
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
|
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
|
||||||
3, GUI.SmallFont);
|
3, GUI.SmallFont);
|
||||||
|
}
|
||||||
|
|
||||||
var wireEnd = end + Vector2.Normalize(start - end) * 30.0f;
|
var wireEnd = end + Vector2.Normalize(start - end) * 30.0f;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,44 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
|
partial class ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
public override void UpdateHUD(Character character)
|
public static Wire HighlightedWire;
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
if (GuiFrame == null) return;
|
||||||
|
new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform), DrawConnections, null)
|
||||||
|
{
|
||||||
|
UserData = this
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Move(Vector2 amount)
|
||||||
|
{
|
||||||
|
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) return;
|
||||||
|
MoveConnectedWires(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldDrawHUD(Character character)
|
||||||
|
{
|
||||||
|
return character == Character.Controlled && character == user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
GuiFrame?.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (character != Character.Controlled || character != user) return;
|
if (character != Character.Controlled || character != user) return;
|
||||||
|
|
||||||
@@ -21,12 +50,17 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
private void DrawConnections(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||||
{
|
{
|
||||||
if (character != Character.Controlled || character != user) return;
|
if (user != Character.Controlled || user == null) return;
|
||||||
|
|
||||||
HighlightedWire = null;
|
HighlightedWire = null;
|
||||||
Connection.DrawConnections(spriteBatch, this, character);
|
Connection.DrawConnections(spriteBatch, this, user);
|
||||||
|
|
||||||
|
foreach (UISprite sprite in GUI.Style.GetComponentStyle("ConnectionPanelFront").Sprites[GUIComponent.ComponentState.None])
|
||||||
|
{
|
||||||
|
sprite.Draw(spriteBatch, GuiFrame.Rect, Color.White, SpriteEffects.None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +81,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private void ApplyRemoteState(NetBuffer msg)
|
private void ApplyRemoteState(NetBuffer msg)
|
||||||
{
|
{
|
||||||
List<Wire> prevWires = Connections.SelectMany(c => Array.FindAll(c.Wires, w => w != null)).ToList();
|
List<Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
|
||||||
List<Wire> newWires = new List<Wire>();
|
List<Wire> newWires = new List<Wire>();
|
||||||
|
|
||||||
foreach (Connection connection in Connections)
|
foreach (Connection connection in Connections)
|
||||||
@@ -69,7 +103,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
newWires.Add(wireComponent);
|
newWires.Add(wireComponent);
|
||||||
|
|
||||||
connection.Wires[i] = wireComponent;
|
connection.SetWire(i, wireComponent);
|
||||||
wireComponent.Connect(connection, false);
|
wireComponent.Connect(connection, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class CustomInterface
|
||||||
|
{
|
||||||
|
private List<GUIComponent> uiElements = new List<GUIComponent>();
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
uiElements.Clear();
|
||||||
|
|
||||||
|
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center))
|
||||||
|
{ RelativeSpacing = 0.05f, Stretch = true };
|
||||||
|
|
||||||
|
foreach (CustomInterfaceElement ciElement in customInterfaceElementList)
|
||||||
|
{
|
||||||
|
if (ciElement.ContinuousSignal)
|
||||||
|
{
|
||||||
|
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), ciElement.Label)
|
||||||
|
{
|
||||||
|
UserData = ciElement
|
||||||
|
};
|
||||||
|
tickBox.OnSelected += (tBox) =>
|
||||||
|
{
|
||||||
|
if (GameMain.Client == null)
|
||||||
|
{
|
||||||
|
TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.CreateClientEvent(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
uiElements.Add(tickBox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var btn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), ciElement.Label)
|
||||||
|
{
|
||||||
|
UserData = ciElement
|
||||||
|
};
|
||||||
|
btn.OnClicked += (_, userdata) =>
|
||||||
|
{
|
||||||
|
if (GameMain.Client == null)
|
||||||
|
{
|
||||||
|
ButtonClicked(userdata as CustomInterfaceElement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMain.Client.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.components.IndexOf(this), userdata as CustomInterfaceElement });
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
uiElements.Add(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void UpdateLabelsProjSpecific()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < labels.Length && i < uiElements.Count; i++)
|
||||||
|
{
|
||||||
|
if (uiElements[i] is GUIButton button)
|
||||||
|
{
|
||||||
|
button.Text = labels[i];
|
||||||
|
}
|
||||||
|
else if (uiElements[i] is GUITickBox tickBox)
|
||||||
|
{
|
||||||
|
tickBox.Text = labels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||||
|
{
|
||||||
|
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
|
||||||
|
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||||
|
{
|
||||||
|
if (customInterfaceElementList[i].ContinuousSignal)
|
||||||
|
{
|
||||||
|
msg.Write(((GUITickBox)uiElements[i]).Selected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.Write(extraData != null && extraData.Any(d => d as CustomInterfaceElement == customInterfaceElementList[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||||
|
{
|
||||||
|
bool elementState = msg.ReadBoolean();
|
||||||
|
if (customInterfaceElementList[i].ContinuousSignal)
|
||||||
|
{
|
||||||
|
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||||
|
TickBoxToggled(customInterfaceElementList[i], elementState);
|
||||||
|
}
|
||||||
|
else if (elementState)
|
||||||
|
{
|
||||||
|
ButtonClicked(customInterfaceElementList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class MotionSensor : IDrawableComponent
|
||||||
|
{
|
||||||
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
|
{
|
||||||
|
if (!editing || !MapEntity.SelectedList.Contains(item)) return;
|
||||||
|
|
||||||
|
Vector2 pos = item.WorldPosition + detectOffset;
|
||||||
|
pos.Y = -pos.Y;
|
||||||
|
GUI.DrawRectangle(spriteBatch, pos - new Vector2(rangeX, rangeY), new Vector2(rangeX, rangeY) * 2.0f, Color.Cyan * 0.5f, isFilled: false, thickness: 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class WifiComponent : IDrawableComponent
|
||||||
|
{
|
||||||
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
|
{
|
||||||
|
if (!editing || !MapEntity.SelectedList.Contains(item)) return;
|
||||||
|
|
||||||
|
Vector2 pos = new Vector2(item.DrawPosition.X, -item.DrawPosition.Y);
|
||||||
|
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitY * range, pos - Vector2.UnitY * range, Color.Cyan * 0.5f, 2);
|
||||||
|
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitX * range, pos - Vector2.UnitX * range, Color.Cyan * 0.5f, 2);
|
||||||
|
ShapeExtensions.DrawCircle(spriteBatch, pos, range, 32, Color.Cyan * 0.5f, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,8 +35,7 @@ namespace Barotrauma.Items.Components
|
|||||||
SpriteEffects.None,
|
SpriteEffects.None,
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Sprite wireSprite;
|
private static Sprite wireSprite;
|
||||||
|
|
||||||
private static Wire draggingWire;
|
private static Wire draggingWire;
|
||||||
@@ -45,7 +44,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing)
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
{
|
{
|
||||||
if (sections.Count == 0 && !IsActive)
|
if (sections.Count == 0 && !IsActive || Hidden)
|
||||||
{
|
{
|
||||||
Drawable = false;
|
Drawable = false;
|
||||||
return;
|
return;
|
||||||
@@ -187,8 +186,7 @@ namespace Barotrauma.Items.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//check if close enough to a node
|
//check if close enough to a node
|
||||||
float temp = 0.0f;
|
int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out _);
|
||||||
int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out temp);
|
|
||||||
if (closestIndex > -1)
|
if (closestIndex > -1)
|
||||||
{
|
{
|
||||||
highlightedNodeIndex = closestIndex;
|
highlightedNodeIndex = closestIndex;
|
||||||
@@ -209,37 +207,40 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check which wire is highlighted with the cursor
|
|
||||||
Wire highlighted = null;
|
Wire highlighted = null;
|
||||||
float closestDist = float.PositiveInfinity;
|
|
||||||
foreach (Wire w in wires)
|
//check which wire is highlighted with the cursor
|
||||||
|
if (GUI.MouseOn == null)
|
||||||
{
|
{
|
||||||
Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
float closestDist = float.PositiveInfinity;
|
||||||
if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
|
foreach (Wire w in wires)
|
||||||
|
|
||||||
float dist = 0.0f;
|
|
||||||
int highlightedNode = w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out dist);
|
|
||||||
if (highlightedNode > -1)
|
|
||||||
{
|
{
|
||||||
if (dist < closestDist)
|
Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||||
|
if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
|
||||||
|
|
||||||
|
int highlightedNode = w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out float dist);
|
||||||
|
if (highlightedNode > -1)
|
||||||
{
|
{
|
||||||
highlightedNodeIndex = highlightedNode;
|
if (dist < closestDist)
|
||||||
highlighted = w;
|
{
|
||||||
closestDist = dist;
|
highlightedNodeIndex = highlightedNode;
|
||||||
|
highlighted = w;
|
||||||
|
closestDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
|
||||||
|
{
|
||||||
|
//prefer nodes over sections
|
||||||
|
if (dist + nodeSelectDist * 0.5f < closestDist)
|
||||||
|
{
|
||||||
|
highlightedNodeIndex = null;
|
||||||
|
highlighted = w;
|
||||||
|
closestDist = dist + nodeSelectDist * 0.5f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
|
|
||||||
{
|
|
||||||
//prefer nodes over sections
|
|
||||||
if (dist + nodeSelectDist * 0.5f < closestDist)
|
|
||||||
{
|
|
||||||
highlightedNodeIndex = null;
|
|
||||||
highlighted = w;
|
|
||||||
closestDist = dist + nodeSelectDist * 0.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlighted != null)
|
if (highlighted != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -137,53 +137,77 @@ namespace Barotrauma.Items.Components
|
|||||||
hudPos += Vector2.UnitX * 50.0f;
|
hudPos += Vector2.UnitX * 50.0f;
|
||||||
|
|
||||||
List<string> texts = new List<string>();
|
List<string> texts = new List<string>();
|
||||||
|
List<Color> textColors = new List<Color>();
|
||||||
|
|
||||||
if (target.Info != null)
|
if (target.Info != null)
|
||||||
{
|
{
|
||||||
texts.Add(target.Name);
|
texts.Add(target.Name);
|
||||||
|
textColors.Add(Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.IsDead)
|
if (target.IsDead)
|
||||||
{
|
{
|
||||||
texts.Add(TextManager.Get("Deceased"));
|
texts.Add(TextManager.Get("Deceased"));
|
||||||
texts.Add(TextManager.Get("CauseOfDeath") + ": " + TextManager.Get("CauseOfDeath." + target.CauseOfDeath.ToString()));
|
textColors.Add(Color.Red);
|
||||||
|
texts.Add(
|
||||||
|
target.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
|
||||||
|
TextManager.Get("CauseOfDeath") + ": " +TextManager.Get("CauseOfDeath." + target.CauseOfDeath.Type.ToString()));
|
||||||
|
textColors.Add(Color.Red);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (target.IsUnconscious) texts.Add(TextManager.Get("Unconscious"));
|
if (target.IsUnconscious)
|
||||||
if (target.Stun > 0.01f) texts.Add(TextManager.Get("Stunned"));
|
{
|
||||||
|
texts.Add(TextManager.Get("Unconscious"));
|
||||||
int healthTextIndex = target.Health > 95.0f ? 0 :
|
textColors.Add(Color.Orange);
|
||||||
MathHelper.Clamp((int)Math.Ceiling((1.0f - (target.Health / 200.0f + 0.5f)) * HealthTexts.Length), 0, HealthTexts.Length - 1);
|
}
|
||||||
|
if (target.Stun > 0.01f)
|
||||||
texts.Add(HealthTexts[healthTextIndex]);
|
{
|
||||||
|
texts.Add(TextManager.Get("Stunned"));
|
||||||
|
textColors.Add(Color.Orange);
|
||||||
|
}
|
||||||
|
|
||||||
int oxygenTextIndex = MathHelper.Clamp((int)Math.Floor((1.0f - (target.Oxygen / 100.0f)) * OxygenTexts.Length), 0, OxygenTexts.Length - 1);
|
int oxygenTextIndex = MathHelper.Clamp((int)Math.Floor((1.0f - (target.Oxygen / 100.0f)) * OxygenTexts.Length), 0, OxygenTexts.Length - 1);
|
||||||
texts.Add(OxygenTexts[oxygenTextIndex]);
|
texts.Add(OxygenTexts[oxygenTextIndex]);
|
||||||
|
textColors.Add(Color.Lerp(Color.Red, Color.Green, target.Oxygen / 100.0f));
|
||||||
|
|
||||||
if (target.Bleeding > 0.0f)
|
if (target.Bleeding > 0.0f)
|
||||||
{
|
{
|
||||||
int bleedingTextIndex = MathHelper.Clamp((int)Math.Floor(target.Bleeding / 4.0f) * BleedingTexts.Length, 0, BleedingTexts.Length - 1);
|
int bleedingTextIndex = MathHelper.Clamp((int)Math.Floor(target.Bleeding / 100.0f) * BleedingTexts.Length, 0, BleedingTexts.Length - 1);
|
||||||
texts.Add(BleedingTexts[bleedingTextIndex]);
|
texts.Add(BleedingTexts[bleedingTextIndex]);
|
||||||
|
textColors.Add(Color.Lerp(Color.Red, Color.Green, target.Bleeding / 100.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.huskInfection != null)
|
var allAfflictions = target.CharacterHealth.GetAllAfflictions();
|
||||||
|
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
|
||||||
|
foreach (Affliction affliction in allAfflictions)
|
||||||
{
|
{
|
||||||
if (target.huskInfection.State == HuskInfection.InfectionState.Transition)
|
if (affliction.Strength < affliction.Prefab.ActivationThreshold || affliction.Strength < affliction.Prefab.ShowIconThreshold) continue;
|
||||||
|
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
|
||||||
{
|
{
|
||||||
texts.Add(TextManager.Get("HuskInfectionTransition"));
|
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
|
||||||
}
|
}
|
||||||
else if (target.huskInfection.State == HuskInfection.InfectionState.Active)
|
else
|
||||||
{
|
{
|
||||||
texts.Add(TextManager.Get("HuskInfectionActive"));
|
combinedAfflictionStrengths[affliction.Prefab] = affliction.Strength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (AfflictionPrefab affliction in combinedAfflictionStrengths.Keys)
|
||||||
|
{
|
||||||
|
texts.Add(affliction.Name + ": " + ((int)combinedAfflictionStrengths[affliction]).ToString() + " %");
|
||||||
|
textColors.Add(Color.Lerp(Color.Red, Color.Green, combinedAfflictionStrengths[affliction] / affliction.MaxStrength));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string text in texts)
|
GUI.DrawString(spriteBatch, hudPos, texts[0], textColors[0] * alpha, Color.Black * 0.7f * alpha, 2);
|
||||||
|
hudPos.X += 5.0f;
|
||||||
|
hudPos.Y += 24.0f;
|
||||||
|
|
||||||
|
for (int i = 1; i < texts.Count; i++)
|
||||||
{
|
{
|
||||||
GUI.DrawString(spriteBatch, hudPos, text, Color.LightGreen * alpha, Color.Black * 0.7f * alpha, 2);
|
GUI.DrawString(spriteBatch, hudPos, texts[i], textColors[i] * alpha, Color.Black * 0.7f * alpha, 2, GUI.SmallFont);
|
||||||
hudPos.Y += 24.0f;
|
hudPos.Y += 18.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user