diff --git a/.gitignore b/.gitignore index 94b6e9383..a52d698e5 100644 --- a/.gitignore +++ b/.gitignore @@ -383,3 +383,5 @@ VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.Pa VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.Test.csproj VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.csproj VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/editmode-results.xml + +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index fb5cfd54c..da5906e21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Built with Unity 2020.3. ### Added +- A *Drop Target Bank* component ([#333](https://github.com/freezy/VisualPinball.Engine/pull/333), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html)). - Editor: Enable manual trigger for coils, switches, lamps and wires during gameplay ([#332](https://github.com/freezy/VisualPinball.Engine/pull/332)) - Support for dynamic wires, also known as *Fast Flip* ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330), [Documentation](https://docs.visualpinball.org/creators-guide/editor/wire-manager.html#dynamic)). - Component for light groups, allowing easy grouping of GI lamps. ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330) [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/light-groups.html)). diff --git a/VisualPinball.Engine/Common/Constants.cs b/VisualPinball.Engine/Common/Constants.cs index 132239791..7b661da9e 100644 --- a/VisualPinball.Engine/Common/Constants.cs +++ b/VisualPinball.Engine/Common/Constants.cs @@ -151,5 +151,6 @@ public static class InputConstants public const string ActionCoinDoorAdvance = "Coin Door Advance"; public const string ActionCoinDoorUpDown = "Coin Door Up/Down"; public const string ActionSlamTilt = "Slam Tilt"; + public const string ActionSelfTest = "Self Test"; } } diff --git a/VisualPinball.Engine/VPT/DropTargetBank.meta b/VisualPinball.Engine/VPT/DropTargetBank.meta new file mode 100644 index 000000000..76049f470 --- /dev/null +++ b/VisualPinball.Engine/VPT/DropTargetBank.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d826a143ee3e049bda4aa037c46d74e9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs b/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs index 6a0acd3a8..d9b243ab1 100644 --- a/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Engine.VPT.Flipper { diff --git a/VisualPinball.Engine/VPT/Light/Light.cs b/VisualPinball.Engine/VPT/Light/Light.cs index cf16973e7..7d9b8c50b 100644 --- a/VisualPinball.Engine/VPT/Light/Light.cs +++ b/VisualPinball.Engine/VPT/Light/Light.cs @@ -18,6 +18,7 @@ using System.IO; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Engine.VPT.Light { @@ -57,7 +58,7 @@ public static Light GetDefault(string name, float x, float y) }; return new Light(lightData); } - + public static Light GetDefault(Table.Table table) => GetDefault(table.GetNewName("Light"), table.Width / 2f, table.Height / 2f); #region IRenderable diff --git a/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs b/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs index 9933b9fa0..6bc4db508 100644 --- a/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs @@ -18,6 +18,7 @@ using VisualPinball.Engine.Common; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Engine.VPT.Primitive { diff --git a/VisualPinball.Engine/VPT/Surface/SurfaceMeshGenerator.cs b/VisualPinball.Engine/VPT/Surface/SurfaceMeshGenerator.cs index 9e17acff6..a2707ba3a 100644 --- a/VisualPinball.Engine/VPT/Surface/SurfaceMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Surface/SurfaceMeshGenerator.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Engine.VPT.Surface { diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png new file mode 100644 index 000000000..eafb43c73 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png.meta new file mode 100644 index 000000000..a55d4df01 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 9f470fe26ae0b634e95c061f962a6904 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/chip.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/chip.png.meta index 89399f709..276a6c06d 100644 --- a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/chip.png.meta +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/chip.png.meta @@ -10,7 +10,7 @@ TextureImporter: sRGBTexture: 1 linearTexture: 0 fadeOut: 0 - borderMipMap: 0 + borderMipMap: 1 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 @@ -32,12 +32,12 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 - wrapU: -1 - wrapV: -1 - wrapW: -1 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 @@ -55,6 +55,8 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png new file mode 100644 index 000000000..22e00bb0b Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png.meta new file mode 100644 index 000000000..58d846ffe --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 19295d93f1b8ac84a84897fdab35ccbf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/hit_target.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/hit_target.png.meta index d0fd1ad6c..21344358f 100644 --- a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/hit_target.png.meta +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/hit_target.png.meta @@ -10,7 +10,7 @@ TextureImporter: sRGBTexture: 1 linearTexture: 0 fadeOut: 0 - borderMipMap: 0 + borderMipMap: 1 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/keyboard.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/keyboard.png.meta index 1788485e9..2257855e2 100644 --- a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/keyboard.png.meta +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/keyboard.png.meta @@ -10,7 +10,7 @@ TextureImporter: sRGBTexture: 1 linearTexture: 0 fadeOut: 0 - borderMipMap: 0 + borderMipMap: 1 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 @@ -32,12 +32,12 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 - wrapU: -1 - wrapV: -1 - wrapW: -1 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 @@ -55,6 +55,8 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png new file mode 100644 index 000000000..8084858f4 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png.meta new file mode 100644 index 000000000..83b431228 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 78449ad3fb42f5d448f6390edd1512dc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png new file mode 100644 index 000000000..a01d167d7 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png.meta new file mode 100644 index 000000000..5dbaa99ce --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 3f516a199e071c14b9bf8793cf88917d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png new file mode 100644 index 000000000..ea6ba0475 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png.meta new file mode 100644 index 000000000..e9059e134 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 834626c5c64e7f244959841228607de4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png new file mode 100644 index 000000000..7e62e45cb Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png.meta new file mode 100644 index 000000000..c9a938624 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: d4d01ea0b8134494c9e9da2fe7605d42 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png new file mode 100644 index 000000000..97c6f6f57 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png.meta new file mode 100644 index 000000000..b40c7ea49 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 0d845933275a5b244b607c94adef066d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png new file mode 100644 index 000000000..5de2f2166 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png.meta new file mode 100644 index 000000000..ba22fcfdb --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/drop_target_bank.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 203ac59b18a95344f91cc5ebb8ba2fe7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab b/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab new file mode 100644 index 000000000..605a9d912 --- /dev/null +++ b/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab @@ -0,0 +1,52 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6315943650588709701 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1547207884189045889} + - component: {fileID: 3547369771264680983} + m_Layer: 0 + m_Name: DropTargetBank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1547207884189045889 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6315943650588709701} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3547369771264680983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6315943650588709701} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0807d76d30f7a44ec9b4905761134eb9, type: 3} + m_Name: + m_EditorClassIdentifier: + _isLocked: 0 + _editorLayer: 0 + _editorLayerName: + _editorLayerVisibility: 1 + BankSize: 1 + DropTargets: + - {fileID: 0} diff --git a/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab.meta b/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab.meta new file mode 100644 index 000000000..119a26f8f --- /dev/null +++ b/VisualPinball.Unity/Assets/Resources/Prefabs/DropTargetBank.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cfbe6687c1d9f45e38f32cdcce7c14ea +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-coil-manager.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-coil-manager.png new file mode 100644 index 000000000..46cfb8c65 Binary files /dev/null and b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-coil-manager.png differ diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector-runtime.gif b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector-runtime.gif new file mode 100644 index 000000000..7ce28584b Binary files /dev/null and b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector-runtime.gif differ diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector.png new file mode 100644 index 000000000..0a7545e09 Binary files /dev/null and b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-bank-inspector.png differ diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-banks.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-banks.md new file mode 100644 index 000000000..ff5610291 --- /dev/null +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/drop-target-banks.md @@ -0,0 +1,31 @@ +--- +uid: drop-target-banks +title: Drop Target Banks +description: VPE supports with drop target banks, which are made out of multiple drop targets. +--- + +# Drop Target Banks + +A Drop Target Bank is a collection of one or more drop targets that are reset (raised) when a coil is fired. + +## Setup + +You can create a Drop Target Bank in two different ways. + +1. If your game has a single bank drop target, or multiple single bank drop targets, it is preferred to add it directly to the drop target. Select the drop target you want to add it to, click on *Add Component* in the inspector and select *Visual Pinball -> Game Item -> Drop Target Bank*. +2. If your game has drop target banks with multiple drop targets, click on *Drop Target Bank* in the toolbox. This will add a *Drop Target Banks* hierarchy to the playfield and create a new GameObject with the right component assigned. + + + +To configure the drop target bank, select the total number of drop targets from the *Banks* drop down. Then, under *Playfield Links*, select each drop target belonging to the bank. + +To configure the reset coil, use the [Coil Manager](xref:coil_manager) and associate the corresponding game logic engine coil with the *Reset Coil* exposed by the drop target bank: + +![Coil Manager](drop-target-bank-coil-manager.png) + +## Runtime + + + + +During gameplay, the inspector shows you switch information for each of the drop targets. You can also drop or reset a drop target by using the *Drop* and *Reset* buttons. To test resetting a drop target bank from the *Coil Manager*, click the icon next to the corresponding reset coil. diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml index f62cb5b9c..63dd79668 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml +++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml @@ -49,3 +49,5 @@ href: manual/mechanisms/slingshots.md - name: Light Groups href: manual/mechanisms/light-groups.md + - name: Drop Target Banks + href: manual/mechanisms/drop-target-banks.md diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs new file mode 100644 index 000000000..f2c125026 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs @@ -0,0 +1,210 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable AssignmentInConditionalExpression + +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(DropTargetBankComponent)), CanEditMultipleObjects] + public class DropTargetBankInspector : ItemInspector + { + private static readonly string[] BankSizeLabels = { + "Single", + "2 Bank", + "3 Bank", + "4 Bank", + "5 Bank", + "6 Bank" + }; + + private static readonly int[] BankSizeValues = { + 1, + 2, + 3, + 4, + 5, + 6 + }; + + private bool _togglePlayfield = true; + + private SerializedProperty _bankSizeProperty; + private SerializedProperty _dropTargetsProperty; + + protected override MonoBehaviour UndoTarget => throw new System.NotImplementedException(); + + override protected void OnEnable() + { + base.OnEnable(); + + _bankSizeProperty = serializedObject.FindProperty(nameof(DropTargetBankComponent.BankSize)); + _dropTargetsProperty = serializedObject.FindProperty(nameof(DropTargetBankComponent.DropTargets)); + } + + public override void OnInspectorGUI() + { + BeginEditing(); + + OnPreInspectorGUI(); + + DropDownProperty("Banks", _bankSizeProperty, BankSizeLabels, BankSizeValues); + + while (_dropTargetsProperty.arraySize < _bankSizeProperty.intValue) + { + _dropTargetsProperty.InsertArrayElementAtIndex(_dropTargetsProperty.arraySize); + } + + if (!Application.isPlaying) + { + if (_togglePlayfield = EditorGUILayout.BeginFoldoutHeaderGroup(_togglePlayfield, "Playfield Links")) + { + EditorGUI.indentLevel++; + + for (var index = 0; index < _bankSizeProperty.intValue; index++) + { + PropertyField(_dropTargetsProperty.GetArrayElementAtIndex(index), $"Drop Target {index + 1}"); + } + + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFoldoutHeaderGroup(); + } + + base.OnInspectorGUI(); + + EndEditing(); + + if (Application.isPlaying) + { + EditorGUILayout.Separator(); + + TableApi tableApi = TableComponent.GetComponent().TableApi; + DropTargetBankApi dropTargetBankApi = tableApi.DropTargetBank(target.name); + + GUILayout.BeginVertical(); + + if (_togglePlayfield = EditorGUILayout.BeginFoldoutHeaderGroup(_togglePlayfield, "Playfield Links")) + { + EditorGUI.indentLevel++; + + for (var index = 0; index < _bankSizeProperty.intValue; index++) + { + GUILayout.BeginHorizontal(); + + var dropTargetComponent = (DropTargetComponent)_dropTargetsProperty.GetArrayElementAtIndex(index).objectReferenceValue; + + if (dropTargetComponent != null) + { + var dropTargetApi = tableApi.DropTarget(dropTargetComponent); + + DrawSwitch($"Drop Target {index + 1} ({dropTargetComponent.name})", dropTargetApi.IsSwitchEnabled); + + if (GUILayout.Button(dropTargetApi.IsDropped ? "Reset" : "Drop")) + { + dropTargetApi.IsDropped = !dropTargetApi.IsDropped; + } + } + else + { + GUILayout.Label($"Drop Target {index + 1}"); + + GUIStyle style = new GUIStyle(GUI.skin.label); + style.fontStyle = FontStyle.Italic; + style.alignment = TextAnchor.MiddleRight; + + GUILayout.Label("Not configured", style); + } + + GUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.Separator(); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Drop All")) + { + for (var index = 0; index < _bankSizeProperty.intValue; index++) + { + var dropTargetComponent = (DropTargetComponent)_dropTargetsProperty.GetArrayElementAtIndex(index).objectReferenceValue; + + if (dropTargetComponent != null) + { + tableApi.DropTarget(dropTargetComponent).IsDropped = true; + } + } + } + + if (GUILayout.Button("Reset All")) + { + for (var index = 0; index < _bankSizeProperty.intValue; index++) + { + var dropTargetComponent = (DropTargetComponent)_dropTargetsProperty.GetArrayElementAtIndex(index).objectReferenceValue; + + if (dropTargetComponent != null) + { + tableApi.DropTarget(dropTargetComponent).IsDropped = false; + } + } + } + + GUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + + DrawCoil("Reset Coil", dropTargetBankApi.ResetCoil); + + GUILayout.EndVertical(); + } + } + + private static void DrawSwitch(string label, bool sw) + { + var labelPos = EditorGUILayout.GetControlRect(); + labelPos.height = 18; + + var icon = Icons.Switch(sw, IconSize.Small, sw ? IconColor.Orange : IconColor.Gray); + var width = ((labelPos.height / icon.height) * icon.width) + 2; + + labelPos.x += width; + labelPos.width -= width; + + var switchPos = new Rect(labelPos.x - width, labelPos.y, labelPos.height, labelPos.height); + GUI.Label(labelPos, label); + GUI.DrawTexture(switchPos, icon); + } + + private static void DrawCoil(string label, DeviceCoil coil) + { + var labelPos = EditorGUILayout.GetControlRect(); + labelPos.height = 18; + var switchPos = new Rect((float)(labelPos.x + (double)EditorGUIUtility.labelWidth - 20.0), labelPos.y, labelPos.height, labelPos.height); + GUI.Label(labelPos, label); + GUI.DrawTexture(switchPos, Icons.Bolt(IconSize.Small, coil.IsEnabled ? IconColor.Orange : IconColor.Gray)); + } + + protected override void FinishEdit(string label, bool dirtyMesh = true) + { + base.FinishEdit(label, dirtyMesh); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs.meta new file mode 100644 index 000000000..e8e9662e8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DropTargetBankInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf4386f8e437b4740bde20a3336d5021 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs index 93e96edb1..c451bd8bf 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs @@ -15,6 +15,8 @@ // along with this program. If not, see . using System; +using System.Collections.Generic; +using System.Linq; using UnityEditor; using UnityEngine; using VisualPinball.Engine.VPT; @@ -167,8 +169,16 @@ private void OnGUI() CreateItem(Trough.GetDefault, "New Trough"); } + if (CreateButton("Drop Target\nBank", Icons.DropTargetBank(color: iconColor), iconSize, buttonStyle)) + { + CreatePrefab("Drop Target Banks", "Prefabs/DropTargetBank"); + } + + GUILayout.EndHorizontal(); + GUILayout.BeginHorizontal(); + if (CreateButton("Slingshot", Icons.Slingshot(color: iconColor), iconSize, buttonStyle)) { - CreatePrefab("Slingshots", "Prefabs/Slingshot"); + CreatePrefab("Slingshots", "Prefabs/Slingshot"); } GUILayout.EndHorizontal(); @@ -201,7 +211,7 @@ private GameObject CreateRenderable(IItem item) return converter.InstantiateAndPersistPrefab(item).GameObject; } - private void CreatePrefab(string groupName, string path) + private void CreatePrefab(string groupName, string path) where T : Component { var converter = new VpxSceneConverter(TableComponent); TableComponent.TableContainer.Refresh(); @@ -210,10 +220,30 @@ private void CreatePrefab(string groupName, string path) var prefab = Resources.Load(path); var go = PrefabUtility.InstantiatePrefab(prefab) as GameObject; + if (go) { + go.name = GetNewPrefabName(go.name); + go.transform.SetParent(parentGo.transform, false); } + Selection.activeGameObject = go; } + + private string GetNewPrefabName(string prefix) where T : Component + { + var dict = TableComponent.GetComponentsInChildren() + .ToDictionary(component => component.name.ToLower(), component => component); + + var n = 0; + do + { + var elementName = $"{prefix}{++n}"; + if (!dict.ContainsKey(elementName.ToLower())) + { + return elementName; + } + } while (true); + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs index 50d9fcb34..2651b0af5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs @@ -40,6 +40,7 @@ public IconVariant(string name, IconSize size, IconColor color) private const string BoltName = "bolt"; private const string CoilName = "coil"; private const string DropTargetName = "drop_target"; + private const string DropTargetBankName = "drop_target_bank"; private const string FlasherName = "light_flasher"; private const string FlipperName = "flipper"; private const string GateName = "gate"; @@ -64,14 +65,14 @@ public IconVariant(string name, IconSize size, IconColor color) private const string SwitchNoName = "switch_no"; private static readonly string[] Names = { - BumperName, BoltName, CoilName, DropTargetName, FlasherName, FlipperName, HitTargetName, GateName, KeyName, KickerName, LightGroupName, - LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName, TableName, TriggerName, - TroughName, SlingshotName, SwitchNcName, SwitchNoName + BumperName, BoltName, CoilName, DropTargetName, DropTargetBankName, FlasherName, FlipperName, HitTargetName, GateName, KeyName, KickerName, + LightGroupName, LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName, TableName, + TriggerName, TroughName, SlingshotName, SwitchNcName, SwitchNoName }; - private readonly Dictionary _icons = new Dictionary(); - private static readonly MethodInfo CopyMonoScriptIconToImporters = typeof(MonoImporter).GetMethod("CopyMonoScriptIconToImporters", BindingFlags.Static|BindingFlags.NonPublic); - private static readonly MethodInfo SetIconForObject = typeof(EditorGUIUtility).GetMethod("SetIconForObject", BindingFlags.Static|BindingFlags.NonPublic); + private readonly Dictionary _icons = new Dictionary(); + private static readonly MethodInfo CopyMonoScriptIconToImporters = typeof(MonoImporter).GetMethod("CopyMonoScriptIconToImporters", BindingFlags.Static | BindingFlags.NonPublic); + private static readonly MethodInfo SetIconForObject = typeof(EditorGUIUtility).GetMethod("SetIconForObject", BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo SetGizmoEnabled = Assembly.GetAssembly(typeof(UnityEditor.Editor))?.GetType("UnityEditor.AnnotationUtility")?.GetMethod("SetGizmoEnabled", BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo SetIconEnabled = Assembly.GetAssembly(typeof(UnityEditor.Editor))?.GetType("UnityEditor.AnnotationUtility")?.GetMethod("SetIconEnabled", BindingFlags.Static | BindingFlags.NonPublic); @@ -84,12 +85,16 @@ public IconVariant(string name, IconSize size, IconColor color) private Icons() { const string iconPath = "Packages/org.visualpinball.engine.unity/VisualPinball.Unity/Assets/Editor/Icons"; - foreach (var name in Names) { - foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) { - foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) { + foreach (var name in Names) + { + foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) + { + foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) + { var variant = new IconVariant(name, size, color); var path = $"{iconPath}/{size.ToString().ToLower()}_{color.ToString().ToLower()}/{name}.png"; - if (File.Exists(path)) { + if (File.Exists(path)) + { _icons[variant] = AssetDatabase.LoadAssetAtPath(path); } } @@ -99,6 +104,7 @@ private Icons() public static Texture2D Bumper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BumperName, size, color); public static Texture2D DropTarget(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetName, size, color); + public static Texture2D DropTargetBank(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetBankName, size, color); public static Texture2D Flasher(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(FlasherName, size, color); public static Texture2D Flipper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(FlipperName, size, color); public static Texture2D Gate(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(GateName, size, color); @@ -126,9 +132,11 @@ private Icons() public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) where T : class { - switch (mb) { + switch (mb) + { case BumperComponent _: return Bumper(size, color); case DropTargetComponent _: return DropTarget(size, color); + case DropTargetBankComponent _: return DropTargetBank(size, color); //case FlasherComponent _: return Flasher(size, color); case FlipperComponent _: return Flipper(size, color); case GateComponent _: return Gate(size, color); @@ -160,6 +168,7 @@ public static void DisableGizmoIcons() DisableGizmo(); DisableGizmo(); DisableGizmo(); + DisableGizmo(); DisableGizmo(); DisableGizmo(); //DisableGizmo(); @@ -214,30 +223,35 @@ public static void DisableGizmoIcons() public static void ApplyToComponent(Object target, Texture2D tex) where T : MonoBehaviour { - if (target == null || tex == null) { + if (target == null || tex == null) + { throw new ArgumentNullException(); } - SetIconForObject.Invoke(null, new object[]{ target, tex }); + SetIconForObject.Invoke(null, new object[] { target, tex }); DisableGizmo(); var monoScript = target as MonoScript; - if (monoScript) { - CopyMonoScriptIconToImporters.Invoke(null, new object[]{ monoScript }); + if (monoScript) + { + CopyMonoScriptIconToImporters.Invoke(null, new object[] { monoScript }); } } private Texture2D GetItem(string name, IconSize size, IconColor color) { var variant = new IconVariant(name, size, color); - if (!_icons.ContainsKey(variant)) { + if (!_icons.ContainsKey(variant)) + { variant = new IconVariant(name, IconSize.Large, color); } - if (!_icons.ContainsKey(variant)) { + if (!_icons.ContainsKey(variant)) + { variant = new IconVariant(name, IconSize.Large, IconColor.Gray); } - if (!_icons.ContainsKey(variant)) { + if (!_icons.ContainsKey(variant)) + { throw new InvalidOperationException($"Cannot find {variant.Size} {variant.Name} icon of color {variant.Color}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs index 6368230fe..7e1ff7b7d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs @@ -142,6 +142,37 @@ protected static TroughComponent CreateTrough(GameObject tableGo, GameObject par return troughComponent; } + /// + /// Creates a drop target bank component. + /// + /// Table game object, for retrieving references + /// Parent game object of the new trough + /// Name of the new drop target bank + /// A list of drop targets that are in the drop target bank. + + protected static DropTargetBankComponent CreateDropTargetBank(GameObject tableGo, GameObject go, + string name = "DropTargetBank", params string[] dropTargetNames) + { + var playfieldGo = go.GetComponentInParent().gameObject; + var dropTargetBankParentGo = GetOrCreateGameObject(playfieldGo, "Drop Target Banks"); + + var dropTargetBankGo = PrefabUtility.InstantiatePrefab(DropTargetBankComponent.LoadPrefab(), dropTargetBankParentGo.transform) as GameObject; + var dropTargetBank = dropTargetBankGo!.GetComponent(); + + var compIndex = tableGo.GetComponentsInChildren() + .ToDictionary(dtc => dtc.name, dtc => dtc); + var dropTargetComponents = dropTargetNames + .Where(n => compIndex.ContainsKey(n)) + .Select(n => compIndex[n]) + .ToArray(); + + dropTargetBank.name = name; + dropTargetBank.BankSize = dropTargetComponents.Length; + dropTargetBank.DropTargets = dropTargetComponents; + + return dropTargetBank; + } + #endregion #region Light Helpers diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs new file mode 100644 index 000000000..f515ad9ae --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs @@ -0,0 +1,121 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable StringLiteralTypo +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +using UnityEngine; +using VisualPinball.Engine.VPT; + +namespace VisualPinball.Unity.Patcher +{ + [MetaMatch(TableName = "Rock", AuthorName = "jpsalas")] + public class Rock : TablePatcher + { + #region Global + + public override void PostPatch(GameObject tableGo) + { + var playfieldGo = Playfield(tableGo); + playfieldGo.isStatic = true; + + SetupDropTargetBanks(tableGo, playfieldGo); + SetupTrough(tableGo, playfieldGo); + SetupPinMame(tableGo, playfieldGo); + SetupDisplays(tableGo); + } + + private static void SetupDropTargetBanks(GameObject tableGo, GameObject playfieldGo) + { + CreateDropTargetBank(tableGo, playfieldGo, "4PosBankUpper", + new string[] { "sw40", "sw50", "sw60", "sw70" }); + + CreateDropTargetBank(tableGo, playfieldGo, "5PosBankLower", + new string[] { "sw51", "sw61", "sw71", "sw62", "sw72" }); + } + + private static void SetupTrough(GameObject tableGo, GameObject playfieldGo) + { + var troughComponent = CreateTrough(tableGo, playfieldGo); + troughComponent.Type = TroughType.ClassicSingleBall; + troughComponent.BallCount = 1; + troughComponent.SwitchCount = 1; + troughComponent.KickTime = 100; + troughComponent.RollTime = 300; + } + + private static void SetupPinMame(GameObject tableGo, GameObject playfieldGo) + { + #if !NO_PINMAME + var tableComponent = tableGo.GetComponent(); + + // GLE + Object.DestroyImmediate(tableGo.GetComponent()); + var pinmameGle = tableGo.AddComponent(); + pinmameGle.Game = new Engine.PinMAME.Games.Rock(); + pinmameGle.romId = "rock"; + tableComponent.RepopulateHardware(pinmameGle); + TableSelector.Instance.TableUpdated(); + #endif + } + + private static void SetupDisplays(GameObject tableGo) + { + const float scale = 0.5f; + var cabinetGo = tableGo.transform.Find("Cabinet").gameObject; + var go = new GameObject { + name = "Segment Display [0]", + transform = { + localEulerAngles = new Vector3(0, 0, 0), + localPosition = new Vector3(0, 0.31f, 1.1f), + localScale = new Vector3(scale, scale, scale) + } + }; + go.transform.SetParent(cabinetGo.transform, false); + + var segment = go.AddComponent(); + segment.Id = "display0"; + segment.SegmentTypeName = "Seg16"; + segment.NumSegments = 14; + segment.SeparatorType = 2; + segment.NumChars = 20; + segment.LitColor = Color.green; + + go = new GameObject + { + name = "Segment Display [1]", + transform = { + localEulerAngles = new Vector3(0, 0, 0), + localPosition = new Vector3(0, 0.21f, 1.1f), + localScale = new Vector3(scale, scale, scale) + } + }; + go.transform.SetParent(cabinetGo.transform, false); + + segment = go.AddComponent(); + segment.Id = "display1"; + segment.SegmentTypeName = "Seg16"; + segment.NumSegments = 14; + segment.SeparatorType = 2; + segment.NumChars = 20; + segment.LitColor = Color.green; + } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs.meta new file mode 100644 index 000000000..e75a42c58 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Rock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ad1e1403cf484e69bb0b81423e75c53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index 3c1f7adba..e9f8f913c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -332,6 +332,18 @@ public void SkullKicker(KickerComponent kickerComponent) #endregion + #region Drop Target Banks + + [NameMatch("sw77")] + public void CreateDropTargetBank(GameObject dropTargetGo, DropTargetComponent dropTargetComponent) + { + var dropTargetBank = dropTargetGo.AddComponent(); + dropTargetBank.BankSize = 1; + dropTargetBank.DropTargets = new[] { dropTargetComponent }; + } + + #endregion + #region Materials [NameMatch("_Plastics")] diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs index 3c52c0c46..5d9a36739 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs @@ -30,11 +30,6 @@ public class DeviceSwitch : IApiSwitch /// public event EventHandler Switch; - /// - /// Indicates whether the switch is currently opened or closed. - /// - public bool IsEnabled => _switchHandler.IsEnabled; - /// /// Guesses whether the switch is closed or not. /// @@ -44,7 +39,12 @@ public class DeviceSwitch : IApiSwitch /// in case the switch default is configurable, we don't actually know, because then it depends /// on each individual mapping. /// - public bool IsSwitchClosed => _switchDefault == SwitchDefault.NormallyClosed ? !IsEnabled : IsEnabled; + public bool IsSwitchClosed => _switchDefault == SwitchDefault.NormallyClosed ? !IsSwitchEnabled : IsSwitchEnabled; + + /// + /// Indicates whether the switch is currently opened or closed. + /// + public bool IsSwitchEnabled => _switchHandler.IsEnabled; private readonly bool _isPulseSwitch; private readonly SwitchDefault _switchDefault; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index 13f7b650b..0c9ecdd32 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -239,11 +239,16 @@ public void RegisterLampGroup(LightGroupComponent component) Register(new LightGroupApi(component.Lights.Select(l => l.GetApi(this)).ToArray()), component); } - public void RegisterMech(CannonComponent component) + public void RegisterCannonComponent(CannonComponent component) { Register(new CannonApi(component.gameObject, this), component); } + public void RegisterDropTargetBankComponent(DropTargetBankComponent component) + { + Register(new DropTargetBankApi(component.gameObject, this), component); + } + public void RegisterPlunger(PlungerComponent component, Entity entity, Entity parentEntity, InputActionReference actionRef) { var plungerApi = new PlungerApi(component.gameObject, entity, parentEntity, this); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Input/InputManager.cs b/VisualPinball.Unity/VisualPinball.Unity/Input/InputManager.cs index 5232e2c84..70787998b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Input/InputManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Input/InputManager.cs @@ -146,6 +146,7 @@ public static InputActionAsset GetDefaultInputActionAsset() map.AddAction(InputConstants.ActionCoinDoorAdvance, InputActionType.Button, "/8"); map.AddAction(InputConstants.ActionCoinDoorUpDown, InputActionType.Button, "/7"); map.AddAction(InputConstants.ActionSlamTilt, InputActionType.Button, "/home"); + map.AddAction(InputConstants.ActionSelfTest, InputActionType.Button, "/8"); asset.AddActionMap(map); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs index e3346cc86..877682de8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs @@ -47,11 +47,13 @@ public BumperApi(GameObject go, Entity entity, Entity parentEntity, Player playe #region Wiring + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; + IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + IApiCoil IApiCoilDevice.Coil(string deviceItem) => this; IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => this; - IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig.WithPulse(true)); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank.meta new file mode 100644 index 000000000..85474ddb7 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c98f9bb9a2c6847f59bc327f6f557022 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs new file mode 100644 index 000000000..8bd4cbd33 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs @@ -0,0 +1,66 @@ +using System; +using Logger = NLog.Logger; +using NLog; +using UnityEngine; +using System.Collections.Generic; + +namespace VisualPinball.Unity +{ + public class DropTargetBankApi : IApi, IApiCoilDevice + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly DropTargetBankComponent _dropTargetBankComponent; + private Player _player; + + private List _dropTargetApis = new List(); + public DeviceCoil ResetCoil; + + public event EventHandler Init; + + internal DropTargetBankApi(GameObject go, Player player) + { + _dropTargetBankComponent = go.GetComponentInChildren(); + _player = player; + } + + IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); + + private IApiCoil Coil(string deviceItem) + { + return deviceItem switch + { + DropTargetBankComponent.ResetCoilItem => ResetCoil, + _ => throw new ArgumentException($"Unknown reset coil \"{deviceItem}\". Valid name is \"{DropTargetBankComponent.ResetCoilItem}\".") + }; + } + + void IApi.OnInit(BallManager ballManager) + { + ResetCoil = new DeviceCoil(OnResetCoilEnabled); + + for (var index = 0; index < _dropTargetBankComponent.BankSize; index++) + { + _dropTargetApis.Add(_player.TableApi.DropTarget(_dropTargetBankComponent.DropTargets[index])); + } + + Init?.Invoke(this, EventArgs.Empty); + } + + private void OnResetCoilEnabled() + { + Logger.Info($"OnResetCoilEnabled - resetting {_dropTargetBankComponent.name}"); + + foreach (var dropTargetApi in _dropTargetApis) + { + dropTargetApi.IsDropped = false; + } + } + + void IApi.OnDestroy() + { + Logger.Info($"Destroying {_dropTargetBankComponent.name}"); + } + } +} + diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs.meta new file mode 100644 index 000000000..4dd292a86 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f5a02e2607acc4f39bf904878391f68a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs new file mode 100644 index 000000000..35347a7e7 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using UnityEngine; +using VisualPinball.Engine.Game.Engines; +using System.ComponentModel; +using System; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Drop Target Bank")] + [HelpURL("https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html")] + public class DropTargetBankComponent : MonoBehaviour, ICoilDeviceComponent + { + public const string ResetCoilItem = "reset_coil"; + + [ToolboxItem("The number of the drop targets. See documentation of a description of each type.")] + public int BankSize = 1; + + [SerializeField] + [Tooltip("Drop Targets")] + public DropTargetComponent[] DropTargets = Array.Empty(); + + public IEnumerable AvailableCoils => new[] { + new GamelogicEngineCoil(ResetCoilItem) { + Description = "Reset Coil" + } + }; + + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils; + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + + public static GameObject LoadPrefab() => Resources.Load("Prefabs/DropTargetBank"); + + #region Runtime + + private void Awake() + { + GetComponentInParent().RegisterDropTargetBankComponent(this); + } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs.meta new file mode 100644 index 000000000..b656acf67 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/DropTargetBank/DropTargetBankComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0807d76d30f7a44ec9b4905761134eb9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 203ac59b18a95344f91cc5ebb8ba2fe7, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs index 7af8c9869..5d41e5b89 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs @@ -171,12 +171,14 @@ private void OnDualWoundCoil(bool enabled, bool isHoldCoil) #region Wiring - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + #endregion #region Events diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs index f529acc28..a473677b1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs @@ -80,13 +80,14 @@ public GateApi(GameObject go, Entity entity, Entity parentEntity, Player player) #region Wiring - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; - + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig.WithPulse(true)); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + #endregion #region Collider Generation diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs index 75556d15f..d5768a3a9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs @@ -49,12 +49,12 @@ public class DropTargetApi : CollidableApi /// /// Thrown if target is not a drop target (but a hit target, which can't be dropped) - public bool IsDropped { + public bool IsDropped + { get => EntityManager.GetComponentData(Entity).IsDropped; set => SetIsDropped(value); } - internal DropTargetApi(GameObject go, Entity entity, Entity parentEntity, Player player) : base(go, entity, parentEntity, player) { @@ -73,22 +73,30 @@ private void SetIsDropped(bool isDropped) if (isDropped) { data.MoveDown = true; - } else { + Switch?.Invoke(this, new SwitchEventArgs(true, Entity.Null)); + OnSwitch(true); + } + else { data.MoveDown = false; data.TimeStamp = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem().TimeMsec; + + Switch?.Invoke(this, new SwitchEventArgs(false, Entity.Null)); + OnSwitch(false); } } else { data.IsDropped = isDropped; } + EntityManager.SetComponentData(Entity, data); } #region Wiring + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; + IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig); IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; - - IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); - void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig.WithPulse(true)); + + void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs index c0be08726..e0b50df38 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs @@ -47,13 +47,14 @@ internal HitTargetApi(GameObject go, Entity entity, Entity parentEntity, Player #region Wiring - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; - + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig.WithPulse(true)); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + #endregion #region Collider Generation diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/TargetComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/TargetComponent.cs index 882d73923..c6030fa4e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/TargetComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/TargetComponent.cs @@ -102,7 +102,7 @@ public Matrix3D GetTransformationMatrix() #region Wiring public IEnumerable AvailableSwitches => new[] { - new GamelogicEngineSwitch(SwitchItem) { IsPulseSwitch = true } + new GamelogicEngineSwitch(SwitchItem) { IsPulseSwitch = !(this is DropTargetComponent) } }; public SwitchDefault SwitchDefault => SwitchDefault.Configurable; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs index ec934cce7..6b9d3578c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs @@ -168,6 +168,11 @@ internal interface IApiSwitch /// Note that for pulse switches, you currently only get the "closed" event. /// event EventHandler Switch; + + /// + /// True if switch is enabled, false otherwise. Note that enabled != closed. + /// + bool IsSwitchEnabled { get; } } /// diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs index ef6212e75..22d676451 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs @@ -44,7 +44,7 @@ public abstract class ItemApi internal VisualPinballSimulationSystemGroup SimulationSystemGroup => World.DefaultGameObjectInjectionWorld.GetOrCreateSystem(); private readonly Player _player; - private readonly SwitchHandler _switchHandler; + private protected readonly SwitchHandler SwitchHandler; private protected BallManager BallManager; private protected TableComponent TableComponent; @@ -53,7 +53,7 @@ protected ItemApi(GameObject go, Player player) GameObject = go; MainComponent = go.GetComponent(); _player = player; - _switchHandler = new SwitchHandler(Name, player); + SwitchHandler = new SwitchHandler(Name, player); } protected void OnInit(BallManager ballManager) @@ -71,12 +71,12 @@ private protected void DestroyBall(Entity ballEntity) private protected DeviceSwitch CreateSwitch(string name, bool isPulseSwitch, SwitchDefault switchDefault = SwitchDefault.Configurable) => new DeviceSwitch(name, isPulseSwitch, switchDefault, _player); - private protected IApiSwitchStatus AddSwitchDest(SwitchConfig switchConfig) => _switchHandler.AddSwitchDest(switchConfig); + private protected IApiSwitchStatus AddSwitchDest(SwitchConfig switchConfig) => SwitchHandler.AddSwitchDest(switchConfig); - internal void AddWireDest(WireDestConfig wireConfig) => _switchHandler.AddWireDest(wireConfig); - internal void RemoveWireDest(string destId) => _switchHandler.RemoveWireDest(destId); + internal void AddWireDest(WireDestConfig wireConfig) => SwitchHandler.AddWireDest(wireConfig); + internal void RemoveWireDest(string destId) => SwitchHandler.RemoveWireDest(destId); - private protected void OnSwitch(bool closed) => _switchHandler.OnSwitch(closed); + private protected void OnSwitch(bool closed) => SwitchHandler.OnSwitch(closed); #endregion } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs index cd9b2a786..5ff8f40ad 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Unity.Entities; using Unity.Mathematics; using UnityEngine; @@ -109,20 +110,28 @@ public void DestroyBall() #region Wiring - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; + void IApiSwitch.DestroyBall(Entity ballEntity) + { + if (ballEntity != Entity.Null) + { + BallManager.DestroyEntity(ballEntity); + SimulationSystemGroup.QueueAfterBallCreation(OnBallDestroyed); + } + } + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem); - private IApiCoil Coil(string deviceItem) => _coils.ContainsKey(deviceItem) ? _coils[deviceItem] : null; - - void IApiSwitch.DestroyBall(Entity ballEntity) + private IApiCoil Coil(string deviceItem) { - if (ballEntity != Entity.Null) { - BallManager.DestroyEntity(ballEntity); - SimulationSystemGroup.QueueAfterBallCreation(OnBallDestroyed); + if (_coils.ContainsKey(deviceItem)) { + return _coils[deviceItem]; } + + throw new ArgumentException($"Unknown coil \"{deviceItem}\". Valid names are [ {string.Join(", ", _coils.Select(item => $"\"{item.Key}\""))} ]."); } private void OnBallDestroyed() diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs index 2bc6f3448..f610492bb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs @@ -20,8 +20,7 @@ private enum Direction private readonly CannonComponent _cannonComponent; private Player _player; - private DeviceCoil GunMotorCoil; - + public DeviceCoil GunMotorCoil; public DeviceSwitch GunHomeSwitch; public DeviceSwitch GunMarkSwitch; @@ -37,23 +36,25 @@ internal CannonApi(GameObject go, Player player) _player = player; } - IApiCoil IApiCoilDevice.Coil(string deviceItem) + IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); + + private IApiCoil Coil(string deviceItem) { - return deviceItem == CannonComponent.GunMotorCoilItem ? GunMotorCoil : null; + return deviceItem switch + { + CannonComponent.GunMotorCoilItem => GunMotorCoil, + _ => throw new ArgumentException($"Unknown coil \"{deviceItem}\". Valid name is: \"{CannonComponent.GunMotorCoilItem}\".") + }; } IApiSwitch IApiSwitchDevice.Switch(string deviceItem) { - if (deviceItem == CannonComponent.GunHomeSwitchItem) + return deviceItem switch { - return GunHomeSwitch; - } - else if (deviceItem == CannonComponent.GunMarkSwitchItem) - { - return GunMarkSwitch; - } - - return null; + CannonComponent.GunHomeSwitchItem => GunHomeSwitch, + CannonComponent.GunMarkSwitchItem => GunMarkSwitch, + _ => throw new ArgumentException($"Unknown switch \"{deviceItem}\". Valid names are: [ \"{CannonComponent.GunHomeSwitchItem}\", \"{CannonComponent.GunMarkSwitchItem}\" ].") + }; } void IApi.OnInit(BallManager ballManager) @@ -79,14 +80,14 @@ private void OnGunMotorCoilEnabled() { _enabled = true; - Logger.Info("OnGunMotorCoilEnabled"); + Logger.Info("OnGunMotorCoilEnabled - starting rotation"); } private void OnGunMotorCoilDisabled() { _enabled = false; - Logger.Info("OnGunMotorCoilDisabled"); + Logger.Info("OnGunMotorCoilDisabled - stopping rotation"); } private void OnUpdate(object sender, EventArgs eventArgs) @@ -123,38 +124,38 @@ private void OnUpdate(object sender, EventArgs eventArgs) if (_position >= 0 && _position <= 5) { - if (!GunHomeSwitch.IsEnabled) + if (!GunHomeSwitch.IsSwitchEnabled) { GunHomeSwitch.SetSwitch(true); } } - else if (GunHomeSwitch.IsEnabled) + else if (GunHomeSwitch.IsSwitchEnabled) { GunHomeSwitch.SetSwitch(false); } if (_position >= 98 && _position <= 105) { - if (!GunMarkSwitch.IsEnabled) + if (!GunMarkSwitch.IsSwitchEnabled) { GunMarkSwitch.SetSwitch(true); } } - else if (GunMarkSwitch.IsEnabled) + else if (GunMarkSwitch.IsSwitchEnabled) { GunMarkSwitch.SetSwitch(false); } _cannonComponent.UpdateRotation(_position / Length); - Logger.Debug($"Cannon position={_position}"); + Logger.Debug($"{_cannonComponent.name} position={_position}"); } void IApi.OnDestroy() { _player.OnUpdate -= OnUpdate; - Logger.Info("Destroying cannon!"); + Logger.Info($"Destroying {_cannonComponent.name}"); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs index 1dba7989e..c8e0c6e94 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs @@ -47,7 +47,7 @@ private void Awake() return; } - player.RegisterMech(this); + player.RegisterCannonComponent(this); } public void UpdateRotation(float y) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs index 837c09b80..a06218240 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs @@ -140,25 +140,19 @@ public void Fire() EntityManager.SetComponentData(Entity, velocityData); } + IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); + IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem); private IApiCoil Coil(string deviceItem) { - switch (deviceItem) { - case PlungerComponent.FireCoilId: - return FireCoil; - - case PlungerComponent.PullCoilId: - return PullCoil; - - default: - return null; - } + return deviceItem switch + { + PlungerComponent.FireCoilId => FireCoil, + PlungerComponent.PullCoilId => PullCoil, + _ => throw new ArgumentException($"Unknown plunger coil \"{deviceItem}\". Valid names are: [ \"{PlungerComponent.FireCoilId}\", \"{PlungerComponent.PullCoilId}\" ].") + }; } - IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); - - IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem); - #region Collider Generation protected override void CreateColliders(List colliders, float margin) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs index baba2f3a4..f152640f7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs @@ -25,6 +25,7 @@ using VisualPinball.Engine.Math; using VisualPinball.Engine.Math.Mesh; using VisualPinball.Engine.VPT; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Unity { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs index 6b1483731..e161dee67 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs @@ -30,6 +30,7 @@ using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Primitive; using VisualPinball.Engine.VPT.Table; +using MathF = VisualPinball.Engine.Math.MathF; using Mesh = VisualPinball.Engine.VPT.Mesh; namespace VisualPinball.Unity diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs index 31c9a3e61..7c9b24b76 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs @@ -31,6 +31,7 @@ using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Ramp; using VisualPinball.Engine.VPT.Table; +using MathF = VisualPinball.Engine.Math.MathF; namespace VisualPinball.Unity { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs index 7957ec5a2..1948d2278 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs @@ -72,12 +72,14 @@ public SpinnerApi(GameObject go, Entity entity, Entity parentEntity, Player play #region IApiSwitch - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig.WithPulse(true)); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig.WithPulse(true)); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + #endregion #region Collider Generation diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs index 1c8e1a5da..f5b64795f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs @@ -42,7 +42,9 @@ public class TableApi : IApi private readonly Dictionary _triggersByName = new Dictionary(); private readonly Dictionary _troughsByName = new Dictionary(); private readonly Dictionary _primitivesByName = new Dictionary(); - private readonly Dictionary _mechsByName = new Dictionary(); + private readonly Dictionary _cannonsByName = new Dictionary(); + private readonly Dictionary _dropTargetBanksByName = new Dictionary(); + private readonly Dictionary _bumpersByComponent = new Dictionary(); private readonly Dictionary _flippersByComponent = new Dictionary(); @@ -60,7 +62,8 @@ public class TableApi : IApi private readonly Dictionary _triggersByComponent = new Dictionary(); private readonly Dictionary _troughsByComponent = new Dictionary(); private readonly Dictionary _primitivesByComponent = new Dictionary(); - private readonly Dictionary _mechsByComponent = new Dictionary(); + private readonly Dictionary _cannonsByComponent = new Dictionary(); + private readonly Dictionary _dropTargetBanksByComponent = new Dictionary(); #endregion @@ -192,13 +195,29 @@ public TableApi(Player player) public TroughApi Trough(MonoBehaviour component) => Get(component); /// - /// Returns a mech by name. + /// Returns a cannon by name. /// - /// Name of the mech - /// Primitive or `null` if no mech with that name exists. + /// Name of the cannon + /// Cannon or `null` if no cannon with that name exists. public CannonApi Cannon(string name) => Get(name); public CannonApi Cannon(MonoBehaviour component) => Get(component); + /// + /// Returns a drop target by name. + /// + /// Name of the drop target + /// Drop target or `null` if no drop target with that name exists. + public DropTargetApi DropTarget(string name) => Get(name); + public DropTargetApi DropTarget(MonoBehaviour component) => Get(component); + + /// + /// Returns a drop target bank by name. + /// + /// Name of the drop target bank + /// Drop target bank or `null` if no drop target with that name exists. + public DropTargetBankApi DropTargetBank(string name) => Get(name); + public DropTargetBankApi DropTargetBank(MonoBehaviour component) => Get(component); + #endregion #region Registration @@ -238,7 +257,8 @@ private Dictionary GetNameDictionary(Type t) where T : IApi if (t == typeof(TriggerApi)) return _triggersByName as Dictionary; if (t == typeof(TroughApi)) return _troughsByName as Dictionary; if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; - if (t == typeof(CannonApi)) return _mechsByName as Dictionary; + if (t == typeof(CannonApi)) return _cannonsByName as Dictionary; + if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByName as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } @@ -260,7 +280,8 @@ private Dictionary GetComponentDictionary(Type t) where T : if (t == typeof(TriggerApi)) return _triggersByComponent as Dictionary; if (t == typeof(TroughApi)) return _troughsByComponent as Dictionary; if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; - if (t == typeof(CannonApi)) return _mechsByComponent as Dictionary; + if (t == typeof(CannonApi)) return _cannonsByComponent as Dictionary; + if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByComponent as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs index d71cfba44..be77359e6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs @@ -52,13 +52,14 @@ internal TriggerApi(GameObject go, Entity entity, Entity parentEntity, Player pl #region Wiring - IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; - + public bool IsSwitchEnabled => SwitchHandler.IsEnabled; IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig) => AddSwitchDest(switchConfig); void IApiSwitch.AddWireDest(WireDestConfig wireConfig) => AddWireDest(wireConfig); void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId); void IApiSwitch.DestroyBall(Entity ballEntity) => DestroyBall(ballEntity); + IApiSwitch IApiSwitchDevice.Switch(string deviceItem) => this; + #endregion #region Collider Generation diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughApi.cs index 90d0042db..9910cccfc 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughApi.cs @@ -259,7 +259,7 @@ private void AddBall() break; case TroughType.ClassicSingleBall: - if (!EntrySwitch.IsEnabled) { + if (!EntrySwitch.IsSwitchEnabled) { EntrySwitch.SetSwitch(true); _countedStackBalls++; // entry and stack is the same here @@ -302,7 +302,7 @@ private void DrainBall() case TroughType.TwoCoilsOneSwitch: case TroughType.ClassicSingleBall: - if (EntrySwitch.IsEnabled) { // if the drain slot is already occupied, queue it. + if (EntrySwitch.IsSwitchEnabled) { // if the drain slot is already occupied, queue it. UncountedDrainBalls++; } else { // otherwise just close the entry switch @@ -336,7 +336,7 @@ private void OnEntryCoilEnabled() case TroughType.TwoCoilsNSwitches: case TroughType.TwoCoilsOneSwitch: // push the ball from the drain to the trough - if (EntrySwitch.IsEnabled) { + if (EntrySwitch.IsSwitchEnabled) { EntrySwitch.SetSwitch(false); RollOverEntryBall(0); DrainNextUncountedBall(); @@ -345,7 +345,7 @@ private void OnEntryCoilEnabled() case TroughType.ClassicSingleBall: // balls get ejected immediately - if (EntrySwitch.IsEnabled) { + if (EntrySwitch.IsSwitchEnabled) { EntrySwitch.SetSwitch(false); EjectBall(); DrainNextUncountedBall(); @@ -385,7 +385,7 @@ private void RollOverEntryBall(int t) case TroughType.ModernMech: case TroughType.TwoCoilsNSwitches: // if entry position is occupied by another ball that just went in, queue. - if (_stackSwitches[pos].IsEnabled) { + if (_stackSwitches[pos].IsSwitchEnabled) { UncountedStackBalls++; return; } @@ -441,7 +441,7 @@ public bool EjectBall() case TroughType.ModernOpto: case TroughType.ModernMech: case TroughType.TwoCoilsNSwitches: - if (!_stackSwitches[0].IsEnabled) { + if (!_stackSwitches[0].IsSwitchEnabled) { Logger.Warn("Ball not in eject position yet, ignoring."); return false; } @@ -452,7 +452,7 @@ public bool EjectBall() break; case TroughType.ClassicSingleBall: - if (!EntrySwitch.IsEnabled) { + if (!EntrySwitch.IsSwitchEnabled) { Logger.Warn("No ball, ignoring."); return false; } @@ -534,7 +534,7 @@ private void RollOverStackBalls() case TroughType.TwoCoilsOneSwitch: // there is only one switch in the trough, so if it's closed, open it. - if (StackSwitch().IsEnabled) { + if (StackSwitch().IsSwitchEnabled) { StackSwitch().ScheduleSwitch(false, MainComponent.RollTimeDisabled); } break; @@ -608,6 +608,9 @@ IApiSwitch IApiSwitchDevice.Switch(string deviceItem) return _switchLookup.ContainsKey(deviceItem) ? _switchLookup[deviceItem] : null; } + IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); + IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem); + /// /// Returns a coil by ID. Same principle as /// @@ -615,22 +618,14 @@ IApiSwitch IApiSwitchDevice.Switch(string deviceItem) /// private IApiCoil Coil(string deviceItem) { - switch (deviceItem) { - case TroughComponent.EntryCoilId: - return EntryCoil; - - case TroughComponent.EjectCoilId: - return ExitCoil; - - default: - return null; - } + return deviceItem switch + { + TroughComponent.EntryCoilId => EntryCoil, + TroughComponent.EjectCoilId => ExitCoil, + _ => throw new ArgumentException($"Unknown trough coil \"{deviceItem}\". Valid names are: [ \"{TroughComponent.EntryCoilId}\", \"{TroughComponent.EjectCoilId}\" ].") + }; } - IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem); - - IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem); - void IApi.OnDestroy() { Logger.Info("Destroying trough!");