diff --git a/Assets/_Project/Art/Sprites/RaceIcons/BloodAngels.jpg b/Assets/_Project/Art/Sprites/BloodAngels.jpg similarity index 100% rename from Assets/_Project/Art/Sprites/RaceIcons/BloodAngels.jpg rename to Assets/_Project/Art/Sprites/BloodAngels.jpg diff --git a/Assets/_Project/Art/Sprites/RaceIcons/BloodAngels.jpg.meta b/Assets/_Project/Art/Sprites/BloodAngels.jpg.meta similarity index 100% rename from Assets/_Project/Art/Sprites/RaceIcons/BloodAngels.jpg.meta rename to Assets/_Project/Art/Sprites/BloodAngels.jpg.meta diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png deleted file mode 100644 index f2a24b8..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1b119eb6ab2d6c01573bce480df9fdb6676449398f4afde46673c3c2c2710fcc -size 13324 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png.meta deleted file mode 100644 index 8523ae6..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/BlinkIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: df5903159b157404d8e92942029f08f7 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png deleted file mode 100644 index 6503be4..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5569ff4e8d0780e2d79dfb9575f34856d59cb99ac751dd4f8caf4c2219eb7976 -size 8730 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png.meta deleted file mode 100644 index eef1834..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/DoubleUpIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: e81c6ebff6b98ac44b884d3006611ae6 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png deleted file mode 100644 index 7ef1d14..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4779891d6890994436e47c586b11768d6a8eead32c4e740f4c99713598783fea -size 15796 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png.meta deleted file mode 100644 index eb15613..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/FlightIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: 39ac5850677a092479550234de13e868 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png deleted file mode 100644 index ffb3b3e..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6e2d28ff550b9a9e83fe317c6c692115d3f5ef27f20f9aa9220e7f5aeb91768f -size 15522 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png.meta deleted file mode 100644 index 42c8511..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/NoBountyIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: ea9802d37489c9442ba2ffd4a41c6cb2 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png deleted file mode 100644 index e57b4db..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f0919f710e6673a55f44b1dbd55a16e19105fa5fe7d643330a4baea97eff095 -size 19587 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png.meta deleted file mode 100644 index 57b7944..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/SplitIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: 43490fdb6e2477643a275956ce5f4596 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png b/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png deleted file mode 100644 index 92cd276..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:90a7787cfc6120d1e6816d59a523093250f0f21200d3ad29fc6c99974837a7ef -size 18309 diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png.meta b/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png.meta deleted file mode 100644 index 6198141..0000000 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons/ThiefIcon.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: 315be3feae908714a911f596b8533317 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons.meta deleted file mode 100644 index 16c1caf..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 319f59716d010174aa75cc757855ffd3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells.meta deleted file mode 100644 index 599da31..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b086eebc9f3f87543bf2c98de8c8e4af -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png deleted file mode 100644 index 6c62964..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c58fd337b19c098a34a4eb7730e87fad72ec3b4819665e00535676b008348146 -size 177456 diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png.meta deleted file mode 100644 index 25bac7d..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/FireballSpell.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: eff45e5e3dab24f438c054a095d34578 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png deleted file mode 100644 index 9f0cdef..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3d54e2ec41954205c8775d2c6f09e6a134e8a960a797394c6e01ce67daebc840 -size 357045 diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png.meta deleted file mode 100644 index 98e89b4..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Spells/SlowSpell.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: 5f5072d8c9f626c4690a7b231c7488f9 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower.meta deleted file mode 100644 index 3e3ff27..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 06352dd9c76072941bbe7ad909c5f2f9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png deleted file mode 100644 index d7e8a96..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5e1b3dd4114b2639901392675da17a1c33146aa112157663fa13cf1dbb718cf4 -size 7076 diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png.meta b/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png.meta deleted file mode 100644 index bbe72c7..0000000 --- a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/ArrowTowerUpgrade_1.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: a140f62a10b8dc04e84625f8008e0c24 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - 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: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/RaceIcons.meta b/Assets/_Project/Art/Sprites/RaceIcons.meta deleted file mode 100644 index 361ea99..0000000 --- a/Assets/_Project/Art/Sprites/RaceIcons.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 45b4fc03b527ce444a7c37579965d990 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers.meta b/Assets/_Project/Art/Sprites/Towers.meta similarity index 100% rename from Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers.meta rename to Assets/_Project/Art/Sprites/Towers.meta diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/arrow.png b/Assets/_Project/Art/Sprites/Towers/arrow.png similarity index 100% rename from Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/arrow.png rename to Assets/_Project/Art/Sprites/Towers/arrow.png diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/arrow.png.meta b/Assets/_Project/Art/Sprites/Towers/arrow.png.meta similarity index 100% rename from Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/ArrowTower/arrow.png.meta rename to Assets/_Project/Art/Sprites/Towers/arrow.png.meta diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/siege.png b/Assets/_Project/Art/Sprites/Towers/siege.png similarity index 100% rename from Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/siege.png rename to Assets/_Project/Art/Sprites/Towers/siege.png diff --git a/Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/siege.png.meta b/Assets/_Project/Art/Sprites/Towers/siege.png.meta similarity index 100% rename from Assets/_Project/Art/Sprites/PlayerDraftIcons/Towers/siege.png.meta rename to Assets/_Project/Art/Sprites/Towers/siege.png.meta diff --git a/Assets/_Project/Art/Sprites/RaceIcons/Ultramarines.jpg b/Assets/_Project/Art/Sprites/Ultramarines.jpg similarity index 100% rename from Assets/_Project/Art/Sprites/RaceIcons/Ultramarines.jpg rename to Assets/_Project/Art/Sprites/Ultramarines.jpg diff --git a/Assets/_Project/Art/Sprites/RaceIcons/Ultramarines.jpg.meta b/Assets/_Project/Art/Sprites/Ultramarines.jpg.meta similarity index 100% rename from Assets/_Project/Art/Sprites/RaceIcons/Ultramarines.jpg.meta rename to Assets/_Project/Art/Sprites/Ultramarines.jpg.meta diff --git a/Assets/_Project/Art/VFX/spells.meta b/Assets/_Project/Art/VFX/spells.meta deleted file mode 100644 index b5edea7..0000000 --- a/Assets/_Project/Art/VFX/spells.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 204a6f4885c16648c8bd80385fcbe93f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/Fireball.prefab b/Assets/_Project/Art/VFX/spells/Fireball.prefab deleted file mode 100644 index b7e0984..0000000 --- a/Assets/_Project/Art/VFX/spells/Fireball.prefab +++ /dev/null @@ -1,133 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &158073311046191680 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7644069561715729860} - - component: {fileID: 4501491015215836543} - - component: {fileID: 4205765680785243152} - - component: {fileID: 8766422769305713616} - m_Layer: 0 - m_Name: Fireball - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &7644069561715729860 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 158073311046191680} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -53.04094, y: 0, z: -31.13852} - m_LocalScale: {x: 5, y: 5, z: 5} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &4501491015215836543 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 158073311046191680} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &4205765680785243152 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 158073311046191680} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 94a6d1000bea4e36492489f6ab3d6349, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_MaskInteraction: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!114 &8766422769305713616 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 158073311046191680} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 883bd1d14f70a623ea1b252cf7015a92, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.FallFromSkyVisual - dropHeight: 20 - duration: 1.2 - fallCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - fallAngleDegrees: 25.6 - fallDirection: {x: 0.2, y: 0.2, z: 1} diff --git a/Assets/_Project/Art/VFX/spells/Fireball.prefab.meta b/Assets/_Project/Art/VFX/spells/Fireball.prefab.meta deleted file mode 100644 index 5557f85..0000000 --- a/Assets/_Project/Art/VFX/spells/Fireball.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 80eaad6d0b024835482b64625b63053c -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/FireballMaterial.mat b/Assets/_Project/Art/VFX/spells/FireballMaterial.mat deleted file mode 100644 index bfa1880..0000000 --- a/Assets/_Project/Art/VFX/spells/FireballMaterial.mat +++ /dev/null @@ -1,137 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &-5733238300184794208 -MonoBehaviour: - m_ObjectHideFlags: 11 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion - version: 10 ---- !u!21 &2100000 -Material: - serializedVersion: 8 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: FireballMaterial - m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} - m_Parent: {fileID: 0} - m_ModifiedSerializedProperties: 0 - m_ValidKeywords: [] - m_InvalidKeywords: [] - m_LightmapFlags: 4 - m_EnableInstancingVariants: 0 - m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 - stringTagMap: - RenderType: Opaque - disabledShaderPasses: - - MOTIONVECTORS - m_LockedProperties: - m_SavedProperties: - serializedVersion: 3 - m_TexEnvs: - - _BaseMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _BumpMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailAlbedoMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailMask: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailNormalMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _EmissionMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _MainTex: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _MetallicGlossMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _OcclusionMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _ParallaxMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _SpecGlossMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - unity_Lightmaps: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - unity_LightmapsInd: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - unity_ShadowMasks: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - m_Ints: [] - m_Floats: - - _AddPrecomputedVelocity: 0 - - _AlphaClip: 0 - - _AlphaToMask: 0 - - _Blend: 0 - - _BlendModePreserveSpecular: 1 - - _BumpScale: 1 - - _ClearCoatMask: 0 - - _ClearCoatSmoothness: 0 - - _Cull: 2 - - _Cutoff: 0.5 - - _DetailAlbedoMapScale: 1 - - _DetailNormalMapScale: 1 - - _DstBlend: 0 - - _DstBlendAlpha: 0 - - _EnvironmentReflections: 1 - - _GlossMapScale: 0 - - _Glossiness: 0 - - _GlossyReflections: 0 - - _Metallic: 0 - - _OcclusionStrength: 1 - - _Parallax: 0.005 - - _QueueOffset: 0 - - _ReceiveShadows: 1 - - _Smoothness: 0.5 - - _SmoothnessTextureChannel: 0 - - _SpecularHighlights: 1 - - _SrcBlend: 1 - - _SrcBlendAlpha: 1 - - _Surface: 0 - - _WorkflowMode: 1 - - _XRMotionVectorsPass: 1 - - _ZWrite: 1 - m_Colors: - - _BaseColor: {r: 0.6196744, g: 0, b: 0, a: 1} - - _Color: {r: 0.6196744, g: 0, b: 0, a: 1} - - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} - m_BuildTextureStacks: [] - m_AllowLocking: 1 diff --git a/Assets/_Project/Art/VFX/spells/FireballMaterial.mat.meta b/Assets/_Project/Art/VFX/spells/FireballMaterial.mat.meta deleted file mode 100644 index 4161053..0000000 --- a/Assets/_Project/Art/VFX/spells/FireballMaterial.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 94a6d1000bea4e36492489f6ab3d6349 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx b/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx deleted file mode 100644 index 8e02032..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx +++ /dev/null @@ -1,2692 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &114340500867371532 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d01270efd3285ea4a9d6c555cb0a8027, type: 3} - m_Name: VFXUI - m_EditorClassIdentifier: - groupInfos: - - title: Burst - position: - serializedVersion: 2 - x: 264 - y: 295 - width: 1055 - height: 2398 - contents: - - model: {fileID: 8926484042661614700} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614707} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614756} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614976} - id: 0 - isStickyNote: 0 - stickyNoteInfos: [] - categories: [] - uiBounds: - serializedVersion: 2 - x: 264 - y: 295 - width: 1055 - height: 2398 ---- !u!114 &114350483966674976 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7d4c867f6b72b714dbb5fd1780afe208, type: 3} - m_Name: VFX_fireball_impact - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614700} - - {fileID: 8926484042661614707} - - {fileID: 8926484042661614756} - - {fileID: 8926484042661614976} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_UIInfos: {fileID: 114340500867371532} - m_CustomAttributes: [] - m_ParameterInfo: [] - m_ImportDependencies: [] - m_GraphVersion: 19 - m_ResourceVersion: 1 - m_SubgraphDependencies: [] - m_CategoryPath: ---- !u!2058629511 &8926484042661614527 -VisualEffectResource: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: VFX_fireball_impact - m_Graph: {fileID: 114350483966674976} - m_Infos: - m_RendererSettings: - motionVectorGenerationMode: 0 - shadowCastingMode: 0 - m_CullingFlags: 3 - m_UpdateMode: 0 - m_PreWarmDeltaTime: 0.05 - m_PreWarmStepCount: 0 - m_InitialEventName: OnPlay - m_InstancingMode: 0 - m_InstancingCapacity: 64 ---- !u!114 &8926484042661614700 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 73a13919d81fb7444849bae8b5c812a2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614703} - m_UIPosition: {x: 289, y: 354} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614879} - - {fileID: 8926484042661614975} - m_OutputSlots: [] - m_Label: Spawn system - m_Data: {fileID: 8926484042661614702} - m_InputFlowSlot: - - link: [] - - link: [] - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614707} - slotIndex: 0 - loopDuration: 1 - loopCount: 1 - delayBeforeLoop: 0 - delayAfterLoop: 0 ---- !u!114 &8926484042661614702 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f68759077adc0b143b6e1c101e82065e, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - title: - m_Owners: - - {fileID: 8926484042661614700} ---- !u!114 &8926484042661614703 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5e382412bb691334bb79457a6c127924, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614700} - m_Children: [] - m_UIPosition: {x: 0, y: 2} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614704} - - {fileID: 8926484042661614705} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614706} - repeat: 0 - spawnMode: 0 - delayMode: 0 ---- !u!114 &8926484042661614704 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614704} - m_MasterData: - m_Owner: {fileID: 8926484042661614703} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 128 - m_Space: -1 - m_Property: - name: Count - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614705 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614705} - m_MasterData: - m_Owner: {fileID: 8926484042661614703} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0 - m_Space: -1 - m_Property: - name: Delay - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614706 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614706} - m_MasterData: - m_Owner: {fileID: 8926484042661614703} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614707 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9dfea48843f53fc438eabc12a3a30abc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614722} - - {fileID: 8926484042661614956} - - {fileID: 8926484042661614912} - m_UIPosition: {x: 289, y: 800} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614880} - - {fileID: 8926484042661614889} - m_OutputSlots: [] - m_Label: Initialize Particles - m_Data: {fileID: 8926484042661614721} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614700} - slotIndex: 0 - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614756} - slotIndex: 0 ---- !u!114 &8926484042661614721 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d78581a96eae8bf4398c282eb0b098bd, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - title: Simple Burst - m_Owners: - - {fileID: 8926484042661614707} - - {fileID: 8926484042661614756} - - {fileID: 8926484042661614976} - dataType: 0 - capacity: 128 - stripCapacity: 1 - particlePerStripCount: 32 - needsComputeBounds: 0 - boundsMode: 0 - m_Space: 1 ---- !u!114 &8926484042661614722 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614707} - m_Children: [] - m_UIPosition: {x: 292.6464, y: 1481.9946} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614723} - - {fileID: 8926484042661614724} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614725} - attribute: lifetime - Composition: 0 - Source: 0 - Random: 2 - channels: 6 ---- !u!114 &8926484042661614723 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614723} - m_MasterData: - m_Owner: {fileID: 8926484042661614722} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.5 - m_Space: -1 - m_Property: - name: A - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614724 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614724} - m_MasterData: - m_Owner: {fileID: 8926484042661614722} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 1 - m_Space: -1 - m_Property: - name: B - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614725 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614725} - m_MasterData: - m_Owner: {fileID: 8926484042661614722} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614756 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2dc095764ededfa4bb32fa602511ea4b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614922} - - {fileID: 8926484042661614929} - m_UIPosition: {x: 289, y: 1535} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: [] - m_OutputSlots: [] - m_Label: Update Particles - m_Data: {fileID: 8926484042661614721} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614707} - slotIndex: 0 - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614976} - slotIndex: 0 - integration: 0 - angularIntegration: 0 - ageParticles: 1 - reapParticles: 1 - skipZeroDeltaUpdate: 0 ---- !u!114 &8926484042661614879 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614879} - m_MasterData: - m_Owner: {fileID: 8926484042661614700} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 2 - m_Space: -1 - m_Property: - name: LoopDuration - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614881} - - {fileID: 8926484042661614885} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 8926484042661614707} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"center":{"x":0.0,"y":-2.0,"z":0.0},"size":{"x":7.0,"y":8.0,"z":7.0}}' - m_Space: 0 - m_Property: - name: bounds - m_serializedType: - m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614881 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614880} - m_Children: - - {fileID: 8926484042661614882} - - {fileID: 8926484042661614883} - - {fileID: 8926484042661614884} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: center - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614882 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614881} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614883 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614881} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614884 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614881} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614885 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614880} - m_Children: - - {fileID: 8926484042661614886} - - {fileID: 8926484042661614887} - - {fileID: 8926484042661614888} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: size - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614886 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614885} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614887 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614885} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614888 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614885} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614880} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614889 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614890} - - {fileID: 8926484042661614891} - - {fileID: 8926484042661614892} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614889} - m_MasterData: - m_Owner: {fileID: 8926484042661614707} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"x":0.5,"y":0.5,"z":0.5}' - m_Space: -1 - m_Property: - name: boundsPadding - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614890 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614889} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614889} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614891 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614889} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614889} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614892 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614889} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614889} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614912 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26096dfac7c062b4b94c293605ba085e, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614707} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614913} - - {fileID: 8926484042661614918} - - {fileID: 8926484042661614919} - - {fileID: 8926484042661614920} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614921} - composition: 0 - speedMode: 1 ---- !u!114 &8926484042661614913 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e8f2b4a846fd4c14a893cde576ad172b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614914} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614913} - m_MasterData: - m_Owner: {fileID: 8926484042661614912} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"direction":{"x":0.0,"y":1.0,"z":0.0}}' - m_Space: 0 - m_Property: - name: Direction - m_serializedType: - m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614914 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614913} - m_Children: - - {fileID: 8926484042661614915} - - {fileID: 8926484042661614916} - - {fileID: 8926484042661614917} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614913} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: direction - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614915 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614914} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614913} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614916 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614914} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614913} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614917 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614914} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614913} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614918 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614918} - m_MasterData: - m_Owner: {fileID: 8926484042661614912} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.5 - m_Space: -1 - m_Property: - name: MinSpeed - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614919 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614919} - m_MasterData: - m_Owner: {fileID: 8926484042661614912} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 4.5 - m_Space: -1 - m_Property: - name: MaxSpeed - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614920 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614920} - m_MasterData: - m_Owner: {fileID: 8926484042661614912} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0 - m_Space: -1 - m_Property: - name: DirectionBlend - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614921 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614921} - m_MasterData: - m_Owner: {fileID: 8926484042661614912} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614922 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e5dce54ae3368c042b26ab1f305e15b2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614756} - m_Children: [] - m_UIPosition: {x: 0, y: 2} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614923} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614928} ---- !u!114 &8926484042661614923 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a9f9544b71b7dab44a4644b6807e8bf6, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614924} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614923} - m_MasterData: - m_Owner: {fileID: 8926484042661614922} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"vector":{"x":0.0,"y":-9.8100004196167,"z":0.0}}' - m_Space: 1 - m_Property: - name: Force - m_serializedType: - m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614924 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614923} - m_Children: - - {fileID: 8926484042661614925} - - {fileID: 8926484042661614926} - - {fileID: 8926484042661614927} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614923} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: vector - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614925 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614924} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614923} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614926 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614924} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614923} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614927 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614924} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614923} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614928 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614928} - m_MasterData: - m_Owner: {fileID: 8926484042661614922} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614929 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b294673e879f9cf449cc9de536818ea9, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614756} - m_Children: [] - m_UIPosition: {x: 0, y: 77} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614930} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614931} - UseParticleSize: 0 ---- !u!114 &8926484042661614930 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614930} - m_MasterData: - m_Owner: {fileID: 8926484042661614929} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.5 - m_Space: -1 - m_Property: - name: dragCoefficient - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614931 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614931} - m_MasterData: - m_Owner: {fileID: 8926484042661614929} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614956 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fb1f6794ace8b0c4592af9c5604cddbf, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614707} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614957} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614974} - compositionPosition: 0 - compositionAxes: 0 - compositionDirection: 0 - positionMode: 0 - spawnMode: 0 - shape: 0 - heightMode: 1 - applyOrientation: 1 - killOutliers: 0 - projectionSteps: 2 ---- !u!114 &8926484042661614957 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614958} - - {fileID: 8926484042661614973} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 8926484042661614956} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"sphere":{"transform":{"position":{"x":0.0,"y":0.0,"z":0.0},"angles":{"x":0.0,"y":0.0,"z":0.0},"scale":{"x":1.0,"y":1.0,"z":1.0}},"radius":0.15000000596046449},"arc":6.28000020980835}' - m_Space: 0 - m_Property: - name: arcSphere - m_serializedType: - m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614958 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614957} - m_Children: - - {fileID: 8926484042661614959} - - {fileID: 8926484042661614972} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: sphere - m_serializedType: - m_SerializableType: UnityEditor.VFX.TSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614959 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3e3f628d80ffceb489beac74258f9cf7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614958} - m_Children: - - {fileID: 8926484042661614960} - - {fileID: 8926484042661614964} - - {fileID: 8926484042661614968} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: transform - m_serializedType: - m_SerializableType: UnityEditor.VFX.Transform, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614960 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614959} - m_Children: - - {fileID: 8926484042661614961} - - {fileID: 8926484042661614962} - - {fileID: 8926484042661614963} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: position - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614961 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614960} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614962 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614960} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614963 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614960} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614964 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614959} - m_Children: - - {fileID: 8926484042661614965} - - {fileID: 8926484042661614966} - - {fileID: 8926484042661614967} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: angles - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614965 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614964} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614966 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614964} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614967 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614964} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614968 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614959} - m_Children: - - {fileID: 8926484042661614969} - - {fileID: 8926484042661614970} - - {fileID: 8926484042661614971} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: scale - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614969 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614968} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614970 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614968} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614971 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614968} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614972 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614958} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: radius - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614973 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614957} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614957} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: arc - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614974 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614974} - m_MasterData: - m_Owner: {fileID: 8926484042661614956} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614975 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4d246e354feb93041a837a9ef59437cb, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotInt - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614975} - m_MasterData: - m_Owner: {fileID: 8926484042661614700} - m_Value: - m_Type: - m_SerializableType: System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 1 - m_Space: -1 - m_Property: - name: LoopCount - m_serializedType: - m_SerializableType: System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614976 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9956086b52aebe1449639a9ac65802c2, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXComposedParticleOutput - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: [] - m_UIPosition: {x: 870, y: 1820} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614977} - - {fileID: 8926484042661614978} - - {fileID: 8926484042661614979} - - {fileID: 8926484042661614980} - m_OutputSlots: [] - m_Label: - m_Data: {fileID: 8926484042661614721} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614756} - slotIndex: 0 - m_OutputFlowSlot: - - link: [] - blendMode: 1 - cullMode: 0 - zWriteMode: 0 - zTestMode: 0 - useAlphaClipping: 0 - generateMotionVector: 0 - excludeFromTUAndAA: 0 - sortingPriority: 0 - m_SubOutputs: - - {fileID: 8926484042661614986} - useBaseColorMap: 3 - colorMapping: 0 - uvMode: 0 - flipbookLayout: 0 - flipbookBlendFrames: 0 - flipbookMotionVectors: 0 - useSoftParticle: 0 - vfxSystemSortPriority: 0 - sort: 0 - sortMode: 0 - revertSorting: 0 - indirectDraw: 0 - computeCulling: 0 - frustumCulling: 0 - castShadows: 0 - useExposureWeight: 0 - enableRayTracing: 0 - decimationFactor: 1 - raytracedScaleMode: 0 - needsOwnSort: 1 - needsOwnAabbBuffer: 0 - m_Topology: - rid: 6358680547474538635 - m_Shading: - rid: 6358680547474538636 - references: - version: 2 - RefIds: - - rid: 6358680547474538635 - type: {class: ParticleTopologyMesh, ns: UnityEditor.VFX, asm: Unity.VisualEffectGraph.Editor} - data: - MeshCount: 1 - lod: 0 - - rid: 6358680547474538636 - type: {class: ParticleShadingShaderGraph, ns: UnityEditor.VFX, asm: Unity.VisualEffectGraph.Editor} - data: - shaderGraph: {fileID: 4333940904281232215, guid: 16dbac556be7c00448dd113d83bf05e1, type: 3} - materialSettings: - m_PropertyNames: [] - m_PropertyValues: [] - renderQueue: -1 ---- !u!114 &8926484042661614977 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b47b8679b468b7347a00cdd50589bc9f, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotMesh - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614977} - m_MasterData: - m_Owner: {fileID: 8926484042661614976} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Mesh, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"obj":{"fileID":10207,"guid":"0000000000000000e000000000000000","type":0}}' - m_Space: -1 - m_Property: - name: mesh - m_serializedType: - m_SerializableType: UnityEngine.Mesh, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614978 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c52d920e7fff73b498050a6b3c4404ca, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotUint - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614978} - m_MasterData: - m_Owner: {fileID: 8926484042661614976} - m_Value: - m_Type: - m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 4294967295 - m_Space: -1 - m_Property: - name: subMeshMask - m_serializedType: - m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614979 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotTexture2D - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614979} - m_MasterData: - m_Owner: {fileID: 8926484042661614976} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"8aafaa78fe944854997fef757ff4ba72","type":3}}' - m_Space: -1 - m_Property: - name: _BaseMap - m_serializedType: - m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614980 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c82227d5759e296488798b1554a72a15, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotColor - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614981} - - {fileID: 8926484042661614982} - - {fileID: 8926484042661614983} - - {fileID: 8926484042661614984} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614980} - m_MasterData: - m_Owner: {fileID: 8926484042661614976} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Color, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"r":0.3019754886627197,"g":0.0,"b":0.01985604129731655,"a":1.0}' - m_Space: -1 - m_Property: - name: _Color - m_serializedType: - m_SerializableType: UnityEngine.Color, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614981 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614980} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614980} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: r - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614982 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614980} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614980} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: g - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614983 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614980} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614980} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: b - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614984 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614980} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614980} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: a - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614986 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 388ad3b1dc9c6ae45b630f914fab638f, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.VFX.URP.VFXURPSubOutput - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 diff --git a/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx.meta b/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx.meta deleted file mode 100644 index 73f1d83..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_fireball_impact.vfx.meta +++ /dev/null @@ -1,15 +0,0 @@ -fileFormatVersion: 2 -guid: 3fa4641e771cdd27880ed1185a588a83 -VisualEffectImporter: - externalObjects: {} - serializedVersion: 2 - template: - name: - category: - description: - icon: {instanceID: 0} - thumbnail: {instanceID: 0} - useAsTemplate: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab deleted file mode 100644 index b5d5e68..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab +++ /dev/null @@ -1,120 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &1462673130280185047 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 30710218362299472} - - component: {fileID: 2262385832724230530} - - component: {fileID: 5239089805406934537} - m_Layer: 0 - m_Name: VFX_slowarea - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &30710218362299472 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1462673130280185047} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -55.61683, y: -0, z: -33.87226} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!2083052967 &2262385832724230530 -VisualEffect: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1462673130280185047} - m_Enabled: 1 - m_Asset: {fileID: 8926484042661614526, guid: 397a5bed36b1e63a0a3eef17b04f65bd, type: 3} - m_InitialEventName: OnPlay - m_InitialEventNameOverriden: 0 - m_StartSeed: 0 - m_ResetSeedOnPlay: 1 - m_AllowInstancing: 1 - m_ResourceVersion: 1 - m_PropertySheet: - m_Float: - m_Array: [] - m_Vector2f: - m_Array: [] - m_Vector3f: - m_Array: [] - m_Vector4f: - m_Array: [] - m_Uint: - m_Array: [] - m_Int: - m_Array: [] - m_Matrix4x4f: - m_Array: [] - m_AnimationCurve: - m_Array: [] - m_Gradient: - m_Array: [] - m_NamedObject: - m_Array: [] - m_Bool: - m_Array: [] ---- !u!73398921 &5239089805406934537 -VFXRenderer: - serializedVersion: 1 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1462673130280185047} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 0 - m_LightProbeUsage: 0 - m_ReflectionProbeUsage: 0 - m_RayTracingMode: 0 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_MaskInteraction: 0 diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta deleted file mode 100644 index ecc94a0..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bf2f1f2a9a54e9162b80673e3f7eeaf6 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx deleted file mode 100644 index a94dcde..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx +++ /dev/null @@ -1,2601 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &114340500867371532 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d01270efd3285ea4a9d6c555cb0a8027, type: 3} - m_Name: VFXUI - m_EditorClassIdentifier: - groupInfos: - - title: Base Loop - position: - serializedVersion: 2 - x: 851 - y: -1433 - width: 475 - height: 2277 - contents: - - model: {fileID: 8926484042661614608} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614613} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614662} - id: 0 - isStickyNote: 0 - - model: {fileID: 8926484042661614681} - id: 0 - isStickyNote: 0 - stickyNoteInfos: [] - categories: [] - uiBounds: - serializedVersion: 2 - x: 852 - y: -1433 - width: 474 - height: 2255 ---- !u!114 &114350483966674976 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7d4c867f6b72b714dbb5fd1780afe208, type: 3} - m_Name: VFX_slowarea - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614608} - - {fileID: 8926484042661614613} - - {fileID: 8926484042661614662} - - {fileID: 8926484042661614681} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_UIInfos: {fileID: 114340500867371532} - m_CustomAttributes: [] - m_ParameterInfo: [] - m_ImportDependencies: [] - m_GraphVersion: 19 - m_ResourceVersion: 1 - m_SubgraphDependencies: [] - m_CategoryPath: ---- !u!2058629511 &8926484042661614527 -VisualEffectResource: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: VFX_slowarea - m_Graph: {fileID: 114350483966674976} - m_Infos: - m_RendererSettings: - motionVectorGenerationMode: 0 - shadowCastingMode: 0 - m_CullingFlags: 3 - m_UpdateMode: 0 - m_PreWarmDeltaTime: 0.05 - m_PreWarmStepCount: 0 - m_InitialEventName: OnPlay - m_InstancingMode: 0 - m_InstancingCapacity: 64 ---- !u!114 &8926484042661614608 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 73a13919d81fb7444849bae8b5c812a2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614610} - m_UIPosition: {x: 877, y: -1374} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: [] - m_OutputSlots: [] - m_Label: Spawn system - m_Data: {fileID: 8926484042661614609} - m_InputFlowSlot: - - link: [] - - link: [] - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614613} - slotIndex: 0 - loopDuration: 0 - loopCount: 0 - delayBeforeLoop: 0 - delayAfterLoop: 0 ---- !u!114 &8926484042661614609 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f68759077adc0b143b6e1c101e82065e, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - title: - m_Owners: - - {fileID: 8926484042661614608} ---- !u!114 &8926484042661614610 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f05c6884b705ce14d82ae720f0ec209f, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614608} - m_Children: [] - m_UIPosition: {x: 357.33423, y: 1216.2454} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614611} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614612} ---- !u!114 &8926484042661614611 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614611} - m_MasterData: - m_Owner: {fileID: 8926484042661614610} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 64 - m_Space: -1 - m_Property: - name: Rate - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614612 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614612} - m_MasterData: - m_Owner: {fileID: 8926484042661614610} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614613 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9dfea48843f53fc438eabc12a3a30abc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614628} - - {fileID: 8926484042661614834} - - {fileID: 8926484042661614806} - m_UIPosition: {x: 877, y: -1086} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614774} - - {fileID: 8926484042661614783} - m_OutputSlots: [] - m_Label: Initialize Particles - m_Data: {fileID: 8926484042661614627} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614608} - slotIndex: 0 - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614662} - slotIndex: 0 ---- !u!114 &8926484042661614627 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d78581a96eae8bf4398c282eb0b098bd, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - title: Simple Loop - m_Owners: - - {fileID: 8926484042661614613} - - {fileID: 8926484042661614662} - - {fileID: 8926484042661614681} - dataType: 0 - capacity: 68 - stripCapacity: 1 - particlePerStripCount: 32 - needsComputeBounds: 0 - boundsMode: 0 - m_Space: 1 ---- !u!114 &8926484042661614628 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614613} - m_Children: [] - m_UIPosition: {x: 357.33423, y: 1214.2454} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614629} - - {fileID: 8926484042661614630} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614631} - attribute: lifetime - Composition: 0 - Source: 0 - Random: 2 - channels: 6 ---- !u!114 &8926484042661614629 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614629} - m_MasterData: - m_Owner: {fileID: 8926484042661614628} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.8 - m_Space: -1 - m_Property: - name: A - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614630 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614630} - m_MasterData: - m_Owner: {fileID: 8926484042661614628} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 1.2 - m_Space: -1 - m_Property: - name: B - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614631 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614631} - m_MasterData: - m_Owner: {fileID: 8926484042661614628} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614662 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2dc095764ededfa4bb32fa602511ea4b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614820} - - {fileID: 8926484042661614827} - m_UIPosition: {x: 877, y: -187} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: [] - m_OutputSlots: [] - m_Label: Update Particles - m_Data: {fileID: 8926484042661614627} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614613} - slotIndex: 0 - m_OutputFlowSlot: - - link: - - context: {fileID: 8926484042661614681} - slotIndex: 0 - integration: 0 - angularIntegration: 0 - ageParticles: 1 - reapParticles: 1 - skipZeroDeltaUpdate: 0 ---- !u!114 &8926484042661614681 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a0b9e6b9139e58d4c957ec54595da7d3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 114350483966674976} - m_Children: - - {fileID: 8926484042661614685} - - {fileID: 8926484042661614830} - - {fileID: 8926484042661614722} - m_UIPosition: {x: 877, y: 214} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614682} - m_OutputSlots: [] - m_Label: Render Quad - m_Data: {fileID: 8926484042661614627} - m_InputFlowSlot: - - link: - - context: {fileID: 8926484042661614662} - slotIndex: 0 - m_OutputFlowSlot: - - link: [] - blendMode: 1 - cullMode: 0 - zWriteMode: 0 - zTestMode: 0 - useAlphaClipping: 0 - generateMotionVector: 0 - excludeFromTUAndAA: 0 - sortingPriority: 0 - m_SubOutputs: - - {fileID: 8926484042661614687} - - {fileID: 8926484042661614833} - useBaseColorMap: 3 - colorMapping: 0 - uvMode: 0 - flipbookLayout: 0 - flipbookBlendFrames: 0 - flipbookMotionVectors: 0 - useSoftParticle: 0 - vfxSystemSortPriority: 0 - sort: 0 - sortMode: 0 - revertSorting: 0 - indirectDraw: 0 - computeCulling: 0 - frustumCulling: 0 - castShadows: 0 - useExposureWeight: 0 - enableRayTracing: 0 - decimationFactor: 1 - raytracedScaleMode: 0 - needsOwnSort: 1 - needsOwnAabbBuffer: 0 - shaderGraph: {fileID: 0} - materialSettings: - m_PropertyNames: [] - m_PropertyValues: [] - renderQueue: -1 - primitiveType: 1 - useGeometryShader: 0 ---- !u!114 &8926484042661614682 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614682} - m_MasterData: - m_Owner: {fileID: 8926484042661614681} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"8aafaa78fe944854997fef757ff4ba72","type":3}}' - m_Space: -1 - m_Property: - name: mainTexture - m_serializedType: - m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614685 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d16c6aeaef944094b9a1633041804207, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614681} - m_Children: [] - m_UIPosition: {x: 0, y: 2} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: [] - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614686} - mode: 0 - axes: 4 - faceRay: 1 ---- !u!114 &8926484042661614686 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614686} - m_MasterData: - m_Owner: {fileID: 8926484042661614685} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614687 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 081ffb0090424ba4cb05370a42ead6b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!114 &8926484042661614722 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 01ec2c1930009b04ea08905b47262415, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614681} - m_Children: [] - m_UIPosition: {x: 508.1385, y: 271.34802} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614723} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614724} - attribute: color - Composition: 2 - AlphaComposition: 0 - SampleMode: 0 - Mode: 1 - ColorMode: 3 - channels: 6 ---- !u!114 &8926484042661614723 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 76f778ff57c4e8145b9681fe3268d8e9, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614723} - m_MasterData: - m_Owner: {fileID: 8926484042661614722} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Gradient, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"colorKeys":[{"color":{"r":0.003921564668416977,"g":0.7162883877754211,"b":0.9725490212440491,"a":1.0},"time":0.0},{"color":{"r":0.2158605307340622,"g":0.6866854429244995,"b":1.0,"a":1.0},"time":1.0}],"alphaKeys":[{"alpha":1.0,"time":0.0},{"alpha":1.0,"time":0.800000011920929},{"alpha":0.0,"time":1.0}],"gradientMode":0}' - m_Space: -1 - m_Property: - name: Color - m_serializedType: - m_SerializableType: UnityEngine.Gradient, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614724 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614724} - m_MasterData: - m_Owner: {fileID: 8926484042661614722} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614774 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614775} - - {fileID: 8926484042661614779} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 8926484042661614613} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"center":{"x":0.0,"y":1.0,"z":0.0},"size":{"x":3.5,"y":4.0,"z":3.5}}' - m_Space: 0 - m_Property: - name: bounds - m_serializedType: - m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614775 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614774} - m_Children: - - {fileID: 8926484042661614776} - - {fileID: 8926484042661614777} - - {fileID: 8926484042661614778} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: center - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614776 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614775} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614777 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614775} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614778 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614775} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614779 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614774} - m_Children: - - {fileID: 8926484042661614780} - - {fileID: 8926484042661614781} - - {fileID: 8926484042661614782} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: size - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614779} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614781 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614779} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614782 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614779} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614774} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614783 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614784} - - {fileID: 8926484042661614785} - - {fileID: 8926484042661614786} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614783} - m_MasterData: - m_Owner: {fileID: 8926484042661614613} - m_Value: - m_Type: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"x":0.5,"y":0.5,"z":0.5}' - m_Space: -1 - m_Property: - name: boundsPadding - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614784 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614783} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614783} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614785 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614783} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614783} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614786 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614783} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614783} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614806 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26096dfac7c062b4b94c293605ba085e, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614613} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614807} - - {fileID: 8926484042661614818} - - {fileID: 8926484042661614819} - - {fileID: 8926484042661614813} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614814} - composition: 0 - speedMode: 1 ---- !u!114 &8926484042661614807 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e8f2b4a846fd4c14a893cde576ad172b, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614808} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614807} - m_MasterData: - m_Owner: {fileID: 8926484042661614806} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"direction":{"x":0.0,"y":1.0,"z":0.0}}' - m_Space: 0 - m_Property: - name: Direction - m_serializedType: - m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614808 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614807} - m_Children: - - {fileID: 8926484042661614809} - - {fileID: 8926484042661614810} - - {fileID: 8926484042661614811} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614807} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: direction - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614809 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614808} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614807} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614810 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614808} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614807} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614811 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614808} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614807} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614813 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614813} - m_MasterData: - m_Owner: {fileID: 8926484042661614806} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.85 - m_Space: -1 - m_Property: - name: DirectionBlend - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614814 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614814} - m_MasterData: - m_Owner: {fileID: 8926484042661614806} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614818 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614818} - m_MasterData: - m_Owner: {fileID: 8926484042661614806} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 4.8 - m_Space: -1 - m_Property: - name: MinSpeed - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614819 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614819} - m_MasterData: - m_Owner: {fileID: 8926484042661614806} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 7.5 - m_Space: -1 - m_Property: - name: MaxSpeed - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614820 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e5dce54ae3368c042b26ab1f305e15b2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614662} - m_Children: [] - m_UIPosition: {x: 0, y: 2} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614821} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614826} ---- !u!114 &8926484042661614821 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a9f9544b71b7dab44a4644b6807e8bf6, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614822} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614821} - m_MasterData: - m_Owner: {fileID: 8926484042661614820} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"vector":{"x":0.0,"y":-9.8100004196167,"z":0.0}}' - m_Space: 1 - m_Property: - name: Force - m_serializedType: - m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614822 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614821} - m_Children: - - {fileID: 8926484042661614823} - - {fileID: 8926484042661614824} - - {fileID: 8926484042661614825} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614821} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: vector - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614823 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614822} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614821} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614824 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614822} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614821} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614825 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614822} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614821} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614826 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614826} - m_MasterData: - m_Owner: {fileID: 8926484042661614820} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: False - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614827 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b294673e879f9cf449cc9de536818ea9, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614662} - m_Children: [] - m_UIPosition: {x: 0, y: 77} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614828} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614829} - UseParticleSize: 0 ---- !u!114 &8926484042661614828 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614828} - m_MasterData: - m_Owner: {fileID: 8926484042661614827} - m_Value: - m_Type: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: 0.5 - m_Space: -1 - m_Property: - name: dragCoefficient - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614829 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614829} - m_MasterData: - m_Owner: {fileID: 8926484042661614827} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614830 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 01ec2c1930009b04ea08905b47262415, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614681} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614831} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614832} - attribute: size - Composition: 2 - AlphaComposition: 0 - SampleMode: 0 - Mode: 1 - ColorMode: 3 - channels: 6 ---- !u!114 &8926484042661614831 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c117b74c5c58db542bffe25c78fe92db, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614831} - m_MasterData: - m_Owner: {fileID: 8926484042661614830} - m_Value: - m_Type: - m_SerializableType: UnityEngine.AnimationCurve, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"frames":[{"time":0.0,"value":0.75,"inTangent":0.0,"outTangent":1.25,"tangentMode":0,"leftTangentMode":2,"rightTangentMode":2,"broken":true},{"time":1.0,"value":2.0,"inTangent":1.25,"outTangent":2.0,"tangentMode":0,"leftTangentMode":2,"rightTangentMode":2,"broken":true}],"preWrapMode":8,"postWrapMode":8,"version":1}' - m_Space: -1 - m_Property: - name: Size - m_serializedType: - m_SerializableType: UnityEngine.AnimationCurve, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614832 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614832} - m_MasterData: - m_Owner: {fileID: 8926484042661614830} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614833 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 388ad3b1dc9c6ae45b630f914fab638f, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 ---- !u!114 &8926484042661614834 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fb1f6794ace8b0c4592af9c5604cddbf, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614613} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 0 - m_UISuperCollapsed: 0 - m_InputSlots: - - {fileID: 8926484042661614871} - m_OutputSlots: [] - m_Disabled: 0 - m_ActivationSlot: {fileID: 8926484042661614852} - compositionPosition: 0 - compositionAxes: 0 - compositionDirection: 0 - positionMode: 1 - spawnMode: 0 - shape: 0 - heightMode: 1 - applyOrientation: 1 - killOutliers: 0 - projectionSteps: 2 ---- !u!114 &8926484042661614852 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614852} - m_MasterData: - m_Owner: {fileID: 8926484042661614834} - m_Value: - m_Type: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_SerializableObject: True - m_Space: -1 - m_Property: - name: _vfx_enabled - m_serializedType: - m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614871 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlot - m_UIIgnoredErrors: [] - m_Parent: {fileID: 0} - m_Children: - - {fileID: 8926484042661614872} - - {fileID: 8926484042661614887} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 8926484042661614834} - m_Value: - m_Type: - m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_SerializableObject: '{"sphere":{"transform":{"position":{"x":0.0,"y":0.0,"z":0.0},"angles":{"x":0.0,"y":0.0,"z":0.0},"scale":{"x":1.0,"y":1.0,"z":1.0}},"radius":1.0},"arc":6.2831854820251469}' - m_Space: 0 - m_Property: - name: arcSphere - m_serializedType: - m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614872 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlot - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614871} - m_Children: - - {fileID: 8926484042661614873} - - {fileID: 8926484042661614886} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: sphere - m_serializedType: - m_SerializableType: UnityEditor.VFX.TSphere, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614873 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3e3f628d80ffceb489beac74258f9cf7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotTransform - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614872} - m_Children: - - {fileID: 8926484042661614874} - - {fileID: 8926484042661614878} - - {fileID: 8926484042661614882} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: transform - m_serializedType: - m_SerializableType: UnityEditor.VFX.Transform, Unity.VisualEffectGraph.Editor, - Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614874 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614873} - m_Children: - - {fileID: 8926484042661614875} - - {fileID: 8926484042661614876} - - {fileID: 8926484042661614877} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: position - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614875 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614874} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614876 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614874} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614877 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614874} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614878 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614873} - m_Children: - - {fileID: 8926484042661614879} - - {fileID: 8926484042661614880} - - {fileID: 8926484042661614881} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: angles - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614879 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614878} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614878} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614881 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614878} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614882 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614873} - m_Children: - - {fileID: 8926484042661614883} - - {fileID: 8926484042661614884} - - {fileID: 8926484042661614885} - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: scale - m_serializedType: - m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614883 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614882} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: x - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614884 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614882} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: y - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614885 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614882} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: z - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614886 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614872} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: radius - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] ---- !u!114 &8926484042661614887 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat - m_UIIgnoredErrors: [] - m_Parent: {fileID: 8926484042661614871} - m_Children: [] - m_UIPosition: {x: 0, y: 0} - m_UICollapsed: 1 - m_UISuperCollapsed: 0 - m_MasterSlot: {fileID: 8926484042661614871} - m_MasterData: - m_Owner: {fileID: 0} - m_Value: - m_Type: - m_SerializableType: - m_SerializableObject: - m_Space: -1 - m_Property: - name: arc - m_serializedType: - m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - m_Direction: 0 - m_LinkedSlots: [] diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta deleted file mode 100644 index b32e89c..0000000 --- a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta +++ /dev/null @@ -1,15 +0,0 @@ -fileFormatVersion: 2 -guid: 397a5bed36b1e63a0a3eef17b04f65bd -VisualEffectImporter: - externalObjects: {} - serializedVersion: 2 - template: - name: - category: - description: - icon: {instanceID: 0} - thumbnail: {instanceID: 0} - useAsTemplate: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Audio/sound_effects.meta b/Assets/_Project/Audio/Sound Effects.meta similarity index 100% rename from Assets/_Project/Audio/sound_effects.meta rename to Assets/_Project/Audio/Sound Effects.meta diff --git a/Assets/_Project/Audio/sound_effects/SellSoundEffect.ogg b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg similarity index 100% rename from Assets/_Project/Audio/sound_effects/SellSoundEffect.ogg rename to Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg diff --git a/Assets/_Project/Audio/sound_effects/SellSoundEffect.ogg.meta b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta similarity index 100% rename from Assets/_Project/Audio/sound_effects/SellSoundEffect.ogg.meta rename to Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta diff --git a/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg b/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg deleted file mode 100644 index 77a3f9b..0000000 --- a/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2263f258fb816411ff3c118c796cf622bf8327c597c2037f628d5b7dee32ab2a -size 54249 diff --git a/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg.meta b/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg.meta deleted file mode 100644 index e3b4013..0000000 --- a/Assets/_Project/Audio/sound_effects/FireballExplosion.ogg.meta +++ /dev/null @@ -1,23 +0,0 @@ -fileFormatVersion: 2 -guid: e54448243d0478045b6566412c54e4a7 -AudioImporter: - externalObjects: {} - serializedVersion: 8 - defaultSettings: - serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 - compressionFormat: 1 - quality: 1 - conversionMode: 0 - preloadAudioData: 0 - platformSettingOverrides: {} - forceToMono: 0 - normalize: 1 - loadInBackground: 0 - ambisonic: 0 - 3D: 1 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Audio/sound_effects/TimeSlow.ogg b/Assets/_Project/Audio/sound_effects/TimeSlow.ogg deleted file mode 100644 index 6540f44..0000000 --- a/Assets/_Project/Audio/sound_effects/TimeSlow.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4d6c70f74ae50b15bcbcf1b53cdf63f521f671b119aa6c32ea9a41c9e07e563 -size 30845 diff --git a/Assets/_Project/Audio/sound_effects/TimeSlow.ogg.meta b/Assets/_Project/Audio/sound_effects/TimeSlow.ogg.meta deleted file mode 100644 index fe80db5..0000000 --- a/Assets/_Project/Audio/sound_effects/TimeSlow.ogg.meta +++ /dev/null @@ -1,23 +0,0 @@ -fileFormatVersion: 2 -guid: 038ff3eab9aa0034bac26ccb648ef2a1 -AudioImporter: - externalObjects: {} - serializedVersion: 8 - defaultSettings: - serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 - compressionFormat: 1 - quality: 1 - conversionMode: 0 - preloadAudioData: 0 - platformSettingOverrides: {} - forceToMono: 0 - normalize: 1 - loadInBackground: 0 - ambisonic: 0 - 3D: 1 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/EnemyDraftIcons.meta b/Assets/_Project/Definitions/Buffs.meta similarity index 77% rename from Assets/_Project/Art/Sprites/EnemyDraftIcons.meta rename to Assets/_Project/Definitions/Buffs.meta index 4257bdb..98de849 100644 --- a/Assets/_Project/Art/Sprites/EnemyDraftIcons.meta +++ b/Assets/_Project/Definitions/Buffs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 42ccb4a3b6aaaab47b73147c8be319bb +guid: eef6329e4294d86c6978ff9453b56956 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset b/Assets/_Project/Definitions/Buffs/ExtraDamage25.asset similarity index 51% rename from Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset rename to Assets/_Project/Definitions/Buffs/ExtraDamage25.asset index 509a039..c707eae 100644 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset +++ b/Assets/_Project/Definitions/Buffs/ExtraDamage25.asset @@ -9,9 +9,9 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: de25a6333a11d074280b5ade557aa8b9, type: 3} - m_Name: EnemyScalingConfig - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyScalingConfig - BaseHpBudget: 5000 - GrowthPerEncounter: 1.18 - BossHpMultiplier: 1.2 + m_Script: {fileID: 11500000, guid: b01f9aea62ee8a1c1991bb2a097de224, type: 3} + m_Name: ExtraDamage25 + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuffDefinition + DisplayName: 25% Increased Damage + Stat: 0 + Multiplier: 1.25 diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset.meta b/Assets/_Project/Definitions/Buffs/ExtraDamage25.asset.meta similarity index 79% rename from Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset.meta rename to Assets/_Project/Definitions/Buffs/ExtraDamage25.asset.meta index 6570ea6..b240b6c 100644 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset.meta +++ b/Assets/_Project/Definitions/Buffs/ExtraDamage25.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: eef28ca7b8844504e9d75ff903a3bb61 +guid: 9ec170e540b1f91cca762dcebe81a856 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset b/Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset new file mode 100644 index 0000000..737c5ab --- /dev/null +++ b/Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 516e8faec948a4b3d977ec019376c438, type: 3} + m_Name: OffensiveBuffs + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuffCategory + DisplayName: Offensive Buffs + Cost: 5 + Pool: + - {fileID: 11400000, guid: 9ec170e540b1f91cca762dcebe81a856, type: 2} diff --git a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset.meta b/Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset.meta similarity index 79% rename from Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset.meta rename to Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset.meta index 61581ca..ced41c2 100644 --- a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset.meta +++ b/Assets/_Project/Definitions/Buffs/OffensiveBuffs.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 051c48f416e5366b59d49b0e062333ac +guid: d8ed3b9535538f7fc82be878cc307d26 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/_Project/Definitions/BuilderSpells.meta b/Assets/_Project/Definitions/BuilderSpells.meta deleted file mode 100644 index 15f3140..0000000 --- a/Assets/_Project/Definitions/BuilderSpells.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f6f56fe562e9b8c229442088bb6ce11c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset deleted file mode 100644 index e713412..0000000 --- a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset +++ /dev/null @@ -1,32 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 22b36bfcd0ae4af4098d908138e874e1, type: 3} - m_Name: FireballSpell - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.FireballSpellDefinition - DisplayName: Fireball - Description: Shoot a fireball - Icon: {fileID: 21300000, guid: eff45e5e3dab24f438c054a095d34578, type: 3} - Cooldown: 15 - TargetType: 0 - Radius: 5 - enemyLayerMask: - serializedVersion: 2 - m_Bits: 1024 - impactVfxPrefab: {fileID: 158073311046191680, guid: 80eaad6d0b024835482b64625b63053c, type: 3} - impactVfxLifetime: 3 - impactDelay: 0.9 - impactSound: - clip: {fileID: 8300000, guid: e54448243d0478045b6566412c54e4a7, type: 3} - volume: 0.603 - minPitch: 1.048 - maxPitch: 0.969 - Damage: 500 diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset deleted file mode 100644 index cb2746a..0000000 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset +++ /dev/null @@ -1,31 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 249c65067c3bac80693255e594d844c7, type: 3} - m_Name: SlowAreaSpell - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.SlowAreaSpellDefinition - DisplayName: Slow Area - Description: Slows enemies in an area - Icon: {fileID: 21300000, guid: 5f5072d8c9f626c4690a7b231c7488f9, type: 3} - Cooldown: 10 - TargetType: 1 - Radius: 5 - enemyLayerMask: - serializedVersion: 2 - m_Bits: 1152 - areaVfxPrefab: {fileID: 1462673130280185047, guid: bf2f1f2a9a54e9162b80673e3f7eeaf6, type: 3} - areaSound: - clip: {fileID: 8300000, guid: 038ff3eab9aa0034bac26ccb648ef2a1, type: 3} - volume: 0.632 - minPitch: 1.04 - maxPitch: 0.96 - SlowFactor: 0.5 - EffectDuration: 8 diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset.meta b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset.meta deleted file mode 100644 index 1518d59..0000000 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d893f46b037536b4ba91307e184cecfe -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset b/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset deleted file mode 100644 index 90d9579..0000000 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset +++ /dev/null @@ -1,31 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 37cc60a4a6e53e24cb6d1c0be310868a, type: 3} - m_Name: SlowAreaUpgradedSpell - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.SlowAreaUpgradedSpellDefinition - DisplayName: Slow Area II - Description: Upgraded Slow Area. Slows for 50% longer. - Icon: {fileID: 21300000, guid: 5f5072d8c9f626c4690a7b231c7488f9, type: 3} - Cooldown: 10 - TargetType: 1 - Radius: 5 - enemyLayerMask: - serializedVersion: 2 - m_Bits: 1152 - areaVfxPrefab: {fileID: 1462673130280185047, guid: bf2f1f2a9a54e9162b80673e3f7eeaf6, type: 3} - areaSound: - clip: {fileID: 8300000, guid: 038ff3eab9aa0034bac26ccb648ef2a1, type: 3} - volume: 0.632 - minPitch: 1.04 - maxPitch: 0.96 - SlowFactor: 0.5 - EffectDuration: 12 diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset.meta b/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset.meta deleted file mode 100644 index 16266b6..0000000 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaUpgradedSpell.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 364edf6abc3c31e33b53d0a01142b8ab -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft.meta b/Assets/_Project/Definitions/Draft.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft.meta rename to Assets/_Project/Definitions/Draft.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderEffect_GoldPerKill.asset b/Assets/_Project/Definitions/Draft/Draft_BuilderEffect_GoldPerKill.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderEffect_GoldPerKill.asset rename to Assets/_Project/Definitions/Draft/Draft_BuilderEffect_GoldPerKill.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderEffect_GoldPerKill.asset.meta b/Assets/_Project/Definitions/Draft/Draft_BuilderEffect_GoldPerKill.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderEffect_GoldPerKill.asset.meta rename to Assets/_Project/Definitions/Draft/Draft_BuilderEffect_GoldPerKill.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_SiegeCannon.asset b/Assets/_Project/Definitions/Draft/Draft_NewTower_SiegeCannon.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_SiegeCannon.asset rename to Assets/_Project/Definitions/Draft/Draft_NewTower_SiegeCannon.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_SiegeCannon.asset.meta b/Assets/_Project/Definitions/Draft/Draft_NewTower_SiegeCannon.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_SiegeCannon.asset.meta rename to Assets/_Project/Definitions/Draft/Draft_NewTower_SiegeCannon.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_TeslaCoil.asset b/Assets/_Project/Definitions/Draft/Draft_NewTower_TeslaCoil.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_TeslaCoil.asset rename to Assets/_Project/Definitions/Draft/Draft_NewTower_TeslaCoil.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_TeslaCoil.asset.meta b/Assets/_Project/Definitions/Draft/Draft_NewTower_TeslaCoil.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_TeslaCoil.asset.meta rename to Assets/_Project/Definitions/Draft/Draft_NewTower_TeslaCoil.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_Wall.asset b/Assets/_Project/Definitions/Draft/Draft_NewTower_Wall.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_Wall.asset rename to Assets/_Project/Definitions/Draft/Draft_NewTower_Wall.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_Wall.asset.meta b/Assets/_Project/Definitions/Draft/Draft_NewTower_Wall.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_NewTower_Wall.asset.meta rename to Assets/_Project/Definitions/Draft/Draft_NewTower_Wall.asset.meta diff --git a/Assets/_Project/Definitions/Enemies/01_Enemy_CrystalGolemBlue_Definition.asset b/Assets/_Project/Definitions/Enemies/01_Enemy_CrystalGolemBlue_Definition.asset index 39b2af6..5a7e5c4 100644 --- a/Assets/_Project/Definitions/Enemies/01_Enemy_CrystalGolemBlue_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/01_Enemy_CrystalGolemBlue_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 01_Enemy_CrystalGolemBlue_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Crystal Elemental (Young) - HpMultiplier: 1.15 - MoveSpeed: 2.6 + MaxHp: 100 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: 5839dc36140d67d4db94c4370a98ea2c, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/02_Enemy_CyclopsGrey_Definition.asset b/Assets/_Project/Definitions/Enemies/02_Enemy_CyclopsGrey_Definition.asset index 2bad6f2..b616fca 100644 --- a/Assets/_Project/Definitions/Enemies/02_Enemy_CyclopsGrey_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/02_Enemy_CyclopsGrey_Definition.asset @@ -13,7 +13,7 @@ MonoBehaviour: m_Name: 02_Enemy_CyclopsGrey_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Cyclops (Young) - HpMultiplier: 1.05 + MaxHp: 200 MoveSpeed: 3 IsFlying: 0 LivesCost: 1 diff --git a/Assets/_Project/Definitions/Enemies/03_Enemy_EntGreen_Definition.asset b/Assets/_Project/Definitions/Enemies/03_Enemy_EntGreen_Definition.asset index 6ca1cb8..48c0a11 100644 --- a/Assets/_Project/Definitions/Enemies/03_Enemy_EntGreen_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/03_Enemy_EntGreen_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 03_Enemy_EntGreen_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Ent (Juvenile) - HpMultiplier: 0.85 - MoveSpeed: 3.4 + MaxHp: 400 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: dc462b86bdb8136488da56eb84d88ab5, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/04_Enemy_CrystalGolemYellow_Definition.asset b/Assets/_Project/Definitions/Enemies/04_Enemy_CrystalGolemYellow_Definition.asset index ed14151..5129b58 100644 --- a/Assets/_Project/Definitions/Enemies/04_Enemy_CrystalGolemYellow_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/04_Enemy_CrystalGolemYellow_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 04_Enemy_CrystalGolemYellow_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Crystal Elemental (Adolescent) - HpMultiplier: 1.25 - MoveSpeed: 2.4 + MaxHp: 500 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: d4ca85138dd41244c9b0ab29c945f064, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/05_Enemy_CyclopsGreen_Definition.asset b/Assets/_Project/Definitions/Enemies/05_Enemy_CyclopsGreen_Definition.asset index 29dbef6..d516ea5 100644 --- a/Assets/_Project/Definitions/Enemies/05_Enemy_CyclopsGreen_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/05_Enemy_CyclopsGreen_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 05_Enemy_CyclopsGreen_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Cyclops (Adult) - HpMultiplier: 1.1 - MoveSpeed: 2.9 + MaxHp: 600 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: 525e51e0dfac75744b39e4609b9245f9, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/06_Enemy_EntBlack_Definition.asset b/Assets/_Project/Definitions/Enemies/06_Enemy_EntBlack_Definition.asset index cd153bb..dc74753 100644 --- a/Assets/_Project/Definitions/Enemies/06_Enemy_EntBlack_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/06_Enemy_EntBlack_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 06_Enemy_EntBlack_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Ent (Mature) - HpMultiplier: 0.9 - MoveSpeed: 3.3 + MaxHp: 700 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: c3cae952216a68b458b9a934d89b8be8, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/07_Enemy_CrystalGolemRed_Definition.asset b/Assets/_Project/Definitions/Enemies/07_Enemy_CrystalGolemRed_Definition.asset index c0b1005..9b8a5b3 100644 --- a/Assets/_Project/Definitions/Enemies/07_Enemy_CrystalGolemRed_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/07_Enemy_CrystalGolemRed_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 07_Enemy_CrystalGolemRed_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Crystal Elemental (Mature) - HpMultiplier: 1.35 - MoveSpeed: 2.2 + MaxHp: 800 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: 2f13fef371bd3464694526ff99edef03, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/08_Enemy_CyclopsRed_Definition.asset b/Assets/_Project/Definitions/Enemies/08_Enemy_CyclopsRed_Definition.asset index a71ed1a..7ca2962 100644 --- a/Assets/_Project/Definitions/Enemies/08_Enemy_CyclopsRed_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/08_Enemy_CyclopsRed_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 08_Enemy_CyclopsRed_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Cyclops (Enraged) - HpMultiplier: 1.2 - MoveSpeed: 2.8 + MaxHp: 900 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: 729e11f4ecd916d4fbeaf26dbbae8b7d, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/09_Enemy_EntOrange_Definition.asset b/Assets/_Project/Definitions/Enemies/09_Enemy_EntOrange_Definition.asset index e2d0b3b..e9d57fa 100644 --- a/Assets/_Project/Definitions/Enemies/09_Enemy_EntOrange_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/09_Enemy_EntOrange_Definition.asset @@ -13,8 +13,8 @@ MonoBehaviour: m_Name: 09_Enemy_EntOrange_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition DisplayName: Ent (Ancient) - HpMultiplier: 0.95 - MoveSpeed: 3.2 + MaxHp: 1000 + MoveSpeed: 3 IsFlying: 0 LivesCost: 1 EnemyPrefab: {fileID: 1455822126534880203, guid: d6eed12cf96ab194ab8d35359e3bc8ee, type: 3} diff --git a/Assets/_Project/Definitions/Enemies/10_Enemy_UndeadDrakeBone_Definition.asset b/Assets/_Project/Definitions/Enemies/10_Enemy_UndeadDrakeBone_Definition.asset index af46c2c..31d1eec 100644 --- a/Assets/_Project/Definitions/Enemies/10_Enemy_UndeadDrakeBone_Definition.asset +++ b/Assets/_Project/Definitions/Enemies/10_Enemy_UndeadDrakeBone_Definition.asset @@ -12,9 +12,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c0d2521d49d21fe4380434f5951944d1, type: 3} m_Name: 10_Enemy_UndeadDrakeBone_Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition - DisplayName: Drake - HpMultiplier: 0.7 - MoveSpeed: 4.5 + DisplayName: Ent (Ancient) + MaxHp: 800 + MoveSpeed: 4 IsFlying: 1 FlightHeight: 3 LivesCost: 1 diff --git a/Assets/_Project/Definitions/RunDefinitions/GoldConfig.asset b/Assets/_Project/Definitions/GoldConfig.asset similarity index 82% rename from Assets/_Project/Definitions/RunDefinitions/GoldConfig.asset rename to Assets/_Project/Definitions/GoldConfig.asset index abf9261..58f29f6 100644 --- a/Assets/_Project/Definitions/RunDefinitions/GoldConfig.asset +++ b/Assets/_Project/Definitions/GoldConfig.asset @@ -17,40 +17,44 @@ MonoBehaviour: - Wave: {fileID: 11400000, guid: 65f66289ea1233b4897f46cd997d9c7a, type: 2} GoldPerEnemy: 5 CompletionBonus: 25 - NoLeaksBonus: 10 + NoLeaksBonus: 50 - Wave: {fileID: 11400000, guid: 190e39db44aa0794aa808fd60976f7c4, type: 2} GoldPerEnemy: 7 CompletionBonus: 30 - NoLeaksBonus: 10 + NoLeaksBonus: 50 - Wave: {fileID: 11400000, guid: 39921b44a1a0a56478200028940c5202, type: 2} GoldPerEnemy: 10 CompletionBonus: 35 - NoLeaksBonus: 10 + NoLeaksBonus: 50 - Wave: {fileID: 11400000, guid: 50f498bc5bfc46e44b064cc96403e2cb, type: 2} GoldPerEnemy: 15 CompletionBonus: 40 - NoLeaksBonus: 10 + NoLeaksBonus: 50 - Wave: {fileID: 11400000, guid: 9ee6dee12f0660844b4d46880f01c02f, type: 2} GoldPerEnemy: 15 CompletionBonus: 45 - NoLeaksBonus: 10 + NoLeaksBonus: 50 - Wave: {fileID: 11400000, guid: 41231de63e8f25d448f19f3816e0c22f, type: 2} GoldPerEnemy: 20 CompletionBonus: 50 - NoLeaksBonus: 10 + NoLeaksBonus: 100 - Wave: {fileID: 11400000, guid: 6290df178cbd3144aa92a0f09833a7be, type: 2} GoldPerEnemy: 20 CompletionBonus: 55 - NoLeaksBonus: 20 + NoLeaksBonus: 100 - Wave: {fileID: 11400000, guid: 86736fd52c18fa84e8ced40f30b514fa, type: 2} GoldPerEnemy: 25 CompletionBonus: 60 - NoLeaksBonus: 20 + NoLeaksBonus: 100 - Wave: {fileID: 11400000, guid: 8fdf53cfc405a5f41a00f376198b8d84, type: 2} GoldPerEnemy: 25 CompletionBonus: 65 - NoLeaksBonus: 20 + NoLeaksBonus: 100 - Wave: {fileID: 11400000, guid: 4db677d2940202340841471f90a5b73a, type: 2} GoldPerEnemy: 25 CompletionBonus: 70 - NoLeaksBonus: 20 + NoLeaksBonus: 100 + - Wave: {fileID: 11400000, guid: fc1a55fab4ce81047b4925f53a3a8b8d, type: 2} + GoldPerEnemy: 50 + CompletionBonus: 75 + NoLeaksBonus: 500 diff --git a/Assets/_Project/Definitions/RunDefinitions/GoldConfig.asset.meta b/Assets/_Project/Definitions/GoldConfig.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/GoldConfig.asset.meta rename to Assets/_Project/Definitions/GoldConfig.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions.meta b/Assets/_Project/Definitions/RunDefinitions.meta deleted file mode 100644 index d07862f..0000000 --- a/Assets/_Project/Definitions/RunDefinitions.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d1d72155425add944a007932c121c951 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft.meta deleted file mode 100644 index 359e56c..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 465572754aa5c7e48b1c00843f1b5d7c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset deleted file mode 100644 index 98bd078..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Blink.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d075c66b381872a4781b3916296ccdc9, type: 3} - m_Name: EnemyUpgrade_Blink - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.AbilityEnemyUpgradeOption - DisplayName: Blink - Description: Enemies occasionally teleport a short distance ahead. - Icon: {fileID: 21300000, guid: df5903159b157404d8e92942029f08f7, type: 3} - Ability: {fileID: 11400000, guid: 030f10c9a264e544ea3e0f4fdb4171bd, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset deleted file mode 100644 index daa0979..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset +++ /dev/null @@ -1,19 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f5e90fe6b8e439e4f99769a6923c2262, type: 3} - m_Name: EnemyUpgrade_DoubleUp - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.DoubleUpEnemyUpgradeOption - DisplayName: Double Dip - Description: Enemies from this wave gain no upgrades, but enemies from the next - wave have two upgrades selected automatically - Icon: {fileID: 21300000, guid: e81c6ebff6b98ac44b884d3006611ae6, type: 3} - BuffsToAutoApply: 2 diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset.meta deleted file mode 100644 index db74d57..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_DoubleUp.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 46e2a6a59c0a3034f9fa44681d9ba422 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset deleted file mode 100644 index 5379694..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d075c66b381872a4781b3916296ccdc9, type: 3} - m_Name: EnemyUpgrade_Flight - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.AbilityEnemyUpgradeOption - DisplayName: Flight - Description: Enemies gain the power of flight - Icon: {fileID: 21300000, guid: 39ac5850677a092479550234de13e868, type: 3} - Ability: {fileID: 11400000, guid: cb2ec6bb70f57d0429b99b7cd4c7db73, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset.meta deleted file mode 100644 index c49dfc4..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Flight.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 80fb851b702ff304183cb6e89c4aa245 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset deleted file mode 100644 index 58af079..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d075c66b381872a4781b3916296ccdc9, type: 3} - m_Name: EnemyUpgrade_NoBounty - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.AbilityEnemyUpgradeOption - DisplayName: Peniless - Description: Enemies no longer drop gold upon death - Icon: {fileID: 21300000, guid: ea9802d37489c9442ba2ffd4a41c6cb2, type: 3} - Ability: {fileID: 11400000, guid: c64c7121b0456bb4a873acec9e0abf91, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset.meta deleted file mode 100644 index bea9c35..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_NoBounty.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a67aa3644d2ad4847a47040f53fea26f -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset deleted file mode 100644 index 2351102..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset +++ /dev/null @@ -1,19 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d075c66b381872a4781b3916296ccdc9, type: 3} - m_Name: EnemyUpgrade_Split - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.AbilityEnemyUpgradeOption - DisplayName: Split on Death - Description: Enemies killed will spawn two more smaller, faster, weaker versions - of themselves. (This only triggers a single time per base enemy) - Icon: {fileID: 21300000, guid: 43490fdb6e2477643a275956ce5f4596, type: 3} - Ability: {fileID: 11400000, guid: 0305468bc8f912d429a8b20bf23f947c, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset.meta deleted file mode 100644 index ca2e9c2..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Split.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f6bfb033a15b6d0419587b80a8286bd1 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset deleted file mode 100644 index e0f0515..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d075c66b381872a4781b3916296ccdc9, type: 3} - m_Name: EnemyUpgrade_Theft - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.AbilityEnemyUpgradeOption - DisplayName: Thief - Description: Enemies that leak steal 15 gold on their way out - Icon: {fileID: 21300000, guid: 315be3feae908714a911f596b8533317, type: 3} - Ability: {fileID: 11400000, guid: a18691a20d75f17479a83b3e171759e7, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset.meta deleted file mode 100644 index f4847ca..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/EnemyDraft/EnemyUpgrade_Theft.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 37d761966a349ba4cb4141f913224d5c -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft.meta deleted file mode 100644 index 18e2f50..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4a6f4d6ffa10ef44da3ac0dd7c7734db -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset deleted file mode 100644 index 5ec8c55..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset +++ /dev/null @@ -1,19 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a574e8aa74d8787f2b949300932af485, type: 3} - m_Name: Draft_BuilderSpellOption_Fireball - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Draft.BuilderSpellDraftOption - DisplayName: Fireball - Description: Shoot a FIREBALL out of your COCK - Icon: {fileID: 0} - Weight: 1 - Kind: 0 diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset.meta deleted file mode 100644 index f9e25b5..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_Fireball.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5f390de69ba43b2a6a0d89cf09580320 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset deleted file mode 100644 index 5dd615e..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset +++ /dev/null @@ -1,19 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a574e8aa74d8787f2b949300932af485, type: 3} - m_Name: Draft_BuilderSpellOption_SlowArea - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Draft.BuilderSpellDraftOption - DisplayName: Slow Area - Description: Slows enemies in the target area - Icon: {fileID: 0} - Weight: 1 - Kind: 1 diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset.meta deleted file mode 100644 index 40f9145..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowArea.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 29b35841f7e5db454903798cb5d83434 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset deleted file mode 100644 index 743c46d..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset +++ /dev/null @@ -1,20 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7b1c5b562f39c72eea3bafd0165af078, type: 3} - m_Name: Draft_BuilderSpellOption_SlowAreaUpgrade - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Draft.BuilderSpellUpgradeDraftOption - DisplayName: Slow Area II - Description: Slows enemies in the area for 50% longer than the default slow area. - Icon: {fileID: 0} - Weight: 1 - BaseKind: 1 - UpgradedKind: 2 diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset.meta deleted file mode 100644 index 13ca9fd..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_BuilderSpellOption_SlowAreaUpgrade.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d180030b68a9a5e1da497bf6f83451d4 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset deleted file mode 100644 index 016e045..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset +++ /dev/null @@ -1,21 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: aeec22f152a57ef5798eae035c091543, type: 3} - m_Name: Draft_TowerUpgrade_Arrow_1 - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Draft.TowerUpgradeDraftOption - DisplayName: Arrow Tower Upgrade 1 - Description: Unlock the ability to upgrade Arrow Towers with more damage and a - faster attack speed - Icon: {fileID: 21300000, guid: a140f62a10b8dc04e84625f8008e0c24, type: 3} - Weight: 1 - BaseTower: {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2} - UpgradedTower: {fileID: 11400000, guid: 86d4c3ab00d4c654eb4c255280ee5701, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset.meta b/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset.meta deleted file mode 100644 index 1009def..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/Draft/PlayerDraft/Draft_TowerUpgrade_Arrow_1.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0b9f4905752751f44b9959b84b620266 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities.meta deleted file mode 100644 index d927cf3..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 37cbc8b63ce7ae2e4b4abcfd7274bee7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset deleted file mode 100644 index ec1b7b5..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4fbb09f55384ac44399ac4655b2b53ec, type: 3} - m_Name: BlinkAbility - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.BlinkAbilityDefinition - DisplayName: Blink - Description: Enemies occasionally teleport a short distance ahead. - IntervalSeconds: 8 - BlinkDistanceMeters: 4 diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset.meta deleted file mode 100644 index 78c2c0b..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/BlinkAbility.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 030f10c9a264e544ea3e0f4fdb4171bd -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset deleted file mode 100644 index 725338e..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: be77d353621f07e40bbdab2e9cc37f51, type: 3} - m_Name: FlightAbility - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.FlightAbilityDefinition - DisplayName: Flight - Description: Enemies gain flying - FlightHeight: 3 - SpeedMultiplier: 1 diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset.meta deleted file mode 100644 index 0b5d052..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/FlightAbility.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cb2ec6bb70f57d0429b99b7cd4c7db73 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset deleted file mode 100644 index fc16c66..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3b770ce042b78f44d9a3df537fe25db0, type: 3} - m_Name: GoldTheftAbility - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.GoldTheftAbilityDefinition - DisplayName: Thief - Description: Enemies that leak out of a player's maze steal 15 gold as they go. - GoldStolen: 15 diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset.meta deleted file mode 100644 index 11247d1..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/GoldTheftAbility.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a18691a20d75f17479a83b3e171759e7 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset deleted file mode 100644 index 0231479..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fd5b12948b24e9c4c8840ef3470b437e, type: 3} - m_Name: NoBountyAbility - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.NoBountyAbilityDefinition - DisplayName: Penniless - Description: Enemies no longer drop gold on death - BountyMultiplier: 0 diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset.meta deleted file mode 100644 index 8aede82..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/NoBountyAbility.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c64c7121b0456bb4a873acec9e0abf91 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset deleted file mode 100644 index 6ca1f9e..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset +++ /dev/null @@ -1,20 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 21543cb1b54f0b16e9c80584f68988b3, type: 3} - m_Name: SplitOnDeathAbility - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.SplitOnDeathAbilityDefinition - DisplayName: Split on Death - Description: The enemy splits when it dies. - Weight: 100 - SplitInto: {fileID: 11400000, guid: a05af37e2256f164d80a66cc2a582466, type: 2} - SplitCount: 2 - ScatterRadius: 0.5 diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset.meta deleted file mode 100644 index fae7041..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyAbilities/SplitOnDeathAbility.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0305468bc8f912d429a8b20bf23f947c -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset.meta b/Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset.meta deleted file mode 100644 index 377b8a5..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/EnemyScalingConfig.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ae9fde0b564e20440ac2e20861fa1ca6 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure.meta deleted file mode 100644 index 5a3abf7..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 11ba3723e03690b47a4f2518bfc68a62 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset b/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset deleted file mode 100644 index 8691b9a..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset +++ /dev/null @@ -1,28 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4202a767d96e70f41b6a7e84eb08a832, type: 3} - m_Name: EnemyUpgradeGroup_Phase1_Basics - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.EnemyUpgradeGroup - DisplayName: Upgrade Group Phase 1 - Options: - - Option: {fileID: 11400000, guid: eef28ca7b8844504e9d75ff903a3bb61, type: 2} - Weight: 1 - - Option: {fileID: 11400000, guid: 46e2a6a59c0a3034f9fa44681d9ba422, type: 2} - Weight: 1 - - Option: {fileID: 11400000, guid: 80fb851b702ff304183cb6e89c4aa245, type: 2} - Weight: 1 - - Option: {fileID: 11400000, guid: a67aa3644d2ad4847a47040f53fea26f, type: 2} - Weight: 1 - - Option: {fileID: 11400000, guid: f6bfb033a15b6d0419587b80a8286bd1, type: 2} - Weight: 1 - - Option: {fileID: 11400000, guid: 37d761966a349ba4cb4141f913224d5c, type: 2} - Weight: 1 diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset.meta deleted file mode 100644 index 04f87c2..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/EnemyUpgradeGroup_Phase1_Basics.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 3dfcbf5323c0a184c84f6b9e80e37257 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset b/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset deleted file mode 100644 index 34c811a..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset +++ /dev/null @@ -1,21 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 8f73fcf0261654d44a6d0939bdc9b88f, type: 3} - m_Name: Phase1 - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Waves.PhaseDefinition - DisplayName: Phase 1 - WaveGroups: - - {fileID: 11400000, guid: 80eaa5ec98fd5df4e950131a8984fd31, type: 2} - BossGroups: - - {fileID: 11400000, guid: 2981ffffb36dfc440aa4517c17cfbbf4, type: 2} - EnemyUpgradeGroups: - - {fileID: 11400000, guid: 3dfcbf5323c0a184c84f6b9e80e37257, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset.meta deleted file mode 100644 index 7fea787..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Phase1.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1d4f04f995c4c3b44be6e5f9d0f6e3f8 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset b/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset deleted file mode 100644 index c77b032..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2b73bb9876b7fdb4480b13ff6bb8bd67, type: 3} - m_Name: Test_Run_Definition - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Waves.RunDefinition - WavesPerCycle: 5 - CyclesPerPhase: 3 - Phases: - - {fileID: 11400000, guid: 1d4f04f995c4c3b44be6e5f9d0f6e3f8, type: 2} diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset.meta deleted file mode 100644 index bcf6074..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/Test_Run_Definition.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1bb81a966192c344d94cce2628c1832b -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset b/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset deleted file mode 100644 index 2e739af..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset +++ /dev/null @@ -1,18 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5625bd25f378bda429666820a4940cee, type: 3} - m_Name: WaveGroup_Phase1_Bosses - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Waves.WaveGroup - DisplayName: Phase 1 Bosses - Waves: - - Wave: {fileID: 11400000, guid: 4db677d2940202340841471f90a5b73a, type: 2} - Weight: 1 diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset.meta deleted file mode 100644 index 174e980..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Bosses.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2981ffffb36dfc440aa4517c17cfbbf4 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset b/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset deleted file mode 100644 index 265c492..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset +++ /dev/null @@ -1,34 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5625bd25f378bda429666820a4940cee, type: 3} - m_Name: WaveGroup_Phase1_Normal - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Waves.WaveGroup - DisplayName: - Waves: - - Wave: {fileID: 11400000, guid: 65f66289ea1233b4897f46cd997d9c7a, type: 2} - Weight: 1 - - Wave: {fileID: 11400000, guid: 190e39db44aa0794aa808fd60976f7c4, type: 2} - Weight: 1 - - Wave: {fileID: 11400000, guid: 39921b44a1a0a56478200028940c5202, type: 2} - Weight: 1 - - Wave: {fileID: 11400000, guid: 50f498bc5bfc46e44b064cc96403e2cb, type: 2} - Weight: 1 - - Wave: {fileID: 11400000, guid: 9ee6dee12f0660844b4d46880f01c02f, type: 2} - Weight: 0.5 - - Wave: {fileID: 11400000, guid: 41231de63e8f25d448f19f3816e0c22f, type: 2} - Weight: 0.5 - - Wave: {fileID: 11400000, guid: 6290df178cbd3144aa92a0f09833a7be, type: 2} - Weight: 0.5 - - Wave: {fileID: 11400000, guid: 86736fd52c18fa84e8ced40f30b514fa, type: 2} - Weight: 0.5 - - Wave: {fileID: 11400000, guid: 8fdf53cfc405a5f41a00f376198b8d84, type: 2} - Weight: 0.5 diff --git a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset.meta b/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset.meta deleted file mode 100644 index c2de13d..0000000 --- a/Assets/_Project/Definitions/RunDefinitions/RunStructure/WaveGroup_Phase1_Normal.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 80eaa5ec98fd5df4e950131a8984fd31 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/Towers/BasicArrowTower.asset b/Assets/_Project/Definitions/Towers/BasicArrowTower.asset index d39d8d9..3a1c5c4 100644 --- a/Assets/_Project/Definitions/Towers/BasicArrowTower.asset +++ b/Assets/_Project/Definitions/Towers/BasicArrowTower.asset @@ -17,12 +17,8 @@ MonoBehaviour: backbone of any maze. FootprintSize: {x: 2, y: 2} GoldCost: 25 - SellRefundPercent: 0.75 - FullRefundIfUnupgraded: 0 BuildTime: 0.5 TowerPrefab: {fileID: 6482414459531823157, guid: 1511641f145758b469e64376d2a0d434, type: 3} - ConstructionPhases: {fileID: 0} - Icon: {fileID: 21300000, guid: afe216737d1b46e783889299bda1c252, type: 3} DamageType: 0 TargetPriority: 0 TargetType: 0 @@ -38,5 +34,5 @@ MonoBehaviour: EffectDuration: 0 ProjectilePrefab: {fileID: 2664719039363295382, guid: dc2e4a4108e03874a8b2dab88dcc8fba, type: 3} ProjectileSpeed: 15 - UpgradePaths: - - {fileID: 11400000, guid: 86d4c3ab00d4c654eb4c255280ee5701, type: 2} + UpgradePaths: [] + Icon: {fileID: 21300000, guid: afe216737d1b46e783889299bda1c252, type: 3} diff --git a/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset b/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset deleted file mode 100644 index 226afff..0000000 --- a/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset +++ /dev/null @@ -1,41 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7b353a757b6e6774d97e6fb8ba138fcc, type: 3} - m_Name: BasicArrowTower_Upgrade_1 - m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.TowerDefinition - DisplayName: Basic Arrow Tower - Description: Single-target tower that fires arrows at ground and air enemies. The - backbone of any maze. - FootprintSize: {x: 2, y: 2} - GoldCost: 50 - SellRefundPercent: 0.75 - FullRefundIfUnupgraded: 0 - BuildTime: 1.5 - TowerPrefab: {fileID: 6482414459531823157, guid: 1511641f145758b469e64376d2a0d434, type: 3} - ConstructionPhases: {fileID: 0} - Icon: {fileID: 21300000, guid: a140f62a10b8dc04e84625f8008e0c24, type: 3} - DamageType: 0 - TargetPriority: 0 - TargetType: 0 - GroundedOnly: 0 - Damage: 15 - Range: 20 - AttacksPerSecond: 6 - SplashRadius: 0 - ChainCount: 0 - ChainRange: 0 - SlowFactor: 0 - DotDamagePerSecond: 0 - EffectDuration: 0 - ProjectilePrefab: {fileID: 2664719039363295382, guid: dc2e4a4108e03874a8b2dab88dcc8fba, type: 3} - ProjectileSpeed: 15 - UpgradePaths: [] diff --git a/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset.meta b/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset.meta deleted file mode 100644 index facefe3..0000000 --- a/Assets/_Project/Definitions/Towers/BasicArrowTower_Upgrade_1.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 86d4c3ab00d4c654eb4c255280ee5701 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves.meta b/Assets/_Project/Definitions/Waves.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves.meta rename to Assets/_Project/Definitions/Waves.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave10Definition.asset b/Assets/_Project/Definitions/Waves/Wave10Definition.asset similarity index 93% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave10Definition.asset rename to Assets/_Project/Definitions/Waves/Wave10Definition.asset index 1bc8617..eb49ceb 100644 --- a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave10Definition.asset +++ b/Assets/_Project/Definitions/Waves/Wave10Definition.asset @@ -13,7 +13,7 @@ MonoBehaviour: m_Name: Wave10Definition m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.WaveDefinition PrepTime: 10 - ReleaseInterval: 2 Entries: - EnemyType: {fileID: 11400000, guid: 1d9809612c00ed049848a955613a4619, type: 2} - Count: 5 + Count: 50 + SpawnInterval: 0.5 diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave10Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave10Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave10Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave10Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave1Definition.asset b/Assets/_Project/Definitions/Waves/Wave1Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave1Definition.asset rename to Assets/_Project/Definitions/Waves/Wave1Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave1Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave1Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave1Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave1Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave2Definition.asset b/Assets/_Project/Definitions/Waves/Wave2Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave2Definition.asset rename to Assets/_Project/Definitions/Waves/Wave2Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave2Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave2Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave2Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave2Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave3Definition.asset b/Assets/_Project/Definitions/Waves/Wave3Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave3Definition.asset rename to Assets/_Project/Definitions/Waves/Wave3Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave3Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave3Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave3Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave3Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave4Definition.asset b/Assets/_Project/Definitions/Waves/Wave4Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave4Definition.asset rename to Assets/_Project/Definitions/Waves/Wave4Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave4Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave4Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave4Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave4Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave5Definition.asset b/Assets/_Project/Definitions/Waves/Wave5Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave5Definition.asset rename to Assets/_Project/Definitions/Waves/Wave5Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave5Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave5Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave5Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave5Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave6Definition.asset b/Assets/_Project/Definitions/Waves/Wave6Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave6Definition.asset rename to Assets/_Project/Definitions/Waves/Wave6Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave6Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave6Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave6Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave6Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave7Definition.asset b/Assets/_Project/Definitions/Waves/Wave7Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave7Definition.asset rename to Assets/_Project/Definitions/Waves/Wave7Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave7Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave7Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave7Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave7Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave8Definition.asset b/Assets/_Project/Definitions/Waves/Wave8Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave8Definition.asset rename to Assets/_Project/Definitions/Waves/Wave8Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave8Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave8Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave8Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave8Definition.asset.meta diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave9Definition.asset b/Assets/_Project/Definitions/Waves/Wave9Definition.asset similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave9Definition.asset rename to Assets/_Project/Definitions/Waves/Wave9Definition.asset diff --git a/Assets/_Project/Definitions/RunDefinitions/Waves/Wave9Definition.asset.meta b/Assets/_Project/Definitions/Waves/Wave9Definition.asset.meta similarity index 100% rename from Assets/_Project/Definitions/RunDefinitions/Waves/Wave9Definition.asset.meta rename to Assets/_Project/Definitions/Waves/Wave9Definition.asset.meta diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab index b4613dd..546fd71 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab @@ -17,7 +17,6 @@ GameObject: - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - component: {fileID: -1575784752119152190} - - component: {fileID: 154042129325690845} m_Layer: 10 m_Name: Enemy_CrystalGolem_Blue m_TagString: Untagged @@ -126,7 +125,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: a05af37e2256f164d80a66cc2a582466, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 1819643351848917197} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -225,19 +224,6 @@ MonoBehaviour: volume: 0.75 minPitch: 0.95 maxPitch: 1.05 ---- !u!114 &154042129325690845 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Red.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Red.prefab index 4f54da4..f183f6e 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Red.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Red.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: 7515565462997402737} m_Layer: 10 m_Name: Enemy_CrystalGolem_Red m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: edc686813aef43743bb15d356b511dff, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 8642767442976997525} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &7515565462997402737 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Yellow.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Yellow.prefab index fb8210c..3144e35 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Yellow.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Yellow.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: -5265869660159140516} m_Layer: 10 m_Name: Enemy_CrystalGolem_Yellow m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: fe31ccfc7a429b24fb8f57279ba96c95, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 7317567842465160949} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &-5265869660159140516 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Green.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Green.prefab index e11218f..dfb934a 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Green.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Green.prefab @@ -17,7 +17,6 @@ GameObject: - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - component: {fileID: -4695266156693656620} - - component: {fileID: -7800194977638654489} m_Layer: 10 m_Name: Enemy_Cyclops_Green m_TagString: Untagged @@ -126,7 +125,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 21c69bd4b2c55cd4fa9cd9b551c6e3fe, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 6910253555362952583} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -216,20 +215,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9df6fea9a86daafae998f8eecc44ee7d, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.EnemyDeathSound - deathSounds: [] ---- !u!114 &-7800194977638654489 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 + deathClips: + - {fileID: 8300000, guid: e007e19b827137ce395021d825927dcc, type: 3} + - {fileID: 8300000, guid: 6cea30689732db2f0a8989fe8f1a07a9, type: 3} --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Grey.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Grey.prefab index d943a11..055ef54 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Grey.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Grey.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: -5218620239817511880} m_Layer: 10 m_Name: Enemy_Cyclops_Grey m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 52d9af0c680bca64a86d66fce2a73668, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 5079596453572633521} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &-5218620239817511880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Red.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Red.prefab index 06a8723..5a0e904 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Red.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Cyclops_Red.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: -7009934292190590155} m_Layer: 10 m_Name: Enemy_Cyclops_Red m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 4b981d8b44098894197507508f655072, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 162562342023078655} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &-7009934292190590155 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Black.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Black.prefab index 829e743..0e12a01 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Black.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Black.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: 3080180597758813642} m_Layer: 10 m_Name: Enemy_Ent_Black m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: bed87a08deeb7e048ba06c8268b0f959, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 6938810086909213800} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &3080180597758813642 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Green.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Green.prefab index b37096d..eeaca4c 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Green.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Green.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: -2371779262468771447} m_Layer: 10 m_Name: Enemy_Ent_Green m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 77f4545654c5b7b41b2760a580da6068, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 2830498994423139172} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &-2371779262468771447 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Orange.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Orange.prefab index 063f5d2..9b366bb 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Orange.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_Ent_Orange.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: 2883007611589499530} m_Layer: 10 m_Name: Enemy_Ent_Orange m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 097d7ba78591cd443a06d637e0822a46, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 471366370285235598} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &2883007611589499530 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_UndeadDrake_Bone.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_UndeadDrake_Bone.prefab index 7994b3a..8acc7db 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_UndeadDrake_Bone.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_UndeadDrake_Bone.prefab @@ -16,7 +16,6 @@ GameObject: - component: {fileID: 3283904430289710888} - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - - component: {fileID: 5647470509798016640} m_Layer: 10 m_Name: Enemy_UndeadDrake_Bone m_TagString: Untagged @@ -125,7 +124,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth ShowTopMostFoldoutHeaderGroup: 1 - definition: {fileID: 11400000, guid: 1d9809612c00ed049848a955613a4619, type: 2} + definition: {fileID: 0} deathAnimator: {fileID: 3345626123719039665} deathAnimationDuration: 1.5 sinkDuration: 1.5 @@ -203,19 +202,6 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 1, z: 0} ---- !u!114 &5647470509798016640 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1455822126534880203} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility - ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Player/Player.prefab b/Assets/_Project/Prefabs/Player/Player.prefab index 240ec88..33c1316 100644 --- a/Assets/_Project/Prefabs/Player/Player.prefab +++ b/Assets/_Project/Prefabs/Player/Player.prefab @@ -13,14 +13,10 @@ GameObject: - component: {fileID: 2918837822014987993} - component: {fileID: 7845089877743661692} - component: {fileID: 4336209376377567030} + - component: {fileID: 2806524246861401760} - component: {fileID: 2806524246861401799} - component: {fileID: 2806524246861401801} - component: {fileID: 5683786710272852339} - - component: {fileID: 6856236869205671849} - - component: {fileID: -4438158474568445526} - - component: {fileID: 2871545571532934715} - - component: {fileID: 1298503032983562452} - - component: {fileID: 8755797571419628899} m_Layer: 0 m_Name: Player m_TagString: Untagged @@ -109,6 +105,21 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PlayerMatchState ShowTopMostFoldoutHeaderGroup: 1 +--- !u!114 &2806524246861401760 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3493329038866903420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7775ee3a2f441b52480aabf54be6c1b6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PlayerBuffManager + ShowTopMostFoldoutHeaderGroup: 1 + categories: + - {fileID: 11400000, guid: d8ed3b9535538f7fc82be878cc307d26, type: 2} --- !u!114 &2806524246861401799 MonoBehaviour: m_ObjectHideFlags: 0 @@ -148,68 +159,3 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderUpgradeManager ShowTopMostFoldoutHeaderGroup: 1 ---- !u!114 &6856236869205671849 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3493329038866903420} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dfa83208b02c50b40866bb1846240c4a, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PlayerSpellLoadout - ShowTopMostFoldoutHeaderGroup: 1 ---- !u!114 &-4438158474568445526 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3493329038866903420} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 65825b3189ae873948659b37b219f5e6, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Dev.DebugCommandRelay - ShowTopMostFoldoutHeaderGroup: 1 ---- !u!114 &2871545571532934715 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3493329038866903420} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f60f6928562351f4891142ad59ab6352, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PlayerTowerUpgrades - ShowTopMostFoldoutHeaderGroup: 1 ---- !u!114 &1298503032983562452 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3493329038866903420} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b7e4c91a08f5d2461a3f8e6c25b09d74, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PlayerTowerDeck - ShowTopMostFoldoutHeaderGroup: 1 ---- !u!114 &8755797571419628899 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3493329038866903420} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2b8f4d1e6c3a497051d8e2f7a9c1b063, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Draft.PlayerDraft - ShowTopMostFoldoutHeaderGroup: 1 diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index a08f1d5..a8d0238 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -2253,7 +2253,7 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::TD.Audio.AudioManager categories: - category: 0 - maxVoices: 6 + maxVoices: 4 volume: 0.5 - category: 1 maxVoices: 4 @@ -2276,56 +2276,6 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &181002639 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 181002641} - - component: {fileID: 181002640} - m_Layer: 0 - m_Name: EnemyAbilityPool - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &181002640 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 181002639} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4409eb25a8be555de8dc3a73d4ed95db, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.EnemyAbilityPool - abilities: - - {fileID: 11400000, guid: 0305468bc8f912d429a8b20bf23f947c, type: 2} - - {fileID: 11400000, guid: 030f10c9a264e544ea3e0f4fdb4171bd, type: 2} - - {fileID: 11400000, guid: cb2ec6bb70f57d0429b99b7cd4c7db73, type: 2} - - {fileID: 11400000, guid: a18691a20d75f17479a83b3e171759e7, type: 2} - - {fileID: 11400000, guid: c64c7121b0456bb4a873acec9e0abf91, type: 2} ---- !u!4 &181002641 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 181002639} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 15.94346, y: 0, z: 194.22044} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!43 &203092944 Mesh: m_ObjectHideFlags: 0 @@ -11584,57 +11534,6 @@ Mesh: - serializedVersion: 1 m_IndexStart: 0 m_IndexCount: 0 ---- !u!1 &759470733 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 759470735} - - component: {fileID: 759470734} - m_Layer: 0 - m_Name: SellEffectSpawner - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &759470734 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 759470733} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e2708c6bac8136f45b48c899d3d40630, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.SellEffectSpawner - coinBurstPrefab: {fileID: 2313150535691989867, guid: 31f8d8c320b42c54d886d610fb13a1e7, type: 3} - sellSound: - clip: {fileID: 8300000, guid: 778b3d5981f4c3045a475794435f43cc, type: 3} - volume: 1 - minPitch: 0.95 - maxPitch: 1.05 - verticalOffset: 0.75 ---- !u!4 &759470735 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 759470733} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 35.63582, y: 0.5, z: 163.67152} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &759520883 GameObject: m_ObjectHideFlags: 0 @@ -13019,57 +12918,6 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 24, y: 1, z: 30} m_Center: {x: 0, y: 0, z: 0} ---- !u!1 &875833597 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 875833599} - - component: {fileID: 875833598} - m_Layer: 0 - m_Name: EnemyUpgradePool - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &875833598 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 875833597} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c4d98a01d9b9a7b438a6f91b0b7f498f, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.EnemyUpgradePool - options: - - {fileID: 11400000, guid: eef28ca7b8844504e9d75ff903a3bb61, type: 2} - - {fileID: 11400000, guid: 46e2a6a59c0a3034f9fa44681d9ba422, type: 2} - - {fileID: 11400000, guid: 80fb851b702ff304183cb6e89c4aa245, type: 2} - - {fileID: 11400000, guid: a67aa3644d2ad4847a47040f53fea26f, type: 2} - - {fileID: 11400000, guid: 37d761966a349ba4cb4141f913224d5c, type: 2} - - {fileID: 11400000, guid: f6bfb033a15b6d0419587b80a8286bd1, type: 2} ---- !u!4 &875833599 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 875833597} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 38.30481, y: 0.5, z: 155.93135} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &902199259 GameObject: m_ObjectHideFlags: 0 @@ -13497,54 +13345,6 @@ Transform: m_Children: [] m_Father: {fileID: 1097152085} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &914832724 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 914832726} - - component: {fileID: 914832725} - m_Layer: 0 - m_Name: BuilderSpellPool - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &914832725 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 914832724} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36a7be1b3824682b8a183fbcf8564652, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.BuilderSpellPool - spells: - - {fileID: 11400000, guid: 051c48f416e5366b59d49b0e062333ac, type: 2} - - {fileID: 11400000, guid: d893f46b037536b4ba91307e184cecfe, type: 2} - - {fileID: 11400000, guid: 364edf6abc3c31e33b53d0a01142b8ab, type: 2} ---- !u!4 &914832726 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 914832724} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -18.90215, y: 6.17317, z: 0.5013} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &921503905 GameObject: m_ObjectHideFlags: 0 @@ -13859,75 +13659,6 @@ Mesh: - serializedVersion: 1 m_IndexStart: 0 m_IndexCount: 0 ---- !u!1 &954434158 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 954434161} - - component: {fileID: 954434160} - - component: {fileID: 954434159} - m_Layer: 0 - m_Name: DebugConsole - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &954434159 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 954434158} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7c6a808e8291552d0b64e36a210879c4, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Dev.DebugConsole - toggleKey: 4 ---- !u!114 &954434160 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 954434158} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} - m_Name: - m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument - m_PanelSettings: {fileID: 11400000, guid: 6aa0af71585acea4db4995c3931dc946, type: 2} - m_ParentUI: {fileID: 0} - sourceAsset: {fileID: 0} - m_SortingOrder: 1 - m_Position: 0 - m_WorldSpaceSizeMode: 1 - m_WorldSpaceWidth: 1920 - m_WorldSpaceHeight: 1080 - m_PivotReferenceSize: 0 - m_Pivot: 0 - m_WorldSpaceCollider: {fileID: 0} ---- !u!4 &954434161 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 954434158} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -52.51635, y: 0, z: -27.6311} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &955672358 GameObject: m_ObjectHideFlags: 0 @@ -13996,129 +13727,6 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 17, y: 1, z: 13} m_Center: {x: 0, y: 0, z: 0} ---- !u!1 &961493951 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 961493954} - - component: {fileID: 961493952} - - component: {fileID: 961493953} - m_Layer: 0 - m_Name: RunState - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &961493952 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 961493951} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 3660389945 - InScenePlacedSourceGlobalObjectIdHash: 0 - DeferredDespawnTick: 0 - Ownership: 1 - AlwaysReplicateAsRoot: 0 - SynchronizeTransform: 1 - ActiveSceneSynchronization: 0 - SceneMigrationSynchronization: 0 - SpawnWithObservers: 1 - DontDestroyWithOwner: 0 - AutoObjectParentSync: 1 - SyncOwnerTransformWhenParented: 1 - AllowOwnerToParent: 0 ---- !u!114 &961493953 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 961493951} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a293cf6dca91dd2478c9f4e799cf9e0d, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.Waves.RunState - ShowTopMostFoldoutHeaderGroup: 1 - runDefinition: {fileID: 11400000, guid: 1bb81a966192c344d94cce2628c1832b, type: 2} ---- !u!4 &961493954 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 961493951} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 38.30481, y: 0.5, z: 155.93135} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &993870443 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 993870445} - - component: {fileID: 993870444} - m_Layer: 0 - m_Name: BuilderSpellCastController - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &993870444 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 993870443} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cc99a2b3d3e8d8178a74e1d68a34553c, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpellCastController - groundLayerMask: - serializedVersion: 2 - m_Bits: 128 - raycastMaxDistance: 500 - aimDecal: {fileID: 0} - pointReticleDiameter: 1.5 - projectionDepth: 50 ---- !u!4 &993870445 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 993870443} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -18.90215, y: 6.17317, z: 0.5013} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &997315214 GameObject: m_ObjectHideFlags: 0 @@ -14648,7 +14256,6 @@ MonoBehaviour: placementManager: {fileID: 1507514108} cameraController: {fileID: 1239994223} rejectionMessageDuration: 2.5 - menuButtonIcon: {fileID: 0} chatMaxHeight: 280 chatMaxMessages: 2147483647 chatSystemColor: {r: 1, g: 0.7, b: 0.2, a: 1} @@ -18434,11 +18041,19 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.WaveManager ShowTopMostFoldoutHeaderGroup: 1 + waveDefinitions: + - {fileID: 11400000, guid: 65f66289ea1233b4897f46cd997d9c7a, type: 2} + - {fileID: 11400000, guid: 190e39db44aa0794aa808fd60976f7c4, type: 2} + - {fileID: 11400000, guid: 39921b44a1a0a56478200028940c5202, type: 2} + - {fileID: 11400000, guid: 50f498bc5bfc46e44b064cc96403e2cb, type: 2} + - {fileID: 11400000, guid: 9ee6dee12f0660844b4d46880f01c02f, type: 2} + - {fileID: 11400000, guid: 41231de63e8f25d448f19f3816e0c22f, type: 2} + - {fileID: 11400000, guid: 6290df178cbd3144aa92a0f09833a7be, type: 2} + - {fileID: 11400000, guid: 86736fd52c18fa84e8ced40f30b514fa, type: 2} + - {fileID: 11400000, guid: 8fdf53cfc405a5f41a00f376198b8d84, type: 2} + - {fileID: 11400000, guid: 4db677d2940202340841471f90a5b73a, type: 2} startingLives: 40 - draftTimeSeconds: 30 - voteTimeSeconds: 25 goldConfig: {fileID: 11400000, guid: d5e01c919f14a1e4888ad494a159241b, type: 2} - enemyScalingConfig: {fileID: 11400000, guid: ae9fde0b564e20440ac2e20861fa1ca6, type: 2} --- !u!43 &1393870843 Mesh: m_ObjectHideFlags: 0 @@ -20308,7 +19923,6 @@ MonoBehaviour: - {fileID: 0} - {fileID: 11400000, guid: d5b2e8fa3c7e9b5f4a1d0c2e7f6b3a91, type: 2} - {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2} - - {fileID: 11400000, guid: 86d4c3ab00d4c654eb4c255280ee5701, type: 2} - {fileID: 11400000, guid: 04219895bbea4fb9a94fd62fef35bf2a, type: 2} - {fileID: 11400000, guid: e3f1a9c2b5d84e76a0c3f1e8d27b4905, type: 2} startingDeck: @@ -23017,7 +22631,6 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::TD.Dev.DevWaveControls hotkey: 94 grantTowerHotkey: 101 - skipToBossHotkey: 100 --- !u!4 &1731269687 Transform: m_ObjectHideFlags: 0 @@ -28077,78 +27690,6 @@ Mesh: - serializedVersion: 1 m_IndexStart: 0 m_IndexCount: 0 ---- !u!1 &2021000666 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2021000669} - - component: {fileID: 2021000667} - - component: {fileID: 2021000668} - m_Layer: 0 - m_Name: WaveVote - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &2021000667 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2021000666} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 3520766009 - InScenePlacedSourceGlobalObjectIdHash: 0 - DeferredDespawnTick: 0 - Ownership: 1 - AlwaysReplicateAsRoot: 0 - SynchronizeTransform: 1 - ActiveSceneSynchronization: 0 - SceneMigrationSynchronization: 0 - SpawnWithObservers: 1 - DontDestroyWithOwner: 0 - AutoObjectParentSync: 1 - SyncOwnerTransformWhenParented: 1 - AllowOwnerToParent: 0 ---- !u!114 &2021000668 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2021000666} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a18321dc2d138034fbdb5f705f19f893, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyUpgrades.WaveVote - ShowTopMostFoldoutHeaderGroup: 1 - optionsPerVote: 3 ---- !u!4 &2021000669 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2021000666} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 38.30481, y: 0.5, z: 155.93135} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!43 &2024389666 Mesh: m_ObjectHideFlags: 0 @@ -29024,11 +28565,7 @@ MonoBehaviour: options: - {fileID: 11400000, guid: 6b1d3f8a2c5e4097b8a1d0c3e6f9b240, type: 2} - {fileID: 11400000, guid: f4a2b8d1c6e93f05a7b2d4c8e1f6a930, type: 2} - - {fileID: 11400000, guid: 0b9f4905752751f44b9959b84b620266, type: 2} - {fileID: 11400000, guid: 65ff25c1c8a89f7df8e88f71968c1c98, type: 2} - - {fileID: 11400000, guid: 5f390de69ba43b2a6a0d89cf09580320, type: 2} - - {fileID: 11400000, guid: 29b35841f7e5db454903798cb5d83434, type: 2} - - {fileID: 11400000, guid: d180030b68a9a5e1da497bf6f83451d4, type: 2} --- !u!4 &2139601601 Transform: m_ObjectHideFlags: 0 @@ -29426,11 +28963,3 @@ SceneRoots: - {fileID: 176580462} - {fileID: 516125087} - {fileID: 2079088113} - - {fileID: 914832726} - - {fileID: 993870445} - - {fileID: 759470735} - - {fileID: 954434161} - - {fileID: 181002641} - - {fileID: 961493954} - - {fileID: 2021000669} - - {fileID: 875833599} diff --git a/Assets/_Project/Scripts/Audio/AudioCategory.cs b/Assets/_Project/Scripts/Audio/AudioCategory.cs index 539e9ba..9a446aa 100644 --- a/Assets/_Project/Scripts/Audio/AudioCategory.cs +++ b/Assets/_Project/Scripts/Audio/AudioCategory.cs @@ -1,5 +1,5 @@ // Assets/_Project/Scripts/Audio/AudioCategory.cs namespace TD.Audio { - public enum AudioCategory { Combat, EnemyHitDeath, UI } + public enum AudioCategory { TowerFire, EnemyHitDeath, UI } } diff --git a/Assets/_Project/Scripts/Audio/AudioManager.cs b/Assets/_Project/Scripts/Audio/AudioManager.cs index 5fbc61b..21099bb 100644 --- a/Assets/_Project/Scripts/Audio/AudioManager.cs +++ b/Assets/_Project/Scripts/Audio/AudioManager.cs @@ -11,12 +11,6 @@ namespace TD.Audio { public AudioCategory category; public int maxVoices; - - // NOTE: currently inert. It seeds each pooled AudioSource at init, but every - // Play() call overwrites src.volume with (per-sound volume × SFX slider), so - // this value never reaches the mix. Left as-is rather than "fixed" because - // multiplying it in would halve every existing sound (authored scenes use 0.5). - // Wire it up only alongside a pass to re-level the per-sound volumes. [Range(0f, 1f)] public float volume; } @@ -64,16 +58,6 @@ namespace TD.Audio } } - /// - /// Plays a one-shot on the given category's voice pool. is - /// the per-sound authored level; it's scaled by the player's SFX slider - /// () on the way in. - /// - /// - /// The scalar is sampled at play time, so a sound already in flight keeps the volume - /// it started with when the slider moves. Every SFX here is short, so that's - /// imperceptible and avoids having to track live voices. - /// public void Play(AudioClip clip, AudioCategory category, float pitch = 1f, float volume = 1f) { if (clip == null) return; @@ -82,7 +66,7 @@ namespace TD.Audio int idx = indices[category]; var src = pool[idx % pool.Length]; src.pitch = pitch; - src.volume = volume * AudioVolumeSettings.SfxScalar; + src.volume = volume; src.clip = clip; src.Play(); indices[category] = idx + 1; diff --git a/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs b/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs deleted file mode 100644 index 5df40a6..0000000 --- a/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs -using UnityEngine; - -namespace TD.Audio -{ - /// - /// Player-facing volume mix, persisted in and shared by - /// every audio consumer in the game. Two buses: - /// - /// Music — the looping scene track played by . - /// SFX — everything routed through - /// (spells, tower fire, build/land, enemy death, sell, UI clicks). - /// - /// - /// - /// Why not named AudioSettings. UnityEngine.AudioSettings already - /// exists, so a TD.Audio.AudioSettings would be an ambiguous reference in any - /// file that has both using UnityEngine; and using TD.Audio;. - /// - /// Units. Public values are ints 0..100 — the numbers the settings slider - /// shows. Consumers multiply by / , - /// which apply a squared taper so the slider's lower half isn't perceptually dead - /// (linear amplitude drops off much faster than perceived loudness). At 100 the - /// scalar is exactly 1, so the default mix is byte-identical to the pre-settings - /// behaviour. - /// - /// Live updates. fires on every mutation. - /// Continuous sources (music) subscribe and re-apply; one-shots read the scalar at - /// play time, so a mid-flight SFX keeps the volume it started with. That's fine — - /// they're all short. - /// - public static class AudioVolumeSettings - { - public const int MinVolume = 0; - public const int MaxVolume = 100; - - private const int DefaultVolume = 100; - private const string MusicKey = "td.audio.music"; - private const string SfxKey = "td.audio.sfx"; - - /// Raised whenever music or SFX volume changes. - public static event System.Action OnChanged; - - // -1 = not yet read from PlayerPrefs. Statics are cleared on domain reload - // (entering play mode in the editor), so the lazy load re-runs each session. - private static int music = -1; - private static int sfx = -1; - - public static int MusicVolume - { - get - { - if (music < 0) music = PlayerPrefs.GetInt(MusicKey, DefaultVolume); - return music; - } - set => Set(ref music, MusicKey, value); - } - - public static int SfxVolume - { - get - { - if (sfx < 0) sfx = PlayerPrefs.GetInt(SfxKey, DefaultVolume); - return sfx; - } - set => Set(ref sfx, SfxKey, value); - } - - /// Amplitude multiplier (0..1) for the music bus. - public static float MusicScalar => ToScalar(MusicVolume); - - /// Amplitude multiplier (0..1) for the sound-effects bus. - public static float SfxScalar => ToScalar(SfxVolume); - - /// - /// Flushes PlayerPrefs to disk. Setters only write the in-memory pref (cheap - /// enough to call on every frame of a slider drag); call this once when the - /// settings UI closes so the choice survives a crash. - /// - public static void Flush() => PlayerPrefs.Save(); - - private static void Set(ref int field, string key, int value) - { - int clamped = Mathf.Clamp(value, MinVolume, MaxVolume); - if (field == clamped) return; - field = clamped; - PlayerPrefs.SetInt(key, clamped); - OnChanged?.Invoke(); - } - - private static float ToScalar(int volume) - { - float linear = Mathf.Clamp01(volume / (float)MaxVolume); - return linear * linear; - } - } -} diff --git a/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs.meta b/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs.meta deleted file mode 100644 index 2b1f334..0000000 --- a/Assets/_Project/Scripts/Audio/AudioVolumeSettings.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4d2f94f5f8df24e8aa1f47d9f0e3ecf4 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Audio/MusicPlayer.cs b/Assets/_Project/Scripts/Audio/MusicPlayer.cs index 781e36e..325b15c 100644 --- a/Assets/_Project/Scripts/Audio/MusicPlayer.cs +++ b/Assets/_Project/Scripts/Audio/MusicPlayer.cs @@ -7,12 +7,6 @@ namespace TD.Audio /// Plays a single looping music track for the scene it lives in. /// Add to a GameObject in the scene, assign a clip, and it starts on load. /// - /// - /// Volume is the authored scaled by the player's music slider - /// (). Unlike one-shot SFX, the track is - /// continuous, so this subscribes to and - /// re-applies live while the slider is dragged. - /// [RequireComponent(typeof(AudioSource))] public class MusicPlayer : MonoBehaviour { @@ -20,36 +14,14 @@ namespace TD.Audio [Range(0f, 1f)] [SerializeField] private float volume = 1f; - private AudioSource source; - - private void Awake() - { - source = GetComponent(); - } - - private void OnEnable() - { - AudioVolumeSettings.OnChanged += ApplyVolume; - } - - private void OnDisable() - { - AudioVolumeSettings.OnChanged -= ApplyVolume; - } - private void Start() { - source.clip = clip; - source.loop = true; - source.playOnAwake = false; - ApplyVolume(); - source.Play(); - } - - private void ApplyVolume() - { - if (source == null) return; - source.volume = volume * AudioVolumeSettings.MusicScalar; + var src = GetComponent(); + src.clip = clip; + src.volume = volume; + src.loop = true; + src.playOnAwake = false; + src.Play(); } } } diff --git a/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs b/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs index eddc323..3334523 100644 --- a/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs +++ b/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs @@ -38,7 +38,7 @@ namespace TD.Combat private void HandleAreaFired(Vector3[] positions) { - AudioManager.Instance?.Play(fireSound.clip, AudioCategory.Combat, fireSound.RandomPitch(), fireSound.volume); + AudioManager.Instance?.Play(fireSound.clip, AudioCategory.TowerFire, fireSound.RandomPitch(), fireSound.volume); } } } diff --git a/Assets/_Project/Scripts/Combat/TowerCombat.cs b/Assets/_Project/Scripts/Combat/TowerCombat.cs index 3001be9..6c1a53f 100644 --- a/Assets/_Project/Scripts/Combat/TowerCombat.cs +++ b/Assets/_Project/Scripts/Combat/TowerCombat.cs @@ -67,6 +67,11 @@ namespace TD.Combat // Cached on OnNetworkSpawn — avoids GetComponent every Update. private TowerInstance towerInstance; + // Lazily resolved on first attack — the owner's slot isn't guaranteed to be + // set at spawn time, so we defer the lookup until combat actually begins. + private PlayerBuffManager ownerBuffManager; + private bool buffManagerResolved; + // Shared OverlapSphere result buffer. 32 covers any realistic enemy // density; size up if profiling reveals overflow. private static readonly Collider[] s_overlapBuffer = new Collider[32]; @@ -234,6 +239,25 @@ namespace TD.Combat ClearTarget(); } + // ----- Buff multiplier lookup ------------------------------------- + + // Resolved lazily on the first attack because the owner slot NetworkVariable + // may not yet have replicated by the time OnNetworkSpawn runs. + private PlayerBuffManager GetOwnerBuffManager() + { + if (buffManagerResolved) return ownerBuffManager; + + var slot = towerInstance.Owner; + if (slot == PlayerSlot.None) return null; + + var matchState = PlayerMatchState.GetForSlot(slot); + if (matchState == null) return null; + + ownerBuffManager = matchState.GetComponent(); + buffManagerResolved = true; + return ownerBuffManager; + } + // ----- Attack tick ------------------------------------------------- private void TickAttack(TowerDefinition def) @@ -241,7 +265,9 @@ namespace TD.Combat attackCooldown -= Time.deltaTime; if (attackCooldown > 0f) return; - attackCooldown = 1f / def.AttacksPerSecond; + float effectiveFireRate = def.AttacksPerSecond + * (GetOwnerBuffManager()?.GetMultiplier(BuffStat.AttackSpeed) ?? 1f); + attackCooldown = 1f / effectiveFireRate; Fire(def); } @@ -458,7 +484,9 @@ namespace TD.Combat private void HitEnemy(in CombatProfile p, EnemyHealth target, PlayerSlot owner) { - target.TakeDamage(p.Damage, p.DamageType, owner); + var multiplier = GetOwnerBuffManager()?.GetMultiplier(BuffStat.Damage) ?? 1f; + float effectiveDamage = p.Damage * multiplier; + target.TakeDamage(effectiveDamage, p.DamageType, owner); ApplyStatusEffect(p, target, owner); } @@ -497,9 +525,11 @@ namespace TD.Combat return; } + float effectiveDamage = def.Damage + * (GetOwnerBuffManager()?.GetMultiplier(BuffStat.Damage) ?? 1f); proj.InitializeServer( target, - def.Damage, + effectiveDamage, p.DamageType, p.TargetType, p.SplashRadius, diff --git a/Assets/_Project/Scripts/Core/BuffStat.cs b/Assets/_Project/Scripts/Core/BuffStat.cs new file mode 100644 index 0000000..3e2132e --- /dev/null +++ b/Assets/_Project/Scripts/Core/BuffStat.cs @@ -0,0 +1,12 @@ +// Assets/_Project/Scripts/Core/BuffStat.cs +namespace TD.Core +{ + /// + /// Identifies which tower stat a modifies. + /// + public enum BuffStat : byte + { + Damage = 0, + AttackSpeed = 1, + } +} diff --git a/Assets/_Project/Scripts/Core/BuffStat.cs.meta b/Assets/_Project/Scripts/Core/BuffStat.cs.meta new file mode 100644 index 0000000..b91fc16 --- /dev/null +++ b/Assets/_Project/Scripts/Core/BuffStat.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fc84fec503f24bc7693ee29558f45d27 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Core/BuilderSpellKind.cs b/Assets/_Project/Scripts/Core/BuilderSpellKind.cs deleted file mode 100644 index 91c56e9..0000000 --- a/Assets/_Project/Scripts/Core/BuilderSpellKind.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace TD.Core -{ - /// - /// Identifies which builder spell a - /// represents. Mirrors - /// — a stable, enum-indexed identifier used by - /// and - /// instead of an asset reference. - /// - public enum BuilderSpellKind : byte - { - Fireball = 0, - SlowArea = 1, - SlowAreaUpgraded = 2, - } -} diff --git a/Assets/_Project/Scripts/Core/BuilderSpellKind.cs.meta b/Assets/_Project/Scripts/Core/BuilderSpellKind.cs.meta deleted file mode 100644 index af62b64..0000000 --- a/Assets/_Project/Scripts/Core/BuilderSpellKind.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a043765d6aa295a5397226e3e32d2c37 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs b/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs deleted file mode 100644 index 3356956..0000000 --- a/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace TD.Core -{ - /// - /// Identifies which enemy ability a - /// represents. Mirrors - /// — a stable, enum-indexed identifier used by - /// instead of an asset reference. - /// - public enum EnemyAbilityKind : byte - { - /// Sentinel for "no ability". Never a real pool entry. - None = 0, - - /// Dies into several smaller, faster copies of itself. - SplitOnDeath = 1, - - /// Grounded enemies take to the air, ignoring the maze entirely. - Flight = 2, - - /// Teleports a short distance further along its path on a timer. - Blink = 3, - - /// Grants no kill bounty. - NoBounty = 4, - - /// Steals gold from the player whose zone it escaped, on top of the life cost. - GoldTheft = 5, - } -} diff --git a/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs.meta b/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs.meta deleted file mode 100644 index 18dd995..0000000 --- a/Assets/_Project/Scripts/Core/EnemyAbilityKind.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: ec52a6b404fed65dfa48a63b5535373d \ No newline at end of file diff --git a/Assets/_Project/Scripts/Core/Enums.cs b/Assets/_Project/Scripts/Core/Enums.cs index 7d49400..95f979a 100644 --- a/Assets/_Project/Scripts/Core/Enums.cs +++ b/Assets/_Project/Scripts/Core/Enums.cs @@ -68,12 +68,8 @@ namespace TD.Core /// /// /// None is a sentinel value used in OwnerGrid to mark tiles not owned by any player zone. - /// Maps use a contiguous prefix of the player values. - /// - /// The enum runs to 9, but only slots are ever - /// allocated. Lobbies capped at 3 for the 2.0 design; the surplus values are kept because - /// they are baked into existing LevelData owner grids, and renumbering the enum would - /// force a re-bake of every map to no runtime benefit. + /// Player1..Player9 cover the maximum supported player count. Maps using fewer players use a + /// contiguous prefix (e.g., a 3-player map uses Player1, Player2, Player3 only). /// /// /// Global phase of a match, driven by MatchState. @@ -96,28 +92,6 @@ namespace TD.Core Defeat = 4, } - /// - /// Which step of the between-encounters sequence is currently running. Replicated by - /// WaveManager so every HUD can label the shared countdown correctly. - /// - /// - /// These run strictly in order and never overlap: players take their personal draft, then vote - /// on the buff for the wave they just cleared, then build. The build timer deliberately does - /// NOT run concurrently with the choices — "after all players have chosen" only means - /// something if it isn't racing a clock players also want to spend on their maze. - /// - public enum InterWaveStage : byte - { - /// No inter-wave step running — a wave is spawning or being fought. - None = 0, - /// Players are picking their personal draft reward. - Draft = 1, - /// Players are voting on the buff for the wave they just cleared. - Vote = 2, - /// Build countdown before the next wave spawns. - Build = 3, - } - /// /// Stable identifier per race. Values 1-16 reserve slots for the planned /// 16-race grid in the lobby; only races with a corresponding diff --git a/Assets/_Project/Scripts/Core/MatchRules.cs b/Assets/_Project/Scripts/Core/MatchRules.cs deleted file mode 100644 index d698547..0000000 --- a/Assets/_Project/Scripts/Core/MatchRules.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Assets/_Project/Scripts/Core/MatchRules.cs -namespace TD.Core -{ - /// - /// Match-wide constants that several unrelated systems have to agree on. - /// - public static class MatchRules - { - /// - /// Maximum players in one lobby. - /// - /// - /// Reduced from 9 to 3 for the 2.0 design as a deliberate scope cut: three players - /// is enough for the shared-lives and shared-vote mechanics to matter, and it shrinks map - /// authoring, balance surface, and network load all at once. - /// - /// Why still runs to 9. Shrinking the enum would - /// invalidate the owner grids baked into existing LevelData assets and force a - /// re-bake of every map, for no runtime benefit — the extra values are simply never - /// allocated. Slot allocation caps here instead, which is the only place that decides who - /// gets a slot at all. Per-slot arrays stay sized to the enum, so they hold a few unused - /// entries; that is intentional and costs nothing. - /// - public const int MaxPlayers = 3; - } -} diff --git a/Assets/_Project/Scripts/Core/MatchRules.cs.meta b/Assets/_Project/Scripts/Core/MatchRules.cs.meta deleted file mode 100644 index 74bb050..0000000 --- a/Assets/_Project/Scripts/Core/MatchRules.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: ac169573e8a2fd046a3ebac7d2e03c8c \ No newline at end of file diff --git a/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs b/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs deleted file mode 100644 index 0bb29d0..0000000 --- a/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Assets/_Project/Scripts/Core/PoolWeightAttribute.cs -using UnityEngine; - -namespace TD.Core -{ - /// - /// Marks a float field as a 0–1 relative draw weight inside an authored pool. The - /// inspector renders it as a slider and, when the value is zero, shows a warning directly - /// beneath explaining that the entry can never be drawn. - /// - /// - /// Relative, not absolute. Weights are normalized against the summed weight of the - /// candidate set at draw time, so entries at equal weight are equally likely and an entry at - /// 0.5 is half as likely as one at 1.0. This is why every weight field defaults to 1 — - /// adding an entry to a pool then never silently re-weights the entries already in it. - /// - /// The warning is advisory. Muting an entry while tuning is a legitimate - /// workflow, so the drawer never clamps the value or blocks the edit. It exists because a - /// zero-weight entry is otherwise indistinguishable, in play, from one that simply hasn't come - /// up yet — the failure is silent, so the authoring surface has to be loud. - /// - public class PoolWeightAttribute : PropertyAttribute - { - /// - /// Noun used in the zero-weight warning ("this wave can never be drawn"). Keep it - /// singular and lowercase. - /// - public readonly string Noun; - - public PoolWeightAttribute(string noun = "entry") - { - Noun = string.IsNullOrWhiteSpace(noun) ? "entry" : noun; - } - } -} diff --git a/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs.meta b/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs.meta deleted file mode 100644 index 2ce9e75..0000000 --- a/Assets/_Project/Scripts/Core/PoolWeightAttribute.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: e171856d7a8fe194f97091853672c19d \ No newline at end of file diff --git a/Assets/_Project/Scripts/Core/SpellTargetType.cs b/Assets/_Project/Scripts/Core/SpellTargetType.cs deleted file mode 100644 index 7ebb6ff..0000000 --- a/Assets/_Project/Scripts/Core/SpellTargetType.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace TD.Core -{ - /// - /// How a is aimed. - /// - /// - /// Deliberately not named TargetType — that name is already taken in this - /// namespace by (Single/Splash/Chain/AllInRange, used by - /// TowerDefinition/TowerCombat), and every combat-adjacent file already - /// has using TD.Core;. - /// - public enum SpellTargetType : byte - { - /// Aimed at a single ground point. No radius preview while aiming, even - /// if the spell has an internal splash radius. - PointTarget = 0, - - /// Aimed at a ground point, affecting everything within - /// . Previewed - /// as a scaled radius decal while aiming. - AreaOfEffect = 1, - } -} diff --git a/Assets/_Project/Scripts/Core/SpellTargetType.cs.meta b/Assets/_Project/Scripts/Core/SpellTargetType.cs.meta deleted file mode 100644 index 0722838..0000000 --- a/Assets/_Project/Scripts/Core/SpellTargetType.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 0ebeda6f965b64f7ca82ecd6f849142a \ No newline at end of file diff --git a/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs b/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs deleted file mode 100644 index 360b2a3..0000000 --- a/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Assets/_Project/Scripts/Dev/DebugCommandRelay.cs -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; -using TD.Gameplay.Draft; -using TD.Gameplay.EnemyUpgrades; -using TD.Gameplay.Waves; - -namespace TD.Dev -{ - /// - /// Debug-only network relay: exposes one RPC that force-applies a - /// by its index, bypassing PlayerDraft's "must currently be - /// offered" check. - /// - /// - /// Lives entirely separate from PlayerDraft/DraftOption/DraftPool — none of those files - /// know this component exists. Removing this component (and TD.Dev.DebugConsole, which - /// calls it) leaves the shipping draft system completely untouched. - /// - /// Added to the Player prefab alongside PlayerDraft/PlayerGoldManager/etc. so it spawns - /// with a per-player OwnerClientId. Static per-client registry mirrors PlayerDraft's - /// GetForClient/Local pattern. - /// - public class DebugCommandRelay : NetworkBehaviour - { - private static readonly Dictionary s_byClientId - = new Dictionary(); - - public static DebugCommandRelay GetForClient(ulong clientId) - { - s_byClientId.TryGetValue(clientId, out var relay); - return relay; - } - - public static DebugCommandRelay Local - { - get - { - var nm = NetworkManager.Singleton; - if (nm == null || !nm.IsClient) return null; - return GetForClient(nm.LocalClientId); - } - } - - public override void OnNetworkSpawn() - { - s_byClientId[OwnerClientId] = this; - } - - public override void OnNetworkDespawn() - { - if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this) - s_byClientId.Remove(OwnerClientId); - } - - /// - /// Owning client: force-apply the DraftOption at (its - /// DraftPool index) immediately, skipping the normal "must be currently offered" gate. - /// Debug/testing only — any connected client can grant themselves anything via this - /// RPC, same tradeoff DevWaveControls already accepts for its hotkeys. - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] - public void DebugGrantDraftOptionRpc(int optionId) - { - var option = DraftPool.Instance != null ? DraftPool.Instance.Get(optionId) : null; - if (option == null) - { - Debug.LogWarning($"[DebugCommandRelay] Grant requested for unknown option id {optionId}."); - return; - } - - if (option.ServerApply(OwnerClientId)) - Debug.Log($"[DebugCommandRelay] Granted '{option.DisplayName}' to client {OwnerClientId}."); - else - Debug.LogWarning($"[DebugCommandRelay] '{option.DisplayName}' could not be applied " + - $"to client {OwnerClientId}."); - } - - /// - /// Force-apply the at (its - /// index) to the run's current wave slot — the same - /// recording WaveVote.ServerResolve does for a vote winner, skipping the vote - /// entirely. Not player-scoped: the effect lands on the run's current wave slot rather - /// than the caller, so any connected client's relay can trigger it. - /// - /// - /// Takes effect the next time this wave slot's enemies spawn, not retroactively on - /// enemies already alive — see 's remarks on why - /// applying is "record on the slot," not a direct mutation. - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] - public void DebugGrantEnemyUpgradeRpc(int optionId) - { - var pool = EnemyUpgradePool.Instance; - var option = pool != null ? pool.Get(optionId) : null; - if (option == null) - { - Debug.LogWarning($"[DebugCommandRelay] Grant requested for unknown enemy upgrade id {optionId}."); - return; - } - - var run = RunState.Instance; - if (run == null) - { - Debug.LogWarning("[DebugCommandRelay] No RunState in this scene."); - return; - } - - int slot = run.CurrentUpgradeSlot; - run.ServerAddUpgrade(slot, optionId); - option.ServerOnApplied(run, slot); - - Debug.Log($"[DebugCommandRelay] Granted '{option.DisplayName}' to wave slot {slot}."); - } - } -} diff --git a/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs.meta b/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs.meta deleted file mode 100644 index d7a2598..0000000 --- a/Assets/_Project/Scripts/Dev/DebugCommandRelay.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 65825b3189ae873948659b37b219f5e6 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Dev/DebugConsole.cs b/Assets/_Project/Scripts/Dev/DebugConsole.cs deleted file mode 100644 index 6ffbf2b..0000000 --- a/Assets/_Project/Scripts/Dev/DebugConsole.cs +++ /dev/null @@ -1,760 +0,0 @@ -// Assets/_Project/Scripts/Dev/DebugConsole.cs -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.UIElements; -using TD.UI; -using TD.Gameplay.Draft; -using TD.Gameplay.EnemyUpgrades; - -namespace TD.Dev -{ - /// - /// Standalone debug console overlay: press the toggle key to open a text - /// input, type a command, Enter to submit, Escape to cancel. - /// - /// - /// Deliberately decoupled from — own GameObject, - /// own UIDocument (it shares HUDPanelSettings, drawn above the HUD via a - /// higher sorting order) — so it can be dropped out of a build entirely by - /// not including that GameObject, the same way - /// is kept separate from shipping systems. - /// - /// The grammar lives in a tree (see - /// ) rather than in hardcoded string compares, - /// so the same definition drives both execution and the autocomplete list. - /// Supports one command so far: "get <type> <name>" grants a - /// to the local player via - /// . - /// - /// Keys while open: Up/Down move the suggestion highlight, Tab accepts it, - /// Enter accepts it while the command is still incomplete and submits once - /// it is complete, Escape closes without submitting. - /// - [RequireComponent(typeof(UIDocument))] - public class DebugConsole : MonoBehaviour - { - public static DebugConsole Instance { get; private set; } - - /// - /// True while the console overlay is showing. Legacy IMGUI (OnGUI) dev tools - /// draw after every runtime UI Toolkit panel regardless of sorting order, so they - /// have to check this and skip drawing rather than rely on layering. - /// - public static bool IsOpen => Instance != null && Instance.consoleOpen; - - [Tooltip("Keyboard shortcut that opens and closes the console. Uses the new Input " + - "System (UnityEngine.InputSystem.Key). Backquote is the physical ` / ~ key.")] - [SerializeField] private Key toggleKey = Key.Backquote; - - private DebugConsoleUI ui; - private bool consoleOpen; - - // Frame on which the console was opened or closed. The toggle key and Enter - // are ignored on that frame and the next so the keypress that opened/closed - // the console doesn't also get typed into the field or immediately submit it. - // Mirrors HUDController's chatToggleSuppressFrame. - private int toggleSuppressFrame = -1; - - // Current completion candidates for what's typed, the highlighted one, and the - // index in the input text where accepting a candidate starts overwriting. - private List suggestions = new List(); - private int selectedIndex; - private int fragmentStart; - - private void Awake() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[DebugConsole] Duplicate instance detected. Destroying the new one."); - Destroy(gameObject); - return; - } - Instance = this; - } - - private void Start() - { - var doc = GetComponent(); - if (doc == null) - { - Debug.LogError("[DebugConsole] No UIDocument component found."); - return; - } - - var root = doc.rootVisualElement; - if (root == null) - { - Debug.LogError("[DebugConsole] rootVisualElement is null. " + - "Check that Panel Settings is assigned."); - return; - } - - ui = new DebugConsoleUI(root); - - // Focus tracking — contributes to the same flag HUDController's chat - // input sets, so camera/builder/spell input all stay gated correctly - // regardless of which text field currently has focus. - ui.CommandInput.RegisterCallback(_ => HUDController.IsTextInputActive = true); - ui.CommandInput.RegisterCallback(_ => HUDController.IsTextInputActive = false); - - ui.CommandInput.RegisterValueChangedCallback(_ => RefreshSuggestions()); - - // Tab and the arrows can't be polled from Keyboard.current the way Enter and - // Escape are (below): UI Toolkit would still insert a tab character and move - // the focus ring before Update runs. Intercept them on the field in the - // trickle-down phase, before the text engine and the focus ring see them. - ui.CommandInput.RegisterCallback(OnConsoleKeyDown, TrickleDown.TrickleDown); - ui.CommandInput.RegisterCallback(OnConsoleNavigationMove, - TrickleDown.TrickleDown); - } - - private void Update() - { - var kb = Keyboard.current; - if (kb == null) return; // no keyboard connected (e.g. headless server) - - if (Time.frameCount <= toggleSuppressFrame) return; - - if (toggleKey != Key.None && kb[toggleKey].wasPressedThisFrame) - { - if (consoleOpen) CloseConsole(); - else OpenConsole(); - return; - } - - if (!consoleOpen) return; - - bool enterDown = kb.enterKey.wasPressedThisFrame || kb.numpadEnterKey.wasPressedThisFrame; - bool escDown = kb.escapeKey.wasPressedThisFrame; - - if (enterDown) SubmitCommand(); - else if (escDown) CloseConsole(); - } - - private void OnConsoleKeyDown(KeyDownEvent evt) - { - if (!consoleOpen) return; - - switch (evt.keyCode) - { - case KeyCode.Tab: - AcceptSelectedSuggestion(); - Swallow(evt); - return; - case KeyCode.DownArrow: - MoveSelection(1); - Swallow(evt); - return; - case KeyCode.UpArrow: - MoveSelection(-1); - Swallow(evt); - return; - } - - // Tab reaches the field twice — once carrying keyCode, once carrying only the - // '\t' character. Swallow the second one too or a literal tab lands in the text. - if (evt.character == '\t') Swallow(evt); - } - - // UI Toolkit also translates Tab into a focus-ring navigation event, separately - // from the key event above. Block it so Tab can't move focus off the console. - private void OnConsoleNavigationMove(NavigationMoveEvent evt) - { - if (!consoleOpen) return; - Swallow(evt); - } - - // Consume an event so neither the text engine nor the focus ring acts on it. - // EventBase.PreventDefault is obsolete in Unity 6; FocusController.IgnoreEvent is - // its replacement for the focus-navigation half. - private void Swallow(EventBase evt) - { - evt.StopImmediatePropagation(); - ui.CommandInput?.panel?.focusController?.IgnoreEvent(evt); - } - - private void OpenConsole() - { - if (ui.CommandInput == null) return; - ui.Show(); - ui.CommandInput.SetValueWithoutNotify(string.Empty); - RefreshSuggestions(); - - // Suppress the toggle key and Enter for this frame and the next so the - // keypress that opened the console doesn't also get typed into the field. - // Focus is deferred a frame for the same reason — UI Toolkit would - // otherwise route the open keypress to the freshly-focused TextField. - toggleSuppressFrame = Time.frameCount + 1; - consoleOpen = true; - StartCoroutine(FocusNextFrame()); - } - - private IEnumerator FocusNextFrame() - { - yield return null; - if (consoleOpen && ui.CommandInput != null) - { - ui.CommandInput.Focus(); - ui.CommandInput.SelectAll(); - } - } - - private void CloseConsole() - { - if (ui.CommandInput != null) - { - ui.CommandInput.SetValueWithoutNotify(string.Empty); - ui.CommandInput.Blur(); - } - ui.Hide(); - - suggestions.Clear(); - selectedIndex = 0; - ui.ClearSuggestions(); - - consoleOpen = false; - toggleSuppressFrame = Time.frameCount + 1; - SuppressHudChatOpen(); - } - - // The Enter that submitted/accepted in this console also gets polled by - // HUDController's chat this same frame — suppress its "Enter opens chat" branch - // (HUDController.HandleChatInput, which gates only on this frame counter) so - // using the debug console never pops chat open too. - private static void SuppressHudChatOpen() - { - HUDController.SuppressChatOpenUntilFrame = Time.frameCount + 1; - } - - private void SubmitCommand() - { - string text = ui.CommandInput?.value ?? string.Empty; - - // Enter doubles as "accept the highlighted suggestion" while the typed - // command isn't runnable yet, so you can drive the whole thing with Enter - // and only ever hit Tab when you want to skip past the highlighted row. - if (!string.IsNullOrWhiteSpace(text) && suggestions.Count > 0 && !IsComplete(text)) - { - AcceptSelectedSuggestion(); - SuppressHudChatOpen(); - return; - } - - CloseConsole(); - - if (string.IsNullOrWhiteSpace(text)) return; - ExecuteCommand(text.Trim()); - } - - // ---------------------------------------------------------------- grammar - - /// - /// One token level of the command grammar. Literal levels list their - /// ; a level that takes a free-form final argument sets - /// to enumerate the valid values for completion. - /// - private sealed class CommandNode - { - public string Token; // literal token; null for the root - public string Hint; // dim one-liner shown beside the token - public Func> Values; // non-null => this level takes a final value - public bool Executable; // a complete command can end here - public Action Execute; // "Values" level: run the completed command - public readonly List Children = new List(); - } - - private const string UsageHint = "Try: get , grant enemy "; - - // Maps the type token in "get " to the DraftOption subclass it - // should match against. Add an entry here whenever a new DraftOption subclass - // should be gettable from the console — the command tree and its autocomplete - // list are both built from this. - private static readonly Dictionary DraftTypeAliases = - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "spell", typeof(BuilderSpellDraftOption) }, - { "tower", typeof(NewTowerDraftOption) }, - { "buff", typeof(BuilderEffectDraftOption) }, - { "effect", typeof(BuilderEffectDraftOption) }, - }; - - private CommandNode commandTree; - private CommandNode CommandTree => commandTree ?? (commandTree = BuildCommandTree()); - - private static CommandNode BuildCommandTree() - { - var root = new CommandNode(); - - var get = new CommandNode - { - Token = "get", - Hint = "grant a draft option to the local player", - }; - root.Children.Add(get); - - foreach (var pair in DraftTypeAliases) - { - string typeToken = pair.Key; - var optionType = pair.Value; - get.Children.Add(new CommandNode - { - Token = typeToken, - Hint = "", - Executable = true, - Values = () => DraftOptionNames(optionType), - Execute = name => ExecuteGet(typeToken, optionType, name), - }); - } - - var grant = new CommandNode - { - Token = "grant", - Hint = "grant a buff to the enemies", - }; - root.Children.Add(grant); - - grant.Children.Add(new CommandNode - { - Token = "enemy", - Hint = "", - Executable = true, - Values = EnemyUpgradeNames, - Execute = ExecuteGrantEnemyAbility, - }); - - return root; - } - - // Display names of every pooled DraftOption of the given subclass, alphabetically. - // Recomputed per keystroke rather than cached: DraftPool is a scene singleton that - // may not exist yet when the console is built, and the pool is only a handful of - // entries. Uses DraftPool's existing Count/Get surface — the same one ExecuteGet - // walks — so completion can never offer something the command can't resolve. - private static List DraftOptionNames(Type optionType) - { - var names = new List(); - - var pool = DraftPool.Instance; - if (pool == null) return names; - - for (int i = 0; i < pool.Count; i++) - { - var option = pool.Get(i); - if (option == null || !optionType.IsInstanceOfType(option)) continue; - - string name = option.DisplayName; - if (string.IsNullOrWhiteSpace(name)) continue; - if (names.Contains(name)) continue; - - names.Add(name); - } - - names.Sort(StringComparer.OrdinalIgnoreCase); - return names; - } - - // Display names of every pooled EnemyUpgradeOption, alphabetically. Mirrors - // DraftOptionNames above — EnemyUpgradePool is the enemy-side equivalent of DraftPool, - // and this is the same Count/Get surface ExecuteGrantEnemyAbility walks. Includes - // non-ability cards too (e.g. the vote-meta "Double Dip") — DebugGrantEnemyUpgradeRpc - // resolves through EnemyUpgradeOption.ServerOnApplied regardless of subclass, so - // there's nothing this command can't actually grant. - private static List EnemyUpgradeNames() - { - var names = new List(); - - var pool = EnemyUpgradePool.Instance; - if (pool == null) return names; - - for (int i = 0; i < pool.Count; i++) - { - var option = pool.Get(i); - if (option == null) continue; - - string name = option.DisplayName; - if (string.IsNullOrWhiteSpace(name)) continue; - if (names.Contains(name)) continue; - - names.Add(name); - } - - names.Sort(StringComparer.OrdinalIgnoreCase); - return names; - } - - // Valid literal tokens at a level, for error messages ("Expected one of: ..."). - private static string ChildTokens(CommandNode node) - { - var tokens = new List(); - for (int i = 0; i < node.Children.Count; i++) tokens.Add(node.Children[i].Token); - tokens.Sort(StringComparer.OrdinalIgnoreCase); - return string.Join(", ", tokens); - } - - private static CommandNode FindChild(CommandNode node, string token) - { - for (int i = 0; i < node.Children.Count; i++) - if (string.Equals(node.Children[i].Token, token, StringComparison.OrdinalIgnoreCase)) - return node.Children[i]; - return null; - } - - // Whitespace tokenizer that also reports where each token starts, so completion - // knows which span of the raw input a candidate would replace. - private static void Tokenize(string text, List tokens, List starts) - { - tokens.Clear(); - starts.Clear(); - - int i = 0; - while (i < text.Length) - { - while (i < text.Length && char.IsWhiteSpace(text[i])) i++; - if (i >= text.Length) break; - - int start = i; - while (i < text.Length && !char.IsWhiteSpace(text[i])) i++; - tokens.Add(text.Substring(start, i - start)); - starts.Add(start); - } - } - - // ------------------------------------------------------------- completion - - private struct Suggestion - { - public string Text; // what replaces the current fragment - public string Hint; // dim trailing text, display only - public bool AppendSpace; // true when more tokens follow this one - } - - private readonly List walkTokens = new List(); - private readonly List walkStarts = new List(); - - /// - /// Candidates for the token currently being typed, plus (via - /// ) the index in where - /// accepting one starts overwriting. - /// - private List ComputeSuggestions(string text, out int fragStart) - { - text = text ?? string.Empty; - Tokenize(text, walkTokens, walkStarts); - - bool endsWithSpace = text.Length > 0 && char.IsWhiteSpace(text[text.Length - 1]); - - var node = CommandTree; - int i = 0; - - while (true) - { - // Free-form final argument: everything from here to the end of the line is - // one value, so multi-word names ("Slow Area") complete as a single unit — - // matching how ExecuteCommand rejoins the trailing tokens. - if (node.Values != null) - { - fragStart = i < walkTokens.Count ? walkStarts[i] : text.Length; - string valueFragment = i < walkTokens.Count - ? text.Substring(fragStart).Trim() - : string.Empty; - return FilterValues(node.Values(), valueFragment); - } - - // Nothing typed at this level yet — offer everything it accepts. - if (i >= walkTokens.Count) - { - fragStart = text.Length; - return FilterChildren(node, string.Empty); - } - - // Last token with no trailing space is still being typed: complete it - // rather than trying to descend through it. - if (i == walkTokens.Count - 1 && !endsWithSpace) - { - fragStart = walkStarts[i]; - return FilterChildren(node, walkTokens[i]); - } - - var child = FindChild(node, walkTokens[i]); - if (child == null) - { - // A finished token that matches nothing — the rest of the line is - // unreachable, so there's nothing useful to suggest. - fragStart = walkStarts[i]; - return new List(); - } - - node = child; - i++; - } - } - - private static List FilterChildren(CommandNode node, string fragment) - { - var result = new List(); - for (int i = 0; i < node.Children.Count; i++) - { - var child = node.Children[i]; - if (fragment.Length > 0 && - !child.Token.StartsWith(fragment, StringComparison.OrdinalIgnoreCase)) - continue; - - result.Add(new Suggestion - { - Text = child.Token, - Hint = child.Hint, - AppendSpace = child.Children.Count > 0 || child.Values != null, - }); - } - result.Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.OrdinalIgnoreCase)); - return result; - } - - // Values are matched on the same normalized form execution uses, so anything the - // list offers for "slow_ar" is something ExecuteGet would also accept. - private static List FilterValues(List values, string fragment) - { - var result = new List(); - string normalizedFragment = Normalize(fragment); - - for (int i = 0; i < values.Count; i++) - { - if (normalizedFragment.Length > 0 && - !Normalize(values[i]).StartsWith(normalizedFragment, StringComparison.Ordinal)) - continue; - - result.Add(new Suggestion { Text = values[i], AppendSpace = false }); - } - return result; - } - - /// True when is a runnable command as typed. - private bool IsComplete(string text) - { - Tokenize(text ?? string.Empty, walkTokens, walkStarts); - - var node = CommandTree; - int i = 0; - - while (i < walkTokens.Count) - { - if (node.Values != null) break; - - var child = FindChild(node, walkTokens[i]); - if (child == null) return false; - - node = child; - i++; - } - - if (!node.Executable) return false; - - if (node.Values != null) - { - if (i >= walkTokens.Count) return false; // value level, nothing typed for it - - string normalized = Normalize(string.Join(" ", walkTokens.GetRange(i, walkTokens.Count - i))); - var values = node.Values(); - for (int v = 0; v < values.Count; v++) - if (Normalize(values[v]) == normalized) return true; - - return false; - } - - return true; - } - - // --------------------------------------------------------- suggestion UI - - private void RefreshSuggestions() - { - if (ui.CommandInput == null) return; - - // Keep the highlight on the same candidate when it survives the new filter, - // so typing another character doesn't silently move what Enter would accept. - string previouslySelected = selectedIndex >= 0 && selectedIndex < suggestions.Count - ? suggestions[selectedIndex].Text - : null; - - suggestions = ComputeSuggestions(ui.CommandInput.value, out fragmentStart); - - selectedIndex = 0; - if (previouslySelected != null) - { - for (int i = 0; i < suggestions.Count; i++) - { - if (!string.Equals(suggestions[i].Text, previouslySelected, StringComparison.Ordinal)) - continue; - selectedIndex = i; - break; - } - } - - ui.RenderSuggestions(ToSuggestionRows(suggestions), selectedIndex); - } - - private static List ToSuggestionRows(List suggestions) - { - var rows = new List(suggestions.Count); - for (int i = 0; i < suggestions.Count; i++) - rows.Add(new DebugConsoleUI.SuggestionRow(suggestions[i].Text, suggestions[i].Hint)); - return rows; - } - - private void MoveSelection(int delta) - { - if (suggestions.Count == 0) return; - - selectedIndex = (selectedIndex + delta) % suggestions.Count; - if (selectedIndex < 0) selectedIndex += suggestions.Count; - - ui.RenderSuggestions(ToSuggestionRows(suggestions), selectedIndex); - } - - private bool AcceptSelectedSuggestion() - { - if (ui.CommandInput == null) return false; - if (selectedIndex < 0 || selectedIndex >= suggestions.Count) return false; - - var suggestion = suggestions[selectedIndex]; - string text = ui.CommandInput.value ?? string.Empty; - int start = Mathf.Clamp(fragmentStart, 0, text.Length); - - string completed = text.Substring(0, start) + suggestion.Text + - (suggestion.AppendSpace ? " " : string.Empty); - - // SetValueWithoutNotify + an explicit refresh instead of assigning value: - // one deterministic recompute, and the caret placement below can't race the - // change callback. - ui.CommandInput.SetValueWithoutNotify(completed); - ui.CommandInput.SelectRange(completed.Length, completed.Length); - RefreshSuggestions(); - return true; - } - - // ------------------------------------------------------------- execution - - private void ExecuteCommand(string text) - { - Tokenize(text, walkTokens, walkStarts); - - var node = CommandTree; - int i = 0; - - while (i < walkTokens.Count && node.Values == null) - { - var child = FindChild(node, walkTokens[i]); - if (child == null) - { - Debug.Log($"[DebugConsole] Unrecognized token \"{walkTokens[i]}\" in " + - $"\"{text}\". Expected one of: {ChildTokens(node)}. {UsageHint}"); - return; - } - - node = child; - i++; - } - - if (node.Values == null || !node.Executable || i >= walkTokens.Count) - { - Debug.Log($"[DebugConsole] Incomplete command: \"{text}\". {UsageHint}"); - return; - } - - string nameToken = string.Join(" ", walkTokens.GetRange(i, walkTokens.Count - i)); - node.Execute(nameToken); - } - - // "get ": grants any DraftOption of the given type whose DisplayName - // matches , via the local player's DebugCommandRelay. Reuses DraftOption's - // existing type-agnostic ServerApply dispatch instead of hardcoding a grant path - // per option type. - private static void ExecuteGet(string typeToken, Type optionType, string nameToken) - { - var pool = DraftPool.Instance; - if (pool == null) - { - Debug.LogWarning("[DebugConsole] No DraftPool in this scene."); - return; - } - - string normalizedTarget = Normalize(nameToken); - for (int i = 0; i < pool.Count; i++) - { - var option = pool.Get(i); - if (option == null || !optionType.IsInstanceOfType(option)) continue; - if (Normalize(option.DisplayName) != normalizedTarget) continue; - - var relay = DebugCommandRelay.Local; - if (relay == null) - { - Debug.LogWarning("[DebugConsole] No local DebugCommandRelay found — " + - "is it on the Player prefab?"); - return; - } - - relay.DebugGrantDraftOptionRpc(i); - return; - } - - Debug.LogWarning($"[DebugConsole] No {typeToken} option named \"{nameToken}\" found."); - } - - // "grant enemy ": the same effect as the post-wave vote picking that ability - // card for the current wave slot — records it via RunState.ServerAddUpgrade and runs - // its ServerOnApplied, mirroring WaveVote.ServerResolve exactly (see DebugCommandRelay. - // DebugGrantEnemyUpgradeRpc). Takes effect the next time this wave slot's enemies - // spawn, not retroactively on enemies already alive. - private static void ExecuteGrantEnemyAbility(string nameToken) - { - var pool = EnemyUpgradePool.Instance; - if (pool == null) - { - Debug.LogWarning("[DebugConsole] No EnemyUpgradePool in this scene."); - return; - } - - string normalizedTarget = Normalize(nameToken); - for (int i = 0; i < pool.Count; i++) - { - var option = pool.Get(i); - if (option == null || Normalize(option.DisplayName) != normalizedTarget) continue; - - var relay = DebugCommandRelay.Local; - if (relay == null) - { - Debug.LogWarning("[DebugConsole] No local DebugCommandRelay found — " + - "is it on the Player prefab?"); - return; - } - - relay.DebugGrantEnemyUpgradeRpc(i); - return; - } - - Debug.LogWarning($"[DebugConsole] No enemy ability named \"{nameToken}\" found."); - } - - // DisplayName is player-facing draft card text (its spacing/casing is chosen for - // presentation, not for typing), so command matching strips everything but letters - // and digits before comparing — "Slow Area", "slow_area", and "SlowArea" all match - // the same option. - private static string Normalize(string s) - { - if (string.IsNullOrEmpty(s)) return string.Empty; - var sb = new StringBuilder(s.Length); - foreach (char c in s) - if (char.IsLetterOrDigit(c)) sb.Append(char.ToLowerInvariant(c)); - return sb.ToString(); - } - - private void OnDestroy() - { - if (Instance == this) Instance = null; - } - } -} diff --git a/Assets/_Project/Scripts/Dev/DebugConsole.cs.meta b/Assets/_Project/Scripts/Dev/DebugConsole.cs.meta deleted file mode 100644 index c9a3292..0000000 --- a/Assets/_Project/Scripts/Dev/DebugConsole.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7c6a808e8291552d0b64e36a210879c4 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs b/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs deleted file mode 100644 index 808dd29..0000000 --- a/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs +++ /dev/null @@ -1,185 +0,0 @@ -// Assets/_Project/Scripts/Dev/DebugConsoleUI.cs -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.UIElements; - -namespace TD.Dev -{ - /// - /// Builds and draws 's VisualElement tree: the input bar and - /// its autocomplete list. Owns presentation only — element construction, styling, and - /// row rendering — no command grammar, keybinding, or suggestion-selection logic; that - /// stays in , which drives this class through its public - /// members and reads/writes directly for focus and value. - /// - internal sealed class DebugConsoleUI - { - // Beyond this many candidates the list is truncated with a "+N more" row so a - // large DraftPool can't grow the console bar off the top of the screen. - private const int MaxVisibleSuggestions = 12; - - /// One row of the autocomplete list: a candidate token plus an optional dim hint. - public readonly struct SuggestionRow - { - public readonly string Text; - public readonly string Hint; - - public SuggestionRow(string text, string hint) - { - Text = text; - Hint = hint; - } - } - - public TextField CommandInput { get; } - - private readonly VisualElement consoleContainer; - private readonly VisualElement suggestionList; - - public DebugConsoleUI(VisualElement uiRoot) - { - // Top-anchored bar, closed by default. Distinct position from the HUD's - // bottom-left chat panel so the two never overlap. - consoleContainer = new VisualElement(); - consoleContainer.pickingMode = PickingMode.Ignore; - consoleContainer.style.position = Position.Absolute; - consoleContainer.style.left = 0; - consoleContainer.style.right = 0; - consoleContainer.style.top = 0; - consoleContainer.style.paddingTop = 8; - consoleContainer.style.paddingBottom = 8; - consoleContainer.style.paddingLeft = 12; - consoleContainer.style.paddingRight = 12; - // Fully opaque: the console is a text-entry overlay that has to stay readable - // over the level, the HUD, and whatever else is on screen. - consoleContainer.style.backgroundColor = new Color(0f, 0f, 0f, 1f); - consoleContainer.style.display = DisplayStyle.None; - - CommandInput = new TextField(); - CommandInput.style.minHeight = 28; - CommandInput.style.width = Length.Percent(100); - CommandInput.maxLength = 200; - CommandInput.isDelayed = false; - StyleConsoleInput(CommandInput); - - suggestionList = new VisualElement(); - suggestionList.pickingMode = PickingMode.Ignore; - suggestionList.style.flexDirection = FlexDirection.Column; - suggestionList.style.marginTop = 4; - suggestionList.style.display = DisplayStyle.None; - - consoleContainer.Add(CommandInput); - consoleContainer.Add(suggestionList); - uiRoot.Add(consoleContainer); - } - - // Mirrors HUDController.StyleChatInputDark — dark background, white text, - // a thin border, and inner padding so ascenders/descenders don't clip. - // Green border (vs. chat's neutral gray) as a quick visual "this is the - // debug console, not chat" cue. - private static void StyleConsoleInput(TextField field) - { - var darkBg = new Color(0.05f, 0.05f, 0.05f, 1f); - var borderClr = new Color(0.35f, 0.75f, 0.35f); - - field.style.backgroundColor = darkBg; - field.style.color = Color.white; - field.style.borderTopWidth = field.style.borderBottomWidth = - field.style.borderLeftWidth = field.style.borderRightWidth = 1; - field.style.borderTopColor = field.style.borderBottomColor = - field.style.borderLeftColor = field.style.borderRightColor = borderClr; - - var inner = field.Q("unity-text-input"); - if (inner != null) - { - inner.style.backgroundColor = darkBg; - inner.style.color = Color.white; - inner.style.paddingTop = 4; - inner.style.paddingBottom = 4; - inner.style.paddingLeft = 6; - inner.style.paddingRight = 6; - } - } - - // One autocomplete row: the candidate token plus an optional dim hint. Rows are - // pickingMode Ignore and keyboard-driven only — nothing here is clickable, which - // avoids the recursive picking-mode problem documented in HUDController's chat - // panel (clicks falling through to the game world via a ScrollView's internal - // wrapper element). - private static VisualElement BuildSuggestionRow(string text, string hint, bool selected) - { - var row = new VisualElement(); - row.pickingMode = PickingMode.Ignore; - row.style.flexDirection = FlexDirection.Row; - row.style.minHeight = 20; - row.style.paddingLeft = 6; - row.style.paddingRight = 6; - row.style.backgroundColor = selected - ? new Color(0.16f, 0.38f, 0.16f, 1f) // matches the green console cue - : new Color(0.05f, 0.05f, 0.05f, 1f); - - var label = new Label(text); - label.pickingMode = PickingMode.Ignore; - label.style.color = Color.white; - label.style.unityFontStyleAndWeight = selected ? FontStyle.Bold : FontStyle.Normal; - row.Add(label); - - if (!string.IsNullOrEmpty(hint)) - { - var hintLabel = new Label(hint); - hintLabel.pickingMode = PickingMode.Ignore; - hintLabel.style.color = new Color(0.6f, 0.6f, 0.6f); - hintLabel.style.marginLeft = 12; - row.Add(hintLabel); - } - - return row; - } - - public void Show() - { - consoleContainer.style.display = DisplayStyle.Flex; - consoleContainer.pickingMode = PickingMode.Position; - } - - public void Hide() - { - consoleContainer.style.display = DisplayStyle.None; - consoleContainer.pickingMode = PickingMode.Ignore; - } - - // Windows the list around selectedIndex so arrowing past MaxVisibleSuggestions - // keeps the selected row on screen instead of scrolling it out of the truncated view. - public void RenderSuggestions(List rows, int selectedIndex) - { - suggestionList.Clear(); - - if (rows == null || rows.Count == 0) - { - suggestionList.style.display = DisplayStyle.None; - return; - } - - suggestionList.style.display = DisplayStyle.Flex; - - int start = rows.Count > MaxVisibleSuggestions - ? Mathf.Clamp(selectedIndex - MaxVisibleSuggestions / 2, 0, - rows.Count - MaxVisibleSuggestions) - : 0; - int end = Mathf.Min(start + MaxVisibleSuggestions, rows.Count); - - for (int i = start; i < end; i++) - suggestionList.Add(BuildSuggestionRow(rows[i].Text, rows[i].Hint, i == selectedIndex)); - - int hidden = rows.Count - (end - start); - if (hidden > 0) - suggestionList.Add(BuildSuggestionRow($"+{hidden} more", null, false)); - } - - public void ClearSuggestions() - { - suggestionList.Clear(); - suggestionList.style.display = DisplayStyle.None; - } - } -} diff --git a/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs.meta b/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs.meta deleted file mode 100644 index 66e439e..0000000 --- a/Assets/_Project/Scripts/Dev/DebugConsoleUI.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: fce39b2f68ef0f3f9bec299aa46d353a \ No newline at end of file diff --git a/Assets/_Project/Scripts/Dev/DevWaveControls.cs b/Assets/_Project/Scripts/Dev/DevWaveControls.cs index 9ffa05e..2dfd6ff 100644 --- a/Assets/_Project/Scripts/Dev/DevWaveControls.cs +++ b/Assets/_Project/Scripts/Dev/DevWaveControls.cs @@ -33,10 +33,6 @@ namespace TD.Dev "verified now. Set to Key.None to use the OnGUI button only.")] [SerializeField] private Key grantTowerHotkey = Key.F8; - [Tooltip("Keyboard shortcut to skip every remaining encounter in the current phase and " + - "go straight to its boss. Set to Key.None to use the OnGUI button only.")] - [SerializeField] private Key skipToBossHotkey = Key.F7; - private void Update() { var kb = Keyboard.current; @@ -47,9 +43,6 @@ namespace TD.Dev if (grantTowerHotkey != Key.None && kb[grantTowerHotkey].wasPressedThisFrame) TryGrantNextTower(); - - if (skipToBossHotkey != Key.None && kb[skipToBossHotkey].wasPressedThisFrame) - TrySkipToBoss(); } private void OnGUI() @@ -59,20 +52,13 @@ namespace TD.Dev if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsServer) return; - // IMGUI draws after every runtime UI Toolkit panel, so this box would cover the - // debug console's autocomplete list no matter what sorting order the console's - // PanelSettings uses. Yield to the console while it's open. - if (DebugConsole.IsOpen) return; - // Anchored below the top HUD bar so it doesn't overlap gold/wave/lives. const float topOffset = 90f; - GUI.Box(new Rect(10, topOffset, 180, 128), "Dev: Wave Controls"); + GUI.Box(new Rect(10, topOffset, 180, 95), "Dev: Wave Controls"); if (GUI.Button(new Rect(20, topOffset + 25, 160, 28), "Force Next Wave")) TryForceNextWave(); if (GUI.Button(new Rect(20, topOffset + 58, 160, 28), "Grant Next Tower")) TryGrantNextTower(); - if (GUI.Button(new Rect(20, topOffset + 91, 160, 28), "Skip To Boss")) - TrySkipToBoss(); } // Dev stand-in for the draft system: grants the local player the first catalog @@ -127,27 +113,5 @@ namespace TD.Dev Debug.Log("[DevWaveControls] Forcing next wave."); wm.ForceAdvanceToNextWave(); } - - // Skips straight to the phase boss so boss content can be tested without playing - // every cycle first. Server-only, like the other cheats. - private void TrySkipToBoss() - { - if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsServer) - { - Debug.LogWarning("[DevWaveControls] Skip-to-boss requested off the server. Ignored."); - return; - } - - var wm = WaveManager.Instance; - if (wm == null) - { - Debug.LogWarning("[DevWaveControls] WaveManager.Instance is null. " + - "Is the scene running with a WaveManager network-spawned?"); - return; - } - - Debug.Log("[DevWaveControls] Skipping to boss."); - wm.ForceAdvanceToBoss(); - } } } diff --git a/Assets/_Project/Scripts/Editor/Core.meta b/Assets/_Project/Scripts/Editor/Core.meta deleted file mode 100644 index 7db3e99..0000000 --- a/Assets/_Project/Scripts/Editor/Core.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 75cc168bfd0b91b41a313a4389d31910 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs b/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs deleted file mode 100644 index 3321b16..0000000 --- a/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs -using UnityEditor; -using UnityEngine; -using TD.Core; - -namespace TD.Editor.Core -{ - /// - /// Draws a field as a 0–1 slider, with an inline warning - /// rendered directly beneath it whenever the weight is zero. - /// - /// - /// Deliberately does not clamp, revert, or disable the field — a designer muting an entry - /// while tuning is normal. The drawer's only job is to make the consequence visible at the - /// point of editing, since a zero-weight entry fails silently at runtime. - /// - [CustomPropertyDrawer(typeof(PoolWeightAttribute))] - public class PoolWeightDrawer : PropertyDrawer - { - // Two lines of text alongside the icon column need more than one line of box height. - private const float HelpBoxLines = 2.4f; - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - float h = EditorGUIUtility.singleLineHeight; - - if (IsZero(property)) - h += EditorGUIUtility.standardVerticalSpacing + HelpBoxHeight(); - - return h; - } - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - if (property.propertyType != SerializedPropertyType.Float) - { - EditorGUI.LabelField(position, label.text, "[PoolWeight] only supports float fields."); - return; - } - - var sliderRect = new Rect(position.x, position.y, position.width, - EditorGUIUtility.singleLineHeight); - EditorGUI.Slider(sliderRect, property, 0f, 1f, label); - - if (!IsZero(property)) return; - - var attr = (PoolWeightAttribute)attribute; - var boxRect = new Rect( - position.x, - position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, - position.width, - HelpBoxHeight()); - - EditorGUI.HelpBox( - boxRect, - $"Weight is 0 — this {attr.Noun} can never be drawn and will not appear in game. " + - $"Raise it above 0 to put it back in the pool.", - MessageType.Warning); - } - - private static bool IsZero(SerializedProperty property) - => property.propertyType == SerializedPropertyType.Float && property.floatValue <= 0f; - - private static float HelpBoxHeight() => EditorGUIUtility.singleLineHeight * HelpBoxLines; - } -} diff --git a/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs.meta b/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs.meta deleted file mode 100644 index 3ec645e..0000000 --- a/Assets/_Project/Scripts/Editor/Core/PoolWeightDrawer.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 8ba57381fc7e6a3479e59d84e45720d9 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs b/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs deleted file mode 100644 index 737b34a..0000000 --- a/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs -using UnityEditor; -using UnityEngine; -using TD.Gameplay; - -namespace TD.Editor.Gameplay -{ - /// - /// Custom property drawer for . Labels each element by its - /// run position ("Encounter 3") rather than "Element 2", and renders a projected-earnings - /// line beneath the fields so the economy can be tuned without arithmetic. - /// - /// - /// Projections are estimates by necessity. Kill income depends on how many enemies the - /// encounter spawns, and the wave filling each slot is drawn at runtime from a phase pool — - /// so the drawer multiplies against - /// instead. The cumulative figure is the number worth watching: it answers "how much could a - /// player have banked by this point in the run", which is what tower prices get balanced - /// against. - /// - [CustomPropertyDrawer(typeof(EncounterGoldEntry))] - public class EncounterGoldEntryDrawer : PropertyDrawer - { - private const float PreviewLineExtraHeight = 4f; - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - if (!property.isExpanded) return EditorGUIUtility.singleLineHeight; - - float h = EditorGUIUtility.singleLineHeight; // foldout - h += SpacedLineHeight() * 3; // the three gold fields - h += SpacedLineHeight() * 2 + PreviewLineExtraHeight; // projection + cumulative - return h; - } - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - int encounterNumber = EncounterNumberFrom(property); - - // Re-label the foldout by run position. Element indices are 0-based and read as - // off-by-one against everything else in the run (RunState, the HUD, the checklist), - // which made miscounting the boss slot easy. - var header = new GUIContent(encounterNumber > 0 - ? $"Encounter {encounterNumber}" - : label.text); - - Rect headerRect = new Rect(position.x, position.y, position.width, - EditorGUIUtility.singleLineHeight); - property.isExpanded = EditorGUI.Foldout(headerRect, property.isExpanded, header, - toggleOnLabelClick: true); - if (!property.isExpanded) return; - - float y = position.y + SpacedLineHeight(); - const float indent = 14f; - Rect Row() - { - Rect r = new Rect(position.x + indent, y, position.width - indent, - EditorGUIUtility.singleLineHeight); - y += SpacedLineHeight(); - return r; - } - - var perEnemyProp = property.FindPropertyRelative("GoldPerEnemy"); - var completionProp = property.FindPropertyRelative("CompletionBonus"); - var noLeaksProp = property.FindPropertyRelative("NoLeaksBonus"); - - EditorGUI.PropertyField(Row(), perEnemyProp); - EditorGUI.PropertyField(Row(), completionProp); - EditorGUI.PropertyField(Row(), noLeaksProp); - - // Read values off the SerializedProperties rather than the backing object: edits - // aren't applied to the instance until ApplyModifiedProperties runs at end of frame, - // so the object would show stale numbers while the designer is still typing. - int perEnemy = perEnemyProp.intValue; - int completion = completionProp.intValue; - int noLeaks = noLeaksProp.intValue; - - var config = property.serializedObject.targetObject as GoldConfig; - int assumed = config != null ? config.PreviewEnemiesPerEncounter : 0; - - int projected = perEnemy * assumed + completion + noLeaks; - - y += PreviewLineExtraHeight; - var style = new GUIStyle(EditorStyles.miniLabel) { fontStyle = FontStyle.Italic }; - - using (new EditorGUI.DisabledScope(true)) - { - EditorGUI.LabelField( - Row(), - $"Projected: {projected} g ({perEnemy} × {assumed} enemies " + - $"+ {completion} clear + {noLeaks} no-leak)", - style); - - // Cumulative only makes sense once we know where this entry sits in the run. - if (config != null && encounterNumber > 0) - { - EditorGUI.LabelField( - Row(), - $"Cumulative by here: {config.ProjectedCumulativeThrough(encounterNumber)} g " + - $"(incl. {config.StartingGold} starting)", - style); - } - } - } - - // Recovers the 1-based run position from a path like "Encounters.Array.data[2]". - // Returns 0 when the entry isn't being drawn as an array element. - private static int EncounterNumberFrom(SerializedProperty property) - { - string path = property.propertyPath; - int open = path.LastIndexOf('['); - int close = path.LastIndexOf(']'); - if (open < 0 || close < open) return 0; - - string inner = path.Substring(open + 1, close - open - 1); - return int.TryParse(inner, out int index) ? index + 1 : 0; - } - - private static float SpacedLineHeight() - => EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - } -} diff --git a/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs.meta b/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs.meta deleted file mode 100644 index 74b7ba7..0000000 --- a/Assets/_Project/Scripts/Editor/Gameplay/EncounterGoldEntryDrawer.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 62f688cf14ba23b42bd0edd63a11ba62 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs b/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs deleted file mode 100644 index 0c08333..0000000 --- a/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs -using UnityEditor; -using UnityEngine; -using TD.Gameplay.Waves; - -namespace TD.Editor.Gameplay -{ - /// - /// Inspector for . Draws the normal fields, then a live - /// validation panel reporting whether the authored pools can actually produce a run. - /// - /// - /// The check that matters here is the distinct-enemy-type one: because enemy upgrades are - /// keyed to a wave slot, a phase must be able to fill its cycle with waves that use different - /// enemies. A pool can look healthy (plenty of entries) and still fail that. Reporting it in - /// the inspector turns a startup error into something a designer sees while authoring. - /// - [CustomEditor(typeof(RunDefinition))] - public class RunDefinitionEditor : UnityEditor.Editor - { - public override void OnInspectorGUI() - { - DrawDefaultInspector(); - - var run = (RunDefinition)target; - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Validation", EditorStyles.boldLabel); - - bool ok = run.Validate(out string report); - EditorGUILayout.HelpBox(report, ok ? MessageType.Info : MessageType.Error); - - // Per-phase capacity readout — the fastest way to see how much headroom a pool has - // before the distinct-type requirement starts biting. - if (run.Phases != null) - { - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Phase capacity", EditorStyles.boldLabel); - - for (int i = 0; i < run.Phases.Length; i++) - { - var phase = run.Phases[i]; - if (phase == null) - { - EditorGUILayout.LabelField($"Phase {i + 1}", "— empty —"); - continue; - } - - int distinct = phase.CountDistinctEnemyTypes(); - string value = $"{distinct} distinct enemy type(s) / {run.WavesPerCycle} needed"; - var style = new GUIStyle(EditorStyles.label) - { - normal = { textColor = distinct >= run.WavesPerCycle - ? EditorStyles.label.normal.textColor - : new Color(0.9f, 0.4f, 0.3f) } - }; - EditorGUILayout.LabelField(phase.Label, value, style); - } - } - - EditorGUILayout.Space(); - if (GUILayout.Button("Rebuild Wave Index")) - { - run.RebuildIndex(); - Debug.Log($"[RunDefinition] Rebuilt wave index: {run.WaveCount} distinct wave(s)."); - } - } - } -} diff --git a/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs.meta b/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs.meta deleted file mode 100644 index 2b46f6d..0000000 --- a/Assets/_Project/Scripts/Editor/Gameplay/RunDefinitionEditor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5f5e8e0197efd154b92817bbb3028b35 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs b/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs new file mode 100644 index 0000000..dff5ca8 --- /dev/null +++ b/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs @@ -0,0 +1,112 @@ +// Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs +using UnityEditor; +using UnityEngine; +using TD.Gameplay; + +namespace TD.Editor.Gameplay +{ + /// + /// Custom property drawer for . Renders the standard fields + /// followed by a read-only "Preview Total" line computed from the entry's values, so + /// designers can see at a glance how much a single player could earn from a wave. + /// + /// + /// The preview includes the kill-reward portion only when the entry's Wave + /// reference is assigned (it's needed to count enemies in that wave). When unset, the + /// preview shows just CompletionBonus + NoLeaksBonus and labels itself so the + /// designer knows to drop a WaveDefinition in for a complete number. + /// + [CustomPropertyDrawer(typeof(WaveGoldEntry))] + public class WaveGoldEntryDrawer : PropertyDrawer + { + private const float PreviewLineExtraHeight = 4f; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + // Sum the children + one extra line for the preview label. We render children + // ourselves rather than using EditorGUI.PropertyField default since we want a + // foldout with our custom preview tacked onto the end. + if (!property.isExpanded) return EditorGUIUtility.singleLineHeight; + + float h = EditorGUIUtility.singleLineHeight; // foldout + h += SpacedLineHeight() * 4; // Wave + GoldPerEnemy + Completion + NoLeaks + h += SpacedLineHeight() + PreviewLineExtraHeight; // preview label + return h; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // Foldout header. + Rect headerRect = new Rect(position.x, position.y, position.width, + EditorGUIUtility.singleLineHeight); + property.isExpanded = EditorGUI.Foldout(headerRect, property.isExpanded, label, + toggleOnLabelClick: true); + if (!property.isExpanded) return; + + float y = position.y + SpacedLineHeight(); + float indent = 14f; + Rect Row() + { + Rect r = new Rect(position.x + indent, y, position.width - indent, + EditorGUIUtility.singleLineHeight); + y += SpacedLineHeight(); + return r; + } + + // Standard property fields. + var waveProp = property.FindPropertyRelative("Wave"); + var perEnemyProp = property.FindPropertyRelative("GoldPerEnemy"); + var completionProp = property.FindPropertyRelative("CompletionBonus"); + var noLeaksProp = property.FindPropertyRelative("NoLeaksBonus"); + + EditorGUI.PropertyField(Row(), waveProp); + EditorGUI.PropertyField(Row(), perEnemyProp); + EditorGUI.PropertyField(Row(), completionProp); + EditorGUI.PropertyField(Row(), noLeaksProp); + + // Compute the preview total. We instantiate the same logic as the runtime + // property — read the serialized values, count enemies in the optional Wave, + // sum it all up. Done inline (rather than calling WaveGoldEntry.PreviewTotalGold + // directly) because SerializedProperty edits aren't applied to the target object + // until ApplyModifiedProperties runs at the end of the frame, so reading the + // backing class instance here would show stale data while the user is typing. + int perEnemy = perEnemyProp.intValue; + int completion = completionProp.intValue; + int noLeaks = noLeaksProp.intValue; + var waveAsset = waveProp.objectReferenceValue as WaveDefinition; + + int enemyCount = 0; + if (waveAsset != null && waveAsset.Entries != null) + { + foreach (var e in waveAsset.Entries) + { + if (e.EnemyType != null && e.Count > 0) + enemyCount += e.Count; + } + } + + int total = perEnemy * enemyCount + completion + noLeaks; + + // Preview line. Slightly dimmed style, italic, non-editable. Includes a + // breakdown so the designer can see where the number came from. + y += PreviewLineExtraHeight; + Rect previewRect = new Rect(position.x + indent, y, position.width - indent, + EditorGUIUtility.singleLineHeight); + + string breakdown = waveAsset != null + ? $"Preview Total: {total} g ({perEnemy} × {enemyCount} enemies " + + $"+ {completion} completion + {noLeaks} no-leak)" + : $"Preview Total: {completion + noLeaks} g (bonuses only — assign Wave " + + $"to include kill rewards)"; + + var prevStyle = new GUIStyle(EditorStyles.miniLabel) { fontStyle = FontStyle.Italic }; + using (new EditorGUI.DisabledScope(true)) + { + EditorGUI.LabelField(previewRect, breakdown, prevStyle); + } + } + + private static float SpacedLineHeight() + => EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } +} diff --git a/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs.meta b/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs.meta new file mode 100644 index 0000000..b9c6f5d --- /dev/null +++ b/Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cc17000144b098340a210921594babca \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs b/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs new file mode 100644 index 0000000..3a54012 --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs @@ -0,0 +1,61 @@ +// Assets/_Project/Scripts/Gameplay/ActiveBuff.cs +using System; +using Unity.Collections; +using Unity.Netcode; +using TD.Core; + +namespace TD.Gameplay +{ + /// + /// One buff currently held by a player. Stored in + /// 's NetworkList so all peers see the same set. + /// + /// + /// IEquatable. NGO's NetworkList indexer setter short-circuits when + /// Equals returns true, silently dropping the write. Every mutable field + /// (only ) is included in the comparison so toggling a + /// buff correctly propagates to clients. + /// + public struct ActiveBuff : INetworkSerializable, IEquatable + { + /// Which tower stat this buff multiplies. + public BuffStat Stat; + + /// Multiplicative factor, e.g. 1.25 for +25%. + public float Multiplier; + + /// + /// False when disabled (e.g. by an enemy ability). Excluded from + /// while false. + /// + public bool IsActive; + + /// Human-readable name for the HUD buff list. + public FixedString64Bytes DisplayName; + + // ----- INetworkSerializable --------------------------------------- + + public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter + { + byte statByte = (byte)Stat; + serializer.SerializeValue(ref statByte); + Stat = (BuffStat)statByte; + + serializer.SerializeValue(ref Multiplier); + serializer.SerializeValue(ref IsActive); + serializer.SerializeValue(ref DisplayName); + } + + // ----- IEquatable ------------------------------------------------- + + public bool Equals(ActiveBuff other) + => Stat == other.Stat + && Multiplier == other.Multiplier + && IsActive == other.IsActive + && DisplayName == other.DisplayName; + + public override bool Equals(object obj) => obj is ActiveBuff other && Equals(other); + + public override int GetHashCode() => HashCode.Combine((int)Stat, Multiplier, IsActive); + } +} diff --git a/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs.meta b/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs.meta new file mode 100644 index 0000000..d6868bd --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/ActiveBuff.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b09203f8acc450bf3b3c4bd8ef3fe84e \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuffCategory.cs b/Assets/_Project/Scripts/Gameplay/BuffCategory.cs new file mode 100644 index 0000000..bad6ee3 --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/BuffCategory.cs @@ -0,0 +1,23 @@ +// Assets/_Project/Scripts/Gameplay/BuffCategory.cs +using UnityEngine; + +namespace TD.Gameplay +{ + /// + /// A purchasable category of buffs. The player pays gold + /// and receives a randomly chosen from . + /// + [CreateAssetMenu(fileName = "BuffCategory", menuName = "TD/Buffs/Buff Category")] + public class BuffCategory : ScriptableObject + { + [Tooltip("Name shown on the buff menu purchase button.")] + public string DisplayName; + + [Tooltip("Gold cost to purchase one random buff from this category.")] + [Min(0)] + public int Cost; + + [Tooltip("Set of buffs the player can receive. One is chosen uniformly at random.")] + public BuffDefinition[] Pool; + } +} diff --git a/Assets/_Project/Scripts/Gameplay/BuffCategory.cs.meta b/Assets/_Project/Scripts/Gameplay/BuffCategory.cs.meta new file mode 100644 index 0000000..c2d766d --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/BuffCategory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 516e8faec948a4b3d977ec019376c438 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs new file mode 100644 index 0000000..951972e --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs @@ -0,0 +1,24 @@ +// Assets/_Project/Scripts/Gameplay/BuffDefinition.cs +using UnityEngine; +using TD.Core; + +namespace TD.Gameplay +{ + /// + /// One possible buff that can be awarded to a player. Lives in a + /// 's pool and is drawn randomly on purchase. + /// + [CreateAssetMenu(fileName = "BuffDefinition", menuName = "TD/Buffs/Buff Definition")] + public class BuffDefinition : ScriptableObject + { + [Tooltip("Name shown in the buff menu and tooltip.")] + public string DisplayName; + + [Tooltip("Which tower stat this buff multiplies.")] + public BuffStat Stat; + + [Tooltip("Multiplicative factor applied to the stat. 1.25 = +25%.")] + [Min(1f)] + public float Multiplier = 1.25f; + } +} diff --git a/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs.meta new file mode 100644 index 0000000..12b38db --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/BuffDefinition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b01f9aea62ee8a1c1991bb2a097de224 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs index 955f301..ce1e258 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs @@ -85,7 +85,6 @@ namespace TD.Gameplay // Cached reference to the local TowerPaintController, looked up lazily (same // rationale as the placement controller). private TowerPaintController cachedPaintController; - private BuilderSpellCastController cachedSpellCastController; // ----- Lifecycle -------------------------------------------------- @@ -121,7 +120,7 @@ namespace TD.Gameplay // Placement and paint are both modal: while either is active, the local // controller for that mode owns left-/right-click, so selection here yields. - bool isModal = IsLocalPlayerPlacing() || IsLocalPlayerPainting() || IsLocalPlayerAimingSpell(); + bool isModal = IsLocalPlayerPlacing() || IsLocalPlayerPainting(); Vector2 mousePos = mouse.position.ReadValue(); // UI Toolkit dispatches button click events AFTER Update runs, but raw mouse @@ -139,11 +138,10 @@ namespace TD.Gameplay // Escape: clear selection. Allowed during placement mode too — Escape never // means anything else here, and clearing selection during placement is fine. - // Suppressed while chat (or any HUD text field) has focus or the gear menu is - // open, since Escape there means "cancel typing" / "back out of the menu" and - // should not also clear the unit selection. + // Suppressed while chat (or any HUD text field) has focus, since Escape there + // means "cancel typing" and should not also clear the unit selection. if (keyboard != null && keyboard.escapeKey.wasPressedThisFrame - && !HUDController.IsUiCapturingInput) + && !HUDController.IsTextInputActive) { SelectionState.Instance?.Clear(); } @@ -152,21 +150,13 @@ namespace TD.Gameplay // controllers handle right-click as cancel there) and when over HUD. if (isModal) return; - // Tab: select the builder, or (if already selected) recenter the camera on it. - if (keyboard != null && keyboard.tabKey.wasPressedThisFrame - && !HUDController.IsUiCapturingInput) + // B: toggle buff menu. + if (keyboard != null && keyboard.bKey.wasPressedThisFrame + && !HUDController.IsTextInputActive) { - var selection = SelectionState.Instance; - if (selection != null && selection.IsSelected(builder)) - { - HUDController.Instance?.CenterCameraOnSelection(); - } - else - { - selection?.Select(builder); - } + HUDController.Instance?.ToggleBuffMenu(); } - + if (pointerOverHud) return; if (!mouse.rightButton.wasPressedThisFrame) return; @@ -287,21 +277,5 @@ namespace TD.Gameplay } return cachedPaintController.IsPainting; } - - private bool IsLocalPlayerAimingSpell() - { - if (cachedSpellCastController == null) - { - // Find lazily — controller may have been added after this component spawned. - cachedSpellCastController = - UnityEngine.Object.FindAnyObjectByType(); - if (cachedSpellCastController == null) return false; - } - // IsAiming covers "aiming, click not yet made"; ConsumedCastClickThisFrame covers the - // frame the confirming click casts and exits aim mode — together they suppress the - // selection click regardless of Update order between the two controllers. - return cachedSpellCastController.IsAiming - || cachedSpellCastController.ConsumedCastClickThisFrame; - } } } \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs deleted file mode 100644 index 557fe3d..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs +++ /dev/null @@ -1,265 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs -using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.Rendering.Universal; -using TD.Core; -using TD.UI; -using TD.Gameplay.BuilderSpells; - -namespace TD.Gameplay -{ - /// - /// Per-client controller for the builder-spell casting UX. Watches - /// to enter aim mode, raycasts against a broad ground layer - /// (must cover the enemy path, not just buildable tiles), previews the aim point, and - /// dispatches the cast to via RPC on confirm. - /// - /// - /// Plain MonoBehaviour. Aiming visuals are purely cosmetic and local, same - /// rationale as . All server-authoritative - /// resolution lives in . - /// - /// Point vs. area preview. shows a - /// small fixed-size reticle, even if the spell has an internal splash radius. - /// scales the same decal to the spell's - /// , mirroring 's - /// diameter-sizing idiom. - /// - /// Single-shot only. Unlike tower placement, there is no chained/shift-held - /// casting — one keypress aims one cast. - /// - public class BuilderSpellCastController : MonoBehaviour - { - // ----- Inspector -------------------------------------------------- - - [Tooltip("Physics layer(s) the aim raycast hits. Must cover the whole level's ground " + - "(including over the enemy path), not just buildable tiles — set this to " + - "'TerrainGeometry', not 'BuildablePlane'.")] - [SerializeField] private LayerMask groundLayerMask; - - [Tooltip("Maximum raycast distance from the camera to the ground.")] - [SerializeField] private float raycastMaxDistance = 500f; - - [Tooltip("Ground decal used for both the point reticle and the area-of-effect " + - "radius preview. Auto-found in children if empty.")] - [SerializeField] private DecalProjector aimDecal; - - [Tooltip("Fixed diameter of the reticle shown for PointTarget spells, regardless of " + - "any internal splash radius the spell may use server-side.")] - [SerializeField] private float pointReticleDiameter = 1.5f; - - [Tooltip("Vertical thickness of the decal projector's projection volume. Should " + - "exceed the map's vertical range so it projects onto terrain at any height.")] - [SerializeField] private float projectionDepth = 50f; - - // ----- Active-aim state --------------------------------------------- - - // -1 when not aiming. - private int activeSlot = -1; - - // Frame on which the confirming cast click was consumed. Lets the selection controller - // ignore that click order-independently — see ConsumedCastClickThisFrame. - private int lastCastClickFrame = -1; - - /// True while a spell is being aimed (awaiting the confirming click). The - /// selection input controller treats this as a modal state, so the click that confirms - /// the cast doesn't also fall through to selection and deselect the builder. - public bool IsAiming => activeSlot >= 0; - - /// True during the frame the confirming cast click was consumed. Aim mode exits - /// the same frame the cast is submitted, flipping false; this stays - /// true for the rest of that frame so the selection controller ignores the click no matter - /// which controller's Update ran first. - public bool ConsumedCastClickThisFrame => lastCastClickFrame == Time.frameCount; - private BuilderSpellDefinition activeDefinition; - - private bool lastHitValid; - private Vector3 lastHitPoint; - - // ----- Lifecycle ---------------------------------------------------- - - private void Awake() - { - if (aimDecal == null) aimDecal = GetComponentInChildren(); - if (aimDecal != null) - { - aimDecal.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); - aimDecal.enabled = false; - } - } - - private void OnDisable() - { - ExitAimMode(); - } - - private void Update() - { - if (!HUDController.IsUiCapturingInput) - ScanHotkeys(); - - if (activeSlot < 0) return; // idle — nothing to aim - - // Deselecting the builder mid-aim cancels the cast, so you can't start aiming while - // selected and then deselect to sneak a cast past the gate above. - if (!LocalBuilderSelected()) - { - ExitAimMode(); - return; - } - - var keyboard = Keyboard.current; - if (keyboard != null && keyboard.escapeKey.wasPressedThisFrame) - { - ExitAimMode(); - return; - } - - var mouse = Mouse.current; - if (mouse == null) return; - - if (mouse.rightButton.wasPressedThisFrame) - { - ExitAimMode(); - return; - } - - if (TryGetGroundHit(mouse.position.ReadValue(), out Vector3 hitPoint)) - { - lastHitValid = true; - lastHitPoint = hitPoint; - ShowAimDecal(hitPoint); - } - else - { - lastHitValid = false; - HideAimDecal(); - } - - if (mouse.leftButton.wasPressedThisFrame && lastHitValid) - { - // Record the frame so the selection controller ignores this click even though - // TrySubmitCast exits aim mode this same frame (IsAiming flips false). Without - // this, whether the click also deselected the builder depended on Update order. - lastCastClickFrame = Time.frameCount; - TrySubmitCast(); - } - } - - // ----- Hotkey scan -------------------------------------------------- - - // True when the local player's own builder is the current selection. Casting is gated - // on this so it matches the spell HUD (shown only for the selected builder). - private static bool LocalBuilderSelected() - { - var selected = SelectionState.Instance?.SelectedObject; - return selected is Builder builder && builder.IsOwner; - } - - private void ScanHotkeys() - { - if (activeSlot >= 0) return; // already aiming — hotkeys re-scanned only when idle - - // Spells cast only while the local player's OWN builder is selected — keeps casting - // in sync with the spell HUD, which is shown only for the selected builder. - if (!LocalBuilderSelected()) return; - - var loadout = PlayerSpellLoadout.Local; - if (loadout == null) return; - - var keyboard = Keyboard.current; - if (keyboard == null) return; - - var layout = SpellHotkeys.Layout; - int slotCount = Mathf.Min(loadout.SlotCount, layout.Length); - - for (int i = 0; i < slotCount; i++) - { - if (!keyboard[layout[i]].wasPressedThisFrame) continue; - if (loadout.IsSlotOnCooldown(i)) continue; - - BeginAiming(i, loadout); - break; - } - } - - private void BeginAiming(int slot, PlayerSpellLoadout loadout) - { - var kind = loadout.GetKind(slot); - if (kind == null) return; - - var definition = BuilderSpellPool.Instance?.Get(kind.Value); - if (definition == null) - { - Debug.LogWarning($"[BuilderSpellCastController] No BuilderSpellDefinition for {kind.Value}."); - return; - } - - activeSlot = slot; - activeDefinition = definition; - lastHitValid = false; - } - - private void ExitAimMode() - { - activeSlot = -1; - activeDefinition = null; - lastHitValid = false; - HideAimDecal(); - } - - // ----- Raycasting --------------------------------------------------- - - private bool TryGetGroundHit(Vector2 screenPos, out Vector3 hitPoint) - { - hitPoint = Vector3.zero; - - var cam = Camera.main; - if (cam == null) return false; - - Ray ray = cam.ScreenPointToRay(new Vector3(screenPos.x, screenPos.y, 0f)); - if (Physics.Raycast(ray, out RaycastHit hit, raycastMaxDistance, groundLayerMask)) - { - hitPoint = hit.point; - return true; - } - return false; - } - - // ----- Aim decal ----------------------------------------------------- - - private void ShowAimDecal(Vector3 point) - { - if (aimDecal == null) return; - - float diameter = activeDefinition.TargetType == SpellTargetType.AreaOfEffect - ? activeDefinition.Radius * 2f - : pointReticleDiameter; - - aimDecal.size = new Vector3(diameter, diameter, projectionDepth); - aimDecal.pivot = Vector3.zero; - aimDecal.transform.position = point; - aimDecal.enabled = true; - } - - private void HideAimDecal() - { - if (aimDecal != null) aimDecal.enabled = false; - } - - // ----- Cast submission ------------------------------------------------ - - private void TrySubmitCast() - { - var loadout = PlayerSpellLoadout.Local; - if (loadout == null) - { - ExitAimMode(); - return; - } - - loadout.RequestCastSpellRpc(activeSlot, lastHitPoint); - ExitAimMode(); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs.meta deleted file mode 100644 index ffe509e..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: cc99a2b3d3e8d8178a74e1d68a34553c \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells.meta deleted file mode 100644 index fb42554..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7f64edca739cf31bfbdf58e2403b4a74 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs deleted file mode 100644 index 2bf7c9e..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Base class for one builder spell — a player-cast, key-triggered ability (e.g. "drop a - /// fireball on a point", "slow enemies in a radius"). Granted via the draft () and tracked per-player by , which owns the hotkey slot and cooldown state. - /// - /// - /// Contrast with . Effects - /// are passive and queried by consumers; spells are active and resolve themselves. - /// is that resolution — it IS the "apply the effect" method, - /// replacing the effect system's IsValidFor-only gate pattern (grant-time validity - /// still lives on ). - /// - /// One asset per kind. is fixed per subclass, same as - /// . uses - /// it to build a fixed-size, enum-indexed lookup table. - /// - /// Server-only resolution, client-only visual. runs on - /// the server and applies damage/status via the same Physics.OverlapSphereNonAlloc + - /// EnemyHealth/EnemyStatus pattern TowerCombat already uses. - /// Presentation is split into (on cast) and - /// (on contact, seconds later for a - /// projectile spell), both running on every peer including the server. - /// - public abstract class BuilderSpellDefinition : ScriptableObject - { - /// Which builder spell this asset's data belongs to. - public abstract BuilderSpellKind Kind { get; } - - [Header("Presentation")] - [Tooltip("Name shown on the draft card and the cast hotbar.")] - public string DisplayName; - - [Tooltip("Short description shown on the draft card.")] - [TextArea(2, 4)] - public string Description; - - [Tooltip("Icon shown on the draft card and the cast hotbar.")] - public Sprite Icon; - - [Header("Casting")] - [Tooltip("Seconds before this spell can be cast again after a successful cast.")] - [Min(0f)] - public float Cooldown = 5f; - - [Tooltip("How the cast controller aims this spell. AreaOfEffect previews Radius as a " + - "decal while aiming; PointTarget does not, even if Radius is used internally " + - "(e.g. a splash radius).")] - public SpellTargetType TargetType; - - [Tooltip("AreaOfEffect: the resolution radius AND the client-side preview size. " + - "PointTarget: optional internal-only radius (e.g. splash) with no preview.")] - [Min(0f)] - public float Radius; - - [Tooltip("Physics layer(s) enemies occupy, queried by this spell's own OverlapSphere " + - "call. Each spell asset authors its own mask — same convention as " + - "TowerCombat/Projectile's per-instance enemyLayerMask.")] - [SerializeField] - protected LayerMask enemyLayerMask; - - // Shared scratch buffer for OverlapSphereNonAlloc queries. The server processes casts - // sequentially (one RPC handler at a time), so a static buffer shared across all spell - // assets is safe — mirrors TowerCombat.s_overlapBuffer, but sized larger (64 vs. 32): - // OverlapSphereNonAlloc silently truncates past the buffer length with no way to - // detect the truncation, and spells are more likely than a single tower's splash/chain - // radius to catch a dense horde. TowerCombat's buffer is intentionally left at 32 — - // out of scope here, flagged separately for the team to revisit. - protected static readonly Collider[] s_overlapBuffer = new Collider[64]; - - /// - /// Server-only: resolve this spell's effect at for the - /// casting player. Returns false if the cast could not be applied (e.g. hit nothing) — - /// treats a false return as a no-op and does not start - /// the cooldown. - /// - public abstract bool ServerCast(ulong clientId, Vector3 targetPoint); - - /// - /// Seconds between the cast and the effect landing. 0 = instant: damage and the impact - /// sound resolve immediately on cast. A projectile-style spell (e.g. the Fireball meteor) - /// overrides this with its fall/travel time, so spawns the - /// visual on cast but holds (damage) and - /// (sound) until the projectile reaches the ground. Set it to match the VFX's fall time. - /// - public virtual float ImpactDelay => 0f; - - /// - /// Runs on every peer (via 's ClientRpc) the moment the - /// spell is cast. Spawns the visual: for an instant spell that's the whole effect; for a - /// delayed spell it's the projectile/travel visual that lands after . - /// Default no-op. - /// - public virtual void ClientSpawnVfx(Vector3 targetPoint) { } - - /// - /// Runs on every peer when the spell makes contact — immediately for an instant spell, or - /// seconds after cast for a delayed one. Play the impact sound - /// (and any impact-moment visual) here so it lands with the effect, not the throw. - /// Default no-op. - /// - public virtual void ClientPlayImpact(Vector3 targetPoint) { } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs.meta deleted file mode 100644 index 57deb3e..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9fca3191d98aa2652a9c5475d5c6b153 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs deleted file mode 100644 index 1327be9..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs -using System; -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Scene singleton holding every available this match, - /// authored as a flat array in the inspector for convenience. Internally it builds a - /// fixed-size table indexed by so lookups are a single array - /// access, not a scan. - /// - /// - /// Plain MonoBehaviour: identical on every peer (same assets), so there is nothing to sync. - /// The server reads it to resolve casts; clients read it to resolve / and to render the cast hotbar. Mirrors - /// exactly. - /// - public class BuilderSpellPool : MonoBehaviour - { - public static BuilderSpellPool Instance { get; private set; } - - [Tooltip("Every BuilderSpellDefinition asset available this match. One entry per " + - "BuilderSpellKind — order doesn't matter, Kind on the asset itself decides " + - "its slot.")] - [SerializeField] private BuilderSpellDefinition[] spells; - - // Fixed-size, enum-indexed lookup built once in Awake. Sized to the enum's entry count, - // not authored count, so an out-of-range Kind is a compile-time impossibility rather - // than a bounds check we'd otherwise need on every Get(). - private BuilderSpellDefinition[] byKind; - - private void Awake() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[BuilderSpellPool] Multiple instances detected. Only one per scene."); - return; - } - Instance = this; - - int kindCount = Enum.GetValues(typeof(BuilderSpellKind)).Length; - byKind = new BuilderSpellDefinition[kindCount]; - if (spells == null) return; - - for (int i = 0; i < spells.Length; i++) - { - var def = spells[i]; - if (def == null) continue; - byKind[(int)def.Kind] = def; - } - } - - private void OnDestroy() - { - if (Instance == this) Instance = null; - } - - /// Returns the spell asset for , or null if none is - /// authored in this pool. - public BuilderSpellDefinition Get(BuilderSpellKind kind) - { - int i = (int)kind; - return (byKind != null && i >= 0 && i < byKind.Length) ? byKind[i] : null; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs.meta deleted file mode 100644 index 52803c7..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 36a7be1b3824682b8a183fbcf8564652 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs deleted file mode 100644 index b4917ca..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs -using UnityEngine; -using TD.Audio; -using TD.Core; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Builder spell #1 — drop a fireball on a point, dealing direct damage to whatever's - /// there plus splash damage to nearby enemies. - /// - /// - /// is - /// — the cast controller shows only a fixed-size reticule, even though - /// is still used internally here as the splash - /// radius (0 = no splash, direct hit only). - /// - [CreateAssetMenu(fileName = "FireballSpell", menuName = "TD/Builder Spells/Fireball")] - public class FireballSpellDefinition : BuilderSpellDefinition - { - public override BuilderSpellKind Kind => BuilderSpellKind.Fireball; - - [Header("Impact VFX")] - [Tooltip("Prefab spawned at the target point on a successful cast. Optional — leave empty for no visual.")] - [SerializeField] private GameObject impactVfxPrefab; - - [Tooltip("Seconds before the spawned VFX instance is destroyed.")] - [Min(0f)] - [SerializeField] private float impactVfxLifetime = 2f; - - [Tooltip("Seconds from cast until the falling fireball reaches the ground. Damage and the " + - "impact sound are held until then so they land with the visual — SET THIS TO MATCH " + - "the meteor VFX's fall time. 0 = everything resolves instantly on cast.")] - [Min(0f)] - [SerializeField] private float impactDelay = 0.8f; - - public override float ImpactDelay => impactDelay; - - [Header("Impact Sound")] - [Tooltip("Sound played on every peer when this spell resolves successfully. Same " + - "SoundConfig struct TowerBuiltSound uses — reuse a tower's clip directly if " + - "you want the same sound.")] - [SerializeField] private SoundConfig impactSound; - - [Header("Fireball")] - [Tooltip("Damage dealt to every enemy within Radius of the target point.")] - [Min(0f)] - public float Damage = 50f; - - public override bool ServerCast(ulong clientId, Vector3 targetPoint) - { - PlayerSlot owner = PlayerMatchState.SlotForClient(clientId); - - int count = Physics.OverlapSphereNonAlloc( - targetPoint, Mathf.Max(Radius, 0.01f), s_overlapBuffer, enemyLayerMask); - - bool hitAny = false; - for (int i = 0; i < count; i++) - { - var enemyHealth = s_overlapBuffer[i].GetComponent(); - if (enemyHealth == null || enemyHealth.IsDead) continue; - - enemyHealth.TakeDamage(Damage, DamageType.Fire, owner); - hitAny = true; - } - - return hitAny; - } - - public override void ClientSpawnVfx(Vector3 targetPoint) - { - // The meteor VFX plays its full fall-and-crash animation from here; it reaches the - // ground after ImpactDelay, which is when ClientPlayImpact and ServerCast fire. - if (impactVfxPrefab != null) - Destroy(Instantiate(impactVfxPrefab, targetPoint, Quaternion.identity), impactVfxLifetime); - } - - public override void ClientPlayImpact(Vector3 targetPoint) - { - if (impactSound.clip != null) - AudioManager.Instance?.Play(impactSound.clip, AudioCategory.Combat, - impactSound.RandomPitch(), impactSound.volume); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs.meta deleted file mode 100644 index 0871524..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 22b36bfcd0ae4af4098d908138e874e1 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs deleted file mode 100644 index 4885848..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs -using UnityEngine; -using TD.Audio; -using TD.Core; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Builder spell #2 — slow every enemy within an area for a duration. - /// - /// - /// is - /// — the cast controller previews as a decal - /// while aiming, and this spell resolves against that same radius (no separate field). - /// Reuses the existing slow/DoT system () rather than - /// introducing a new status mechanism. - /// - /// The cast spawns a that lingers for - /// and keeps re-applying the slow to anything standing in - /// the radius, so enemies walking through the area get slowed rather than only whatever - /// happened to be standing there at the exact instant of cast. - /// - /// - [CreateAssetMenu(fileName = "SlowAreaSpell", menuName = "TD/Builder Spells/Slow Area")] - public class SlowAreaSpellDefinition : BuilderSpellDefinition - { - public override BuilderSpellKind Kind => BuilderSpellKind.SlowArea; - - [Header("Area VFX")] - [Tooltip("Prefab spawned at the target point on a successful cast, authored at a 1-unit " + - "radius — scaled up to match Radius here. Lives for EffectDuration, matching " + - "how long the slow itself lasts. Optional — leave empty for no visual.")] - [SerializeField] private GameObject areaVfxPrefab; - - [Tooltip("Sound played on every peer when this spell resolves successfully.")] - [SerializeField] private SoundConfig areaSound; - - [Header("Slow Area")] - [Tooltip("Speed multiplier applied to affected enemies for EffectDuration " + - "(e.g. 0.5 = half speed).")] - [Range(0f, 1f)] - public float SlowFactor = 0.5f; - - [Tooltip("Seconds the slow lasts on an affected enemy, and how long the area itself " + - "lingers, re-slowing anything that walks through it. Re-casting on an " + - "already-slowed enemy refreshes it.")] - [Min(0f)] - public float EffectDuration = 3f; - - public override bool ServerCast(ulong clientId, Vector3 targetPoint) - { - PlayerSlot owner = PlayerMatchState.SlotForClient(clientId); - - SlowAreaZone.Spawn(targetPoint, Mathf.Max(Radius, 0.01f), SlowFactor, - EffectDuration, enemyLayerMask, owner); - - return true; - } - - public override void ClientSpawnVfx(Vector3 targetPoint) - { - if (areaVfxPrefab != null) - { - var instance = Instantiate(areaVfxPrefab, targetPoint, Quaternion.identity); - instance.transform.localScale *= Mathf.Max(Radius, 0.01f); - Destroy(instance, EffectDuration); - } - } - - public override void ClientPlayImpact(Vector3 targetPoint) - { - // Instant spell (ImpactDelay = 0), so this fires on cast alongside ClientSpawnVfx. - if (areaSound.clip != null) - AudioManager.Instance?.Play(areaSound.clip, AudioCategory.Combat, - areaSound.RandomPitch(), areaSound.volume); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs.meta deleted file mode 100644 index 1ba03fa..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 249c65067c3bac80693255e594d844c7 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs deleted file mode 100644 index dd339f7..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs - -using TD.Core; -using UnityEngine; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Draft upgrade for — identical behavior, just a - /// distinct so can replace the base spell - /// with this one in the player's loadout. All fields (SlowFactor, EffectDuration, etc.) - /// are inherited; author this asset with a longer EffectDuration than the base spell. - /// - [CreateAssetMenu(fileName = "SlowAreaUpgradedSpell", - menuName = "TD/Builder Spells/Slow Area (Upgraded)")] - public class SlowAreaUpgradedSpellDefinition : SlowAreaSpellDefinition - { - public override BuilderSpellKind Kind => BuilderSpellKind.SlowAreaUpgraded; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs.meta deleted file mode 100644 index af8991f..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaUpgradedSpellDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 37cc60a4a6e53e24cb6d1c0be310868a \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs deleted file mode 100644 index de1c76a..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.BuilderSpells -{ - /// - /// Server-only, non-networked lingering area spawned by - /// . Re-scans its radius on an - /// interval for its lifetime and keeps refreshing the slow on anything standing - /// inside, so enemies get slowed as they walk through rather than only at the - /// instant of cast. - /// - /// - /// Never spawned as a — it runs - /// server-side only, and the slow it applies already reaches clients through - /// 's own NetworkVariable, the same as an instant hit. - /// - public class SlowAreaZone : MonoBehaviour - { - private const float TickInterval = 0.2f; - - private float radius; - private float slowFactor; - private float effectDuration; - private LayerMask enemyLayerMask; - private PlayerSlot owner; - - private readonly Collider[] overlapBuffer = new Collider[64]; - private float tickTimer; - - public static SlowAreaZone Spawn(Vector3 position, float radius, float slowFactor, - float effectDuration, LayerMask enemyLayerMask, PlayerSlot owner) - { - var zoneObject = new GameObject("SlowAreaZone (Server)"); - zoneObject.transform.position = position; - - var zone = zoneObject.AddComponent(); - zone.radius = radius; - zone.slowFactor = slowFactor; - zone.effectDuration = effectDuration; - zone.enemyLayerMask = enemyLayerMask; - zone.owner = owner; - zone.ApplyToOverlapping(); - - Destroy(zoneObject, effectDuration); - return zone; - } - - private void Update() - { - tickTimer -= Time.deltaTime; - if (tickTimer > 0f) return; - - ApplyToOverlapping(); - } - - private void ApplyToOverlapping() - { - tickTimer = TickInterval; - - int count = Physics.OverlapSphereNonAlloc( - transform.position, radius, overlapBuffer, enemyLayerMask); - - for (int i = 0; i < count; i++) - { - var enemyHealth = overlapBuffer[i].GetComponent(); - if (enemyHealth == null || enemyHealth.IsDead) continue; - - var enemyStatus = overlapBuffer[i].GetComponent(); - if (enemyStatus == null) continue; - - enemyStatus.ApplyEffect(DamageType.Cold, slowFactor, effectDuration, owner); - } - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs.meta b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs.meta deleted file mode 100644 index 7c880a9..0000000 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7b00a1f57e8be13cd91c0ed5f515bfc8 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderUpgradeManager.cs b/Assets/_Project/Scripts/Gameplay/BuilderUpgradeManager.cs index 6b81aea..5f07d31 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderUpgradeManager.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderUpgradeManager.cs @@ -9,7 +9,8 @@ namespace TD.Gameplay { /// /// Per-player set of granted builder effects. Lives on the Player prefab alongside - /// and . + /// , , and + /// . /// /// /// List of granted kinds. A builder effect carries no per-grant state (no @@ -20,9 +21,8 @@ namespace TD.Gameplay /// same constraint on a struct); byte already does, for free. /// /// Granted via draft. - /// calls when a player picks it. Effects are otherwise - /// permanent for the match — the only way one leaves the granted set is - /// swapping it for its upgraded replacement. + /// calls when a player picks it. Effects are permanent for + /// the match — there is no revoke. /// /// Query, don't snapshot. Consumers (e.g. awarding /// kill gold) query this manager live at the point of use rather than towers caching their @@ -118,24 +118,5 @@ namespace TD.Gameplay grantedKinds.Add(value); return true; } - - /// - /// Server-only: replaces a previously granted effect with a different one (an upgrade - /// pick). No-op if the old effect isn't currently granted or the new one already is. - /// Returns true if the swap happened. - /// - public bool ServerUpgradeEffect(BuilderEffectKind oldKind, BuilderEffectKind newKind) - { - if (!IsServer) return false; - - byte newValue = (byte)newKind; - if (grantedKinds.Contains(newValue)) return false; - - byte oldValue = (byte)oldKind; - if (!grantedKinds.Remove(oldValue)) return false; - - grantedKinds.Add(newValue); - return true; - } } } diff --git a/Assets/_Project/Scripts/Gameplay/CameraController.cs b/Assets/_Project/Scripts/Gameplay/CameraController.cs index 4a2009a..b80f33e 100644 --- a/Assets/_Project/Scripts/Gameplay/CameraController.cs +++ b/Assets/_Project/Scripts/Gameplay/CameraController.cs @@ -227,18 +227,16 @@ namespace TD.Gameplay { Vector2 dir = Vector2.zero; - // Keyboard: arrow keys only. WASD is reserved for tower-build hotkeys (the command - // grid) — camera panning is arrow keys plus the mouse edge-pan below. Suppressed - // entirely while the player is typing (so arrow keys in chat navigate text instead - // of panning) or while the gear menu is open. Edge-pan below is mouse-driven and - // gated separately by the pointer-over-HUD check, which the menu overlay satisfies. - var kb = HUDController.IsUiCapturingInput ? null : Keyboard.current; + // Keyboard: WASD + arrow keys. Suppressed entirely while the player + // is typing — pressing 'a' or 'w' into chat should not pan the camera. + // (Edge-pan below stays active since it's mouse-driven.) + var kb = HUDController.IsTextInputActive ? null : Keyboard.current; if (kb != null) { - if (kb.leftArrowKey.isPressed) dir.x -= 1f; - if (kb.rightArrowKey.isPressed) dir.x += 1f; - if (kb.downArrowKey.isPressed) dir.y -= 1f; - if (kb.upArrowKey.isPressed) dir.y += 1f; + if (kb.aKey.isPressed || kb.leftArrowKey.isPressed) dir.x -= 1f; + if (kb.dKey.isPressed || kb.rightArrowKey.isPressed) dir.x += 1f; + if (kb.sKey.isPressed || kb.downArrowKey.isPressed) dir.y -= 1f; + if (kb.wKey.isPressed || kb.upArrowKey.isPressed) dir.y += 1f; } // Edge-pan: mouse near screen edge adds to keyboard direction. diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs deleted file mode 100644 index 46022b5..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs -using UnityEngine; -using TD.Core; -using TD.Gameplay.BuilderEffects; - -namespace TD.Gameplay.Draft -{ - /// - /// Draft choice — "upgrade a builder effect you already have". Replaces - /// with in the player's - /// . - /// - /// - /// Mirrors , but swaps rather than adds. Only offered - /// while the player currently has granted — once taken, - /// is removed, which automatically makes this option (and any sibling - /// upgrade branching off the same base) invalid for future drafts. - /// - [CreateAssetMenu(fileName = "BuilderEffectUpgradeOption", - menuName = "TD/Draft/Builder Effect Upgrade Option")] - public class BuilderEffectUpgradeDraftOption : DraftOption - { - [Header("Payload")] - [Tooltip("The builder effect this option upgrades from.")] - public BuilderEffectKind BaseKind; - - [Tooltip("The builder effect this option upgrades to.")] - public BuilderEffectKind UpgradedKind; - - public override bool IsValidFor(ulong clientId) - { - var upgrades = BuilderUpgradeManager.GetForClient(clientId); - return upgrades != null && upgrades.PlayerHasEffect(BaseKind); - } - - public override bool ServerApply(ulong clientId) - { - var upgrades = BuilderUpgradeManager.GetForClient(clientId); - return upgrades != null && upgrades.ServerUpgradeEffect(BaseKind, UpgradedKind); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs.meta b/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs.meta deleted file mode 100644 index 393a4c1..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderEffectUpgradeDraftOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 717648113e8090fc6856744d898ab375 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs deleted file mode 100644 index 360a566..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs -using UnityEngine; -using TD.Core; -using TD.Gameplay.BuilderSpells; - -namespace TD.Gameplay.Draft -{ - /// - /// Draft choice — "gain a builder spell". Grants the player a key-triggered active ability, - /// adding it to their . - /// - /// - /// Mirrors : carries the - /// directly rather than an asset reference, since the enum value is the stable identifier - /// and already key off of. - /// also checks slot capacity — once - /// is reached, no further spell options are - /// offered. Gates on rather than - /// current possession, so a base spell already upgraded past (see - /// ) is never re-offered. - /// - [CreateAssetMenu(fileName = "BuilderSpellOption", menuName = "TD/Draft/Builder Spell Option")] - public class BuilderSpellDraftOption : DraftOption - { - [Header("Payload")] - [Tooltip("The builder spell this option grants.")] - public BuilderSpellKind Kind; - - public override bool IsValidFor(ulong clientId) - { - var loadout = PlayerSpellLoadout.GetForClient(clientId); - if (loadout == null) return false; - if (loadout.SlotCount >= PlayerSpellLoadout.MaxSpellSlots) return false; - return !loadout.PlayerHasEverGranted(Kind); - } - - public override bool ServerApply(ulong clientId) - { - var loadout = PlayerSpellLoadout.GetForClient(clientId); - return loadout != null && loadout.ServerGrantSpell(Kind); - } - - /// Inherits the granted spell's icon (resolved from the pool by - /// ) unless this option assigns an override. - public override Sprite ResolveIcon() - { - if (Icon != null) return Icon; - var def = BuilderSpellPool.Instance != null ? BuilderSpellPool.Instance.Get(Kind) : null; - return def != null ? def.Icon : null; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs.meta b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs.meta deleted file mode 100644 index a45da95..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a574e8aa74d8787f2b949300932af485 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs deleted file mode 100644 index a9d56bd..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs -using UnityEngine; -using TD.Core; -using TD.Gameplay.BuilderSpells; - -namespace TD.Gameplay.Draft -{ - /// - /// Draft choice — "upgrade a builder spell you already have". Replaces - /// with in the player's - /// , in place — the upgraded spell keeps the same hotkey - /// slot the base spell occupied. - /// - /// - /// Mirrors , but swaps rather than adds (so it doesn't - /// consume a slot). Only offered while the player currently has - /// granted — once taken, is removed, which automatically makes this - /// option (and any sibling upgrade branching off the same base) invalid for future drafts. - /// - [CreateAssetMenu(fileName = "BuilderSpellUpgradeOption", - menuName = "TD/Draft/Builder Spell Upgrade Option")] - public class BuilderSpellUpgradeDraftOption : DraftOption - { - [Header("Payload")] - [Tooltip("The builder spell this option upgrades from.")] - public BuilderSpellKind BaseKind; - - [Tooltip("The builder spell this option upgrades to.")] - public BuilderSpellKind UpgradedKind; - - public override bool IsValidFor(ulong clientId) - { - var loadout = PlayerSpellLoadout.GetForClient(clientId); - return loadout != null && loadout.PlayerHasSpell(BaseKind); - } - - public override bool ServerApply(ulong clientId) - { - var loadout = PlayerSpellLoadout.GetForClient(clientId); - return loadout != null && loadout.ServerUpgradeSpell(BaseKind, UpgradedKind); - } - - /// Inherits the upgraded spell's icon (resolved from the pool by - /// ) unless this option assigns an override. - public override Sprite ResolveIcon() - { - if (Icon != null) return Icon; - var def = BuilderSpellPool.Instance != null ? BuilderSpellPool.Instance.Get(UpgradedKind) : null; - return def != null ? def.Icon : null; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs.meta b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs.meta deleted file mode 100644 index 2d6304f..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellUpgradeDraftOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7b1c5b562f39c72eea3bafd0165af078 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs index c098caf..8ae8e94 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs @@ -34,19 +34,9 @@ namespace TD.Gameplay.Draft [TextArea(2, 4)] public string Description; - [Tooltip("OPTIONAL override for the draft card icon. Leave empty to inherit the icon of " + - "the item this option grants (its tower / spell); assign one only when you want " + - "to override that inherited icon.")] + [Tooltip("Icon shown on the draft card. Optional for placeholder content.")] public Sprite Icon; - /// - /// The icon actually shown on the draft card. Returns the explicit - /// override when one is assigned; otherwise subclasses fall back to the icon of the item - /// they grant (tower, spell). The base class has no referenced item, so it just returns - /// (which may be null). - /// - public virtual Sprite ResolveIcon() => Icon; - [Header("Generation")] [Tooltip("Relative draw weight. Higher = offered more often. Rarer rewards use " + "lower weights. Must be > 0.")] diff --git a/Assets/_Project/Scripts/Gameplay/Draft/DraftService.cs b/Assets/_Project/Scripts/Gameplay/Draft/DraftService.cs index f95a423..3b9ea5f 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/DraftService.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/DraftService.cs @@ -82,7 +82,7 @@ namespace TD.Gameplay.Draft draft.ServerOffer(resultScratch); } - /// Server-only: auto-resolve any unpicked drafts (called when the timer expires). + /// Server-only: auto-resolve any unpicked drafts (called at prep end). public void ServerAutoResolveAll() { if (!IsServer) return; @@ -90,29 +90,6 @@ namespace TD.Gameplay.Draft PlayerDraft.GetForClient(pms.OwnerClientId)?.ServerAutoResolve(); } - /// - /// True once every connected player has resolved their draft. The inter-wave step polls - /// this to end the draft timer early instead of making everyone wait out the clock. - /// - /// - /// Returns false when nobody is connected, so an empty lobby can't trip the barrier and - /// race the sequence forward. - /// - public static bool AllPlayersPicked - { - get - { - bool any = false; - foreach (var pms in PlayerMatchState.AllPlayers) - { - any = true; - var draft = PlayerDraft.GetForClient(pms.OwnerClientId); - if (draft != null && draft.HasActiveDraft) return false; - } - return any; - } - } - // ----- Generation ------------------------------------------------- // Weighted random draw WITHOUT replacement: picks `count` distinct option ids from diff --git a/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs index e7af9f6..aab2a98 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs @@ -48,9 +48,5 @@ namespace TD.Gameplay.Draft return deck.ServerGrantTower(typeId); } - - /// Inherits the granted tower's icon unless this option assigns an override. - public override Sprite ResolveIcon() - => Icon != null ? Icon : (Tower != null ? Tower.Icon : null); } } diff --git a/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs b/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs index 1ac355b..41a7c04 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs @@ -18,10 +18,7 @@ namespace TD.Gameplay.Draft /// Authority. The server offers (), resolves /// ( / ), and applies the /// chosen option. The owning client only sends intent via - /// . - /// - /// The paid reroll is disabled for the 2.0 MVP — see the commented-out block at - /// the bottom of this file for why it was kept rather than removed. + /// and . /// /// Generation lives in ; this component is just /// the replicated state + the pick/buy entry points. @@ -146,38 +143,25 @@ namespace TD.Gameplay.Draft ServerResolve(optionId); } - // ----- Extra-draft shop (DISABLED for the 2.0 MVP) -------------------- - // - // Kept rather than deleted: the shop is expected back, but as a SHARED gold sink — the - // whole lobby pools money toward one collective extra draft for everyone — rather than - // the per-player reroll implemented here. When it returns, this method is the wrong shape - // (per-player deduction, per-player offer) but the surrounding plumbing is right, so it - // stays as the reference for what to rebuild against. - // - // Re-enabling this alone would also break the inter-wave barrier: DraftService. - // AllPlayersPicked ends the draft stage the moment everyone has resolved, so a player - // buying a roll after that point would be offered cards the sequence has already moved - // past. - // - // /// - // /// Owning client: buy a fresh roll of options for gold. Rejected if the player can't - // /// afford it or already has an unresolved draft (resolve the current one first so a - // /// free pick is never silently overwritten). - // /// - // [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] - // public void RequestBuyRerollRpc() - // { - // if (HasActiveDraft) return; // resolve the pending draft before buying another - // - // var service = DraftService.Instance; - // if (service == null) return; - // - // var gold = PlayerGoldManager.GetForClient(OwnerClientId); - // int cost = service.RerollCost; - // if (gold == null || gold.CurrentGold < cost) return; - // - // gold.DeductGold(cost); - // service.ServerOfferTo(OwnerClientId); - // } + /// + /// Owning client: buy a fresh roll of options for gold. Rejected if the player can't + /// afford it or already has an unresolved draft (resolve the current one first so a + /// free pick is never silently overwritten). + /// + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] + public void RequestBuyRerollRpc() + { + if (HasActiveDraft) return; // resolve the pending draft before buying another + + var service = DraftService.Instance; + if (service == null) return; + + var gold = PlayerGoldManager.GetForClient(OwnerClientId); + int cost = service.RerollCost; + if (gold == null || gold.CurrentGold < cost) return; + + gold.DeductGold(cost); + service.ServerOfferTo(OwnerClientId); + } } } diff --git a/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs deleted file mode 100644 index 841d627..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs -using UnityEngine; -using TD.Towers; - -namespace TD.Gameplay.Draft -{ - /// - /// Draft choice — "unlock an upgrade". Adds to the player's - /// set, letting them spend gold converting a placed - /// into it. The base tower stays buildable. - /// - /// - /// Unlock, not swap. This option used to replace the base tower in the player's - /// deck, which made the draft pick itself the whole upgrade — free, instant, and retroactive to - /// every tower built afterward. The 2.0 model splits it: the draft grants access, gold - /// grants the tower. So the deck is untouched here and already-placed towers are - /// upgraded one at a time, each paid for. - /// - /// Prerequisites fall out of the tree. An upgrade is offerable only once its - /// parent is reachable — either the parent is a base tower in the player's deck, or it's an - /// upgrade node they've already unlocked. That single rule is what gates deep nodes behind - /// shallow ones without any explicit prerequisite list: authoring the tree in - /// is enough. - /// - [CreateAssetMenu(fileName = "TowerUpgradeOption", menuName = "TD/Draft/Tower Upgrade Option")] - public class TowerUpgradeDraftOption : DraftOption - { - [Header("Payload")] - [Tooltip("The tower this upgrade branches from — the tree node that must already be " + - "reachable (in the player's deck, or itself an unlocked upgrade) for this " + - "option to be offered.")] - public TowerDefinition BaseTower; - - [Tooltip("The tower this option unlocks as an upgrade target. Must be in the " + - "TowerPlacementManager catalog (that's where its TowerTypeId comes from) and " + - "should be listed in BaseTower's UpgradePaths so the conversion is legal.")] - public TowerDefinition UpgradedTower; - - public override bool IsValidFor(ulong clientId) - { - var deck = PlayerTowerDeck.GetForClient(clientId); - var upgrades = PlayerTowerUpgrades.GetForClient(clientId); - var pm = TowerPlacementManager.Instance; - - if (deck == null || upgrades == null || pm == null) return false; - if (BaseTower == null || UpgradedTower == null) return false; - - if (!pm.TryGetTypeId(BaseTower, out int baseTypeId)) return false; - if (!pm.TryGetTypeId(UpgradedTower, out int upgradedTypeId)) return false; - - // Already unlocked — offering it again would waste the pick. - if (upgrades.Contains(upgradedTypeId)) return false; - - // The parent must be reachable: a base tower they can build, or an upgrade they've - // already taken. This is the whole prerequisite mechanism. - return deck.Contains(baseTypeId) || upgrades.Contains(baseTypeId); - } - - public override bool ServerApply(ulong clientId) - { - var upgrades = PlayerTowerUpgrades.GetForClient(clientId); - var pm = TowerPlacementManager.Instance; - if (upgrades == null || pm == null || UpgradedTower == null) return false; - - if (!pm.TryGetTypeId(UpgradedTower, out int upgradedTypeId)) - { - Debug.LogError($"[TowerUpgradeDraftOption] '{UpgradedTower.name}' is not in the " + - $"tower catalog; cannot apply. Add it to " + - $"TowerPlacementManager.towerDefinitions."); - return false; - } - - return upgrades.ServerUnlock(upgradedTypeId); - } - - /// Inherits the upgraded tower's icon unless this option assigns an override. - public override Sprite ResolveIcon() - => Icon != null ? Icon : (UpgradedTower != null ? UpgradedTower.Icon : null); - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs.meta b/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs.meta deleted file mode 100644 index a35a5d2..0000000 --- a/Assets/_Project/Scripts/Gameplay/Draft/TowerUpgradeDraftOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: aeec22f152a57ef5798eae035c091543 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities.meta deleted file mode 100644 index 099a1ab..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1c918164b61faf1d5af9f782c5237a60 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs deleted file mode 100644 index c00904c..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Every few seconds, the enemy teleports a short distance further along its path — skipping - /// tiles, and the towers covering them. - /// - /// - /// Blinks follow the path rather than cutting toward the goal, so the maze still shapes the - /// route; the buff shortens time-under-fire rather than bypassing walls. See - /// EnemyMovement.ServerBlinkForward. - /// - /// The cooldown lives in this enemy's own timer slot rather than on the asset. A field - /// here would be shared by every enemy carrying the buff, so the whole wave would blink in - /// perfect unison — which looks like a bug even when the timing is right. - /// - [CreateAssetMenu(fileName = "BlinkAbility", menuName = "TD/Enemy Abilities/Blink")] - public class BlinkAbilityDefinition : EnemyAbilityDefinition - { - public override EnemyAbilityKind Kind => EnemyAbilityKind.Blink; - - [Header("Blink")] - [Tooltip("Seconds between blinks.")] - [Min(0.1f)] - public float IntervalSeconds = 8f; - - [Tooltip("World units to advance along the path per blink.")] - [Min(0.1f)] - public float BlinkDistanceMeters = 4f; - - public override void ServerOnSpawn(EnemyAbility instance, int abilityIndex) - { - // Seed each enemy's cooldown with a random point within the full interval, as if it - // spawned already partway through a cooldown. A small jitter window near zero would - // still let a burst of enemies spawned together sync up and blink as a visible cluster - // every cycle; spreading across the whole interval avoids that regardless of how - // IntervalSeconds is tuned. Done once, here, rather than on the first tick — a tick-time - // check would have to distinguish "never started" from "just blinked", and both - // states read as a zero timer. - instance.TimerFor(abilityIndex) = -Random.Range(0f, IntervalSeconds); - } - - public override void ServerTick(EnemyAbility instance, int abilityIndex, float dt) - { - ref float timer = ref instance.TimerFor(abilityIndex); - timer += dt; - if (timer < IntervalSeconds) return; - - timer = 0f; - instance.GetComponent()?.ServerBlinkForward(BlinkDistanceMeters); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs.meta deleted file mode 100644 index b7af88b..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/BlinkAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4fbb09f55384ac44399ac4655b2b53ec \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs deleted file mode 100644 index d80b430..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Base class for one enemy ability (e.g. "split into smaller enemies on death"). Abilities - /// are attached to a wave slot by the post-wave player vote, and every enemy that wave - /// spawns from then on carries the whole accumulated set. - /// - /// - /// Assignment is deterministic, not random. This system originally rolled an - /// ability per individual enemy against a no-ability weight. Under the 2.0 design the players - /// choose it, it applies to every enemy in the wave, and it persists for the rest of the phase - /// — so the roll is gone and WaveManager reads the slot's set instead. What survived is - /// the shape: one asset per kind, server-only hooks. - /// - /// Abilities stack. A wave can collect several across a phase's cycles, so an - /// enemy holds a list and every hook below runs once per ability. Implementations must not - /// assume they are the only ability on the enemy. - /// - /// Server-only hooks. All hooks run on the server only — - /// gates every call on IsServer. They default to no-ops so a new card only overrides the - /// one or two it actually needs. - /// - /// No per-enemy state on the asset. A single asset is shared by every enemy - /// carrying the ability, across every wave and match. Anything per-instance belongs on the - /// component or the enemy itself. - /// - public abstract class EnemyAbilityDefinition : ScriptableObject - { - /// Which enemy ability this asset's data belongs to. - public abstract EnemyAbilityKind Kind { get; } - - [Header("Presentation")] - [Tooltip("Name shown in debug logs and the enemy-info panel.")] - public string DisplayName; - - [Tooltip("Short description shown in the enemy-info panel.")] - [TextArea(2, 4)] - public string Description; - - // ----- Spawn-time stat modification -------------------------------- - - /// - /// Server-only: alter what this enemy spawns as, before it is built. Runs for every enemy - /// of the buffed wave. Default no-op. - /// - /// - /// This is the hook for cards that change what an enemy fundamentally is — flight, - /// health, speed, size. It must run before the enemy exists, because spawn position - /// (flyers are raised) and EnemyHealth/EnemyMovement initialization all read - /// these values once and keep them. - /// - /// When several abilities stack, they see each other's edits in application order, - /// so multiplicative modifiers compose naturally. Prefer multiplying over assigning for - /// anything numeric, or the last card to run silently wins. - /// - public virtual void ServerModifySpawn(ref EnemySpawnContext context) { } - - // ----- Lifetime hooks ---------------------------------------------- - - /// Server-only: called once, right after the ability set is assigned (before the - /// enemy's NetworkObject is spawned to clients). Default no-op. - /// This ability's slot on — the - /// same index receives, so per-enemy timers can be seeded here. - public virtual void ServerOnSpawn(EnemyAbility instance, int abilityIndex) { } - - /// - /// Server-only: called every frame this ability is active on a live enemy. Default no-op. - /// - /// This ability's slot on . Pass it - /// to to reach a per-enemy float this ability owns. - /// - /// The asset holds no per-enemy state. One - /// instance is shared by every enemy carrying the ability, so a cooldown stored in a field - /// here would be shared by the entire wave — every enemy would blink in lockstep, or worse, - /// race each other's writes. gives each enemy its own - /// slot by reference, which is enough for the timer-driven abilities and costs no - /// allocation. - /// - public virtual void ServerTick(EnemyAbility instance, int abilityIndex, float dt) { } - - /// Server-only: called the instant the enemy's HP reaches zero, before the - /// death animation/despawn sequence plays. Default no-op. - public virtual void ServerOnDeath(EnemyAbility instance, EnemyHealth health) { } - - // ----- Economy hooks ----------------------------------------------- - - /// - /// Server-only: adjust the gold a player earns for killing this enemy. Returns the reward - /// to pass on; default is unchanged. - /// - /// - /// Chained across a stacked ability set, each ability receiving the previous one's result. - /// Callers clamp the final value at zero, so returning a negative is safe but pointless. - /// - public virtual int ServerModifyKillReward(EnemyAbility instance, int reward) => reward; - - /// - /// Server-only: called when this enemy reaches the defense point, after lives have been - /// deducted. The hook for leak-punishing cards that cost more than lives. Default no-op. - /// - public virtual void ServerOnReachedGoal(EnemyAbility instance, PlayerSlot originZone) { } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs.meta deleted file mode 100644 index b94f8dd..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 855f7f0848d3086868816d25295fcdd6 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs deleted file mode 100644 index 09a0880..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs -using System; -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Scene singleton holding every available this match, - /// authored as a flat array in the inspector for convenience. Internally it builds a - /// fixed-size table indexed by so lookups are a single array - /// access, not a scan. Mirrors exactly. - /// - /// - /// Plain MonoBehaviour: identical on every peer (same assets), so there is nothing to sync. - /// - /// Lookup only — no rolling. This pool used to draw a random ability per spawned - /// enemy against a "no ability" weight. Under the 2.0 design abilities are chosen by the - /// players' post-wave vote and apply to every enemy in the wave, so the draw moved to - /// WaveVote (over cards, not abilities) and this is purely the kind→asset table - /// WaveManager resolves against at spawn time. - /// - public class EnemyAbilityPool : MonoBehaviour - { - public static EnemyAbilityPool Instance { get; private set; } - - [Tooltip("Every EnemyAbilityDefinition asset available this match. One entry per " + - "EnemyAbilityKind — order doesn't matter, Kind on the asset itself decides " + - "its slot.")] - [SerializeField] private EnemyAbilityDefinition[] abilities; - - // Fixed-size, enum-indexed lookup built once in Awake. Sized to the enum's entry count, - // not authored count, so an out-of-range Kind is a compile-time impossibility rather - // than a bounds check we'd otherwise need on every Get(). - private EnemyAbilityDefinition[] byKind; - - private void Awake() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[EnemyAbilityPool] Multiple instances detected. Only one per scene."); - return; - } - Instance = this; - - int kindCount = Enum.GetValues(typeof(EnemyAbilityKind)).Length; - byKind = new EnemyAbilityDefinition[kindCount]; - if (abilities == null) return; - - for (int i = 0; i < abilities.Length; i++) - { - var def = abilities[i]; - if (def == null) continue; - byKind[(int)def.Kind] = def; - } - } - - private void OnDestroy() - { - if (Instance == this) Instance = null; - } - - /// Returns the ability asset for , or null if none is - /// authored in this pool. - public EnemyAbilityDefinition Get(EnemyAbilityKind kind) - { - int i = (int)kind; - return (byKind != null && i >= 0 && i < byKind.Length) ? byKind[i] : null; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs.meta deleted file mode 100644 index a951ada..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4409eb25a8be555de8dc3a73d4ed95db \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs deleted file mode 100644 index 67fda7b..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Mutable per-spawn copy of an enemy's stats, handed to each of its abilities before the - /// enemy is built so they can alter what it spawns as. - /// - /// - /// Why a context rather than more parameters. Wave buffs like "grounded enemies become - /// flying" or "enemies spawn at half health" have to land before - /// EnemyHealth.InitializeServer and before the spawn position is computed (flyers are - /// raised by their flight height). Threading each new stat through SpawnEnemy as another - /// argument was already unwieldy at two; this keeps the signature flat and gives abilities one - /// obvious place to write. - /// - /// Seeded from the , never written back to it — the - /// definition is a shared asset and a buff that mutated it would leak across waves, matches, - /// and (in the editor) sessions. - /// - public struct EnemySpawnContext - { - public float MaxHp; - public float MoveSpeed; - public bool IsFlying; - public float FlightHeight; - public int LivesCost; - - /// Uniform transform scale relative to the prefab's authored scale. - public float VisualScale; - - /// - /// Seeds a context from an enemy definition's authored stats, with health supplied by the - /// caller. - /// - /// The type being spawned. Supplies everything except health. - /// Health this enemy spawns with, already resolved from the - /// encounter's budget and the type's — see - /// . Passed in rather than read off the - /// definition because it depends on run position and the wave's enemy count, neither of - /// which the asset knows about. - public static EnemySpawnContext FromDefinition(EnemyDefinition def, float resolvedMaxHp) - => new EnemySpawnContext - { - MaxHp = resolvedMaxHp, - MoveSpeed = def.MoveSpeed, - IsFlying = def.IsFlying, - FlightHeight = def.FlightHeight, - LivesCost = def.LivesCost, - VisualScale = 1f, - }; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs.meta deleted file mode 100644 index d812b43..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemySpawnContext.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2f4b0f77b422a474cbe82f3967e6195b \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs deleted file mode 100644 index 322b2cf..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Grounded enemies take to the air: they path over the baked terrain grid instead of through - /// the maze, and towers flagged ground-only can no longer touch them. - /// - /// - /// The single most punishing card in the set, because it doesn't weaken the maze — it - /// deletes it. Everything a player built to lengthen the route stops mattering for that wave, - /// and only their anti-air coverage counts. Weight it accordingly in the pools. - /// - /// Purely a spawn-time change: EnemyMovement reads the flying flag once at - /// initialization to pick which grid to path on and to opt out of re-path scheduling, and - /// TowerCombat reads the replicated flag on EnemyHealth when filtering targets. - /// Both are already wired for flight — this card only has to flip the bit before the enemy is - /// built. - /// - [CreateAssetMenu(fileName = "FlightAbility", menuName = "TD/Enemy Abilities/Flight")] - public class FlightAbilityDefinition : EnemyAbilityDefinition - { - public override EnemyAbilityKind Kind => EnemyAbilityKind.Flight; - - [Header("Flight")] - [Tooltip("Height above the ground these enemies hover at. Keep modest — tower targeting " + - "uses 3D range, so altitude eats into the effective reach of anything that CAN " + - "shoot them.")] - [Min(0f)] - public float FlightHeight = 3f; - - [Tooltip("Speed multiplier applied when the enemy takes flight. Flying enemies travel a " + - "much shorter route, so values below 1 are a reasonable counterweight.")] - [Range(0.1f, 2f)] - public float SpeedMultiplier = 1f; - - public override void ServerModifySpawn(ref EnemySpawnContext context) - { - // Already-flying enemies keep their authored height rather than being overwritten by - // this card's — the wave was designed around it, and stacking Flight onto a flier - // shouldn't quietly relocate it. - if (!context.IsFlying) - { - context.IsFlying = true; - context.FlightHeight = FlightHeight; - } - - context.MoveSpeed *= SpeedMultiplier; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs.meta deleted file mode 100644 index 82e8217..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/FlightAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: be77d353621f07e40bbdab2e9cc37f51 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs deleted file mode 100644 index 974b59f..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// An enemy that reaches the defense point doesn't just cost a life — it robs the player whose - /// maze it escaped. - /// - /// - /// Charged to the origin zone, not the whole team. Lives are a shared pool, so a leak - /// already punishes everyone equally; billing the gold to whoever let it through is the part - /// that makes this card bite differently from "enemies cost 2 lives". It also keeps the blame - /// legible — the player who leaked is the player who pays. - /// - /// Deducting more gold than a player has simply empties them; there is no debt. Going - /// negative would silently disable building until they clawed back to zero, which reads as a - /// broken HUD rather than a penalty. - /// - [CreateAssetMenu(fileName = "GoldTheftAbility", menuName = "TD/Enemy Abilities/Gold Theft")] - public class GoldTheftAbilityDefinition : EnemyAbilityDefinition - { - public override EnemyAbilityKind Kind => EnemyAbilityKind.GoldTheft; - - [Header("Theft")] - [Tooltip("Flat gold taken from the leaking player, on top of the normal life cost.")] - [Min(0)] - public int GoldStolen = 15; - - public override void ServerOnReachedGoal(EnemyAbility instance, PlayerSlot originZone) - { - if (GoldStolen <= 0 || originZone == PlayerSlot.None) return; - - var pms = PlayerMatchState.GetForSlot(originZone); - if (pms == null) return; - - var gold = PlayerGoldManager.GetForClient(pms.OwnerClientId); - if (gold == null) return; - - // Clamp to what they actually hold — a leak shouldn't be able to put a player in debt. - int taken = Mathf.Min(GoldStolen, gold.CurrentGold); - if (taken <= 0) return; - - gold.DeductGold(taken); - - // Surface it in-world on every peer so the loss isn't just a number quietly ticking - // down in the corner. Routed through WaveManager because the popup has to reach - // clients and a ScriptableObject has no NetworkBehaviour to send from. - WaveManager.Instance?.ServerBroadcastGoldLoss(instance.transform.position, taken); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs.meta deleted file mode 100644 index aa23919..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 3b770ce042b78f44d9a3df537fe25db0 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs deleted file mode 100644 index 42d2bab..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// Killing these enemies pays little or nothing. The wave gets no harder to survive — it gets - /// harder to profit from. - /// - /// - /// Attacks the economy, not the maze. Every other card makes a wave more dangerous; - /// this one makes clearing it worthless, which compounds instead across cycles — a wave that - /// pays nothing on cycle 1 also pays nothing on cycles 2 and 3, so the players who voted it in - /// are choosing to be poorer for the rest of the phase. That slow squeeze is the point, and - /// it's why the card reads as mild and isn't. - /// - /// Wave-completion and no-leak bonuses are untouched — those are paid per player by - /// WaveManager, not per kill, so a wave carrying this still rewards clearing it. - /// - [CreateAssetMenu(fileName = "NoBountyAbility", menuName = "TD/Enemy Abilities/No Bounty")] - public class NoBountyAbilityDefinition : EnemyAbilityDefinition - { - public override EnemyAbilityKind Kind => EnemyAbilityKind.NoBounty; - - [Header("Bounty")] - [Tooltip("Fraction of the normal kill bounty these enemies still pay. 0 = nothing at all.")] - [Range(0f, 1f)] - public float BountyMultiplier = 0f; - - public override int ServerModifyKillReward(EnemyAbility instance, int reward) - => Mathf.FloorToInt(reward * BountyMultiplier); - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs.meta deleted file mode 100644 index a2f48ff..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/NoBountyAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: fd5b12948b24e9c4c8840ef3470b437e \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs deleted file mode 100644 index 1d96391..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyAbilities -{ - /// - /// On death, spawns smaller copies of the dying enemy's own type at - /// the corpse's position, continuing on toward the goal instead of restarting from the wave's - /// spawner. - /// - /// - /// No separate minion asset. The copies reuse whichever - /// and prefab the dying enemy was spawned from; every stat is expressed here as a percentage - /// of what the parent actually spawned with, so one card covers any enemy it lands on. - /// - /// Percentages are of the PARENT, not the asset. If other cards on the same wave - /// have already modified the enemy, the minions scale off the modified values — a split of a - /// buffed enemy produces buffed minions, which is what players will expect from watching it. - /// - /// Minions inherit no abilities at all — not even this one. That is what makes the - /// recursion terminate: a minion of a splitting enemy is a plain enemy, so a wave carrying - /// Split produces exactly one extra generation regardless of how many other cards it has - /// collected. Enforced at the spawn site, not here. - /// - [CreateAssetMenu(fileName = "SplitOnDeathAbility", menuName = "TD/Enemy Abilities/Split On Death")] - public class SplitOnDeathAbilityDefinition : EnemyAbilityDefinition - { - public override EnemyAbilityKind Kind => EnemyAbilityKind.SplitOnDeath; - - [Header("Split")] - [Tooltip("How many copies spawn when the parent dies.")] - [Min(1)] - public int SplitCount = 2; - - [Header("Minion stats (percent of the parent's spawned values)")] - [Tooltip("Minion max HP as a fraction of the parent's max HP.")] - [Range(0.01f, 2f)] - public float HpPercent = 0.5f; - - [Tooltip("Minion move speed as a fraction of the parent's speed. Above 1 makes the split " + - "faster than what died — the classic 'smaller and quicker' read.")] - [Range(0.01f, 3f)] - public float SpeedPercent = 1.25f; - - [Tooltip("Minion transform scale as a fraction of the parent's scale. Requires the enemy " + - "prefab's NetworkTransform to sync scale, or minions render full-size on remote peers.")] - [Range(0.1f, 2f)] - public float ScalePercent = 0.6f; - - [Tooltip("Minion lives cost as a fraction of the parent's, rounded down but never below 1 " + - "— a leak always has to hurt, or splits become a way to farm free ground.")] - [Range(0f, 2f)] - public float LivesCostPercent = 1f; - - [Tooltip("Minion flight height as a fraction of the parent's. Only meaningful when the " + - "parent is flying; ground splits ignore it.")] - [Range(0.1f, 2f)] - public float FlightHeightPercent = 1f; - - [Header("Placement")] - [Tooltip("Random scatter radius (world units) applied to each spawn so minions don't " + - "stack exactly on top of each other.")] - [Min(0f)] - public float ScatterRadius = 0.5f; - - public override void ServerOnDeath(EnemyAbility instance, EnemyHealth health) - { - var def = health.Definition; - if (def == null) return; - - var movement = instance.GetComponent(); - var atTile = GridCoordinates.WorldToGrid(instance.transform.position); - var ownerSlot = movement != null ? movement.OriginZone : PlayerSlot.None; - - // Derive the minion's stats from what the parent actually spawned as. - var parent = instance.SpawnContext; - var minion = new EnemySpawnContext - { - MaxHp = Mathf.Max(1f, parent.MaxHp * HpPercent), - MoveSpeed = Mathf.Max(0.01f, parent.MoveSpeed * SpeedPercent), - IsFlying = parent.IsFlying, - FlightHeight = parent.FlightHeight * FlightHeightPercent, - LivesCost = Mathf.Max(1, Mathf.FloorToInt(parent.LivesCost * LivesCostPercent)), - VisualScale = parent.VisualScale * ScalePercent, - }; - - WaveManager.Instance?.ServerSpawnSplitEnemies( - def, SplitCount, atTile, ownerSlot, ScatterRadius, minion); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs.meta deleted file mode 100644 index 8c2a4f3..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 21543cb1b54f0b16e9c80584f68988b3 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs deleted file mode 100644 index 8913543..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyAbility.cs -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; -using TD.Core; -using TD.Gameplay.EnemyAbilities; - -namespace TD.Gameplay -{ - /// - /// Per-enemy ability set. Holds every its wave has - /// accumulated and drives their server-only hooks. - /// - /// - /// Initialization: Call on the server immediately after - /// Instantiate and before NetworkObject.Spawn(), following the same pattern as - /// EnemyHealth.InitializeServer / EnemyMovement.InitializeServer. - /// - /// A set, not a slot. This used to hold one ability rolled at random per enemy. Wave - /// buffs stack across a phase's cycles, so it now holds a list and fans every hook out over - /// all of them. replicates the set so clients can show players what - /// they're facing. - /// - /// Optional component: Not required by EnemyHealth or EnemyMovement — - /// WaveManager.SpawnEnemy only assigns abilities when this component is present on the - /// prefab, so enemy prefabs without it simply never carry wave buffs. - /// - /// On-death hook is not event-driven: WaveManager.HandleEnemyKilled calls - /// directly rather than this component subscribing to - /// EnemyHealth.OnDied itself — that keeps a split-spawn's activeEnemyCount - /// increment ordered before the triggering kill's decrement, regardless of NetworkBehaviour - /// subscription order. - /// - [RequireComponent(typeof(NetworkObject))] - public class EnemyAbility : NetworkBehaviour - { - // Replicated ability kinds carried by this enemy. Empty means no wave buffs. Exists so - // clients can render "this wave splits and flies" in the enemy-info panel without - // re-deriving it from run state. - private NetworkList kinds; - - // ----- Pre-spawn init (server-local) ---------------------------------- - - private readonly List pendingDefinitions = new List(); - private bool hasPendingInit; - - // ----- Public state ----------------------------------------------------- - - private readonly List definitions = new List(); - - /// The abilities this enemy carries. Server-side; empty on clients. - public IReadOnlyList Definitions => definitions; - - /// True if this enemy carries no abilities at all. - public bool IsPlain => definitions.Count == 0; - - /// - /// The stats this enemy actually spawned with, after every ability's spawn modification. - /// Server-side. - /// - /// - /// Kept so on-death abilities can derive from what the enemy really was rather than from - /// its . Split-on-death needs this: its minions are a - /// percentage of "the enemy that died", which is not the authored asset once other cards - /// on the same wave have modified it. - /// - public EnemySpawnContext SpawnContext { get; private set; } - - private void Awake() - { - kinds = new NetworkList(); - } - - /// Replicated check for a specific ability. Safe on any peer. - public bool HasKind(EnemyAbilityKind kind) - { - byte target = (byte)kind; - for (int i = 0; i < kinds.Count; i++) - if (kinds[i] == target) return true; - return false; - } - - // ----- Server-only pre-spawn init ------------------------------------- - - /// - /// Called by WaveManager on the server after Instantiate and before - /// NetworkObject.Spawn(). may be null or empty, - /// meaning this enemy carries no wave buffs. - /// - /// - /// Copies rather than retains the caller's list — WaveManager reuses one scratch - /// buffer across every enemy in a wave, so holding the reference would alias every enemy - /// to the same (later mutated) contents. - /// - public void InitializeServer(IReadOnlyList abilities, - EnemySpawnContext spawnContext) - { - pendingDefinitions.Clear(); - if (abilities != null) - { - for (int i = 0; i < abilities.Count; i++) - if (abilities[i] != null) pendingDefinitions.Add(abilities[i]); - } - SpawnContext = spawnContext; - hasPendingInit = true; - } - - // ----- NGO lifecycle -------------------------------------------------- - - public override void OnNetworkSpawn() - { - if (!IsServer || !hasPendingInit) return; - - definitions.Clear(); - definitions.AddRange(pendingDefinitions); - hasPendingInit = false; - - timers = definitions.Count > 0 - ? new float[definitions.Count] - : System.Array.Empty(); - - kinds.Clear(); - for (int i = 0; i < definitions.Count; i++) - kinds.Add((byte)definitions[i].Kind); - - for (int i = 0; i < definitions.Count; i++) - definitions[i].ServerOnSpawn(this, i); - } - - // ----- Server tick ------------------------------------------------ - - private void Update() - { - if (!IsServer || definitions.Count == 0) return; - - float dt = Time.deltaTime; - for (int i = 0; i < definitions.Count; i++) - definitions[i].ServerTick(this, i, dt); - } - - // ----- Per-enemy ability scratch ---------------------------------- - - // One float per carried ability, owned by that ability. Exists because the definitions - // are shared ScriptableObjects: a cooldown stored on the asset would be shared by every - // enemy in the wave, making them all fire in lockstep. Allocated once at init, sized to - // the ability count — never resized, since the set is fixed at spawn. - private float[] timers = System.Array.Empty(); - - /// - /// A per-enemy float owned by the ability at , returned by - /// reference so it can be read and written in place. Typically a cooldown accumulator. - /// - public ref float TimerFor(int abilityIndex) - { - if (abilityIndex < 0 || abilityIndex >= timers.Length) - { - // Out-of-range means a caller passed an index that doesn't match its slot. Hand - // back a scratch cell rather than throwing mid-tick; the ability just won't - // accumulate, which is visible in play but not fatal. - Debug.LogError($"[EnemyAbility] TimerFor({abilityIndex}) is out of range on " + - $"{name}. The ability will not keep time."); - return ref timerFallback; - } - return ref timers[abilityIndex]; - } - - private float timerFallback; - - // ----- Server hook fan-out ---------------------------------------- - - /// Server-only: run every carried ability's on-death hook. - public void ServerInvokeOnDeath(EnemyHealth health) - { - if (!IsServer) return; - for (int i = 0; i < definitions.Count; i++) - definitions[i].ServerOnDeath(this, health); - } - - /// - /// Server-only: chain every carried ability's kill-reward modifier. Result is clamped at - /// zero so a stack of reward-suppressing cards can't hand out negative gold. - /// - public int ServerModifyKillReward(int reward) - { - if (!IsServer) return reward; - for (int i = 0; i < definitions.Count; i++) - reward = definitions[i].ServerModifyKillReward(this, reward); - return Mathf.Max(0, reward); - } - - /// Server-only: run every carried ability's reached-goal hook. - public void ServerInvokeReachedGoal(PlayerSlot originZone) - { - if (!IsServer) return; - for (int i = 0; i < definitions.Count; i++) - definitions[i].ServerOnReachedGoal(this, originZone); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs.meta deleted file mode 100644 index 3562455..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9d1a26a32e8969cd29bce6010126a5f6 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyDefinition.cs index bda4e45..15f45f8 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyDefinition.cs @@ -12,13 +12,6 @@ namespace TD.Gameplay /// in project assets, only the asset reference (or its fields) crosses runtime code. /// Replace with a real mesh/animator when art is ready — /// no code changes required. - /// - /// An enemy type is flavour, not a difficulty tier. There is deliberately no - /// absolute health field: health comes from based on how far - /// into the run the encounter sits, and this asset only says how the type deviates from that - /// (). Because waves are drawn at random from a phase pool, any - /// difficulty baked into the roster would be difficulty handed out by the luck of the draw. - /// Every type should be a viable occupant of any slot. /// [CreateAssetMenu(fileName = "EnemyDefinition", menuName = "TD/Enemy Definition", order = 3)] public class EnemyDefinition : ScriptableObject @@ -28,16 +21,10 @@ namespace TD.Gameplay public string DisplayName; [Header("Stats")] - [Tooltip("How tough this enemy is RELATIVE to its encounter's budget — not an absolute " + - "hit-point value. 1.0 = exactly its share of the budget; 1.25 = a quarter " + - "tougher than the slot calls for. Keep it near 1.0 and let the wave's enemy " + - "count express tankiness (fewer enemies each get a bigger share).")] - [Min(0.01f)] - public float HpMultiplier = 1f; + [Tooltip("Maximum hit points for this enemy type.")] + public float MaxHp = 100f; - [Tooltip("Movement speed in world units per second along the A* path. ABSOLUTE and " + - "unscaled — speed is a fixed character trait, not a progression axis. See " + - "EnemyScalingConfig for why.")] + [Tooltip("Movement speed in world units per second along the A* path.")] public float MoveSpeed = 3f; [Tooltip("When true this enemy flies: it paths on the baked terrain grid, ignoring " + diff --git a/Assets/_Project/Scripts/Gameplay/EnemyHealth.cs b/Assets/_Project/Scripts/Gameplay/EnemyHealth.cs index 28f6ab9..10256d2 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyHealth.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyHealth.cs @@ -1,6 +1,5 @@ // Assets/_Project/Scripts/Gameplay/EnemyHealth.cs using System.Collections; -using System.Collections.Generic; using Unity.Netcode; using UnityEngine; using TD.Core; @@ -68,14 +67,13 @@ namespace TD.Gameplay private int pendingLivesCost = 1; private bool pendingIsFlying; private bool pendingIsHeld; - private bool pendingIsBoss; private bool hasPendingInit; // ----- Server-local runtime state ------------------------------------- - // Kill gold is no longer carried per-enemy — it comes from the GoldConfig entry for - // the current encounter (GoldConfig.GetEncounterEntry) at the moment the kill is - // registered. See WaveManager.HandleEnemyKilled. + // Kill gold is no longer carried per-enemy — it comes from + // GoldConfig.Waves[currentWaveIndex].GoldPerEnemy at the moment the kill + // is registered. See WaveManager.HandleEnemyKilled. /// Lives deducted from the shared pool when this enemy reaches the goal. public int LivesCost { get; private set; } = 1; @@ -105,13 +103,6 @@ namespace TD.Gameplay NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); - // Set for enemies spawned by a phase's boss encounter. Replicated because the HUD's boss - // bar is client-side and has to recognise a boss without asking the server. - private readonly NetworkVariable isBoss = new NetworkVariable( - false, - NetworkVariableReadPermission.Everyone, - NetworkVariableWritePermission.Server); - // ----- Public state --------------------------------------------------- public float CurrentHp => hp.Value; @@ -126,19 +117,6 @@ namespace TD.Gameplay /// public bool IsFlying => isFlying.Value; - /// True if this enemy was spawned by a phase's boss encounter. Replicated. - public bool IsBoss => isBoss.Value; - - /// - /// Every live boss, on every peer. Maintained by spawn/despawn so the HUD can render a - /// boss bar without polling the scene. - /// - /// - /// A list rather than a single reference because the boss encounter spawns one boss per - /// player zone — there are as many simultaneous bosses as there are players. - /// - public static readonly List ActiveBosses = new List(); - // ----- Events --------------------------------------------------------- /// @@ -158,14 +136,12 @@ namespace TD.Gameplay /// and before NetworkObject.Spawn(). Mirrors the /// TowerInstance.InitializeServer pattern. /// - public void InitializeServer(float maxHp, int livesCost, bool flying, bool held = false, - bool boss = false) + public void InitializeServer(float maxHp, int livesCost, bool flying, bool held = false) { pendingMaxHp = maxHp; pendingLivesCost = livesCost; pendingIsFlying = flying; pendingIsHeld = held; - pendingIsBoss = boss; hasPendingInit = true; // Cache locally on the server immediately — clients resolve via NV. @@ -182,7 +158,6 @@ namespace TD.Gameplay hp.Value = pendingMaxHp; isFlying.Value = pendingIsFlying; isHeld.Value = pendingIsHeld; - isBoss.Value = pendingIsBoss; hasPendingInit = false; } @@ -190,9 +165,6 @@ namespace TD.Gameplay if (!IsServer) MaxHp = hp.Value; - if (isBoss.Value && !ActiveBosses.Contains(this)) - ActiveBosses.Add(this); - // Apply initial held state on all peers and watch for future changes. // isHeld.OnValueChanged doesn't fire for the initial replication, so we // apply it explicitly here as well. @@ -202,8 +174,6 @@ namespace TD.Gameplay public override void OnNetworkDespawn() { - ActiveBosses.Remove(this); - // If this enemy was the locally-selected ISelectable, clear the // selection so the HUD doesn't keep displaying a stale corpse. // SelectionState is a local UI singleton, safe to query on any peer. diff --git a/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs b/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs index 6815ff2..96a6e30 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs @@ -73,11 +73,6 @@ namespace TD.Gameplay // the goal). Without this, every zone crossing was counted as a leak; only // the originating player should be credited a leak per the design. private PlayerSlot originZone = PlayerSlot.None; - - /// The zone (player) this enemy was originally spawned for — see - /// . Used by on-death abilities (e.g. Split on Death) so - /// spawned children preserve the same leak attribution as their parent. - public PlayerSlot OriginZone => originZone; // Latches once the enemy has crossed its origin zone's leak volume, so we // never double-count a leak if the enemy re-enters its origin (rare but // possible if pathing is dynamic). @@ -282,76 +277,6 @@ namespace TD.Gameplay NetworkObject.Despawn(); } - // ----- Ability-driven movement ---------------------------------------- - - /// - /// Server-only: teleport this enemy forward along its existing path by up to - /// world units. Used by the Blink wave buff. - /// - /// - /// Follows the path rather than the straight line to the goal. Jumping toward the - /// goal as the crow flies would let a grounded enemy blink through walls, which is the - /// flying buff's job, not this one. Walking the path keeps the enemy inside the maze — - /// it cuts corners, it doesn't ignore them. - /// - /// Distance is measured along the path (waypoint to waypoint), consuming the - /// budget one segment at a time, so the landing spot can fall mid-segment rather than - /// snapping to a waypoint. This keeps the blink distance predictable regardless of how - /// far apart the path's waypoints happen to be — unlike skipping a fixed waypoint count, - /// where one blink could span a few tiles or the length of the whole map depending on - /// path smoothing. - /// - /// Zone tracking runs once, on the final landing tile, so an enemy that blinks out - /// of its origin zone still credits its owner a leak. Skipping that would make the buff a - /// way to launder leaks past the no-leak bonus. - /// - /// Blinking onto (or past) the final waypoint resolves as a normal goal arrival, - /// despawn and life cost included. - /// - public void ServerBlinkForward(float meters) - { - if (!IsServer || meters <= 0f) return; - if (hasReachedGoal || remainingPath.Count == 0) return; - if (health != null && health.IsHeld) return; - - float remaining = meters; - Vector3 position = transform.position; - - while (remaining > 0f && remainingPath.Count > 0) - { - Vector3 targetWorld = GridCoordinates.GridToWorld(remainingPath[0]); - Vector3 toTarget = targetWorld - position; - toTarget.y = 0f; - float distance = toTarget.magnitude; - - if (distance <= remaining) - { - // Reach this waypoint fully and keep walking the leftover budget - // into the next segment. - remaining -= distance; - position = new Vector3(targetWorld.x, position.y, targetWorld.z); - remainingPath.RemoveAt(0); - } - else - { - // Budget runs out partway along this segment. - position += toTarget.normalized * remaining; - remaining = 0f; - } - } - - // Preserve Y so flyers stay at altitude and grounded pivots don't sink. - transform.position = position; - - if (remainingPath.Count == 0) - { - HandleGoalReached(); - return; - } - - CheckZoneTransition(GridCoordinates.WorldToGrid(position)); - } - // ----- Path invalidation ---------------------------------------------- // Called by PathfindingService's budgeted scheduler after a walkability change diff --git a/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs b/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs deleted file mode 100644 index 8a833ee..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs -using UnityEngine; - -namespace TD.Gameplay -{ - /// - /// How enemy health scales across a run. Single source of truth for difficulty progression, - /// the health counterpart to . - /// - /// - /// The problem this solves. Waves are drawn at random from a phase pool, so difficulty - /// can no longer live in the assets — an enemy authored at - /// 1000 HP is brutal at encounter 1 and trivial at encounter 40, and the draw decides which - /// you get. Progression has to be a property of how far the players have come, exactly - /// as gold payouts are. - /// - /// Budget, not per-enemy HP. This config scales the total health an - /// encounter presents; per-enemy health is that budget divided by the wave's enemy count. If - /// the curve set per-enemy health instead, enemy count would silently become a second - /// difficulty axis and a 150-strong swarm would hit three times harder than a 50-strong wave - /// in the same slot. Dividing a fixed budget turns count into a texture knob: eight - /// giants and a hundred rats threaten equally, but demand different mazes. - /// - /// Budget is per zone. Every player zone spawns the full wave, so this is the - /// health one player faces, not the lobby total. It does not change with player count. - /// - /// Speed is deliberately absent. Speed stays on the - /// , unscaled. Escalating speed alongside health compounds into - /// a difficulty cliff and quietly invalidates tower balance as a run goes — projectile lead, - /// slow-effect value and time-under-fire all shift. Fast-versus-slow reads best as a fixed - /// character trait; health and the voted wave buffs carry escalation. - /// - [CreateAssetMenu(fileName = "EnemyScalingConfig", menuName = "TD/Enemy Scaling Config", order = 3)] - public class EnemyScalingConfig : ScriptableObject - { - [Header("Health curve")] - [Tooltip("Total enemy health the run's FIRST encounter presents, per player zone. " + - "Per-enemy health is this divided by the wave's enemy count.")] - [Min(1f)] - public float BaseHpBudget = 5000f; - - [Tooltip("Multiplier applied per encounter. 1.18 ≈ +18% health each encounter, so the " + - "budget roughly doubles every four. Encounters are counted continuously across " + - "the whole run, so cycle 2 is strictly harder than cycle 1.")] - [Min(1f)] - public float GrowthPerEncounter = 1.18f; - - [Header("Boss")] - [Tooltip("Extra multiplier on a boss encounter's budget, on top of the curve. Bosses " + - "spawn few enemies, so nearly all of this lands on the single boss body.")] - [Min(1f)] - public float BossHpMultiplier = 6f; - - /// - /// Total health budget for the given 1-based encounter number - /// (RunState.GlobalEncounterNumber), per player zone. - /// - public float GetEncounterHpBudget(int encounterNumber, bool isBoss) - { - int steps = Mathf.Max(0, encounterNumber - 1); - float budget = BaseHpBudget * Mathf.Pow(GrowthPerEncounter, steps); - if (isBoss) budget *= BossHpMultiplier; - return budget; - } - - /// - /// Health for one enemy in the given encounter: the encounter's budget shared across - /// bodies, then skewed by the enemy type's - /// . - /// - /// - /// The archetype multiplier is a deliberate deviation from budget, not a - /// redistribution of it — a wave of 1.25× enemies really is 25% tougher than its slot - /// calls for. Keep multipliers near 1.0 and let the wave's enemy count express tankiness; - /// that is the knob the budget is designed to divide. - /// - public float ResolvePerEnemyHp(int encounterNumber, bool isBoss, int waveEnemyCount, - float archetypeMultiplier) - { - int bodies = Mathf.Max(1, waveEnemyCount); - float share = GetEncounterHpBudget(encounterNumber, isBoss) / bodies; - return Mathf.Max(1f, share * Mathf.Max(0.01f, archetypeMultiplier)); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs.meta deleted file mode 100644 index a428b6f..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyScalingConfig.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: de25a6333a11d074280b5ade557aa8b9 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades.meta deleted file mode 100644 index f5ba3d6..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 95ac4e8d1714a07489dad0c283970bf8 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs deleted file mode 100644 index 3576d6b..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs -using UnityEngine; -using TD.Gameplay.EnemyAbilities; -using TD.Gameplay.Waves; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// The workhorse enemy-buff card: grants an to a wave - /// slot. Every enemy spawned by that wave, in every later cycle of the phase, carries the - /// ability. - /// - /// - /// There is nothing to do at vote-resolution time — recording the option id on the slot IS the - /// effect, because the spawn path builds each enemy's ability set from the slot's recorded - /// options. is what that lookup resolves to. - /// - [CreateAssetMenu(fileName = "EnemyUpgrade_Ability", - menuName = "TD/Enemy Upgrades/Ability Card", order = 20)] - public class AbilityEnemyUpgradeOption : EnemyUpgradeOption - { - [Header("Payload")] - [Tooltip("The ability every enemy in this wave gains. Must also be present in the scene's " + - "EnemyAbilityPool so it can be resolved at spawn time.")] - public EnemyAbilityDefinition Ability; - - public override bool IsValidForSlot(RunState run, int slot) - { - if (Ability == null) return false; - - // Don't offer an ability the slot already has by another card's hand. Exact-id repeats - // are filtered by the caller, but two different cards can grant the same ability, and - // stacking one twice is a no-op the players would rightly feel cheated by. - return !SlotAlreadyHasAbility(run, slot); - } - - // Shared scratch: validation runs on the server during vote generation, which is - // single-threaded, so one reused list beats allocating per candidate per slot. - private static readonly System.Collections.Generic.List s_idScratch - = new System.Collections.Generic.List(); - - private bool SlotAlreadyHasAbility(RunState run, int slot) - { - var pool = EnemyUpgradePool.Instance; - if (run == null || pool == null) return false; - - var ids = s_idScratch; - run.GetUpgradesForSlot(slot, ids); - - foreach (int id in ids) - { - if (pool.Get(id) is AbilityEnemyUpgradeOption other && other.Ability == Ability) - return true; - } - return false; - } - - /// Inherits nothing automatically — carries no - /// icon, so the card's own is the only source. - public override Sprite ResolveIcon() => Icon; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs.meta deleted file mode 100644 index f619df4..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d075c66b381872a4781b3916296ccdc9 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs deleted file mode 100644 index 882dd8f..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs -using UnityEngine; -using TD.Gameplay.Waves; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// Vote-meta card: the next time this wave is cleared, it takes several buffs automatically - /// and the players get no say in which. - /// - /// - /// Not an enemy ability. Nothing about the enemies changes when this is voted in — it - /// changes how the next vote on this slot resolves. That's why it derives from - /// directly instead of wrapping an - /// EnemyAbilityDefinition: the spawn path builds ability sets only from ability cards, - /// so this one is recorded on the slot and otherwise invisible to enemies. - /// - /// The trade is agency for information. Voting this in is choosing to make one - /// future wave worse in exchange for it not being the worst option — the auto-draw is weighted - /// and slot-filtered exactly like a real vote, so it's a gamble on the pool, not a punishment. - /// It also disarms itself after firing (ServerConsumeAutoApply), so a slot can only be - /// doubled once per card. - /// - /// Repeats are prevented by the normal offer filter: the slot records this card like any - /// other, so it can't be offered to the same slot twice in a phase. - /// - [CreateAssetMenu(fileName = "EnemyUpgrade_DoubleUp", - menuName = "TD/Enemy Upgrades/Double Up Card", order = 22)] - public class DoubleUpEnemyUpgradeOption : EnemyUpgradeOption - { - [Header("Payload")] - [Tooltip("How many buffs the wave takes automatically in place of its next vote.")] - [Min(2)] - public int BuffsToAutoApply = 2; - - public override bool IsValidForSlot(RunState run, int slot) - { - // Pointless to offer while the slot is already armed — the player would be trading a - // vote away for nothing. - return run != null && run.GetAutoApplyCount(slot) <= 0; - } - - public override void ServerOnApplied(RunState run, int slot) - { - run?.ServerSetAutoApply(slot, BuffsToAutoApply); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs.meta deleted file mode 100644 index ca93bb2..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/DoubleUpEnemyUpgradeOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f5e90fe6b8e439e4f99769a6923c2262 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs deleted file mode 100644 index 1e0f9f2..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs -using System; -using System.Collections.Generic; -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// One weighted candidate inside an . - /// - /// - /// Weight is relative and normalized at draw time — see . - /// Kept on the entry rather than on the option asset for the same reason wave weights are: - /// a card can be a staple of one phase's pool and a rarity in another's. - /// - [Serializable] - public class EnemyUpgradePoolEntry - { - [Tooltip("The enemy-buff card that may be offered from this group.")] - public EnemyUpgradeOption Option; - - [Tooltip("Relative draw weight within the pool this group contributes to. Entries at " + - "equal weight are equally likely; 0.5 is half as likely as 1.0.")] - [PoolWeight("buff")] - public float Weight = 1f; - } - - /// - /// A named, reusable bag of enemy-buff cards. Groups are the unit designers move between - /// phases: dragging a group into Phase 2's list makes every card in it votable from phase 2 - /// onward, without touching the cards themselves. - /// - /// - /// Buffs are gated by phase, not by cycle — every card a phase allows is votable from - /// its very first wave. Gating by cycle was considered and rejected: the whole point of the - /// cyclical structure is that players choose how hard to make their own next lap, and holding - /// the interesting cards back until cycle 3 would flatten that decision into a formality. - /// - [CreateAssetMenu(fileName = "EnemyUpgradeGroup", - menuName = "TD/Enemy Upgrades/Upgrade Group", order = 21)] - public class EnemyUpgradeGroup : ScriptableObject - { - [Tooltip("Designer-facing name, shown in validation messages. Falls back to the asset name.")] - public string DisplayName; - - [Tooltip("Cards in this group, each with a relative draw weight.")] - public EnemyUpgradePoolEntry[] Options; - - /// Name used in validation and log messages. Falls back to the asset name. - public string Label => string.IsNullOrWhiteSpace(DisplayName) ? name : DisplayName; - - /// - /// Appends every non-null, non-zero-weight entry across into - /// . Zero-weight entries are filtered here so "weight 0 means it - /// can never appear" lives in exactly one place. - /// - public static void CollectCandidates(EnemyUpgradeGroup[] groups, List into) - { - into.Clear(); - if (groups == null) return; - - foreach (var group in groups) - { - if (group?.Options == null) continue; - foreach (var entry in group.Options) - { - if (entry?.Option == null) continue; - if (entry.Weight <= 0f) continue; - into.Add(entry); - } - } - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs.meta deleted file mode 100644 index 3410908..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeGroup.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4202a767d96e70f41b6a7e84eb08a832 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs deleted file mode 100644 index ac43085..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs -using UnityEngine; -using TD.Gameplay.Waves; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// Base class for one card in the post-wave enemy-buff vote. Players collectively choose one - /// of these to permanently attach to the wave they just cleared; it takes effect the next time - /// that wave comes round in the cycle. - /// - /// - /// Mirrors DraftOption deliberately. Same shape — abstract SO, one asset - /// per card, concrete subclasses carry the payload — so the two authoring surfaces read the - /// same way. The difference is who it targets: a draft option applies to a player, an enemy - /// upgrade applies to a wave slot. - /// - /// Identity. Options live in and cross the network - /// as their pool index, the same stable-within-a-match id pattern used by the tower catalog - /// and draft pool. - /// - /// Recording is not this type's job. WaveVote records the winning option id - /// onto the slot via RunState.ServerAddUpgrade; is only - /// for cards that need a side effect beyond being recorded (the vote-meta cards). - /// Ability cards need nothing here — the spawn path reads the slot's recorded set. - /// - public abstract class EnemyUpgradeOption : ScriptableObject - { - [Header("Presentation")] - [Tooltip("Name shown on the vote card.")] - public string DisplayName; - - [Tooltip("Short description shown on the vote card. Say what it does to the enemies, in " + - "the players' terms — this is the only thing they get to judge the vote on.")] - [TextArea(2, 4)] - public string Description; - - [Tooltip("OPTIONAL override for the vote card icon. Leave empty to inherit the icon of " + - "whatever this option grants.")] - public Sprite Icon; - - /// - /// Icon actually shown on the vote card. Subclasses override to fall back to the icon of - /// the thing they grant; the base has nothing to inherit from, so it returns - /// (which may be null). - /// - public virtual Sprite ResolveIcon() => Icon; - - /// - /// Server-only: may this option be OFFERED for right now? Default - /// true; override for cards with prerequisites or ones that would be a no-op. - /// - /// - /// Callers already skip options the slot has taken before, so implementations don't need - /// to re-check that. - /// - public virtual bool IsValidForSlot(RunState run, int slot) => true; - - /// - /// Server-only: side effect to run after this option has been recorded onto - /// . Default no-op — most cards do their work at enemy-spawn time - /// by virtue of being on the slot, not at vote-resolution time. - /// - public virtual void ServerOnApplied(RunState run, int slot) { } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs.meta deleted file mode 100644 index 37a9369..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradeOption.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6b1e9770be72a694a96169d9a9032528 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs deleted file mode 100644 index f6c51e8..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs -using System.Collections.Generic; -using UnityEngine; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// Scene singleton holding every that can appear anywhere in - /// this match. The array index is the option's EnemyUpgradeOptionId — the stable - /// identifier used to replicate vote offers, ballots, and the upgrades recorded on wave slots. - /// - /// - /// Why a flat pool and per-phase groups. The pool supplies network identity: one - /// array, one index per card, identical on every peer. PhaseDefinition.EnemyUpgradeGroups - /// supplies gating: which of those cards a given phase may offer. Folding gating into the pool - /// would make ids phase-relative and therefore unstable across a phase change, which is - /// exactly when replicated slot upgrades are being cleared and rewritten. - /// - /// Plain MonoBehaviour — identical assets on every peer, so there is nothing to sync. - /// The server reads it to generate and resolve votes; clients read it to render vote cards - /// from replicated ids. - /// - public class EnemyUpgradePool : MonoBehaviour - { - public static EnemyUpgradePool Instance { get; private set; } - - [Tooltip("Every EnemyUpgradeOption asset that can appear this match. Array index is the " + - "id used over the network — reordering mid-development is fine, but not between " + - "a host and its clients.")] - [SerializeField] private EnemyUpgradeOption[] options; - - private void Awake() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[EnemyUpgradePool] Multiple instances detected. Only one per scene."); - return; - } - Instance = this; - } - - private void OnDestroy() - { - if (Instance == this) Instance = null; - } - - /// Number of options in the pool. - public int Count => options?.Length ?? 0; - - /// Returns the option at , or null if out of range. - public EnemyUpgradeOption Get(int id) - => (options != null && id >= 0 && id < options.Length) ? options[id] : null; - - /// Resolves an option asset back to its pool id, or -1 if it isn't in the pool. - public int GetId(EnemyUpgradeOption option) - { - if (options == null || option == null) return -1; - for (int i = 0; i < options.Length; i++) - if (options[i] == option) return i; - return -1; - } - - /// - /// Collects the pool ids of every card the given phase groups allow. Cards missing from - /// the pool are reported once and skipped — an authored group referencing an unpooled - /// card is a wiring mistake that would otherwise silently shrink the vote. - /// - public void CollectAllowedIds(EnemyUpgradeGroup[] phaseGroups, - List entryScratch, - List intoIds, - List intoWeights) - { - intoIds.Clear(); - intoWeights.Clear(); - - EnemyUpgradeGroup.CollectCandidates(phaseGroups, entryScratch); - - foreach (var entry in entryScratch) - { - int id = GetId(entry.Option); - if (id < 0) - { - Debug.LogWarning($"[EnemyUpgradePool] '{entry.Option.name}' is referenced by a " + - $"phase's upgrade groups but is not in the pool — it can " + - $"never be offered. Add it to the pool's options array."); - continue; - } - - intoIds.Add(id); - intoWeights.Add(entry.Weight); - } - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs.meta deleted file mode 100644 index 161d578..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/EnemyUpgradePool.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c4d98a01d9b9a7b438a6f91b0b7f498f \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs deleted file mode 100644 index 4d8e872..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs +++ /dev/null @@ -1,419 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; -using TD.Core; -using TD.Gameplay.Waves; - -namespace TD.Gameplay.EnemyUpgrades -{ - /// - /// The shared, open-ballot vote held after each wave clears: players collectively pick - /// which permanent buff the wave they just beat will carry into the next cycle. - /// - /// - /// Ballots are public by design. replicates to everyone the - /// instant a vote is cast, and the HUD paints each voter's slot badge onto the card they chose. - /// That visibility is the point of the mechanic — seeing two teammates converge on "Flying" is - /// what lets the third decide whether to join them or split the vote. A private tally would - /// reduce this to a dice roll with extra steps. - /// - /// Votes stay changeable until the vote resolves, for the same reason. The - /// consequence is that the last player to vote ends the vote instantly (see - /// ), locking their choice in with no chance for anyone to - /// respond. If that reads badly in playtest, the fix is a short grace period after the final - /// ballot rather than closing the ballots. - /// - /// Scene singleton, server-authoritative. Unlike PlayerDraft (one per - /// player) this is one shared object, so votes arrive as plain server RPCs and the server maps - /// the sender to a itself rather than trusting an owner claim. - /// - public class WaveVote : NetworkBehaviour - { - // ----- Singleton --------------------------------------------------- - - public static WaveVote Instance { get; private set; } - - // ----- Inspector --------------------------------------------------- - - [Tooltip("How many buff cards the vote offers. Standard is 3.")] - [SerializeField] private int optionsPerVote = 3; - - // ----- Networked state --------------------------------------------- - - // The EnemyUpgradeOptionIds on the table. Empty when no vote is open. - private NetworkList offeredOptionIds; - - // Ballots indexed by (int)PlayerSlot, sized 10 (slots 0-9; index 0 = PlayerSlot.None and - // is never written). Value is the option id voted for, or NoVote. Public read permission - // is deliberate — see the class remarks. - private NetworkList ballots; - - /// Sentinel stored in for a player who hasn't voted. - public const int NoVote = -1; - - // Wave slot this vote will upgrade, or -1 when no vote is open. - private readonly NetworkVariable targetSlot = new NetworkVariable( - -1, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); - - /// Fired on every peer when the offered set, any ballot, or the open/closed - /// state changes. The HUD subscribes to rebuild the vote panel and its voter badges. - public event System.Action OnVoteChanged; - - // ----- Lifecycle ---------------------------------------------------- - - private void Awake() - { - offeredOptionIds = new NetworkList(); - ballots = new NetworkList(); - } - - public override void OnNetworkSpawn() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[WaveVote] Duplicate WaveVote detected. Only one may exist per scene."); - return; - } - Instance = this; - - if (IsServer) - { - // One entry per PlayerSlot value (None + Player1..Player9). - for (int i = 0; i < 10; i++) ballots.Add(NoVote); - } - - offeredOptionIds.OnListChanged += HandleListChanged; - ballots.OnListChanged += HandleListChanged; - targetSlot.OnValueChanged += HandleTargetChanged; - } - - public override void OnNetworkDespawn() - { - offeredOptionIds.OnListChanged -= HandleListChanged; - ballots.OnListChanged -= HandleListChanged; - targetSlot.OnValueChanged -= HandleTargetChanged; - - if (Instance == this) Instance = null; - } - - private void HandleListChanged(NetworkListEvent _) => OnVoteChanged?.Invoke(); - private void HandleTargetChanged(int _, int __) => OnVoteChanged?.Invoke(); - - // ----- Read API ------------------------------------------------------ - - /// True while a vote is open for players to cast or change a ballot. - public bool IsOpen => targetSlot.Value >= 0; - - /// Wave slot this vote will upgrade, or -1 when closed. - public int TargetSlot => targetSlot.Value; - - public int OptionCount => offeredOptionIds.Count; - - public int GetOptionId(int index) - => (index >= 0 && index < offeredOptionIds.Count) ? offeredOptionIds[index] : -1; - - /// The option voted for, or . - public int GetBallot(PlayerSlot slot) - { - int i = (int)slot; - return (i >= 0 && i < ballots.Count) ? ballots[i] : NoVote; - } - - /// - /// Appends every player slot that voted for . Drives the voter - /// badges the HUD paints onto each card. - /// - public void GetVotersFor(int optionId, List into) - { - into.Clear(); - if (optionId < 0) return; - - foreach (var pms in PlayerMatchState.AllPlayers) - { - if (pms.Slot == PlayerSlot.None) continue; - if (GetBallot(pms.Slot) == optionId) into.Add(pms.Slot); - } - } - - /// - /// True when every connected player with a real slot has cast a ballot. The inter-wave - /// step uses this to end the vote early instead of burning the whole timer. - /// - public bool AllPlayersVoted - { - get - { - if (!IsOpen) return false; - - bool any = false; - foreach (var pms in PlayerMatchState.AllPlayers) - { - if (pms.Slot == PlayerSlot.None) continue; - any = true; - if (GetBallot(pms.Slot) == NoVote) return false; - } - return any; - } - } - - // ----- Server: open / resolve ---------------------------------------- - - // Scratch reused across vote generation; server is single-threaded. - private readonly List entryScratch = new List(); - private readonly List idScratch = new List(); - private readonly List weightScratch = new List(); - private readonly List tiedScratch = new List(); - - /// - /// Server-only: open a vote for , drawing cards from the - /// current phase's allowed pool. Returns false (and opens nothing) if there is nothing - /// legal left to offer — a wave that has already collected every card its phase allows - /// simply gets no vote rather than an empty panel. - /// - public bool ServerOpenVote(int waveSlot) - { - if (!IsServer) return false; - - var run = RunState.Instance; - var pool = EnemyUpgradePool.Instance; - if (run == null || pool == null) - { - Debug.LogWarning("[WaveVote] No RunState or EnemyUpgradePool in scene — " + - "skipping the enemy-buff vote."); - return false; - } - - if (!CollectCandidatesFor(waveSlot, run, pool)) - { - Debug.Log($"[WaveVote] No enemy-buff cards left to offer for wave slot " + - $"{waveSlot}; skipping the vote."); - return false; - } - - // Weighted draw without replacement. - offeredOptionIds.Clear(); - int draws = Mathf.Min(optionsPerVote, idScratch.Count); - for (int n = 0; n < draws; n++) - { - int pick = DrawWeightedIndex(weightScratch); - if (pick < 0) break; - - offeredOptionIds.Add(idScratch[pick]); - idScratch.RemoveAt(pick); - weightScratch.RemoveAt(pick); - } - - ServerClearBallots(); - targetSlot.Value = waveSlot; - return true; - } - - /// - /// Server-only: tally the ballots, apply the winner to the target slot, and close the - /// vote. Returns the winning option id, or -1 if no vote was open. - /// - /// - /// Ties resolve randomly among the tied options. At three players and three cards a 1/1/1 - /// split is common, and with open ballots the players can see it coming and break it - /// themselves — which is the intended pressure, not a flaw in the tie-break. - /// - /// If nobody voted at all (everyone idle), one of the offered cards is chosen at - /// random. Skipping the buff entirely would quietly make idling the optimal play. - /// - public int ServerResolve() - { - if (!IsServer || !IsOpen) return -1; - - int slot = targetSlot.Value; - int winner = TallyWinner(); - - if (winner >= 0) - { - var run = RunState.Instance; - var pool = EnemyUpgradePool.Instance; - - run?.ServerAddUpgrade(slot, winner); - pool?.Get(winner)?.ServerOnApplied(run, slot); - - Debug.Log($"[WaveVote] Wave slot {slot} gains " + - $"'{pool?.Get(winner)?.DisplayName ?? winner.ToString()}'."); - } - - ServerClose(); - return winner; - } - - /// - /// Server-only: apply buffs to outright, - /// with no vote. Returns how many actually landed. Used by the vote-meta cards that trade - /// a future vote away for extra buffs. - /// - /// - /// Deliberately opens no ballot: the card's whole cost is that the players don't get - /// to choose this time. Drawing from the same weighted, slot-filtered candidate set the - /// vote would have used keeps the outcome fair rather than worst-case. - /// - public int ServerAutoApply(int slot, int count) - { - if (!IsServer || count <= 0) return 0; - - var run = RunState.Instance; - var pool = EnemyUpgradePool.Instance; - if (run == null || pool == null) return 0; - - var phase = run.CurrentPhase; - if (phase == null) return 0; - - int applied = 0; - for (int n = 0; n < count; n++) - { - // Re-collect each time: applying one buff can invalidate another (a card the slot - // now has, or one whose prerequisite just changed). - if (!CollectCandidatesFor(slot, run, pool)) break; - - int pick = DrawWeightedIndex(weightScratch); - if (pick < 0) break; - - int id = idScratch[pick]; - run.ServerAddUpgrade(slot, id); - pool.Get(id)?.ServerOnApplied(run, slot); - applied++; - - Debug.Log($"[WaveVote] Auto-applied '{pool.Get(id)?.DisplayName ?? id.ToString()}' " + - $"to wave slot {slot}."); - } - - return applied; - } - - /// Server-only: close the vote without applying anything. - public void ServerClose() - { - if (!IsServer) return; - targetSlot.Value = -1; - offeredOptionIds.Clear(); - ServerClearBallots(); - } - - private void ServerClearBallots() - { - for (int i = 0; i < ballots.Count; i++) ballots[i] = NoVote; - } - - // Highest vote count wins; ties broken at random. No votes cast → random offered card. - private int TallyWinner() - { - if (offeredOptionIds.Count == 0) return -1; - - int best = 0; - tiedScratch.Clear(); - - for (int i = 0; i < offeredOptionIds.Count; i++) - { - int id = offeredOptionIds[i]; - int count = 0; - - foreach (var pms in PlayerMatchState.AllPlayers) - { - if (pms.Slot == PlayerSlot.None) continue; - if (GetBallot(pms.Slot) == id) count++; - } - - if (count > best) - { - best = count; - tiedScratch.Clear(); - tiedScratch.Add(id); - } - else if (count == best && best > 0) - { - tiedScratch.Add(id); - } - } - - if (tiedScratch.Count == 0) - { - // Nobody voted — pick one of the offered cards rather than letting the wave - // escape unbuffed, which would make going idle the strongest play. - return offeredOptionIds[Random.Range(0, offeredOptionIds.Count)]; - } - - return tiedScratch[Random.Range(0, tiedScratch.Count)]; - } - - /// - /// Fills / with the cards this phase - /// allows that can still meaningfully take. Returns false when - /// nothing qualifies. - /// - private bool CollectCandidatesFor(int slot, RunState run, EnemyUpgradePool pool) - { - var phase = run.CurrentPhase; - if (phase == null) return false; - - pool.CollectAllowedIds(phase.EnemyUpgradeGroups, entryScratch, idScratch, weightScratch); - - // Filter to what this slot can actually take: not already applied, and the card itself - // agrees it's a meaningful offer. - for (int i = idScratch.Count - 1; i >= 0; i--) - { - int id = idScratch[i]; - var option = pool.Get(id); - - bool valid = option != null - && !run.SlotHasUpgrade(slot, id) - && option.IsValidForSlot(run, slot); - - if (!valid) - { - idScratch.RemoveAt(i); - weightScratch.RemoveAt(i); - } - } - - return idScratch.Count > 0; - } - - private static int DrawWeightedIndex(List weights) - { - if (weights == null || weights.Count == 0) return -1; - - float total = 0f; - for (int i = 0; i < weights.Count; i++) total += Mathf.Max(0f, weights[i]); - if (total <= 0f) return -1; - - float roll = Random.value * total; - for (int i = 0; i < weights.Count; i++) - { - roll -= Mathf.Max(0f, weights[i]); - if (roll <= 0f) return i; - } - return weights.Count - 1; // float drift fallback - } - - // ----- Client → server ------------------------------------------------ - - /// - /// Cast or change this player's vote. Any client may send; the server resolves the sender - /// to a slot itself and ignores anything it can't attribute or that isn't on the table. - /// - [Rpc(SendTo.Server)] - public void RequestVoteRpc(int optionId, RpcParams rpcParams = default) - { - if (!IsOpen) return; - - var senderSlot = PlayerMatchState.SlotForClient(rpcParams.Receive.SenderClientId); - if (senderSlot == PlayerSlot.None) return; - - // Only options actually on the table are accepted — a client can't vote a card in. - bool offered = false; - for (int i = 0; i < offeredOptionIds.Count; i++) - if (offeredOptionIds[i] == optionId) { offered = true; break; } - if (!offered) return; - - int index = (int)senderSlot; - if (index >= 0 && index < ballots.Count) ballots[index] = optionId; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs.meta b/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs.meta deleted file mode 100644 index 20d621a..0000000 --- a/Assets/_Project/Scripts/Gameplay/EnemyUpgrades/WaveVote.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a18321dc2d138034fbdb5f705f19f893 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/GoldConfig.cs b/Assets/_Project/Scripts/Gameplay/GoldConfig.cs index 2707d91..965ee7e 100644 --- a/Assets/_Project/Scripts/Gameplay/GoldConfig.cs +++ b/Assets/_Project/Scripts/Gameplay/GoldConfig.cs @@ -1,68 +1,91 @@ // Assets/_Project/Scripts/Gameplay/GoldConfig.cs using System; using UnityEngine; -using UnityEngine.Serialization; namespace TD.Gameplay { /// - /// Gold rules for one encounter slot, addressed by position in the run rather than by - /// which wave happens to occupy it. + /// Per-wave gold rules nested under . Each entry maps to one + /// wave by array index in . /// /// - /// Position, not identity. Under the 2.0 run structure the waves filling each slot are - /// drawn at random from a phase pool, so "the gold for wave 3" means the run's third - /// encounter, whatever spawns in it. Payouts are a property of how far the players have - /// progressed — not of which enemy they happened to draw. + /// Pairing with WaveDefinition. The runtime pairing of gold entry to wave is by + /// array index — entry 0 applies to wave 1, etc. The reference here + /// is OPTIONAL and exists purely so the inspector can compute and display the + /// read-only value (which needs to know the wave's + /// total enemy count to multiply against ). Leaving it + /// unset just hides the kill-reward portion of the preview; runtime is unaffected. /// [Serializable] - public class EncounterGoldEntry + public class WaveGoldEntry { - [Tooltip("Gold awarded to the killing player per enemy slain during this encounter. " + - "Applies uniformly to every enemy type.")] + [Tooltip("Optional reference to the WaveDefinition this entry pairs with. " + + "Used ONLY for the inspector preview total — runtime pairing is by " + + "array index in GoldConfig.Waves. Drag the matching WaveDefinition " + + "here to see the live total computed under this entry.")] + public WaveDefinition Wave; + + [Tooltip("Gold awarded to the killing player per enemy slain during this wave. " + + "Applies uniformly to every enemy type in the wave.")] public int GoldPerEnemy = 10; - [Tooltip("Flat bonus gold awarded to every active player when this encounter is fully " + + [Tooltip("Flat bonus gold awarded to every active player when this wave is fully " + "cleared (all enemies dead or reached the goal).")] public int CompletionBonus = 50; - [Tooltip("Extra bonus gold awarded to a player who cleared this encounter without any " + + [Tooltip("Extra bonus gold awarded to a player who cleared this wave without any " + "enemy from their own zone escaping their leak volume. Stacks on top of " + - "CompletionBonus.")] + "CompletionBonus for the no-leak achievement.")] public int NoLeaksBonus = 50; /// - /// Guaranteed gold for a player who clears this encounter: the two bonuses, with no - /// kill income counted. + /// Read-only preview of the maximum gold a single player could earn in this wave: + /// GoldPerEnemy × totalEnemyCount + CompletionBonus + NoLeaksBonus. /// /// - /// Kill income can't be known here — the wave occupying this slot is drawn at runtime, so - /// its enemy count varies per run. - /// supplies an estimate for the inspector's projected totals. + /// Returns just CompletionBonus + NoLeaksBonus if is null + /// (no enemy count to multiply against). Pure computation — safe at edit time and + /// at runtime. The custom inspector under renders this as + /// a non-editable label under the entry's fields. /// - public int GuaranteedBonusGold => CompletionBonus + NoLeaksBonus; - - /// - /// Projected best-case earnings for one player this encounter, given an assumed enemy - /// count. Editor tuning aid only — nothing at runtime reads it. - /// - public int ProjectedTotal(int assumedEnemyCount) - => GoldPerEnemy * Mathf.Max(0, assumedEnemyCount) + GuaranteedBonusGold; + public int PreviewTotalGold + { + get + { + int total = CompletionBonus + NoLeaksBonus; + if (Wave != null && Wave.Entries != null) + { + int enemies = 0; + foreach (var e in Wave.Entries) + { + if (e.EnemyType != null && e.Count > 0) + enemies += e.Count; + } + total += GoldPerEnemy * enemies; + } + return total; + } + } } /// /// Single source of truth for every gold-related tunable in the game. /// /// - /// Wiring. Assign one GoldConfig asset to WaveManager.goldConfig in the Match - /// scene. WaveManager seeds per-player starting gold from , reads - /// for kill rewards, and awards the completion - /// and no-leak bonuses as each encounter clears. + /// Inspector layout. StartingGold is at the top and applies to every player. + /// The Waves array follows, each element collapsible in the inspector with the + /// per-wave rules and a read-only preview total computed from the entry's data. /// - /// No per-enemy-type bounties. Every enemy killed in a given encounter grants the - /// same reward regardless of . With enemy types now drawn at - /// random per phase, per-type bounties would make income depend on the luck of the draw - /// rather than on progression. + /// Wiring. Assign one GoldConfig asset to WaveManager.goldConfig in + /// the Match scene. WaveManager initializes per-player starting gold from + /// at match start, uses + /// to compute kill rewards, and awards / + /// when each wave clears. + /// + /// No per-enemy-type bounties. Every enemy killed in wave N grants the same + /// regardless of . + /// If per-type variation becomes a design need, extend WaveGoldEntry with a per-type + /// table; the current model intentionally favors simplicity. /// [CreateAssetMenu(fileName = "GoldConfig", menuName = "TD/Gold Config", order = 2)] public class GoldConfig : ScriptableObject @@ -70,58 +93,20 @@ namespace TD.Gameplay [Tooltip("Gold each player starts the match with. Same for every player.")] public int StartingGold = 100; - [Tooltip("Gold rules per encounter, in run order. Element 0 = the run's first encounter. " + - "Encounters are counted continuously — cycles do NOT restart the count — so one " + - "phase of 5 waves × 3 cycles + a boss needs 16 entries. Missing entries pay " + - "zero for that encounter.")] - [FormerlySerializedAs("Waves")] - public EncounterGoldEntry[] Encounters; - - [Header("Editor preview")] - [Tooltip("Assumed enemies per encounter, used ONLY to project totals in this inspector. " + - "Nothing at runtime reads it — the real count comes from whichever wave the run " + - "draws into each slot.")] - [Min(0)] - public int PreviewEnemiesPerEncounter = 40; + [Tooltip("Per-wave gold rules. Element 0 = Wave 1. Match the order and length of " + + "WaveManager.waveDefinitions; extra entries are ignored, missing entries " + + "fall back to zero gold for that wave.")] + public WaveGoldEntry[] Waves; /// - /// Returns the gold rules for the given 1-based encounter number - /// (RunState.GlobalEncounterNumber), or null if out of range. + /// Returns the gold entry for the given 1-based wave number, or null if out of range. /// - /// - /// Keyed by run position, not by wave slot within a cycle. The same five waves come - /// round three times per phase, so a slot-keyed table would pay the same on cycle 3 as on - /// cycle 1 while the enemies grew steadily stronger from the buffs voted onto them. A - /// run-long counter lets payouts climb with the difficulty. - /// - public EncounterGoldEntry GetEncounterEntry(int encounterNumber) + public WaveGoldEntry GetWaveEntry(int waveNumber) { - if (Encounters == null) return null; - int index = encounterNumber - 1; - if (index < 0 || index >= Encounters.Length) return null; - return Encounters[index]; - } - - /// Number of authored encounter entries. - public int EncounterCount => Encounters?.Length ?? 0; - - /// - /// Editor tuning aid: cumulative projected earnings for one player from the run's first - /// encounter through inclusive, assuming - /// kills each time and no leaks. - /// - public int ProjectedCumulativeThrough(int encounterNumber) - { - if (Encounters == null) return StartingGold; - - int total = StartingGold; - int last = Mathf.Min(encounterNumber, Encounters.Length); - for (int i = 0; i < last; i++) - { - if (Encounters[i] == null) continue; - total += Encounters[i].ProjectedTotal(PreviewEnemiesPerEncounter); - } - return total; + if (Waves == null) return null; + int index = waveNumber - 1; + if (index < 0 || index >= Waves.Length) return null; + return Waves[index]; } } } diff --git a/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs new file mode 100644 index 0000000..52efbdc --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs @@ -0,0 +1,195 @@ +// Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs +using System.Collections.Generic; +using Unity.Collections; +using Unity.Netcode; +using UnityEngine; +using TD.Core; + +namespace TD.Gameplay +{ + /// + /// Holds all buffs currently owned by one player. Lives on the Player prefab + /// alongside and . + /// + /// + /// Purchase flow. The owning client calls + /// with a category index. The server + /// validates gold, deducts the cost, picks a random + /// from the category's pool, and appends an + /// to the replicated list. + /// + /// Multiplier query. is called by + /// on the server each time a tower fires. + /// It multiplies all active buffs for the requested stat together. + /// + /// Enable / disable. Enemies can call + /// and by index to temporarily suppress buffs + /// without removing them from the list. + /// + public class PlayerBuffManager : NetworkBehaviour + { + // ----- Static registry (mirrors PlayerGoldManager pattern) ----------- + + private static readonly Dictionary s_byClientId + = new Dictionary(); + + /// Returns the PlayerBuffManager owned by the given client, or null. + public static PlayerBuffManager GetForClient(ulong clientId) + { + s_byClientId.TryGetValue(clientId, out var mgr); + return mgr; + } + + /// Convenience: the local client's own buff manager. + public static PlayerBuffManager Local + { + get + { + var nm = NetworkManager.Singleton; + if (nm == null) return null; + return GetForClient(nm.LocalClientId); + } + } + + // ----- Inspector ------------------------------------------------------ + + [Tooltip("Purchasable buff categories shown in the buff menu. Index in this " + + "array is the categoryIndex passed to RequestPurchaseBuffRpc.")] + [SerializeField] private BuffCategory[] categories; + + private NetworkList buffs; + + private void Awake() + { + buffs = new NetworkList(); + } + + // ----- NGO lifecycle ---------------------------------------------- + + public override void OnNetworkSpawn() + { + s_byClientId[OwnerClientId] = this; + } + + public override void OnNetworkDespawn() + { + if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this) + s_byClientId.Remove(OwnerClientId); + } + + // ----- Public API ------------------------------------------------- + + /// + /// Returns the combined multiplier for across all + /// active buffs owned by this player. Returns 1.0 if no matching buffs + /// are active. Safe to call from any peer. + /// + public float GetMultiplier(BuffStat stat) + { + float result = 1f; + for (int i = 0; i < buffs.Count; i++) + { + var buff = buffs[i]; + if (buff.Stat == stat && buff.IsActive) + result *= buff.Multiplier; + } + return result; + } + + /// + /// Returns the number of buff categories available, for building the UI. + /// + public int CategoryCount => categories?.Length ?? 0; + + /// Returns the category at the given index, or null. + public BuffCategory GetCategory(int index) + => (categories != null && index >= 0 && index < categories.Length) + ? categories[index] + : null; + + /// Read-only access to the buff list for UI rendering. + public NetworkList Buffs => buffs; + + // ----- Server helpers --------------------------------------------- + + /// + /// Server-only: disables the buff at . + /// The buff remains in the list and can be re-enabled. + /// + public void ServerDisableBuff(int index) + { + if (!IsServer) return; + if (index < 0 || index >= buffs.Count) return; + + var b = buffs[index]; + if (!b.IsActive) return; + b.IsActive = false; + buffs[index] = b; + } + + /// Server-only: re-enables the buff at . + public void ServerEnableBuff(int index) + { + if (!IsServer) return; + if (index < 0 || index >= buffs.Count) return; + + var b = buffs[index]; + if (b.IsActive) return; + b.IsActive = true; + buffs[index] = b; + } + + // ----- Purchase RPC ----------------------------------------------- + + /// + /// Owning-client entry point. Sends a request to the server to purchase + /// a random buff from the category at . + /// The server validates gold and adds the buff if the purchase succeeds. + /// + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] + public void RequestPurchaseBuffRpc(int categoryIndex) + { + if (categories == null || categoryIndex < 0 || categoryIndex >= categories.Length) + { + Debug.LogWarning("[PlayerBuffManager] RequestPurchaseBuff: invalid category index."); + return; + } + + var category = categories[categoryIndex]; + if (category == null || category.Pool == null || category.Pool.Length == 0) + { + Debug.LogWarning("[PlayerBuffManager] RequestPurchaseBuff: category has no buffs."); + return; + } + + var goldManager = PlayerGoldManager.GetForClient(OwnerClientId); + if (goldManager == null) + { + Debug.LogError("[PlayerBuffManager] RequestPurchaseBuff: no PlayerGoldManager found."); + return; + } + + if (goldManager.CurrentGold < category.Cost) + { + Debug.Log($"[PlayerBuffManager] Client {OwnerClientId} cannot afford " + + $"'{category.DisplayName}' (cost {category.Cost}, " + + $"gold {goldManager.CurrentGold})."); + return; + } + + goldManager.DeductGold(category.Cost); + + var def = category.Pool[Random.Range(0, category.Pool.Length)]; + buffs.Add(new ActiveBuff + { + Stat = def.Stat, + Multiplier = def.Multiplier, + IsActive = true, + DisplayName = new FixedString64Bytes(def.DisplayName ?? string.Empty), + }); + + Debug.Log($"[PlayerBuffManager] Client {OwnerClientId} purchased buff " + + $"'{def.DisplayName}' ({def.Stat} ×{def.Multiplier})."); + } + } +} diff --git a/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs.meta b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs.meta new file mode 100644 index 0000000..b1951a5 --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7775ee3a2f441b52480aabf54be6c1b6 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/PlayerMatchState.cs b/Assets/_Project/Scripts/Gameplay/PlayerMatchState.cs index d572bd7..212dbd7 100644 --- a/Assets/_Project/Scripts/Gameplay/PlayerMatchState.cs +++ b/Assets/_Project/Scripts/Gameplay/PlayerMatchState.cs @@ -210,21 +210,17 @@ namespace TD.Gameplay // --- Slot allocation (server-only) ------------------------------- - // Caps at MatchRules.MaxPlayers rather than at the PlayerSlot enum's range — the enum - // still runs to 9 so baked LevelData owner grids stay valid, but only the first - // MaxPlayers slots are ever handed out. See MatchRules for why. private static PlayerSlot AllocateNextSlot() { - for (int i = 1; i <= MatchRules.MaxPlayers; i++) + for (int i = 1; i <= 9; i++) { var candidate = (PlayerSlot)i; if (!s_assignedSlots.Contains(candidate)) return candidate; } - Debug.LogError($"[PlayerMatchState] No free PlayerSlot (lobby is full at " + - $"{MatchRules.MaxPlayers} players). Returning None — this client " + - $"will be unable to play."); + Debug.LogError("[PlayerMatchState] No free PlayerSlot (already 9 players). " + + "Returning None — this client will be unable to play."); return PlayerSlot.None; } } diff --git a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs b/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs deleted file mode 100644 index 4782e9f..0000000 --- a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs +++ /dev/null @@ -1,268 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs -using System.Collections; -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; -using TD.Core; -using TD.Gameplay.BuilderSpells; - -namespace TD.Gameplay -{ - /// - /// Per-player set of granted builder spells and their cooldowns. Lives on the Player - /// prefab alongside and . - /// - /// - /// Slot == grant order == hotkey. is append-only; a - /// slot's index in the list is both its identity and the index into - /// . There is no player-configurable rebinding. - /// - /// Cast flow. The owning client calls with a - /// slot index and an aimed world point. The server re-validates everything (slot exists, - /// off cooldown, ) since client-side checks in - /// are UX-only, resolves the - /// via . An instant - /// spell ( == 0) resolves on cast: a hit starts - /// the cooldown and fires ; a miss is a no-op. A delayed - /// spell (a projectile, e.g. the Fireball meteor) commits on the throw — cooldown + the falling - /// visual fire immediately — while its damage and impact sound are held until the projectile - /// lands seconds later. - /// - public class PlayerSpellLoadout : NetworkBehaviour - { - /// Hard cap on granted spells, matching the number of hotkey slots available. - public const int MaxSpellSlots = 4; - - // ----- Static registry (mirrors BuilderUpgradeManager) ----- - - private static readonly Dictionary s_byClientId - = new Dictionary(); - - /// Returns the loadout owned by the given client, or null. - public static PlayerSpellLoadout GetForClient(ulong clientId) - { - s_byClientId.TryGetValue(clientId, out var loadout); - return loadout; - } - - /// Convenience: the local client's own loadout. - public static PlayerSpellLoadout Local - { - get - { - var nm = NetworkManager.Singleton; - if (nm == null || !nm.IsClient) return null; - return GetForClient(nm.LocalClientId); - } - } - - // ----- Networked state -------------------------------------------- - - private readonly NetworkList spells = new NetworkList(); - - // Every kind ever granted this match, including ones since upgraded away. Unlike - // `spells`, entries here are never removed — see PlayerHasEverGranted. - private readonly NetworkList everGrantedKinds = new NetworkList(); - - /// Fired on every peer when a spell is granted or a cooldown changes. - public event System.Action OnLoadoutChanged; - - // ----- NGO lifecycle ------------------------------------------------ - - public override void OnNetworkSpawn() - { - s_byClientId[OwnerClientId] = this; - spells.OnListChanged += HandleSpellsChanged; - } - - public override void OnNetworkDespawn() - { - spells.OnListChanged -= HandleSpellsChanged; - - if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this) - s_byClientId.Remove(OwnerClientId); - } - - private void HandleSpellsChanged(NetworkListEvent change) => OnLoadoutChanged?.Invoke(); - - // ----- Read API ----------------------------------------------------- - - /// Number of spells currently granted. - public int SlotCount => spells.Count; - - /// True if this player has already been granted the given spell. - public bool PlayerHasSpell(BuilderSpellKind kind) - { - for (int i = 0; i < spells.Count; i++) - { - if (spells[i].Kind == kind) return true; - } - return false; - } - - /// The spell kind occupying , or null if out of range. - public BuilderSpellKind? GetKind(int slot) - => (slot >= 0 && slot < spells.Count) ? spells[slot].Kind : (BuilderSpellKind?)null; - - /// - /// True if this player has ever been granted the given spell this match, whether or - /// not it's still occupying a slot (e.g. it may have since been upgraded away). Used - /// by so a base spell already - /// upgraded past is never re-offered. - /// - public bool PlayerHasEverGranted(BuilderSpellKind kind) => everGrantedKinds.Contains((byte)kind); - - /// True if is out of range, empty, or still cooling down. - public bool IsSlotOnCooldown(int slot) - { - if (slot < 0 || slot >= spells.Count) return true; - - var nm = NetworkManager.Singleton; - if (nm == null) return false; - - return spells[slot].CooldownEndServerTime > nm.ServerTime.Time; - } - - /// Seconds remaining on 's cooldown, or 0 if ready/invalid. - public float GetCooldownRemaining(int slot) - { - if (slot < 0 || slot >= spells.Count) return 0f; - - var nm = NetworkManager.Singleton; - if (nm == null) return 0f; - - double remaining = spells[slot].CooldownEndServerTime - nm.ServerTime.Time; - return remaining > 0d ? (float)remaining : 0f; - } - - // ----- Server mutation ----------------------------------------------- - - /// - /// Server-only: grants the given spell (a draft pick) into the next free slot. - /// No-op if already granted or slots are full. Returns true if actually granted. - /// - public bool ServerGrantSpell(BuilderSpellKind kind) - { - if (!IsServer) return false; - if (spells.Count >= MaxSpellSlots) return false; - if (PlayerHasSpell(kind)) return false; - - spells.Add(SpellSlot.CreateReady(kind)); - if (!everGrantedKinds.Contains((byte)kind)) everGrantedKinds.Add((byte)kind); - return true; - } - - /// - /// Server-only: replaces a previously granted spell with a different one (an upgrade - /// pick), in place — the upgraded spell keeps the base spell's hotkey slot and starts - /// off cooldown. No-op if the old spell isn't currently granted or the new one already - /// is. Returns true if the swap happened. - /// - public bool ServerUpgradeSpell(BuilderSpellKind oldKind, BuilderSpellKind newKind) - { - if (!IsServer) return false; - if (PlayerHasSpell(newKind)) return false; - - for (int i = 0; i < spells.Count; i++) - { - if (spells[i].Kind == oldKind) - { - spells[i] = SpellSlot.CreateReady(newKind); - if (!everGrantedKinds.Contains((byte)newKind)) everGrantedKinds.Add((byte)newKind); - return true; - } - } - return false; - } - - // ----- Cast RPC ----------------------------------------------------- - - /// - /// Owning-client entry point. Requests the server resolve a cast of the spell in - /// at . All validation happens - /// here on the server; the client only uses this to trigger an attempt. - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] - public void RequestCastSpellRpc(int slot, Vector3 targetPoint) - { - if (MatchState.Instance == null || MatchState.Instance.Phase != MatchPhase.Playing) - return; - - if (slot < 0 || slot >= spells.Count) return; - - var slotValue = spells[slot]; - if (slotValue.CooldownEndServerTime > NetworkManager.ServerTime.Time) return; - - var definition = BuilderSpellPool.Instance?.Get(slotValue.Kind); - if (definition == null) - { - Debug.LogWarning($"[PlayerSpellLoadout] No BuilderSpellDefinition for {slotValue.Kind}."); - return; - } - - if (definition.ImpactDelay <= 0f) - { - // Instant spell (e.g. Slow Area): resolve on cast. A miss (hit nothing) is a no-op - // and does NOT start the cooldown — unchanged behavior. - if (!definition.ServerCast(OwnerClientId, targetPoint)) return; - - StartCooldown(slot, definition); - PlayVfxClientRpc(slotValue.Kind, targetPoint); - } - else - { - // Delayed spell (e.g. the Fireball meteor): the projectile has to fall before it - // lands, so the cast is COMMITTED on the throw — cooldown starts and the falling - // visual spawns now — while damage and the impact sound wait until it hits the - // ground (ImpactDelay later). Enemies are re-scanned at impact, so movement during - // the fall resolves correctly. - StartCooldown(slot, definition); - PlayVfxClientRpc(slotValue.Kind, targetPoint); - StartCoroutine(ServerResolveImpactAfterDelay( - slotValue.Kind, OwnerClientId, targetPoint, definition.ImpactDelay)); - } - } - - // Server-only: stamp the slot's cooldown from the definition and replicate it. - private void StartCooldown(int slot, BuilderSpellDefinition definition) - { - var slotValue = spells[slot]; - slotValue.CooldownEndServerTime = NetworkManager.ServerTime.Time + definition.Cooldown; - spells[slot] = slotValue; - } - - // Server-only: apply a delayed spell's effect once its projectile has landed. Re-resolves - // targets at impact — the enemy set may have shifted during the fall. - private IEnumerator ServerResolveImpactAfterDelay( - BuilderSpellKind kind, ulong clientId, Vector3 targetPoint, float delay) - { - yield return new WaitForSeconds(delay); - if (!IsServer) yield break; - BuilderSpellPool.Instance?.Get(kind)?.ServerCast(clientId, targetPoint); - } - - [ClientRpc] - private void PlayVfxClientRpc(BuilderSpellKind kind, Vector3 targetPoint) - { - var def = BuilderSpellPool.Instance?.Get(kind); - if (def == null) return; - - def.ClientSpawnVfx(targetPoint); // spawn the (possibly falling) visual now - - if (def.ImpactDelay <= 0f) - def.ClientPlayImpact(targetPoint); - else - StartCoroutine(ClientPlayImpactAfterDelay(kind, targetPoint, def.ImpactDelay)); - } - - // Client-side: play the impact (sound + any contact visual) when the projectile lands. - // Timed locally off the same ImpactDelay so it stays in lockstep with this peer's own - // falling visual — no second RPC, no double latency. - private IEnumerator ClientPlayImpactAfterDelay( - BuilderSpellKind kind, Vector3 targetPoint, float delay) - { - yield return new WaitForSeconds(delay); - BuilderSpellPool.Instance?.Get(kind)?.ClientPlayImpact(targetPoint); - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs.meta b/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs.meta deleted file mode 100644 index 559df0e..0000000 --- a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: dfa83208b02c50b40866bb1846240c4a \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/PlayerTowerDeck.cs b/Assets/_Project/Scripts/Gameplay/PlayerTowerDeck.cs index 9d7b54d..eb5687c 100644 --- a/Assets/_Project/Scripts/Gameplay/PlayerTowerDeck.cs +++ b/Assets/_Project/Scripts/Gameplay/PlayerTowerDeck.cs @@ -7,8 +7,8 @@ namespace TD.Gameplay { /// /// Per-player set of unlocked tower types — the player's "deck". Lives on the - /// Player prefab alongside and - /// . + /// Player prefab alongside , + /// , and . /// /// /// Roguelike keystone. Players no longer see every tower in the match @@ -146,30 +146,5 @@ namespace TD.Gameplay unlockedTypeIds.Add(towerTypeId); return true; } - - /// - /// Server-only: replaces a previously unlocked tower type with a different one (an - /// upgrade pick) — every tower of that type placed from now on uses the new definition. - /// Already-placed towers keep whatever type they were placed with; this only changes - /// what's placeable going forward. No-op if the old type isn't currently unlocked or - /// the new one already is. Returns true if the swap happened. - /// - public bool ServerUpgradeTower(int oldTypeId, int newTypeId) - { - if (!IsServer) return false; - if (newTypeId <= 0) return false; - if (Contains(newTypeId)) return false; - - for (int i = 0; i < unlockedTypeIds.Count; i++) - { - if (unlockedTypeIds[i] == oldTypeId) - { - unlockedTypeIds.RemoveAt(i); - unlockedTypeIds.Add(newTypeId); - return true; - } - } - return false; - } } } diff --git a/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs b/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs deleted file mode 100644 index 0b17d88..0000000 --- a/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; - -namespace TD.Gameplay -{ - /// - /// Per-player set of unlocked tower upgrade nodes — the tower types this player is - /// allowed to convert an existing tower into. Lives on the Player prefab alongside - /// . - /// - /// - /// Distinct from the deck, deliberately. is what you - /// can build from scratch; this is what you can upgrade into. They have to be - /// separate sets because the 2.0 model is two-step: a draft pick unlocks a node, and gold spent - /// on an already-placed tower converts it. Unlocking an upgrade must not make it directly - /// buildable, or the gold step — the entire cost of the upgrade — is bypassed. - /// - /// The tree lives in the data. Edges are TowerDefinition.UpgradePaths; this - /// component only records which nodes a player has earned the right to use. Whether a - /// particular tower can take a particular upgrade is a question for the tree (is it a child of - /// what's placed?) crossed with this set (has the player unlocked it?). - /// - /// Append-only within a match, mirroring the deck. Reset happens by re-initializing at - /// match start, so Retry / return-to-lobby cycles start clean. - /// - public class PlayerTowerUpgrades : NetworkBehaviour - { - // ----- Static registry (mirrors PlayerTowerDeck / PlayerGoldManager) ----- - - private static readonly Dictionary s_byClientId - = new Dictionary(); - - public static PlayerTowerUpgrades GetForClient(ulong clientId) - { - s_byClientId.TryGetValue(clientId, out var upgrades); - return upgrades; - } - - public static PlayerTowerUpgrades Local - { - get - { - var nm = NetworkManager.Singleton; - if (nm == null || !nm.IsClient) return null; - return GetForClient(nm.LocalClientId); - } - } - - // ----- Networked state -------------------------------------------- - - // TowerTypeIds (catalog indices) this player may upgrade into. - private NetworkList unlockedNodes; - - /// Fired on every peer when the unlocked set changes. The HUD subscribes so a - /// selected tower's upgrade buttons appear the moment a draft grants them. - public event System.Action OnUpgradesChanged; - - private void Awake() - { - unlockedNodes = new NetworkList(); - } - - public override void OnNetworkSpawn() - { - s_byClientId[OwnerClientId] = this; - unlockedNodes.OnListChanged += HandleListChanged; - } - - public override void OnNetworkDespawn() - { - unlockedNodes.OnListChanged -= HandleListChanged; - if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this) - s_byClientId.Remove(OwnerClientId); - } - - private void HandleListChanged(NetworkListEvent _) => OnUpgradesChanged?.Invoke(); - - // ----- Read API --------------------------------------------------- - - public int Count => unlockedNodes.Count; - - public int GetTypeIdAt(int index) => unlockedNodes[index]; - - /// True if this player has unlocked the given upgrade node. - public bool Contains(int towerTypeId) - { - for (int i = 0; i < unlockedNodes.Count; i++) - if (unlockedNodes[i] == towerTypeId) return true; - return false; - } - - // ----- Server API ------------------------------------------------- - - /// Server-only: clear the unlocked set. Called at match start. - public void ServerInitialize() - { - if (!IsServer) return; - unlockedNodes.Clear(); - } - - /// - /// Server-only: unlock an upgrade node. Returns false if already unlocked (so a draft - /// option can report a wasted pick rather than silently succeeding). - /// - public bool ServerUnlock(int towerTypeId) - { - if (!IsServer) return false; - if (towerTypeId < 0 || Contains(towerTypeId)) return false; - - unlockedNodes.Add(towerTypeId); - return true; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs.meta b/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs.meta deleted file mode 100644 index c0821f7..0000000 --- a/Assets/_Project/Scripts/Gameplay/PlayerTowerUpgrades.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f60f6928562351f4891142ad59ab6352 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs b/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs deleted file mode 100644 index 2f162d1..0000000 --- a/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs -using UnityEngine.InputSystem; - -namespace TD.Gameplay -{ - /// - /// The fixed key bound to each spell hotkey slot (slot index == grant order == - /// list index). Shared by - /// (reads input) and the HUD hotbar (renders key - /// labels) so the two can never drift apart. - /// - /// - /// 's HotkeyLayout already claims the entire - /// Q/W/E/R/T/A/S/D/F/G/Z/X/C/V/B block for the build command grid, so spell casting uses - /// the number row instead. - /// - public static class SpellHotkeys - { - public static readonly Key[] Layout = - { - Key.Digit1, - Key.Digit2, - Key.Digit3, - Key.Digit4, - }; - - public static int MaxSpellSlots => Layout.Length; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs.meta b/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs.meta deleted file mode 100644 index 62da374..0000000 --- a/Assets/_Project/Scripts/Gameplay/SpellHotkeys.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 360482837f8c85d5abe29870dcf9cf1a \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/SpellSlot.cs b/Assets/_Project/Scripts/Gameplay/SpellSlot.cs deleted file mode 100644 index c84e687..0000000 --- a/Assets/_Project/Scripts/Gameplay/SpellSlot.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/SpellSlot.cs -using System; -using Unity.Netcode; -using TD.Core; - -namespace TD.Gameplay -{ - /// - /// One granted builder spell in a . Replicated as part of - /// a ; the entry's index in that list IS the hotkey slot - /// (grant order == key order), so no separate slot index field is needed. - /// - /// - /// One struct, not parallel lists. is set once at grant time; - /// is rewritten on every cast. NetworkList{T}'s - /// indexer setter (spells[i] = newValue) short-circuits the write when - /// Equals on the old value returns true (see for the - /// documented case that first surfaced this). Comparing only would mean - /// a cooldown update — same Kind, new CooldownEndServerTime — never actually replicates. - /// therefore compares every field. - /// - [Serializable] - public struct SpellSlot : INetworkSerializable, IEquatable - { - /// Which spell occupies this slot. Fixed for the slot's lifetime. - public BuilderSpellKind Kind; - - /// - /// NetworkManager.ServerTime.Time at which this slot is next ready to cast. - /// 0 (or any value <= current server time) means ready now. - /// - public double CooldownEndServerTime; - - public static SpellSlot CreateReady(BuilderSpellKind kind) - { - return new SpellSlot { Kind = kind, CooldownEndServerTime = 0d }; - } - - // ----- INetworkSerializable --------------------------------------- - - public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter - { - byte kindByte = (byte)Kind; - serializer.SerializeValue(ref kindByte); - Kind = (BuilderSpellKind)kindByte; - - serializer.SerializeValue(ref CooldownEndServerTime); - } - - // ----- IEquatable ------------------------------------------------- - // - // Full-field comparison — see remarks above. Without this, cooldown writes - // (Kind unchanged, only CooldownEndServerTime updated) would be silently dropped - // by NetworkList's indexer setter. - - public bool Equals(SpellSlot other) => - Kind == other.Kind && CooldownEndServerTime == other.CooldownEndServerTime; - - public override bool Equals(object obj) => obj is SpellSlot other && Equals(other); - - public override int GetHashCode() => (int)Kind; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/SpellSlot.cs.meta b/Assets/_Project/Scripts/Gameplay/SpellSlot.cs.meta deleted file mode 100644 index d9c0bee..0000000 --- a/Assets/_Project/Scripts/Gameplay/SpellSlot.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9c8fdabdb3c89204ab28f9e031678db4 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs index 6128ab4..dfd73a8 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs @@ -303,10 +303,6 @@ namespace TD.Gameplay ApplyTint(); paintColor.OnValueChanged += HandlePaintColorChanged; - // An upgrade swaps the replicated TypeId out from under every peer; re-resolve so - // clients pick up the new stats and tint instead of holding the pre-upgrade asset. - definitionTypeId.OnValueChanged += HandleDefinitionTypeChanged; - // Register for minimap rendering. MinimapEntityRegistry.Register(this); @@ -336,8 +332,7 @@ namespace TD.Gameplay public override void OnNetworkDespawn() { - paintColor.OnValueChanged -= HandlePaintColorChanged; - definitionTypeId.OnValueChanged -= HandleDefinitionTypeChanged; + paintColor.OnValueChanged -= HandlePaintColorChanged; // Un-stamp the footprint when the tower is destroyed (sold, wave end, etc.) // so the tiles become walkable and buildable again. @@ -417,152 +412,6 @@ namespace TD.Gameplay upgradeCount.Value += 1; } - // ----- Upgrading ------------------------------------------------------ - - /// - /// Fired on every peer when this tower's definition changes (i.e. it was upgraded). - /// The HUD subscribes to relabel a selected tower's action grid. - /// - public event System.Action OnDefinitionChanged; - - /// - /// Gold cost to convert this tower into . The target's own - /// is the price — upgrade nodes are never placed - /// directly, so their cost field is free to mean "what this upgrade costs". - /// - public static int GetUpgradeCost(TowerDefinition target) => target != null ? target.GoldCost : 0; - - /// - /// True if is a legal upgrade of this tower's current type: a - /// direct child in the upgrade tree, with a matching footprint. - /// - /// - /// The footprint check is not cosmetic. A tower's occupied/unwalkable tiles are - /// stamped into the grid at its current size; converting to a differently-sized node would - /// leave the stamp describing a shape the tower no longer has, corrupting both pathfinding - /// and future placement checks. Growing a tower's footprint needs a stamp-swap (and a - /// re-validation that the new tiles are even free), which the tree doesn't currently need — - /// so it's rejected loudly rather than half-supported. - /// - public bool CanUpgradeTo(TowerDefinition target) - { - if (target == null || resolvedDefinition == null) return false; - if (resolvedDefinition.UpgradePaths == null) return false; - - bool isChild = false; - foreach (var path in resolvedDefinition.UpgradePaths) - { - if (path == target) { isChild = true; break; } - } - if (!isChild) return false; - - return target.FootprintSize == resolvedDefinition.FootprintSize; - } - - /// - /// Collects the upgrades can currently apply to this tower: - /// direct children of its type that the player has unlocked. Does not filter on gold — - /// the HUD shows unaffordable upgrades disabled rather than hiding them, so players can - /// see what they're saving for. - /// - public void CollectAvailableUpgrades(ulong clientId, List<(TowerDefinition Def, int TypeId)> into) - { - into.Clear(); - - var unlocked = PlayerTowerUpgrades.GetForClient(clientId); - var pm = TowerPlacementManager.Instance; - if (unlocked == null || pm == null || resolvedDefinition?.UpgradePaths == null) return; - - foreach (var path in resolvedDefinition.UpgradePaths) - { - if (path == null) continue; - if (!pm.TryGetTypeId(path, out int typeId)) continue; - if (!unlocked.Contains(typeId)) continue; - if (!CanUpgradeTo(path)) continue; - - into.Add((path, typeId)); - } - } - - /// - /// Client → server request to convert this tower into . - /// Accepted only from the owner, only for a node they've unlocked, only along a real tree - /// edge, and only if they can pay. - /// - /// - /// Every check is repeated here even though the HUD already filters — the HUD is a - /// convenience, this is the authority. Same posture as placement, paint, and sell. - /// - [Rpc(SendTo.Server)] - public void RequestUpgradeServerRpc(int targetTypeId, RpcParams rpcParams = default) - { - if (!IsServer) return; - if (serverSold) return; // mid-sell; nothing to upgrade - - ulong senderClientId = rpcParams.Receive.SenderClientId; - PlayerSlot senderSlot = PlayerMatchState.SlotForClient(senderClientId); - if (senderSlot == PlayerSlot.None || senderSlot != ownerSlot.Value) - { - Debug.Log($"[TowerInstance] Upgrade rejected: client {senderClientId} " + - $"({senderSlot}) does not own tower owned by {ownerSlot.Value}."); - return; - } - - var target = TowerPlacementManager.GetDefinition(targetTypeId); - if (target == null) - { - Debug.Log($"[TowerInstance] Upgrade rejected: TypeId {targetTypeId} is not in the catalog."); - return; - } - - if (!CanUpgradeTo(target)) - { - Debug.Log($"[TowerInstance] Upgrade rejected: '{target.name}' is not a " + - $"same-footprint child of '{resolvedDefinition?.name}'."); - return; - } - - var unlocked = PlayerTowerUpgrades.GetForClient(senderClientId); - if (unlocked == null || !unlocked.Contains(targetTypeId)) - { - Debug.Log($"[TowerInstance] Upgrade rejected: client {senderClientId} has not " + - $"unlocked '{target.name}'."); - return; - } - - int cost = GetUpgradeCost(target); - var gold = PlayerGoldManager.GetForClient(senderClientId); - if (gold == null || gold.CurrentGold < cost) - { - Debug.Log($"[TowerInstance] Upgrade rejected: client {senderClientId} cannot " + - $"afford '{target.name}' ({cost}g)."); - return; - } - - if (cost > 0) gold.DeductGold(cost); - - // Record the spend before switching type, so the refund reflects everything sunk in - // and the tower loses any full-refund-while-unupgraded status. - ServerAddUpgradeInvestment(cost); - - // Switching the replicated TypeId is the upgrade: TowerCombat re-reads Definition - // every tick, so the new stats take effect on the next shot with nothing to notify. - definitionTypeId.Value = targetTypeId; - resolvedDefinition = target; - - OnDefinitionChanged?.Invoke(); - } - - // Re-resolve and re-tint on clients when the type changes under them (an upgrade landed). - private void HandleDefinitionTypeChanged(int previous, int current) - { - if (previous == current) return; - - resolvedDefinition = TowerPlacementManager.GetDefinition(current); - ApplyTint(); - OnDefinitionChanged?.Invoke(); - } - /// /// Client → server request to sell this tower. Accepted only from the tower's owner /// (same ownership rule as placement and paint). The server refunds gold, broadcasts diff --git a/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs b/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs index 05a1613..e6c52e0 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs @@ -73,11 +73,10 @@ namespace TD.Gameplay var keyboard = Keyboard.current; // Right-click or Escape exits paint mode. (Escape is ignored while a HUD text - // field has focus or the gear menu is open, so it means "cancel typing" / - // "back out of the menu" there, matching other systems.) + // field has focus so it means "cancel typing" there, matching other systems.) bool escape = keyboard != null && keyboard.escapeKey.wasPressedThisFrame - && !HUDController.IsUiCapturingInput; + && !HUDController.IsTextInputActive; if (mouse.rightButton.wasPressedThisFrame || escape) { CancelPaint(); diff --git a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs index 3706dfb..9943dc5 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs @@ -388,76 +388,6 @@ namespace TD.Gameplay spawner.Play(worldPos); } - // ----- Phase teardown --------------------------------------------- - - /// - /// Server-only: destroys every built tower on the map, refunding nothing. Called when a - /// phase ends so the next phase starts from bare ground. - /// - /// How many towers were destroyed. - /// - /// Deliberately not the sell path. Selling refunds gold, plays the coin VFX and is - /// owner-gated; none of that applies here. This is confiscation, not a transaction — the - /// maze players spent a whole phase building is the price of the boss going down. - /// - /// Cleanup rides on despawn. - /// already un-stamps the footprint, deregisters from the minimap and clears any local - /// selection pointing at it, so this method only has to despawn. Shelved - /// s self-clean the same way; queued and in-progress jobs are - /// cancelled through their own Builder, which restores their footprint tiles. - /// - /// Queued jobs DO refund. Those towers were never delivered, so eating the - /// gold would punish players for having a build queued when the boss happened to die. The - /// no-refund rule applies to towers that got built. - /// - /// Timing matters for performance. Every despawn fires a walkability change, - /// and a full maze is a lot of them. This runs with the field empty — the boss is dead and - /// the next wave hasn't spawned — so no enemy is registered with the re-path scheduler and - /// the recompute storm that would cause mid-wave never happens. - /// - public int ServerDestroyAllTowers() - { - if (!IsServer) return 0; - - // Cancel build queues first. This despawns their non-shelved visuals and frees the - // footprint tiles they had reserved, so the sweep below only has to deal with what's - // left standing. - foreach (var pms in PlayerMatchState.AllPlayers) - { - var builder = Builder.GetForClient(pms.OwnerClientId); - builder?.ServerCancelAllJobs(); - } - - var spawnManager = NetworkManager.Singleton?.SpawnManager; - if (spawnManager == null) return 0; - - // Snapshot before iterating — despawning mutates the live spawned-objects collection. - var snapshot = new System.Collections.Generic.List( - spawnManager.SpawnedObjectsList); - - int destroyed = 0; - foreach (var no in snapshot) - { - if (no == null || !no.IsSpawned) continue; - - if (no.GetComponent() != null) - { - no.Despawn(destroy: true); - destroyed++; - continue; - } - - // Shelved build sites outlive their Builder's queue, so cancelling jobs above - // doesn't reach them. Left alone they'd sit on the map as ghosts of towers that - // no longer exist, still holding their footprint tiles occupied. - var visual = no.GetComponent(); - if (visual != null && visual.IsShelved) - no.Despawn(destroy: true); - } - - return destroyed; - } - // ----- Server-side commit hooks called by Builder ------------------ /// diff --git a/Assets/_Project/Scripts/Gameplay/WaveDefinition.cs b/Assets/_Project/Scripts/Gameplay/WaveDefinition.cs index 5eeb6e5..7398dd0 100644 --- a/Assets/_Project/Scripts/Gameplay/WaveDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/WaveDefinition.cs @@ -41,70 +41,5 @@ namespace TD.Gameplay [Tooltip("Enemy groups that make up this wave. Processed in order.")] public WaveEntry[] Entries; - - /// - /// The enemy type this wave is "about" — the first assigned entry's type. Null if the - /// wave has no usable entries. - /// - /// - /// The 2.0 design gives each wave a single enemy type, and enemy upgrades are keyed to a - /// wave slot, so this is the identity the phase draw uses to keep slots distinct and the - /// HUD uses to label an upcoming wave. still supports multiple - /// groups (useful for staggering counts of the same type), but mixing types within - /// one wave makes this ambiguous — see . - /// - public EnemyDefinition PrimaryEnemyType - { - get - { - if (Entries == null) return null; - foreach (var e in Entries) - { - if (e.EnemyType != null && e.Count > 0) return e.EnemyType; - } - return null; - } - } - - /// - /// True if every usable entry in this wave spawns the same enemy type. False means - /// is only telling part of the story — the run validator - /// warns on these rather than rejecting them, since a mixed wave still plays fine, it - /// just labels and upgrades oddly. - /// - public bool HasSingleEnemyType - { - get - { - var first = PrimaryEnemyType; - if (first == null) return false; - foreach (var e in Entries) - { - if (e.EnemyType != null && e.Count > 0 && e.EnemyType != first) return false; - } - return true; - } - } - - /// Total enemies spawned per zone by this wave, across all entries. - /// - /// Also the divisor for the encounter's health budget — see - /// . That makes count a texture - /// knob rather than a difficulty one: a wave of 8 spawns eight tanks, a wave of 150 spawns - /// a fragile swarm, and both present the same total health for their slot in the run. - /// - public int TotalEnemyCount - { - get - { - if (Entries == null) return 0; - int total = 0; - foreach (var e in Entries) - { - if (e.EnemyType != null && e.Count > 0) total += e.Count; - } - return total; - } - } } } diff --git a/Assets/_Project/Scripts/Gameplay/WaveManager.cs b/Assets/_Project/Scripts/Gameplay/WaveManager.cs index a40ed28..d1d889b 100644 --- a/Assets/_Project/Scripts/Gameplay/WaveManager.cs +++ b/Assets/_Project/Scripts/Gameplay/WaveManager.cs @@ -5,55 +5,44 @@ using UnityEngine; using TD.Core; using TD.Gameplay.BuilderEffects; using TD.Gameplay.Draft; -using TD.Gameplay.EnemyAbilities; -using TD.Gameplay.EnemyUpgrades; -using TD.Gameplay.Waves; using TD.Levels; using TD.UI; namespace TD.Gameplay { /// - /// Server-authoritative encounter driver. Spawns enemies across all player zones, tracks - /// completion, awards kill gold, and manages the shared lives pool. Which encounter to - /// run comes from ; this class only runs it. + /// Server-authoritative wave controller. Spawns enemies across all player zones, + /// tracks wave completion, awards kill gold, and manages the shared lives pool. /// /// - /// Encounter lifecycle: + /// Wave lifecycle: /// - /// When is entered, asks - /// to draw phase 1 and then runs its first wave. - /// Each encounter is: inter-wave step (draft, then the enemy-buff vote, then the - /// build countdown) → spawn → mop up. See . - /// Each spawns Count enemies per player zone. All - /// spawn held, then release in 10% chunks on ReleaseInterval. - /// The encounter is complete only when every spawned enemy is dead or has leaked. - /// then decides what comes next. - /// Final phase's boss dies → . + /// When is entered, + /// advances + /// immediately (so the HUD shows the wave number during prep), then waits + /// before spawning. + /// Each spawns Count enemies per player zone, + /// one zone per frame-group, with SpawnInterval seconds between + /// individual enemies in the group. + /// After all entries are spawned, the wave is considered complete only when + /// every active enemy is either killed or has reached the goal. + /// All waves exhausted → . /// Lives drop to 0 → . /// /// - /// Why the wave list moved out. Waves used to be a hand-ordered array walked - /// start-to-finish, so "which wave is next" was just an index++. Under the 2.0 cyclical - /// design the same five waves repeat across three cycles while accumulating player-voted - /// upgrades, and each phase draws a fresh five — progression that no longer fits in an index. - /// owns it; this class asks it what to run. - /// /// Kill gold: When an enemy dies, names /// the tower's player. resolves the /// OwnerClientId, and awards - /// the gold. GoldConfig is indexed by - /// — a run-long counter, not a per-cycle one, so - /// per-wave payouts keep climbing as the cycles repeat instead of resetting. + /// the gold. /// /// Zone leak counts: is a NetworkList - /// indexed by (int)PlayerSlot. It is incremented when an enemy + /// indexed by (int)PlayerSlot (indices 0–8). It is incremented when an enemy /// crosses from one player zone into another, giving the HUD a per-player leak score. /// Index 0 corresponds to and is unused. /// /// Inspector setup: /// - /// Assign a RunDefinition to the scene's . + /// Assign in order (Wave 1 at index 0). /// Set to match your level design intent. /// /// @@ -65,29 +54,18 @@ namespace TD.Gameplay // ----- Inspector -------------------------------------------------- + [Tooltip("Wave definitions in order. Index 0 = Wave 1.")] + [SerializeField] private WaveDefinition[] waveDefinitions; + [Tooltip("Shared lives pool at the start of a match.")] [SerializeField] private int startingLives = 20; - [Tooltip("Seconds players get to make their personal draft pick. Ends early once every " + - "player has picked. Be generous — this is reading time, not reaction time.")] - [SerializeField] private float draftTimeSeconds = 30f; - - [Tooltip("Seconds players get to vote on the enemy buff. Ends early once every player " + - "has voted. Generous enough that players can watch each other's votes land and " + - "change their own in response.")] - [SerializeField] private float voteTimeSeconds = 25f; - [Tooltip("Single source of truth for every gold tunable: starting gold, per-wave " + "kill rewards, completion bonus, no-leak bonus. Required for a real match; " + "if unset the game falls back to per-player startingGold defaults and grants " + "no kill/wave rewards (designer-error indicator, not a supported runtime mode).")] [SerializeField] private GoldConfig goldConfig; - [Tooltip("How enemy health scales across the run. Required for a real match; if unset, " + - "every enemy spawns at a flat fallback health and difficulty never progresses " + - "(designer-error indicator, not a supported runtime mode).")] - [SerializeField] private EnemyScalingConfig enemyScalingConfig; - // ----- Networked state -------------------------------------------- // Per-slot total leak counters across the whole match. Index = (int)PlayerSlot; @@ -116,27 +94,14 @@ namespace TD.Gameplay readPerm: NetworkVariableReadPermission.Everyone, writePerm: NetworkVariableWritePermission.Server); - // Which inter-wave stage the countdown above belongs to. One countdown serves all three - // stages (they never overlap), so the HUD needs this to label it correctly. - private readonly NetworkVariable interWaveStage = - new NetworkVariable( - value: InterWaveStage.None, - readPerm: NetworkVariableReadPermission.Everyone, - writePerm: NetworkVariableWritePermission.Server); - // ----- Server-local runtime state --------------------------------- private int remainingLives; private int activeEnemyCount; private bool spawningComplete; - private bool runStarted; + private int currentWaveIndex = -1; // -1 = not yet started private Coroutine activeWaveCoroutine; - // Wave slot the NEXT inter-wave vote will buff — captured when an encounter clears, before - // the run advances past it. -1 means "no vote due": the run's first encounter (nothing has - // been beaten yet) or straight after a boss (the phase's slots are being wiped). - private int pendingVoteSlot = -1; - private readonly System.Collections.Generic.List heldEnemies = new System.Collections.Generic.List(); @@ -212,11 +177,6 @@ namespace TD.Gameplay { var deck = PlayerTowerDeck.GetForClient(pms.OwnerClientId); if (deck != null) deck.ServerInitialize(startingTypeIds); - - // Upgrade nodes start empty — every one is earned through the draft. Cleared - // rather than left alone so Retry / return-to-lobby doesn't carry a previous - // run's unlocks into a new one. - PlayerTowerUpgrades.GetForClient(pms.OwnerClientId)?.ServerInitialize(); } } else @@ -226,7 +186,7 @@ namespace TD.Gameplay } if (ms.Phase == MatchPhase.Playing) - StartRun(); + StartNextWave(); } public override void OnNetworkDespawn() @@ -239,6 +199,13 @@ namespace TD.Gameplay // ----- Public accessors ------------------------------------------- + /// + /// Total number of waves in this match. Same on every peer because + /// is a serialized prefab field, identical + /// on host and clients. Returns 0 if the array is unassigned. + /// + public int TotalWaves => waveDefinitions?.Length ?? 0; + /// /// Number of times enemies have leaked out of the given player's zone over the /// entire match. Replicated — safe to call on any peer. @@ -262,82 +229,34 @@ namespace TD.Gameplay /// public float PrepCountdown => prepCountdown.Value; - /// - /// Which inter-wave step the current countdown belongs to, or - /// while a wave is spawning or being fought. Replicated; - /// safe on any peer. The HUD uses it to label the shared countdown. - /// - public InterWaveStage CurrentInterWaveStage => interWaveStage.Value; - - - /// - /// 1-based encounter number since the run began, or 0 before it starts. This is the key - /// is indexed by. Replicated via , so it's - /// safe on any peer. - /// - public int CurrentEncounterNumber - => RunState.Instance != null && runStarted ? RunState.Instance.GlobalEncounterNumber : 0; // ----- Phase handling --------------------------------------------- private void HandlePhaseChanged(MatchPhase previous, MatchPhase next) { if (!IsServer) return; - if (next == MatchPhase.Playing) StartRun(); + if (next == MatchPhase.Playing && currentWaveIndex < 0) + StartNextWave(); } - // ----- Run control ------------------------------------------------ + // ----- Wave coroutine --------------------------------------------- - /// - /// Server-only: begin the run. Draws phase 1 and starts its first encounter. Idempotent — - /// re-entering won't restart a run in progress. - /// - private void StartRun() + private void StartNextWave(bool skipPrep = false) { - if (!IsServer || runStarted) return; + currentWaveIndex++; - var run = RunState.Instance; - if (run == null) + if (waveDefinitions == null || currentWaveIndex >= waveDefinitions.Length) { - Debug.LogError("[WaveManager] No RunState in the scene — no waves can run. " + - "Add a RunState object and assign it a RunDefinition."); + Debug.Log("[WaveManager] All waves complete. Victory."); + MatchState.Instance?.SetPhase(MatchPhase.Victory); return; } - if (!run.ServerBeginRun()) - { - // ServerBeginRun already logged the specific reason (missing asset, unplayable - // pools). Bail rather than spawn an empty encounter that can never complete. - Debug.LogError("[WaveManager] Run could not be started; see the RunState error above."); - return; - } + // Advance the replicated wave counter at the START of prep so the HUD + // shows the upcoming wave number during the countdown. + MatchState.Instance?.SetCurrentWave(currentWaveIndex + 1); // 1-based - runStarted = true; - StartEncounter(skipInterWave: false); - } - - /// - /// Server-only: run whatever encounter is currently pointing at. - /// - /// Skip the draft/vote/build step and spawn immediately. - /// Used by the dev force-advance cheat. - private void StartEncounter(bool skipInterWave) - { - var run = RunState.Instance; - var def = run?.CurrentWave; - - if (def == null) - { - Debug.LogError($"[WaveManager] No wave drawn for {run?.ProgressLabel ?? "?"} — " + - $"the run cannot continue."); - return; - } - - // Publish the run-long encounter number so the HUD and the gold lookup agree on - // which encounter's payout table applies. - MatchState.Instance?.SetCurrentWave(run.GlobalEncounterNumber); - - // Reset per-wave bookkeeping for the encounter that's about to begin: + // Reset per-wave bookkeeping for the wave that's about to begin: // - waveLeakCounts: per-slot leaks this wave, used for the no-leak bonus. // - PlayerGoldManager.goldEarnedThisWave: HUD top-bar resets so the // "+N g/wave" counter starts at 0. @@ -352,100 +271,23 @@ namespace TD.Gameplay activeEnemyCount = 0; spawningComplete = false; - activeWaveCoroutine = StartCoroutine(RunEncounter(def, skipInterWave)); - } - - /// - /// Server-only: the encounter is over — ask what's next and either - /// start it or end the match. - /// - private void AdvanceRun() - { - var run = RunState.Instance; - if (run == null) return; - - switch (run.ServerAdvance()) - { - case RunAdvance.RunComplete: - Debug.Log("[WaveManager] Final boss defeated. Victory."); - MatchState.Instance?.SetPhase(MatchPhase.Victory); - return; - - case RunAdvance.BossReady: - Debug.Log($"[WaveManager] All cycles cleared — boss incoming " + - $"({run.ProgressLabel})."); - break; - - case RunAdvance.NextPhase: - { - // A phase boundary resets the board as well as the enemies: the maze players - // spent the phase building is torn down, unrefunded, so the new phase starts - // from bare ground. Runs here rather than inside RunState.ServerAdvance - // because it touches player structures, which the run has no business owning. - int destroyed = TowerPlacementManager.Instance?.ServerDestroyAllTowers() ?? 0; - NotifyTowersWipedClientRpc(destroyed); - - Debug.Log($"[WaveManager] Boss down. New phase drawn: {run.ProgressLabel}. " + - $"Enemy upgrades wiped; {destroyed} tower(s) destroyed."); - break; - } - - case RunAdvance.NextCycle: - Debug.Log($"[WaveManager] Cycle complete — same waves return upgraded " + - $"({run.ProgressLabel})."); - break; - } - - StartEncounter(skipInterWave: false); + activeWaveCoroutine = StartCoroutine( + RunWave(waveDefinitions[currentWaveIndex], skipPrep)); } // ----- Dev / cheats ----------------------------------------------- /// - /// Dev cheat: skip the rest of the current encounter (despawn any remaining enemies, kill - /// the timers) and start the next one immediately. Server-only — silently no-ops on - /// clients. Safe to call during the inter-wave step, mid-spawn, or while enemies are alive. + /// Dev cheat: skip the rest of the current wave (despawn any remaining + /// enemies, kill the prep timer) and start the next wave immediately. + /// Server-only — silently no-ops on clients. Safe to call during prep, + /// mid-spawn, or while enemies are alive. /// public void ForceAdvanceToNextWave() { - if (!IsServer || !runStarted) return; - ClearFieldAndStopEncounter(); - AdvanceRun(); - } + if (!IsServer) return; - /// - /// Dev cheat: skip whole encounters until the run reaches this phase's boss. Useful for - /// testing boss content without playing fifteen waves. Server-only. - /// - public void ForceAdvanceToBoss() - { - if (!IsServer || !runStarted) return; - - var run = RunState.Instance; - if (run == null || run.IsBossStage) return; - - ClearFieldAndStopEncounter(); - - // Advance until the boss is up (or the run ends, which shouldn't happen from a - // non-boss encounter but is guarded anyway). - int guard = run.EncountersPerPhase + 1; - while (!run.IsBossStage && guard-- > 0) - { - if (run.ServerAdvance() == RunAdvance.RunComplete) - { - MatchState.Instance?.SetPhase(MatchPhase.Victory); - return; - } - } - - StartEncounter(skipInterWave: false); - } - - // Shared teardown for the dev cheats: stop the running encounter, wipe the field, and - // resolve anything the players had open so nothing is left dangling mid-skip. - private void ClearFieldAndStopEncounter() - { - // Stop the current encounter's coroutine (cancels timers + remaining spawns). + // Stop the current wave's coroutine (cancels prep timer + remaining spawns). if (activeWaveCoroutine != null) { StopCoroutine(activeWaveCoroutine); @@ -473,41 +315,59 @@ namespace TD.Gameplay } } + // Reset bookkeeping and start the next wave's RunWave coroutine, + // skipping the prep timer so spawning starts immediately. activeEnemyCount = 0; spawningComplete = false; heldEnemies.Clear(); - // Skipping ahead interrupts the inter-wave step, so resolve anything the players had - // open before moving on. The draft auto-resolves (a free reward shouldn't vanish - // because a dev pressed a key); the vote is closed WITHOUT resolving, since applying a - // buff nobody finished voting on would silently rewrite the run. + // Force-advancing interrupts the prep phase, so resolve any drafts the players + // had open before skipping ahead. DraftService.Instance?.ServerAutoResolveAll(); - WaveVote.Instance?.ServerClose(); - interWaveStage.Value = InterWaveStage.None; - prepCountdown.Value = 0f; + StartNextWave(skipPrep: true); } - // ----- Encounter coroutine ---------------------------------------- - - private IEnumerator RunEncounter(WaveDefinition def, bool skipInterWave = false) + private IEnumerator RunWave(WaveDefinition def, bool skipPrep = false) { - // Draft, enemy-buff vote, then the build countdown. Skipped entirely when a dev - // cheat forces the encounter to start immediately. - if (!skipInterWave) - yield return RunInterWave(def); + // Prep phase — players build while the countdown ticks. Skipped when + // a dev cheat forces the wave to start immediately. We tick the + // replicated prepCountdown each frame so every HUD can render the + // remaining time consistently. Server is the only writer; clients + // observe the value via NetworkVariable replication. + if (!skipPrep) + { + // Open a draft for every player at the start of the build phase. They pick + // during prep; any unpicked draft is auto-resolved when the timer expires. + DraftService.Instance?.ServerOfferToAll(); + prepCountdown.Value = def.PrepTime; + float remaining = def.PrepTime; + // Throttle network sync to ~10 Hz. NetworkVariable replicates on every + // mutation; at 60 fps we'd send ~600 deltas per 10s prep purely to + // animate text that only changes once per second on the HUD. 0.1s + // gives a smooth-enough fall while keeping bandwidth minimal. + const float NetworkSyncInterval = 0.1f; + float nextSync = def.PrepTime - NetworkSyncInterval; + while (remaining > 0f) + { + yield return null; + remaining = Mathf.Max(0f, remaining - Time.deltaTime); + if (remaining <= nextSync || remaining <= 0f) + { + prepCountdown.Value = remaining; + nextSync = remaining - NetworkSyncInterval; + } + } + + // Prep timer expired — auto-resolve any draft the player didn't pick so + // the free reward isn't wasted. + DraftService.Instance?.ServerAutoResolveAll(); + } // Ensure the countdown reads zero entering the spawn phase, regardless of - // whether the build step was skipped or just expired. + // whether prep was skipped or just expired. prepCountdown.Value = 0f; - // Resolve this wave slot's voted buffs once, here — the set is fixed for the whole - // encounter, so doing it per enemy would repeat the same lookup hundreds of times. - // Must run AFTER the inter-wave step, since the vote that just closed may have added - // to a slot this very encounter re-runs on a later cycle. - ResolveCurrentWaveAbilities(); - ResolveCurrentEncounterHealth(def); - // Spawn all enemies at once in a held (untargetable, immobile) state. if (def.Entries != null) { @@ -544,197 +404,6 @@ namespace TD.Gameplay CheckWaveComplete(); } - // ----- Inter-wave step --------------------------------------------- - - /// - /// The step between encounters: players take their personal draft, then vote on the buff - /// the wave they just cleared will carry into the next cycle, then build. - /// - /// - /// The three stages run strictly in sequence and never overlap. The build countdown used - /// to double as the draft window, which made "wait until everyone has chosen" impossible - /// to express — players who wanted to build were paying for teammates who wanted to read - /// their cards. Separating them costs a few seconds per wave and makes both steps mean - /// what they say. - /// - /// Each stage ends early the moment every player has acted, so the generous timers - /// are a ceiling for deliberation, not a floor everyone sits through. - /// - private IEnumerator RunInterWave(WaveDefinition def) - { - // ----- 1. Personal draft ----- - // Offered to everyone at once. Anyone who hasn't picked when the timer expires has - // their draft auto-resolved, so an idle player never wastes a free reward. - interWaveStage.Value = InterWaveStage.Draft; - DraftService.Instance?.ServerOfferToAll(); - yield return TickCountdown(draftTimeSeconds, () => DraftService.AllPlayersPicked); - DraftService.Instance?.ServerAutoResolveAll(); - - // ----- 2. Enemy-buff vote ----- - // Votes on the wave that was just cleared, which is the slot captured before the run - // advanced. Skipped on the run's first encounter (nothing has been defeated yet) and - // after a boss (that phase's slots are being wiped anyway). - if (pendingVoteSlot >= 0) - { - var vote = WaveVote.Instance; - var run = RunState.Instance; - - // A vote-meta card may have armed this slot to skip its next vote and take - // several buffs outright. That's the card's whole effect, so it pre-empts the - // normal vote rather than running alongside it. - int autoCount = run != null ? run.GetAutoApplyCount(pendingVoteSlot) : 0; - - if (autoCount > 0 && vote != null) - { - int applied = vote.ServerAutoApply(pendingVoteSlot, autoCount); - run.ServerConsumeAutoApply(pendingVoteSlot); - Debug.Log($"[WaveManager] Wave slot {pendingVoteSlot} auto-took {applied} " + - $"buff(s); no vote held."); - } - else if (vote != null && vote.ServerOpenVote(pendingVoteSlot)) - { - interWaveStage.Value = InterWaveStage.Vote; - yield return TickCountdown(voteTimeSeconds, () => vote.AllPlayersVoted); - vote.ServerResolve(); - } - - pendingVoteSlot = -1; - } - - // ----- 3. Build ----- - interWaveStage.Value = InterWaveStage.Build; - yield return TickCountdown(def.PrepTime); - - interWaveStage.Value = InterWaveStage.None; - } - - /// - /// Ticks down from to zero, - /// exiting early once returns true. - /// - /// - /// Network sync is throttled to ~10 Hz. NetworkVariable replicates on every - /// mutation, so ticking at frame rate would push ~600 deltas across a 10-second countdown - /// purely to animate text that changes once a second. A tenth of a second still falls - /// smoothly while keeping the traffic negligible. - /// - private IEnumerator TickCountdown(float seconds, System.Func finishedEarly = null) - { - const float NetworkSyncInterval = 0.1f; - - prepCountdown.Value = seconds; - float remaining = seconds; - float nextSync = seconds - NetworkSyncInterval; - - while (remaining > 0f) - { - if (finishedEarly != null && finishedEarly()) break; - - yield return null; - remaining = Mathf.Max(0f, remaining - Time.deltaTime); - - if (remaining <= nextSync || remaining <= 0f) - { - prepCountdown.Value = remaining; - nextSync = remaining - NetworkSyncInterval; - } - } - - prepCountdown.Value = 0f; - } - - // ----- Wave ability resolution ------------------------------------- - - // Abilities carried by every enemy of the encounter currently spawning. Rebuilt once per - // encounter (not per enemy) since a wave's buff set is fixed for its whole duration. - private readonly System.Collections.Generic.List currentWaveAbilities - = new System.Collections.Generic.List(); - - private readonly System.Collections.Generic.List upgradeIdScratch - = new System.Collections.Generic.List(); - - /// - /// Server-only: resolve the current wave slot's voted upgrades into the ability list every - /// enemy of this encounter will carry. - /// - /// - /// Called once at the top of an encounter's spawn phase. Cards that resolve to nothing - /// (missing pool entry, non-ability card) are skipped silently here — the vote already - /// validated them, and a warning per enemy would flood the log. - /// - private void ResolveCurrentWaveAbilities() - { - currentWaveAbilities.Clear(); - - var run = RunState.Instance; - var pool = EnemyUpgradePool.Instance; - if (run == null || pool == null) return; - - run.GetUpgradesForSlot(run.CurrentUpgradeSlot, upgradeIdScratch); - - foreach (int id in upgradeIdScratch) - { - if (pool.Get(id) is AbilityEnemyUpgradeOption card && card.Ability != null) - currentWaveAbilities.Add(card.Ability); - } - - if (currentWaveAbilities.Count > 0) - Debug.Log($"[WaveManager] {run.ProgressLabel} enemies carry " + - $"{currentWaveAbilities.Count} wave buff(s)."); - } - - // ----- Encounter health resolution --------------------------------- - - // Health one enemy of this encounter gets BEFORE its type's HpMultiplier is applied: - // the encounter's budget divided across the wave's bodies. Resolved once per encounter - // for the same reason the ability list is — it's fixed for the whole wave, and the - // divisor would otherwise be recomputed for every spawn. - private float currentEncounterHpShare = FallbackEnemyHp; - - // Used only when no EnemyScalingConfig is assigned. Enemies stay killable so the match - // is still playable, but difficulty never progresses — see the field's tooltip. - private const float FallbackEnemyHp = 100f; - - /// - /// Server-only: work out the per-enemy health share for the encounter about to spawn. - /// - /// - /// Splits the encounter's total budget across the wave's enemy count, so a swarm and an - /// elite wave in the same slot present the same threat. The type's - /// is applied later, per enemy, so a wave - /// mixing types skews each one independently off the shared share. - /// - private void ResolveCurrentEncounterHealth(WaveDefinition def) - { - if (enemyScalingConfig == null) - { - currentEncounterHpShare = FallbackEnemyHp; - Debug.LogWarning("[WaveManager] No EnemyScalingConfig assigned — enemies spawn at " + - $"a flat {FallbackEnemyHp} HP and difficulty will not progress."); - return; - } - - var run = RunState.Instance; - int encounter = CurrentEncounterNumber; - bool isBoss = run?.IsBossStage ?? false; - - int bodies = def != null ? def.TotalEnemyCount : 0; - if (bodies <= 0) - { - // An empty wave can't be divided into. Nothing will spawn from it either, so this - // only guards against a divide-by-zero on a misauthored asset. - currentEncounterHpShare = FallbackEnemyHp; - return; - } - - currentEncounterHpShare = - enemyScalingConfig.ResolvePerEnemyHp(encounter, isBoss, bodies, archetypeMultiplier: 1f); - - Debug.Log($"[WaveManager] Encounter {encounter}{(isBoss ? " (BOSS)" : "")}: " + - $"{enemyScalingConfig.GetEncounterHpBudget(encounter, isBoss):0} HP budget " + - $"across {bodies} enemies = {currentEncounterHpShare:0} each before type modifiers."); - } - // ----- Spawn helpers ---------------------------------------------- private void SpawnEnemyInAllZones(EnemyDefinition def, bool held = false) @@ -760,9 +429,7 @@ namespace TD.Gameplay // PlayerZoneVolume (so OwnerGrid[spawnerTile] = None). var spawner = zone.Spawners[0]; (float xHalf, float zHalf) = ComputeSpawnerHalfExtents(spawner.TileArea); - SpawnEnemy(def, spawner.TilePosition, zone.Owner, currentWaveAbilities, - xHalfExtent: xHalf, zHalfExtent: zHalf, held: held, - facing: spawner.Facing); + SpawnEnemy(def, spawner.TilePosition, zone.Owner, xHalf, zHalf, held, spawner.Facing); } } @@ -787,16 +454,7 @@ namespace TD.Gameplay return (xHalf, zHalf); } - /// - /// Server-only: build and spawn one enemy. - /// - /// Wave buffs this enemy carries. Null/empty for a plain enemy. - /// Pre-computed stats to spawn with, bypassing both the - /// definition's values and ' spawn modifications. Used by - /// split-on-death, whose minions are derived from the parent rather than the asset. private void SpawnEnemy(EnemyDefinition def, Vector2Int spawnerTile, PlayerSlot ownerSlot, - System.Collections.Generic.IReadOnlyList abilities, - EnemySpawnContext? contextOverride = null, float xHalfExtent = 0f, float zHalfExtent = 0f, bool held = false, Direction facing = Direction.South) { @@ -806,17 +464,6 @@ namespace TD.Gameplay return; } - // Resolve the stats this enemy will actually spawn with. Abilities get first say — - // flight, health and size all have to be settled before the position is computed and - // before EnemyHealth/EnemyMovement read them, since each is captured once. - var context = contextOverride - ?? EnemySpawnContext.FromDefinition(def, currentEncounterHpShare * def.HpMultiplier); - if (contextOverride == null && abilities != null) - { - for (int i = 0; i < abilities.Count; i++) - abilities[i]?.ServerModifySpawn(ref context); - } - Vector3 spawnPos = GridCoordinates.GridToWorld(spawnerTile); if (xHalfExtent > 0f) spawnPos.x += Random.Range(-xHalfExtent, xHalfExtent); @@ -826,8 +473,8 @@ namespace TD.Gameplay // Flying enemies spawn elevated so they visually soar over towers. The // movement code preserves Y per-frame, so this height persists for the // enemy's whole flight. NetworkTransform replicates the raised position. - if (context.IsFlying) - spawnPos.y += context.FlightHeight; + if (def.IsFlying) + spawnPos.y += def.FlightHeight; float yaw = facing switch { @@ -843,12 +490,6 @@ namespace TD.Gameplay spawnPos, Quaternion.Euler(0f, yaw, 0f)); - // Scales the whole prefab hierarchy uniformly (split minions, size-changing buffs). - // Relies on the enemy prefab's NetworkTransform syncing scale to clients — verify - // that's enabled if a scaled spawn doesn't look smaller on remote peers. - if (!Mathf.Approximately(context.VisualScale, 1f)) - go.transform.localScale *= context.VisualScale; - var health = go.GetComponent(); var movement = go.GetComponent(); @@ -860,25 +501,8 @@ namespace TD.Gameplay return; } - // Boss-ness comes from the run's position (this is the phase's boss encounter), not - // from the wave asset — the same WaveDefinition could legally sit in both a cycle pool - // and a boss pool, and it's only a boss when drawn as one. Split minions inherit it - // via the context override path, which never sets the flag. - bool isBoss = contextOverride == null && (RunState.Instance?.IsBossStage ?? false); - - health.InitializeServer(context.MaxHp, context.LivesCost, context.IsFlying, held, isBoss); - movement.InitializeServer(context.MoveSpeed, spawnerTile, ownerSlot, context.IsFlying); - - // Optional — only prefabs with an EnemyAbility component can carry wave buffs. See - // EnemyAbility's remarks for why on-death abilities aren't event-subscription driven. - var ability = go.GetComponent(); - if (ability != null) - ability.InitializeServer(abilities, context); - else if (abilities != null && abilities.Count > 0) - Debug.LogWarning($"[WaveManager] '{def.EnemyPrefab.name}' has no EnemyAbility " + - $"component, so this wave's {abilities.Count} buff(s) will not " + - $"apply to it. Add the component to the prefab."); - + health.InitializeServer(def.MaxHp, def.LivesCost, def.IsFlying, held); + movement.InitializeServer(def.MoveSpeed, spawnerTile, ownerSlot, def.IsFlying); if (held) heldEnemies.Add(health); health.OnDied += HandleEnemyKilled; @@ -890,55 +514,17 @@ namespace TD.Gameplay go.GetComponent().Spawn(); } - /// - /// Server-only: spawns copies of at - /// , continuing that tile's A* path onward rather than - /// restarting from a wave spawner. Used by on-death abilities (e.g. - /// SplitOnDeathAbilityDefinition) to spawn smaller enemies from a corpse's - /// position. Reuses so split children get the same - /// activeEnemyCount/event-wiring bookkeeping as any other spawn. - /// - /// - /// Minions inherit nothing. They are spawned with an empty ability list, so a split - /// can never chain into further splits or pick up any other buff the parent's wave carries. - /// That is the whole termination argument for the recursion — one extra generation, always, - /// however many cards the wave has collected. - /// - /// Their stats come entirely from , which the calling - /// ability derives from the parent's own spawned values. Passing it as an override also - /// bypasses spawn modification, which is correct: those modifiers already applied to the - /// parent and are baked into what's being scaled here. - /// - public void ServerSpawnSplitEnemies(EnemyDefinition def, int count, Vector2Int atTile, - PlayerSlot ownerSlot, float scatterRadius, - EnemySpawnContext context) - { - if (!IsServer) return; - for (int i = 0; i < count; i++) - SpawnEnemy(def, atTile, ownerSlot, - abilities: null, - contextOverride: context, - xHalfExtent: scatterRadius, zHalfExtent: scatterRadius); - } - // ----- Enemy event handlers (server-only) ------------------------- private void HandleEnemyKilled(EnemyHealth health) { - // Kill reward comes from GoldConfig for the current encounter — same value for - // every enemy in it regardless of EnemyDefinition type. Missing config or an - // unauthored encounter → 0 reward (gold flow disabled, designer-error mode). + // Kill reward comes from GoldConfig for the current wave — same value for + // every enemy in the wave regardless of EnemyDefinition type. Missing config + // or out-of-range wave → 0 reward (gold flow disabled, designer-error mode). int killReward = 0; - var goldEntry = goldConfig?.GetEncounterEntry(CurrentEncounterNumber); + var goldEntry = goldConfig?.GetWaveEntry(currentWaveIndex + 1); if (goldEntry != null) killReward = goldEntry.GoldPerEnemy; - // Wave buffs get to alter the bounty before anything else sees it — this is what - // reward-suppressing cards hook. Applied before the builder's gold-per-kill bonus so - // a card that zeroes the bounty doesn't also cancel a player's own upgrade. - var enemyAbility = health.GetComponent(); - if (enemyAbility != null) - killReward = enemyAbility.ServerModifyKillReward(killReward); - // Award kill gold to the tower owner that landed the killing blow. The builder's // "gold per kill" effect (if granted) is queried live here rather than cached on // the killing tower — see BuilderUpgradeManager's "query, don't snapshot" note. @@ -965,12 +551,6 @@ namespace TD.Gameplay if (totalReward > 0) ShowGoldRewardClientRpc(health.transform.position, totalReward); - // Resolve on-death abilities BEFORE unsubscribing/decrementing. A split-spawn's - // activeEnemyCount++ (inside ServerSpawnSplitEnemies -> SpawnEnemy) must land before - // this kill's activeEnemyCount-- below, or a split on a wave's last enemy could let - // CheckWaveComplete see activeEnemyCount hit 0 and advance the wave prematurely. - enemyAbility?.ServerInvokeOnDeath(health); - UnsubscribeEnemy(health); DecrementAndCheckComplete(); } @@ -997,11 +577,6 @@ namespace TD.Gameplay if (livesCost > 0) ShowLifeLossClientRpc(leakPos, livesCost); - // Wave buffs that punish leaks beyond the life cost hook here, while the enemy is - // still alive enough to be queried. Runs before the defeat check so a leak that ends - // the match still applies its full penalty. - movement.GetComponent()?.ServerInvokeReachedGoal(movement.OriginZone); - UnsubscribeEnemy(movement.GetComponent()); remainingLives = Mathf.Max(0, remainingLives - livesCost); @@ -1034,41 +609,8 @@ namespace TD.Gameplay OnLifeLost?.Invoke(amount); } - [ClientRpc] - private void ShowGoldLossClientRpc(Vector3 worldPos, int amount) - { - FloatingTextSpawner.Instance?.SpawnGoldLoss(worldPos, amount); - } - - /// - /// Server-only: show a "-N gold" popup on every peer. Exposed because enemy abilities run - /// inside ScriptableObjects, which have no NetworkBehaviour of their own to send a - /// ClientRpc from. - /// - public void ServerBroadcastGoldLoss(Vector3 worldPos, int amount) - { - if (!IsServer || amount <= 0) return; - ShowGoldLossClientRpc(worldPos, amount); - } - - // Announces the end-of-phase tower wipe on every peer. Sent rather than derived locally - // because the despawns arrive as individual NetworkObject removals with nothing tying them - // together — without this a client just watches its maze evaporate for no stated reason. - [ClientRpc] - private void NotifyTowersWipedClientRpc(int destroyedCount) - { - OnTowersWiped?.Invoke(destroyedCount); - } - // ----- Local-only notification events ----------------------------- - /// - /// Fired on every peer when a phase ends and every built tower is destroyed. Argument is - /// how many towers went down. HUD subscribes to explain what just happened; audio and - /// camera-shake hooks can use it too. - /// - public static event System.Action OnTowersWiped; - /// /// Fired on every peer immediately after a life-loss popup spawns. /// HUD subscribes to flash a centered banner; gameplay code can also @@ -1115,24 +657,17 @@ namespace TD.Gameplay // no-leak bonus only if the player's waveLeakCounts entry is exactly 0. AwardWaveCompletionBonuses(); - // Capture which slot the upcoming vote will buff BEFORE advancing past it — the vote - // is on "the wave you just beat", but by the time the inter-wave step runs the run has - // already moved on. A boss clear is excluded: its phase's slots are about to be wiped, - // so voting a buff onto them would be voting into a bin. - var run = RunState.Instance; - pendingVoteSlot = (run != null && !run.IsBossStage) ? run.CurrentUpgradeSlot : -1; - - Debug.Log($"[WaveManager] {run?.ProgressLabel ?? "Encounter"} complete."); - AdvanceRun(); + Debug.Log($"[WaveManager] Wave {currentWaveIndex + 1} complete. Starting next wave."); + StartNextWave(); } // Server-only. Iterates active players, awards CompletionBonus to each, plus // NoLeaksBonus to those whose per-wave leak counter is zero. Floating-text popups // are spawned at each player's builder position so the reward is visible in-world. - // Skipped silently if no goldConfig or no entry for this encounter. + // Skipped silently if no goldConfig or no entry for this wave. private void AwardWaveCompletionBonuses() { - var entry = goldConfig?.GetEncounterEntry(CurrentEncounterNumber); + var entry = goldConfig?.GetWaveEntry(currentWaveIndex + 1); if (entry == null) return; int completionBonus = entry.CompletionBonus; diff --git a/Assets/_Project/Scripts/Gameplay/Waves.meta b/Assets/_Project/Scripts/Gameplay/Waves.meta deleted file mode 100644 index 67bd139..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f65ba25aee224c24dad3648d9e5e953e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs b/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs deleted file mode 100644 index 2700d59..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs -using System.Collections.Generic; -using UnityEngine; - -namespace TD.Gameplay.Waves -{ - /// - /// One phase of a run: the pool its cycle waves are drawn from, and the pool its boss is - /// drawn from. A phase runs the same drawn wave set for every one of its cycles, then ends - /// in a boss. - /// - /// - /// Groups, not waves. Both pools are lists of assets rather - /// than flat wave lists, so re-balancing a run means dragging a group between phases instead - /// of re-authoring individual entries. Listing the same group in two phases is legal — the - /// draws are independent. - /// - /// Draw contract. RunState draws WavesPerCycle waves from - /// with distinct enemy types, because enemy upgrades are keyed - /// to a wave slot and two slots sharing an enemy type would make "which wave did this buff - /// apply to" ambiguous. That makes the real authoring requirement stricter than the entry - /// count: a phase needs at least WavesPerCycle distinct enemy types across its groups, - /// not just that many waves. exists so the draw can - /// fail loudly at match start rather than mid-run. - /// - [CreateAssetMenu(fileName = "PhaseDefinition", menuName = "TD/Run/Phase Definition", order = 11)] - public class PhaseDefinition : ScriptableObject - { - [Tooltip("Designer-facing name for this phase, shown in validation messages. " + - "Falls back to the asset name when empty.")] - public string DisplayName; - - [Tooltip("Groups this phase's cycle waves are drawn from. All groups are pooled " + - "together for the draw; group membership is an authoring convenience, not a " + - "draw boundary.")] - public WaveGroup[] WaveGroups; - - [Tooltip("Groups this phase's boss is drawn from. A boss is an ordinary WaveDefinition " + - "that happens to spawn a single powerful enemy.")] - public WaveGroup[] BossGroups; - - [Tooltip("Enemy-buff cards votable during this phase. Gating is per PHASE, not per cycle " + - "— every card listed here can be voted on from this phase's very first wave. " + - "Cards must also appear in the scene's EnemyUpgradePool to be offerable.")] - public EnemyUpgrades.EnemyUpgradeGroup[] EnemyUpgradeGroups; - - /// Name used in validation and log messages. Falls back to the asset name. - public string Label => string.IsNullOrWhiteSpace(DisplayName) ? name : DisplayName; - - /// - /// Appends every non-null, non-zero-weight entry across into - /// . Zero-weight entries are filtered here (not at draw time) so - /// "weight 0 means it can never appear" is enforced in exactly one place. - /// - public static void CollectCandidates(WaveGroup[] groups, List into) - { - into.Clear(); - if (groups == null) return; - - for (int g = 0; g < groups.Length; g++) - { - var group = groups[g]; - if (group?.Waves == null) continue; - - for (int i = 0; i < group.Waves.Length; i++) - { - var entry = group.Waves[i]; - if (entry?.Wave == null) continue; - if (entry.Weight <= 0f) continue; - into.Add(entry); - } - } - } - - /// Collects this phase's cycle-wave candidates. - public void CollectWaveCandidates(List into) - => CollectCandidates(WaveGroups, into); - - /// Collects this phase's boss candidates. - public void CollectBossCandidates(List into) - => CollectCandidates(BossGroups, into); - - /// - /// How many distinct enemy types are reachable across this phase's wave groups. The - /// upper bound on how many wave slots this phase can fill, since the draw requires - /// distinct types. - /// - public int CountDistinctEnemyTypes() - { - var candidates = new List(); - CollectWaveCandidates(candidates); - - var seen = new HashSet(); - foreach (var entry in candidates) - { - var type = entry.Wave.PrimaryEnemyType; - if (type != null) seen.Add(type); - } - return seen.Count; - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs.meta deleted file mode 100644 index c397855..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/PhaseDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 8f73fcf0261654d44a6d0939bdc9b88f \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs b/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs deleted file mode 100644 index 6b0feb3..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs +++ /dev/null @@ -1,209 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs -using System.Collections.Generic; -using System.Text; -using UnityEngine; - -namespace TD.Gameplay.Waves -{ - /// - /// The whole run: how many waves make a cycle, how many cycles make a phase, and the - /// per-phase pools everything is drawn from. One asset assigned to RunState in the - /// match scene; replaces WaveManager's old flat, hand-ordered wave array. - /// - /// - /// Stable wave ids. Waves are replicated by index into a flat list this asset builds - /// by walking its phases, groups, and entries in declaration order (see - /// ). Because every peer loads the identical asset, the same walk - /// produces the same ids everywhere — the same trick the tower catalog and - /// DraftPool already use, and the reason the server can say "wave slot 2 is wave #7" - /// in a single int. - /// - /// The index is frozen for the match. RunState builds it once on spawn - /// and never rebuilds, so editing this asset mid-play-session cannot renumber ids out from - /// under in-flight replication. Edit-time changes invalidate the cache normally. - /// - [CreateAssetMenu(fileName = "RunDefinition", menuName = "TD/Run/Run Definition", order = 12)] - public class RunDefinition : ScriptableObject - { - [Header("Structure")] - [Tooltip("Waves in one cycle. The phase draws this many distinct-enemy-type waves and " + - "replays them every cycle.")] - [Min(1)] - public int WavesPerCycle = 5; - - [Tooltip("Cycles before the phase's boss appears. The same drawn waves repeat each " + - "cycle, carrying whatever upgrades players voted onto them.")] - [Min(1)] - public int CyclesPerPhase = 3; - - [Tooltip("Phases in order. Beating the last phase's boss wins the run. The MVP ships " + - "one phase; the full design is three.")] - public PhaseDefinition[] Phases; - - // ----- Flat wave index (network identity) -------------------------- - - // Built lazily and cached. Null means "not built yet". Rebuilt only on explicit request - // or on edit-time validation — never spontaneously during play, since ids in flight - // would be invalidated. - private List waveIndex; - private Dictionary waveIds; - - /// Number of distinct waves reachable anywhere in this run. - public int WaveCount - { - get { EnsureIndex(); return waveIndex.Count; } - } - - /// Resolves a replicated wave id back to its asset, or null if out of range. - public WaveDefinition GetWave(int waveId) - { - EnsureIndex(); - return (waveId >= 0 && waveId < waveIndex.Count) ? waveIndex[waveId] : null; - } - - /// Resolves a wave asset to its replicated id. - public bool TryGetWaveId(WaveDefinition wave, out int waveId) - { - EnsureIndex(); - if (wave != null && waveIds.TryGetValue(wave, out waveId)) return true; - waveId = -1; - return false; - } - - /// - /// Rebuilds the flat wave index from the current asset contents. Called once by - /// RunState on every peer at match start so ids agree, and by the editor when - /// the asset changes. - /// - public void RebuildIndex() - { - waveIndex ??= new List(); - waveIds ??= new Dictionary(); - waveIndex.Clear(); - waveIds.Clear(); - - if (Phases == null) return; - - // Declaration-order walk. Every peer runs this over the same asset, so the - // resulting ids match without any negotiation. Zero-weight entries are indexed - // too: they can't be drawn, but indexing them keeps ids stable if a designer - // re-weights between sessions. - foreach (var phase in Phases) - { - if (phase == null) continue; - IndexGroups(phase.WaveGroups); - IndexGroups(phase.BossGroups); - } - } - - private void IndexGroups(WaveGroup[] groups) - { - if (groups == null) return; - foreach (var group in groups) - { - if (group?.Waves == null) continue; - foreach (var entry in group.Waves) - { - if (entry?.Wave == null) continue; - if (waveIds.ContainsKey(entry.Wave)) continue; // first occurrence wins - waveIds[entry.Wave] = waveIndex.Count; - waveIndex.Add(entry.Wave); - } - } - } - - private void EnsureIndex() - { - if (waveIndex == null || waveIds == null) RebuildIndex(); - } - - // ----- Validation -------------------------------------------------- - - /// - /// Checks that this run can actually be played: at least one phase, every phase able to - /// fill slots with distinct enemy types, and every phase able - /// to produce a boss. Returns true when the run is playable; - /// carries the problems either way (it may hold warnings even - /// on success). - /// - /// - /// The distinct-enemy-type requirement is the one that bites in practice: a phase can - /// hold twenty waves and still be unplayable if they all point at the same three enemies. - /// Checking it up front turns that into a startup error instead of a draw that silently - /// runs short a wave. - /// - public bool Validate(out string report) - { - var sb = new StringBuilder(); - bool ok = true; - - if (Phases == null || Phases.Length == 0) - { - sb.AppendLine("• No phases assigned — the run has nothing to play."); - report = sb.ToString(); - return false; - } - - var candidates = new List(); - - for (int i = 0; i < Phases.Length; i++) - { - var phase = Phases[i]; - string label = phase != null ? phase.Label : $"Phase {i + 1}"; - - if (phase == null) - { - sb.AppendLine($"• {label}: slot is empty."); - ok = false; - continue; - } - - int distinctTypes = phase.CountDistinctEnemyTypes(); - if (distinctTypes < WavesPerCycle) - { - sb.AppendLine($"• {label}: needs {WavesPerCycle} distinct enemy types to fill " + - $"a cycle but only {distinctTypes} are reachable. Add waves " + - $"using other enemies, or lower Waves Per Cycle."); - ok = false; - } - - phase.CollectBossCandidates(candidates); - if (candidates.Count == 0) - { - sb.AppendLine($"• {label}: no boss candidates (every boss group is empty, " + - $"unassigned, or entirely zero-weight)."); - ok = false; - } - - // Warnings — these don't block a run, they just play oddly. - phase.CollectWaveCandidates(candidates); - foreach (var entry in candidates) - { - if (entry.Wave.PrimaryEnemyType == null) - sb.AppendLine($"• (warning) {label}: '{entry.Wave.name}' has no usable " + - $"enemy entries and can never be drawn meaningfully."); - else if (!entry.Wave.HasSingleEnemyType) - sb.AppendLine($"• (warning) {label}: '{entry.Wave.name}' mixes enemy " + - $"types. Upgrades and HUD labels will use " + - $"'{entry.Wave.PrimaryEnemyType.name}' only."); - } - } - - report = sb.Length > 0 ? sb.ToString() : "Run structure OK."; - return ok; - } - -#if UNITY_EDITOR - private void OnValidate() - { - // Only invalidate outside play mode. Clearing the cache mid-match would renumber - // wave ids while replicated slot references are still pointing at the old numbering. - if (!Application.isPlaying) - { - waveIndex = null; - waveIds = null; - } - } -#endif - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs.meta b/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs.meta deleted file mode 100644 index 6c2d0d3..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/RunDefinition.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2b73bb9876b7fdb4480b13ff6bb8bd67 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs b/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs deleted file mode 100644 index b31b585..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs +++ /dev/null @@ -1,468 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Waves/RunState.cs -using System.Collections.Generic; -using Unity.Netcode; -using UnityEngine; - -namespace TD.Gameplay.Waves -{ - /// - /// Outcome of advancing the run by one encounter. Returned by - /// so WaveManager can react without - /// re-deriving the progression maths. - /// - public enum RunAdvance : byte - { - /// Moved to the next wave inside the current cycle. - NextWave = 0, - /// Moved to the first wave of a new cycle — the same waves come round again, - /// now carrying whatever upgrades players voted onto them. - NextCycle = 1, - /// Every cycle in the phase is done; the boss is up next. - BossReady = 2, - /// The boss died and a new phase was drawn. Upgrades were wiped. - NextPhase = 3, - /// The final phase's boss died — the run is won. - RunComplete = 4, - } - - /// - /// Server-authoritative owner of run progression: which phase and cycle we're in, which waves - /// this phase drew, and which upgrades the players have voted onto each wave slot. - /// - /// - /// Split of duties with WaveManager. This type is the run's state — - /// counters, draws, upgrade sets — and knows nothing about spawning. WaveManager is the - /// driver: it runs an encounter, and when the field is clear it calls - /// and acts on the returned . Keeping them - /// apart is what stops WaveManager (already a large class) from also owning pool draws and - /// upgrade bookkeeping. - /// - /// Linear encounter index. Rather than replicate cycle and wave separately and - /// keep them in sync, one counter runs - /// 0 .. CyclesPerPhase*WavesPerCycle inclusive, with the final value meaning "boss". - /// Cycle and wave slot are derived from it, so they cannot disagree. - /// - /// Upgrades are keyed by wave slot, not enemy type. The phase draw guarantees the - /// slots hold distinct enemy types, which makes slot and type interchangeable as a key — and - /// slot is the one that survives a phase change cleanly, since the next phase reassigns every - /// slot to a fresh enemy anyway. - /// - public class RunState : NetworkBehaviour - { - // ----- Singleton -------------------------------------------------- - - public static RunState Instance { get; private set; } - - // ----- Inspector -------------------------------------------------- - - [Tooltip("The run this match plays: phase pools, waves per cycle, cycles per phase. " + - "Required — without it no waves can be drawn.")] - [SerializeField] private RunDefinition runDefinition; - - // ----- Networked state -------------------------------------------- - - private readonly NetworkVariable phaseIndex = new NetworkVariable( - 0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); - - // 0 .. (CyclesPerPhase * WavesPerCycle), where the top value means "boss". - private readonly NetworkVariable encounterInPhase = new NetworkVariable( - 0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); - - // Wave ids (indices into RunDefinition's flat index) drawn for this phase's slots. - // Exactly WavesPerCycle entries once a phase has been drawn. - private NetworkList drawnWaveIds; - - private readonly NetworkVariable bossWaveId = new NetworkVariable( - -1, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); - - // Upgrades voted onto wave slots, packed as (slot << SlotShift) | optionId. A flat - // append-only list rather than a per-slot structure because NGO has no nested-collection - // support and the counts here are tiny (a handful per slot, per phase). - private NetworkList waveUpgrades; - - private const int SlotShift = 16; - private const int OptionMask = (1 << SlotShift) - 1; - - // Per-slot count of buffs to apply automatically, skipping the next vote for that slot. - // Indexed by upgrade slot (0..WavesPerCycle, the last being the boss). Zero means a normal - // vote. Written by the vote-meta cards, consumed by the inter-wave step. - private NetworkList autoApplyCounts; - - /// - /// Fired on every peer whenever run progression or the drawn/upgraded wave set changes. - /// The HUD subscribes to relabel without polling. - /// - public event System.Action OnRunChanged; - - // ----- Lifecycle --------------------------------------------------- - - private void Awake() - { - drawnWaveIds = new NetworkList(); - waveUpgrades = new NetworkList(); - autoApplyCounts = new NetworkList(); - } - - public override void OnNetworkSpawn() - { - if (Instance != null && Instance != this) - { - Debug.LogError("[RunState] Duplicate RunState detected. Only one may exist per scene."); - return; - } - Instance = this; - - // Freeze the wave index on EVERY peer (not just the server) before any id crosses - // the wire. Same asset, same declaration-order walk, same numbering. - runDefinition?.RebuildIndex(); - - // One auto-apply counter per upgrade slot, plus one for the boss slot. - if (IsServer) - { - for (int i = 0; i <= WavesPerCycle; i++) autoApplyCounts.Add(0); - } - - phaseIndex.OnValueChanged += HandleIntChanged; - encounterInPhase.OnValueChanged += HandleIntChanged; - bossWaveId.OnValueChanged += HandleIntChanged; - drawnWaveIds.OnListChanged += HandleListChanged; - waveUpgrades.OnListChanged += HandleListChanged; - } - - public override void OnNetworkDespawn() - { - phaseIndex.OnValueChanged -= HandleIntChanged; - encounterInPhase.OnValueChanged -= HandleIntChanged; - bossWaveId.OnValueChanged -= HandleIntChanged; - drawnWaveIds.OnListChanged -= HandleListChanged; - waveUpgrades.OnListChanged -= HandleListChanged; - - if (Instance == this) Instance = null; - } - - private void HandleIntChanged(int _, int __) => OnRunChanged?.Invoke(); - private void HandleListChanged(NetworkListEvent _) => OnRunChanged?.Invoke(); - - // ----- Structure accessors ----------------------------------------- - - /// The run asset driving this match, or null if unassigned (designer error). - public RunDefinition Definition => runDefinition; - - public int WavesPerCycle => runDefinition != null ? Mathf.Max(1, runDefinition.WavesPerCycle) : 5; - public int CyclesPerPhase => runDefinition != null ? Mathf.Max(1, runDefinition.CyclesPerPhase) : 3; - public int PhaseCount => runDefinition?.Phases?.Length ?? 0; - - /// Encounters in one phase, counting its boss. - public int EncountersPerPhase => CyclesPerPhase * WavesPerCycle + 1; - - // ----- Progression accessors --------------------------------------- - - /// Zero-based phase index. - public int PhaseIndex => phaseIndex.Value; - - /// - /// The phase currently being played, or null if the run isn't set up. Read by the vote - /// generator to find which enemy-buff cards this phase allows. - /// - public PhaseDefinition CurrentPhase - { - get - { - var phases = runDefinition?.Phases; - if (phases == null) return null; - int i = phaseIndex.Value; - return (i >= 0 && i < phases.Length) ? phases[i] : null; - } - } - - /// Zero-based cycle index within the current phase. Reads as the last cycle - /// while the boss is up (the boss belongs to the phase, not to a fourth cycle). - public int CycleIndex => Mathf.Min(encounterInPhase.Value / WavesPerCycle, CyclesPerPhase - 1); - - /// Zero-based wave slot within the current cycle. Meaningless while - /// is true. - public int WaveSlot => encounterInPhase.Value % WavesPerCycle; - - /// True when the next/current encounter is this phase's boss. - public bool IsBossStage => encounterInPhase.Value >= CyclesPerPhase * WavesPerCycle; - - /// - /// 1-based count of encounters since the run began, including bosses. This is the key - /// GoldConfig.Encounters is indexed by, so payouts scale monotonically across the - /// whole run rather than resetting every cycle. - /// - public int GlobalEncounterNumber - => phaseIndex.Value * EncountersPerPhase + encounterInPhase.Value + 1; - - /// Human-readable progress line for the HUD, e.g. "Phase 1 · Cycle 2 · Wave 3/5". - public string ProgressLabel - => IsBossStage - ? $"Phase {phaseIndex.Value + 1} · BOSS" - : $"Phase {phaseIndex.Value + 1} · Cycle {CycleIndex + 1} · " + - $"Wave {WaveSlot + 1}/{WavesPerCycle}"; - - // ----- Wave accessors ---------------------------------------------- - - /// The wave asset drawn for , or null if not drawn yet. - public WaveDefinition GetSlotWave(int slot) - { - if (runDefinition == null) return null; - if (slot < 0 || slot >= drawnWaveIds.Count) return null; - return runDefinition.GetWave(drawnWaveIds[slot]); - } - - /// This phase's boss wave, or null if not drawn yet. - public WaveDefinition BossWave - => runDefinition != null ? runDefinition.GetWave(bossWaveId.Value) : null; - - /// The wave the run is currently pointing at — boss or cycle wave. - public WaveDefinition CurrentWave => IsBossStage ? BossWave : GetSlotWave(WaveSlot); - - /// - /// The slot key upgrades attach to for the current encounter. The boss occupies the slot - /// one past the last cycle wave, so boss upgrades (if ever voted) don't collide with it. - /// - public int CurrentUpgradeSlot => IsBossStage ? WavesPerCycle : WaveSlot; - - // ----- Upgrade accessors ------------------------------------------- - - /// - /// Collects the upgrade option ids voted onto , in the order they - /// were applied. Safe on any peer. - /// - public void GetUpgradesForSlot(int slot, List into) - { - into.Clear(); - for (int i = 0; i < waveUpgrades.Count; i++) - { - int packed = waveUpgrades[i]; - if ((packed >> SlotShift) == slot) into.Add(packed & OptionMask); - } - } - - /// How many upgrades are stacked on . - public int CountUpgradesForSlot(int slot) - { - int n = 0; - for (int i = 0; i < waveUpgrades.Count; i++) - if ((waveUpgrades[i] >> SlotShift) == slot) n++; - return n; - } - - /// True if already carries . - /// Used to keep the vote from offering a buff a wave already has. - public bool SlotHasUpgrade(int slot, int optionId) - { - int packed = (slot << SlotShift) | (optionId & OptionMask); - for (int i = 0; i < waveUpgrades.Count; i++) - if (waveUpgrades[i] == packed) return true; - return false; - } - - /// Server-only: stack an upgrade onto a wave slot. Ignores exact duplicates. - public void ServerAddUpgrade(int slot, int optionId) - { - if (!IsServer) return; - if (slot < 0 || optionId < 0) return; - if (SlotHasUpgrade(slot, optionId)) return; - - waveUpgrades.Add((slot << SlotShift) | (optionId & OptionMask)); - } - - // ----- Auto-apply (vote-meta cards) -------------------------------- - - /// - /// How many buffs will take automatically instead of holding its - /// next vote. Zero means a normal vote. - /// - public int GetAutoApplyCount(int slot) - => (slot >= 0 && slot < autoApplyCounts.Count) ? autoApplyCounts[slot] : 0; - - /// - /// Server-only: arm to auto-take buffs in - /// place of its next vote. Takes the larger value if already armed, so two vote-meta cards - /// on one slot don't cancel each other down. - /// - public void ServerSetAutoApply(int slot, int count) - { - if (!IsServer) return; - if (slot < 0 || slot >= autoApplyCounts.Count || count <= 0) return; - autoApplyCounts[slot] = Mathf.Max(autoApplyCounts[slot], count); - } - - /// Server-only: disarm after its auto-apply has fired. - public void ServerConsumeAutoApply(int slot) - { - if (!IsServer) return; - if (slot < 0 || slot >= autoApplyCounts.Count) return; - autoApplyCounts[slot] = 0; - } - - private void ServerClearAutoApply() - { - for (int i = 0; i < autoApplyCounts.Count; i++) autoApplyCounts[i] = 0; - } - - // ----- Server: run control ------------------------------------------ - - /// - /// Server-only: start the run at phase 0 and draw its waves. Returns false if the run - /// definition is missing or unplayable — the caller should treat that as fatal rather - /// than limping along with an empty schedule. - /// - public bool ServerBeginRun() - { - if (!IsServer) return false; - - if (runDefinition == null) - { - Debug.LogError("[RunState] No RunDefinition assigned — cannot start a run."); - return false; - } - - if (!runDefinition.Validate(out string report)) - { - Debug.LogError($"[RunState] RunDefinition '{runDefinition.name}' is not playable:\n{report}"); - return false; - } - - phaseIndex.Value = 0; - encounterInPhase.Value = 0; - waveUpgrades.Clear(); - ServerClearAutoApply(); - - return ServerDrawPhase(0); - } - - /// - /// Server-only: advance one encounter, drawing a new phase (and wiping upgrades) when the - /// boss falls. See for what the caller should do with each result. - /// - public RunAdvance ServerAdvance() - { - if (!IsServer) return RunAdvance.NextWave; - - // Boss just died: the phase is over. Either draw the next one or win the run. - if (IsBossStage) - { - int next = phaseIndex.Value + 1; - if (next >= PhaseCount) return RunAdvance.RunComplete; - - phaseIndex.Value = next; - encounterInPhase.Value = 0; - - // A new phase means five brand-new waves, so every upgrade voted onto the old - // slots is meaningless — wiped by design, not by omission. Armed auto-applies go - // with them: they were promises made about waves that no longer exist. - waveUpgrades.Clear(); - ServerClearAutoApply(); - ServerDrawPhase(next); - return RunAdvance.NextPhase; - } - - int previousCycle = CycleIndex; - encounterInPhase.Value++; - - if (IsBossStage) return RunAdvance.BossReady; - if (CycleIndex != previousCycle) return RunAdvance.NextCycle; - return RunAdvance.NextWave; - } - - // ----- Server: phase draw ------------------------------------------- - - // Scratch list reused across draws; server is single-threaded so sharing is safe. - private readonly List candidateScratch = new List(); - - /// - /// Server-only: draw this phase's cycle waves and boss. Cycle waves are drawn by relative - /// weight without replacement and with distinct enemy types; the boss is a plain - /// weighted draw. - /// - private bool ServerDrawPhase(int index) - { - if (!IsServer) return false; - - var phases = runDefinition?.Phases; - if (phases == null || index < 0 || index >= phases.Length || phases[index] == null) - { - Debug.LogError($"[RunState] Phase {index + 1} is missing — cannot draw waves."); - return false; - } - - var phase = phases[index]; - int needed = WavesPerCycle; - - phase.CollectWaveCandidates(candidateScratch); - drawnWaveIds.Clear(); - - for (int drawn = 0; drawn < needed; drawn++) - { - var pick = DrawWeighted(candidateScratch); - if (pick == null) - { - Debug.LogError( - $"[RunState] {phase.Label}: ran out of candidates after {drawn} of " + - $"{needed} wave(s). The phase needs {needed} waves with DISTINCT enemy " + - $"types — check the RunDefinition inspector's phase-capacity readout."); - return false; - } - - if (!runDefinition.TryGetWaveId(pick.Wave, out int waveId)) - { - Debug.LogError($"[RunState] Wave '{pick.Wave.name}' is not in the run's wave " + - $"index. This should be impossible — the index is built from " + - $"the same pools. Skipping."); - candidateScratch.Remove(pick); - drawn--; - continue; - } - - drawnWaveIds.Add(waveId); - - // Retire every remaining candidate sharing this enemy type, so distinctness is - // enforced by shrinking the pool rather than by reject-and-retry. - var type = pick.Wave.PrimaryEnemyType; - candidateScratch.RemoveAll( - e => e.Wave == pick.Wave || (type != null && e.Wave.PrimaryEnemyType == type)); - } - - // Boss draw — independent pool, no distinctness constraint. - phase.CollectBossCandidates(candidateScratch); - var boss = DrawWeighted(candidateScratch); - if (boss == null || !runDefinition.TryGetWaveId(boss.Wave, out int bossId)) - { - Debug.LogError($"[RunState] {phase.Label}: no boss could be drawn."); - bossWaveId.Value = -1; - return false; - } - bossWaveId.Value = bossId; - - Debug.Log($"[RunState] Drew {phase.Label}: {needed} wave(s) + boss " + - $"'{boss.Wave.name}'."); - return true; - } - - // Relative-weight draw. Weights are normalized against the candidate set's total, so a - // pool of three 1.0 entries is uniform and a 0.5 entry is half as likely as a 1.0 one. - // Zero-weight entries never reach here — PhaseDefinition filters them during collection. - private static WavePoolEntry DrawWeighted(List candidates) - { - if (candidates == null || candidates.Count == 0) return null; - - float total = 0f; - for (int i = 0; i < candidates.Count; i++) - total += Mathf.Max(0f, candidates[i].Weight); - - if (total <= 0f) return null; - - float roll = Random.value * total; - for (int i = 0; i < candidates.Count; i++) - { - roll -= Mathf.Max(0f, candidates[i].Weight); - if (roll <= 0f) return candidates[i]; - } - - return candidates[candidates.Count - 1]; // float drift fallback - } - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs.meta b/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs.meta deleted file mode 100644 index 4905373..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/RunState.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a293cf6dca91dd2478c9f4e799cf9e0d \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs b/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs deleted file mode 100644 index 9d1c129..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs -using System; -using UnityEngine; -using TD.Core; - -namespace TD.Gameplay.Waves -{ - /// - /// One weighted candidate inside a : a wave that may be drawn, - /// and how likely it is to be drawn relative to the group's other entries. - /// - /// - /// Weight is RELATIVE, not an absolute probability. The draw normalizes every - /// candidate's weight against the summed weight of the whole candidate set, so three - /// entries at 1.0 each are equally likely (33% apiece) and an entry at 0.5 is half as - /// likely to be drawn as one at 1.0. This is what makes the default sane: new entries - /// start at 1.0, so adding a wave to a group never silently re-weights the others. - /// - /// A class rather than a struct specifically so can carry a - /// field initializer — Unity runs it when the inspector creates a fresh array element, - /// which is what gives new entries their equal-by-default weighting. Mirrors - /// . - /// - [Serializable] - public class WavePoolEntry - { - [Tooltip("The wave that may be drawn from this group.")] - public WaveDefinition Wave; - - [Tooltip("Relative draw weight within this group's pool. Entries at equal weight are " + - "equally likely; an entry at 0.5 is half as likely as one at 1.0. NOT an " + - "absolute percentage.")] - [PoolWeight("wave")] - public float Weight = 1f; - } - - /// - /// A named, reusable bag of candidate waves. Groups are the unit designers move between - /// phases: dragging a group asset from Phase 1's pool to Phase 2's moves every wave in it - /// (and their weights) in one action. - /// - /// - /// Why weights live on the entry, not on . Weight is a - /// property of "how common is this wave in this pool", not of the wave itself. Keeping - /// it here means the same asset can be a staple of one group and - /// a rarity in another, and a group carries its tuning with it when moved between phases. - /// - /// Boss groups use the same type. A boss wave is just a - /// whose entries spawn a single powerful enemy, so boss pools - /// are ordinary s referenced from - /// . - /// - [CreateAssetMenu(fileName = "WaveGroup", menuName = "TD/Run/Wave Group", order = 10)] - public class WaveGroup : ScriptableObject - { - [Tooltip("Designer-facing name for this group, shown in run-structure validation " + - "messages. Falls back to the asset name when empty.")] - public string DisplayName; - - [Tooltip("Candidate waves in this group, each with a relative draw weight.")] - public WavePoolEntry[] Waves; - - /// Name used in validation and log messages. Falls back to the asset name. - public string Label => string.IsNullOrWhiteSpace(DisplayName) ? name : DisplayName; - - /// Number of entries, including any that are null or zero-weight. - public int Count => Waves?.Length ?? 0; - } -} diff --git a/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs.meta b/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs.meta deleted file mode 100644 index 817269e..0000000 --- a/Assets/_Project/Scripts/Gameplay/Waves/WaveGroup.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5625bd25f378bda429666820a4940cee \ No newline at end of file diff --git a/Assets/_Project/Scripts/UI/FloatingTextSpawner.cs b/Assets/_Project/Scripts/UI/FloatingTextSpawner.cs index 49b4e66..392b1a2 100644 --- a/Assets/_Project/Scripts/UI/FloatingTextSpawner.cs +++ b/Assets/_Project/Scripts/UI/FloatingTextSpawner.cs @@ -74,11 +74,6 @@ namespace TD.UI public void SpawnGoldReward(Vector3 worldPos, int amount) => SpawnInternal(worldPos, $"+{amount}", goldColor); - /// Spawns a gold-loss popup (e.g. "-15") at the given world position. Same colour - /// as a reward so it reads as gold; the sign carries the meaning. - public void SpawnGoldLoss(Vector3 worldPos, int amount) - => SpawnInternal(worldPos, $"-{amount}", goldColor); - /// Spawns a life-loss popup (e.g. "-1") at the given world position. public void SpawnLifeLoss(Vector3 worldPos, int amount) => SpawnInternal(worldPos, $"-{amount}", livesColor); diff --git a/Assets/_Project/Scripts/UI/GameMenuView.cs b/Assets/_Project/Scripts/UI/GameMenuView.cs deleted file mode 100644 index 7db20bd..0000000 --- a/Assets/_Project/Scripts/UI/GameMenuView.cs +++ /dev/null @@ -1,407 +0,0 @@ -// Assets/_Project/Scripts/UI/GameMenuView.cs -using UnityEngine; -using UnityEngine.UIElements; -using TD.Audio; - -namespace TD.UI -{ - /// - /// The in-match menu: a gear button in the top-right of the HUD top bar plus a modal - /// overlay with two options — Return to Title Screen and Audio Settings. - /// - /// - /// Ownership. A plain class (not a MonoBehaviour), constructed by - /// and given the HUD's root element — same pattern as - /// MinimapView. Everything is built programmatically and appended last, so it - /// z-orders above the rest of the HUD with no extra UIDocument or PanelSettings. - /// - /// Modality. The overlay is full-screen with - /// , which both dims the match and makes - /// true everywhere — so clicks - /// can't reach towers or the ground underneath. HUDController also sets - /// while it's open, which gates keyboard-driven - /// gameplay (camera pan, hotkeys, Escape handlers). The match does not pause: - /// this is a multiplayer game and waves keep running. - /// - /// Pages. One panel, three swapped bodies: the option list, the audio mixer, - /// and a confirm step for leaving the match. Escape backs out one page at a time and - /// closes from the root page. - /// - public class GameMenuView - { - private enum Page { Root, Audio, ConfirmLeave } - - // ----- Wiring ----------------------------------------------------- - - private readonly System.Action onReturnToTitle; - - private readonly VisualElement overlay; - private readonly Label header; - private readonly VisualElement rootPage; - private readonly VisualElement audioPage; - private readonly VisualElement confirmPage; - - private readonly SliderInt musicSlider; - private readonly Label musicValue; - private readonly SliderInt sfxSlider; - private readonly Label sfxValue; - - private Page page = Page.Root; - - // ----- Public API ------------------------------------------------- - - public bool IsOpen { get; private set; } - - /// The HUD's rootVisualElement. The overlay is appended to it. - /// The top-bar "menu-button" from HUD.uxml. May be null - /// (Escape still works); the gear glyph is painted into it here. - /// Optional sprite for the gear. When null, the icon is drawn - /// procedurally so the button never depends on an art asset existing. - /// Invoked once the player confirms leaving the match. - public GameMenuView(VisualElement root, Button gearButton, Sprite gearIcon, - System.Action onReturnToTitle) - { - this.onReturnToTitle = onReturnToTitle; - - if (gearButton != null) - { - gearButton.text = string.Empty; - gearButton.Add(CreateGearIcon(gearIcon)); - gearButton.clicked += Toggle; - gearButton.tooltip = "Menu (Esc)"; - } - - // ----- Overlay + panel shell ---------------------------------- - - overlay = new VisualElement(); - overlay.style.position = Position.Absolute; - overlay.style.left = 0; - overlay.style.right = 0; - overlay.style.top = 0; - overlay.style.bottom = 0; - overlay.style.alignItems = Align.Center; - overlay.style.justifyContent = Justify.Center; - overlay.style.backgroundColor = new Color(0f, 0f, 0f, 0.55f); - overlay.style.display = DisplayStyle.None; - overlay.pickingMode = PickingMode.Position; - - var panel = new VisualElement(); - panel.style.minWidth = 360; - panel.style.paddingTop = panel.style.paddingBottom = 24; - panel.style.paddingLeft = panel.style.paddingRight = 32; - panel.style.backgroundColor = new Color(0.08f, 0.08f, 0.10f, 0.97f); - panel.style.borderTopWidth = panel.style.borderBottomWidth = - panel.style.borderLeftWidth = panel.style.borderRightWidth = 2; - var border = new Color(0.4f, 0.4f, 0.45f); - panel.style.borderTopColor = panel.style.borderBottomColor = - panel.style.borderLeftColor = panel.style.borderRightColor = border; - panel.style.alignItems = Align.Center; - overlay.Add(panel); - - header = new Label("Menu"); - header.style.fontSize = 24; - header.style.color = Color.white; - header.style.marginBottom = 18; - header.style.unityFontStyleAndWeight = FontStyle.Bold; - panel.Add(header); - - // ----- Page 1: option list ------------------------------------ - - rootPage = new VisualElement(); - rootPage.style.alignItems = Align.Center; - rootPage.Add(MakeMenuButton("Return to Title Screen", () => GoTo(Page.ConfirmLeave))); - rootPage.Add(MakeMenuButton("Audio Settings", () => GoTo(Page.Audio))); - rootPage.Add(MakeMenuButton("Resume", Close)); - panel.Add(rootPage); - - // ----- Page 2: audio mixer ------------------------------------ - - audioPage = new VisualElement(); - audioPage.style.alignItems = Align.Stretch; - audioPage.style.display = DisplayStyle.None; - - audioPage.Add(BuildVolumeRow("Music", AudioVolumeSettings.MusicVolume, - v => AudioVolumeSettings.MusicVolume = v, - out musicSlider, out musicValue)); - audioPage.Add(BuildVolumeRow("Sound Effects", AudioVolumeSettings.SfxVolume, - v => AudioVolumeSettings.SfxVolume = v, - out sfxSlider, out sfxValue)); - - var audioNote = new Label("Sound effects covers spells, towers, building, and enemies."); - audioNote.style.fontSize = 11; - audioNote.style.color = new Color(0.6f, 0.6f, 0.65f); - audioNote.style.marginTop = 4; - audioNote.style.marginBottom = 12; - audioNote.style.whiteSpace = WhiteSpace.Normal; - audioPage.Add(audioNote); - - var audioBack = MakeMenuButton("Back", () => GoTo(Page.Root)); - audioBack.style.alignSelf = Align.Center; - audioPage.Add(audioBack); - panel.Add(audioPage); - - // ----- Page 3: leave confirmation ----------------------------- - - confirmPage = new VisualElement(); - confirmPage.style.alignItems = Align.Center; - confirmPage.style.display = DisplayStyle.None; - - var confirmText = new Label("Leave the match and return to the title screen?"); - confirmText.style.color = new Color(0.88f, 0.88f, 0.9f); - confirmText.style.whiteSpace = WhiteSpace.Normal; - confirmText.style.marginBottom = 16; - confirmText.style.unityTextAlign = TextAnchor.MiddleCenter; - confirmPage.Add(confirmText); - - var confirmRow = new VisualElement(); - confirmRow.style.flexDirection = FlexDirection.Row; - confirmPage.Add(confirmRow); - - var leaveBtn = MakeMenuButton("Leave Match", ConfirmLeave); - leaveBtn.style.marginRight = 12; - leaveBtn.style.minWidth = 150; - confirmRow.Add(leaveBtn); - - var cancelBtn = MakeMenuButton("Cancel", () => GoTo(Page.Root)); - cancelBtn.style.minWidth = 150; - confirmRow.Add(cancelBtn); - panel.Add(confirmPage); - - root.Add(overlay); - } - - public void Open() - { - if (IsOpen) return; - IsOpen = true; - GoTo(Page.Root); - overlay.style.display = DisplayStyle.Flex; - } - - public void Close() - { - if (!IsOpen) return; - IsOpen = false; - overlay.style.display = DisplayStyle.None; - // Volume setters only touch the in-memory pref so a slider drag stays cheap; - // write it out now that the player is done adjusting. - AudioVolumeSettings.Flush(); - } - - public void Toggle() - { - if (IsOpen) Close(); - else Open(); - } - - /// - /// Escape while the menu is open: back out one page, or close from the root page. - /// - public void Back() - { - if (page == Page.Root) Close(); - else GoTo(Page.Root); - } - - // ----- Pages ------------------------------------------------------ - - private void GoTo(Page next) - { - page = next; - - rootPage.style.display = next == Page.Root ? DisplayStyle.Flex : DisplayStyle.None; - audioPage.style.display = next == Page.Audio ? DisplayStyle.Flex : DisplayStyle.None; - confirmPage.style.display = next == Page.ConfirmLeave ? DisplayStyle.Flex : DisplayStyle.None; - - header.text = next switch - { - Page.Audio => "Audio Settings", - Page.ConfirmLeave => "Leave Match", - _ => "Menu", - }; - - // Another surface could have changed the volumes since this page was last - // shown (a future title-screen mixer, a debug command). Re-sync on entry so - // the sliders never display a stale value. - if (next == Page.Audio) SyncSlidersFromSettings(); - } - - private void SyncSlidersFromSettings() - { - // SetValueWithoutNotify: writing the settings value back through the change - // callback would be a no-op today (the setter early-outs on an unchanged value) - // but it's the wrong direction of data flow, so don't. - musicSlider.SetValueWithoutNotify(AudioVolumeSettings.MusicVolume); - musicValue.text = AudioVolumeSettings.MusicVolume.ToString(); - sfxSlider.SetValueWithoutNotify(AudioVolumeSettings.SfxVolume); - sfxValue.text = AudioVolumeSettings.SfxVolume.ToString(); - } - - private void ConfirmLeave() - { - AudioVolumeSettings.Flush(); - IsOpen = false; - overlay.style.display = DisplayStyle.None; - onReturnToTitle?.Invoke(); - } - - // ----- Element builders ------------------------------------------- - - private static Button MakeMenuButton(string text, System.Action onClick) - { - var btn = new Button(() => onClick?.Invoke()) { text = text }; - btn.style.minWidth = 260; - btn.style.height = 40; - btn.style.fontSize = 16; - btn.style.marginBottom = 8; - return btn; - } - - // One mixer row: name, 0..100 slider, live numeric readout. - private static VisualElement BuildVolumeRow(string label, int initial, - System.Action onChange, - out SliderInt slider, out Label valueLabel) - { - var row = new VisualElement(); - row.style.flexDirection = FlexDirection.Row; - // FlexStart, not Center: the labels are aligned to the slider's track by - // AlignLabelsToTrack below, which needs every child's box to start at the same - // top edge. See that method for why centering the boxes isn't enough. - row.style.alignItems = Align.FlexStart; - row.style.marginBottom = 10; - - var name = new Label(label); - name.style.color = new Color(0.88f, 0.88f, 0.9f); - name.style.fontSize = 14; - name.style.width = 110; - name.style.flexShrink = 0; - name.style.unityTextAlign = TextAnchor.MiddleLeft; - row.Add(name); - - slider = new SliderInt(AudioVolumeSettings.MinVolume, AudioVolumeSettings.MaxVolume); - slider.style.width = 200; - slider.style.flexShrink = 0; - slider.SetValueWithoutNotify(initial); - row.Add(slider); - - // Fixed width + right-align so the slider doesn't shift as the number goes - // from 1 to 3 digits while dragging. - var value = new Label(initial.ToString()); - value.style.color = Color.white; - value.style.fontSize = 14; - value.style.width = 40; - value.style.flexShrink = 0; - value.style.unityTextAlign = TextAnchor.MiddleRight; - row.Add(value); - - AlignLabelsToTrack(row, slider, name, value); - - var captured = value; - slider.RegisterValueChangedCallback(evt => - { - captured.text = evt.newValue.ToString(); - onChange(evt.newValue); - }); - - valueLabel = value; - return row; - } - - // Vertically lines the row's text up with the groove the player actually sees. - // - // The default runtime theme gives a horizontal slider a box that's taller than its - // track and does NOT center the track inside it, so `align-items: center` on the row - // centers the *boxes* and leaves the text sitting well below the groove. The exact - // offset is a theme detail, so it's measured rather than hardcoded: with the row - // aligned FlexStart every child's box starts at the same top edge, so giving a label - // a height of twice the track's offset from that edge puts its vertically-centered - // text exactly on the track's center line. - // - // Runs on GeometryChangedEvent (not once at build time) because layout hasn't - // happened yet during construction, and because it needs to re-solve when the panel - // is rescaled or the menu is reopened at a different resolution. - private static void AlignLabelsToTrack(VisualElement row, SliderInt slider, - params Label[] labels) - { - // Align to the *tracker* — the thin groove. Not the drag-container: that's the - // full hit area, tall enough to hold the dragger handle (which overhangs the - // groove on both sides), so its center sits below the groove. Fall back through - // the container to the slider itself if the theme's internal names ever change; - // worst case is the old box-centered look, not a broken layout. - VisualElement track = slider.Q(className: "unity-base-slider__tracker") - ?? slider.Q(className: "unity-base-slider__drag-container") - ?? slider; - - void Align(GeometryChangedEvent _) - { - float rowTop = row.worldBound.y; - float trackCenter = track.worldBound.center.y; - float half = trackCenter - rowTop; - if (half <= 0f || float.IsNaN(half)) return; // pre-layout; a later event fixes it - - foreach (var label in labels) - label.style.height = half * 2f; - } - - row.RegisterCallback(Align); - track.RegisterCallback(Align); - } - - // Gear glyph. Drawn with Painter2D rather than a font glyph or a texture: Unity's - // default runtime font has no U+2699 gear, and a procedural icon keeps the button - // working in any scene without an imported sprite. Pass a sprite to override. - private static VisualElement CreateGearIcon(Sprite icon) - { - var el = new VisualElement(); - el.pickingMode = PickingMode.Ignore; - el.style.flexGrow = 1; - - if (icon != null) - { - el.style.backgroundImage = new StyleBackground(icon); - return el; - } - - el.generateVisualContent += PaintGear; - // generateVisualContent runs against contentRect, which is 0×0 until the first - // layout pass — repaint once the element actually has a size. - el.RegisterCallback(_ => el.MarkDirtyRepaint()); - return el; - } - - private static void PaintGear(MeshGenerationContext ctx) - { - var rect = ctx.visualElement.contentRect; - if (rect.width < 4f || rect.height < 4f) return; - - var painter = ctx.painter2D; - Vector2 center = rect.center; - float outer = Mathf.Min(rect.width, rect.height) * 0.5f - 1f; - float ring = outer * 0.62f; - float hub = outer * 0.24f; - - painter.strokeColor = new Color(0.95f, 0.93f, 0.75f); - painter.lineWidth = Mathf.Max(1.5f, outer * 0.20f); - - // Teeth: radial spokes from just inside the ring out to the edge. - const int teeth = 8; - painter.BeginPath(); - for (int i = 0; i < teeth; i++) - { - float angle = i * Mathf.PI * 2f / teeth; - var dir = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); - painter.MoveTo(center + dir * (ring * 0.85f)); - painter.LineTo(center + dir * outer); - } - painter.Stroke(); - - painter.BeginPath(); - painter.Arc(center, ring, new Angle(0f, AngleUnit.Degree), new Angle(360f, AngleUnit.Degree)); - painter.Stroke(); - - painter.BeginPath(); - painter.Arc(center, hub, new Angle(0f, AngleUnit.Degree), new Angle(360f, AngleUnit.Degree)); - painter.Stroke(); - } - } -} diff --git a/Assets/_Project/Scripts/UI/GameMenuView.cs.meta b/Assets/_Project/Scripts/UI/GameMenuView.cs.meta deleted file mode 100644 index 0d488ea..0000000 --- a/Assets/_Project/Scripts/UI/GameMenuView.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 0f5b5b3bcd6ea4765a92a784b9c8de13 \ No newline at end of file diff --git a/Assets/_Project/Scripts/UI/HUDController.cs b/Assets/_Project/Scripts/UI/HUDController.cs index 7b51380..f581be9 100644 --- a/Assets/_Project/Scripts/UI/HUDController.cs +++ b/Assets/_Project/Scripts/UI/HUDController.cs @@ -8,10 +8,7 @@ using UnityEngine.SceneManagement; using UnityEngine.UIElements; using TD.Core; using TD.Gameplay; -using TD.Gameplay.BuilderSpells; using TD.Gameplay.Draft; -using TD.Gameplay.EnemyUpgrades; -using TD.Gameplay.Waves; using TD.Towers; using TD.UI.Minimap; @@ -45,10 +42,6 @@ namespace TD.UI [Header("Settings")] [SerializeField] private float rejectionMessageDuration = 2.5f; - [Tooltip("Optional icon for the top-right menu button. Leave empty to use the " + - "procedurally-drawn gear (no art asset required).")] - [SerializeField] private Sprite menuButtonIcon; - [Tooltip("Maximum visible height of the chat feed in pixels. Content past this " + "height is clipped — older messages scroll off the top of the visible area " + "but stay in history (scroll up while chat is open to view).")] @@ -77,19 +70,6 @@ namespace TD.UI private Label nextWaveLabel; // prep countdown ("next: 0:12") private Label leakedLabel; // local player's origin-leak count ("leaked: 3") private Label incomeLabel; // top-bar per-wave gold-earned counter ("+150 g/wave") - - // Top-bar row of buff badges for the wave currently spawning. Rebuilt only when the - // underlying set changes — see waveBuffSignature. - private VisualElement waveBuffRow; - - // Cheap change-detector for the buff row. RefreshTopBar runs every frame, and rebuilding - // a handful of VisualElements at 60 Hz would churn the UI system for no reason. Encodes - // the slot plus the option ids on it, so it changes when the wave advances OR when a vote - // lands on the slot the players are about to face again. - private int waveBuffSignature = int.MinValue; - - private readonly System.Collections.Generic.List waveBuffScratch - = new System.Collections.Generic.List(); private VisualElement playerListContainer; // right-panel scoreboard rows private Label portraitName; private Label levelLabel; @@ -120,6 +100,10 @@ namespace TD.UI // Match-end overlay — built once on Start and toggled on Phase changes. private VisualElement matchEndOverlay; + + // Buff menu overlay — toggled by the B key via ToggleBuffMenu(). + private VisualElement buffMenuOverlay; + private VisualElement buffMenuContent; private Label matchEndTitle; // Draft overlay (roguelike between-waves draft). Non-modal: the card row floats at @@ -127,59 +111,10 @@ namespace TD.UI // shown when no draft is pending so a paid roll can be bought any time. private VisualElement draftPanel; private VisualElement draftCardRow; + private Button draftBuyButton; private bool draftSubscribed; private PlayerDraft subscribedDraft; - // Enemy-buff vote overlay. Shares the draft overlay's position and card styling, but the - // cards are shared rather than per-player and carry live voter badges. - private VisualElement votePanel; - private VisualElement voteCardRow; - private Label voteTitle; - private bool voteSubscribed; - private WaveVote subscribedVote; - - // Boss health bar. Shown only while a boss is alive; polled per frame like lives/gold - // rather than event-driven, since HP changes continuously anyway. - private VisualElement bossBarPanel; - private VisualElement bossHealthFill; - private Label bossHealthText; - private Label bossNameLabel; - - // Reused when painting voter badges so a rebuild-per-ballot doesn't allocate a list per - // card. The HUD is single-threaded, so one shared buffer is safe. - private readonly System.Collections.Generic.List voteVoterScratch - = new System.Collections.Generic.List(); - - // Reused when building a selected tower's upgrade buttons. - private readonly System.Collections.Generic.List<(TowerDefinition Def, int TypeId)> - upgradeOptionScratch - = new System.Collections.Generic.List<(TowerDefinition, int)>(); - - // Spell hotbar (bottom-ui Section 6). Frame is visibility:hidden (but still occupies - // its reserved width, so the centered command bar never shifts) while the local player - // has no granted spells; rebuilt on grant (append-only, so this is rare). Cooldown - // state changes continuously and has no change event, so it's polled every Update. - private VisualElement spellHotbarFrame; - private VisualElement spellHotbar; - private bool spellLoadoutSubscribed; - private PlayerSpellLoadout subscribedSpellLoadout; - // The loadout the hotbar is currently showing — the SELECTED builder's, or null when - // no builder is selected (hotbar hidden). Cooldown polling reads this. - private PlayerSpellLoadout displayedSpellLoadout; - private readonly List spellSlotUis = new List(); - - private readonly struct SpellSlotUi - { - public readonly VisualElement Cell; - public readonly Label CooldownLabel; - - public SpellSlotUi(VisualElement cell, Label cooldownLabel) - { - Cell = cell; - CooldownLabel = cooldownLabel; - } - } - // Chat panel (bottom-left, above portrait) — programmatic. The container // holds both the scrollable feed and the input. Highlight + scroll // interactivity are toggled on the container when typing. @@ -196,34 +131,8 @@ namespace TD.UI // Set true whenever the chat input or any other text field on the HUD has // keyboard focus. Camera, builder input, and hotkey handlers all gate on - // this to keep typing from driving gameplay. Setter is internal (not - // private) so other standalone text-input surfaces — e.g. TD.Dev.DebugConsole, - // which is not part of HUDController — can contribute to the same flag - // instead of every gameplay script needing to know about every input widget. - public static bool IsTextInputActive { get; internal set; } - - /// - /// True while a modal UI surface (currently the gear menu) owns the screen. Gameplay - /// systems should treat this exactly like — see - /// , which is the flag they actually gate on. - /// - public static bool IsModalUiOpen { get; private set; } - - /// - /// True when any UI surface is consuming keyboard/mouse input this frame: a focused - /// text field OR an open modal menu. Gameplay input handlers (camera, selection, - /// hotkeys, Escape-to-cancel) gate on this so typing or a menu never doubles as a - /// gameplay command. - /// - public static bool IsUiCapturingInput => IsTextInputActive || IsModalUiOpen; - - // Frame until which chat's "Enter opens chat" behavior is suppressed. Other - // standalone text-input surfaces (e.g. TD.Dev.DebugConsole) set this when their - // own Enter-driven submit/close already consumed the keypress, so the same - // Enter press doesn't also get interpreted as "open chat" this frame. Without - // this, submitting a debug console command with Enter would immediately pop - // chat open too, since both systems poll the raw key independently. - internal static int SuppressChatOpenUntilFrame = -1; + // this to keep typing from driving gameplay. + public static bool IsTextInputActive { get; private set; } // ----- State ------------------------------------------------------ @@ -240,10 +149,7 @@ namespace TD.UI private bool matchStateSubscribed; // true once OnPhaseChanged is hooked private bool deckSubscribed; // true once we've hooked the local PlayerTowerDeck.OnDeckChanged private PlayerTowerDeck subscribedDeck; // the deck we hooked, so we can unsubscribe the same instance - private bool upgradesSubscribed; // true once we've hooked the local PlayerTowerUpgrades - private PlayerTowerUpgrades subscribedUpgrades; private MinimapView minimapView; - private GameMenuView gameMenu; // gear button + modal menu overlay private IPanel myPanel; // tracked separately so OnDestroy only clears the static if it still points at us // ----- Hotkeys ---------------------------------------------------- @@ -371,19 +277,6 @@ namespace TD.UI PopulateGridForSelection(SelectionState.Instance?.SelectedObject); } - // Same idea for unlocked upgrade nodes: a draft pick can grant an upgrade while the - // player already has the target tower selected, and the new branch should appear in the - // action grid without needing a reselect. - private void TrySubscribeUpgrades() - { - var upgrades = PlayerTowerUpgrades.Local; - if (upgrades == null) return; - upgrades.OnUpgradesChanged += HandleDeckChanged; - subscribedUpgrades = upgrades; - upgradesSubscribed = true; - PopulateGridForSelection(SelectionState.Instance?.SelectedObject); - } - // Hook the local player's draft so the overlay rebuilds when options are offered, // picked, or rerolled. Retried each Update until the local PlayerDraft exists. private void TrySubscribeDraft() @@ -401,28 +294,11 @@ namespace TD.UI RebuildDraftCards(); } - // Hook the local player's spell loadout so the hotbar rebuilds when a new spell is - // granted. Retried each Update until the local PlayerSpellLoadout exists. - private void TrySubscribeSpellLoadout() - { - var loadout = PlayerSpellLoadout.Local; - if (loadout == null) return; - loadout.OnLoadoutChanged += HandleSpellLoadoutChanged; - subscribedSpellLoadout = loadout; - spellLoadoutSubscribed = true; - RebuildSpellHotbar(); - } - - private void HandleSpellLoadoutChanged() - { - RebuildSpellHotbar(); - } - // ----- Draft overlay ---------------------------------------------- - // Non-modal draft UI: a card row floats at top-center while the local player has an - // unresolved offer. The host panel ignores picks so empty space clicks through to the - // world — the player can still pan and inspect their maze while deciding. + // Non-modal draft UI: a card row floats at top-center while a draft is active, and + // a "Buy Roll" button shows when no draft is pending. The host panel ignores picks + // so empty space clicks through to the world — the player keeps building during prep. private void BuildDraftOverlay(VisualElement root) { draftPanel = new VisualElement(); @@ -444,8 +320,12 @@ namespace TD.UI draftCardRow.pickingMode = PickingMode.Ignore; box.Add(draftCardRow); - // The "Buy Roll" button lived here. Removed with the extra-draft shop for the 2.0 MVP - // — see PlayerDraft's commented-out RequestBuyRerollRpc for why the backend was kept. + draftBuyButton = new Button(() => PlayerDraft.Local?.RequestBuyRerollRpc()) + { + text = "Buy Roll" + }; + draftBuyButton.style.marginTop = 6; + box.Add(draftBuyButton); draftPanel.Add(box); root.Add(draftPanel); @@ -500,10 +380,9 @@ namespace TD.UI title.style.marginBottom = 6; card.Add(title); - var iconSprite = option.ResolveIcon(); - if (iconSprite != null) + if (option.Icon != null) { - var img = new Image { sprite = iconSprite }; + var img = new Image { sprite = option.Icon }; img.style.width = 48; img.style.height = 48; img.style.marginBottom = 6; @@ -524,444 +403,35 @@ namespace TD.UI return card; } - // Shows the draft row only while the local player has an unresolved offer. With the - // extra-draft shop gone there is nothing else in this panel, so it hides entirely once - // the player has picked — which also gives them a clear "I'm done, waiting on others" - // signal during the barrier. + // Per-frame: toggles the card row vs. the buy button and keeps the buy button's + // label/enabled state in sync with gold. Cheap (mirrors the gold label's per-frame + // refresh); only allocates a string while the buy button is shown. private void UpdateDraftVisibility() { if (draftPanel == null) return; - var draft = PlayerDraft.Local; - bool hasDraft = draft != null && draft.HasActiveDraft; + var draft = PlayerDraft.Local; + var service = DraftService.Instance; + var gold = PlayerGoldManager.Local; + + bool hasDraft = draft != null && draft.HasActiveDraft; + bool canShowBuy = draft != null && service != null && !hasDraft; if (draftCardRow != null) draftCardRow.style.display = hasDraft ? DisplayStyle.Flex : DisplayStyle.None; - draftPanel.style.display = hasDraft ? DisplayStyle.Flex : DisplayStyle.None; - } - - // ----- Enemy-buff vote overlay -------------------------------------- - - // Shared vote UI. Same anchor and card language as the draft row (they never show at the - // same time — the inter-wave stages are strictly sequential), but every peer sees the same - // three cards, and each card carries badges for the players currently voting for it. - private void BuildVoteOverlay(VisualElement root) - { - votePanel = new VisualElement(); - votePanel.style.position = Position.Absolute; - votePanel.style.left = 0; - votePanel.style.right = 0; - votePanel.style.top = 70; // below the top bar, same as the draft row - votePanel.style.alignItems = Align.Center; - votePanel.pickingMode = PickingMode.Ignore; - votePanel.style.display = DisplayStyle.None; - - var box = new VisualElement(); - box.style.flexDirection = FlexDirection.Column; - box.style.alignItems = Align.Center; - box.pickingMode = PickingMode.Ignore; - - voteTitle = new Label("Choose how this wave comes back"); - voteTitle.style.fontSize = 15; - voteTitle.style.color = new Color(0.95f, 0.72f, 0.55f); - voteTitle.style.unityFontStyleAndWeight = FontStyle.Bold; - voteTitle.style.marginBottom = 6; - box.Add(voteTitle); - - voteCardRow = new VisualElement(); - voteCardRow.style.flexDirection = FlexDirection.Row; - voteCardRow.pickingMode = PickingMode.Ignore; - box.Add(voteCardRow); - - votePanel.Add(box); - root.Add(votePanel); - - UpdateVoteVisibility(); - } - - // Hook the shared vote so the panel rebuilds whenever a ballot lands. Retried each Update - // until the scene's WaveVote has network-spawned. - private void TrySubscribeVote() - { - var vote = WaveVote.Instance; - if (vote == null) return; - vote.OnVoteChanged += HandleVoteChanged; - subscribedVote = vote; - voteSubscribed = true; - RebuildVoteCards(); - } - - private void HandleVoteChanged() - { - RebuildVoteCards(); - } - - // Rebuilt on every ballot change, not just when the offered set changes — the voter - // badges are the point of the panel, so they have to track votes as they land. - private void RebuildVoteCards() - { - if (voteCardRow == null) return; - voteCardRow.Clear(); - - var vote = WaveVote.Instance; - var pool = EnemyUpgradePool.Instance; - - if (vote != null && pool != null && vote.IsOpen) + if (draftBuyButton != null) { - for (int i = 0; i < vote.OptionCount; i++) + draftBuyButton.style.display = canShowBuy ? DisplayStyle.Flex : DisplayStyle.None; + if (canShowBuy) { - int id = vote.GetOptionId(i); - var option = pool.Get(id); - if (option == null) continue; - voteCardRow.Add(CreateVoteCard(option, id, vote)); + int cost = service.RerollCost; + draftBuyButton.text = $"Buy Roll ({cost}g)"; + draftBuyButton.SetEnabled(gold != null && gold.CurrentGold >= cost); } } - UpdateVoteVisibility(); - } - - private VisualElement CreateVoteCard(EnemyUpgradeOption option, int optionId, WaveVote vote) - { - var localSlot = PlayerMatchState.Local != null - ? PlayerMatchState.Local.Slot - : PlayerSlot.None; - bool isLocalChoice = localSlot != PlayerSlot.None - && vote.GetBallot(localSlot) == optionId; - - var card = new VisualElement(); - card.style.width = 160; - card.style.marginLeft = card.style.marginRight = 4; - card.style.paddingTop = card.style.paddingBottom = 10; - card.style.paddingLeft = card.style.paddingRight = 10; - card.style.backgroundColor = new Color(0.13f, 0.09f, 0.09f, 0.96f); - card.style.borderTopWidth = card.style.borderBottomWidth = - card.style.borderLeftWidth = card.style.borderRightWidth = 2; - - // The local player's current choice gets a bright border so they can tell at a glance - // which one is theirs among everyone else's badges. - var border = isLocalChoice - ? new Color(0.95f, 0.72f, 0.35f) - : new Color(0.45f, 0.30f, 0.30f); - card.style.borderTopColor = card.style.borderBottomColor = - card.style.borderLeftColor = card.style.borderRightColor = border; - card.style.alignItems = Align.Center; - - var title = new Label(option.DisplayName); - title.style.fontSize = 14; - title.style.color = Color.white; - title.style.unityFontStyleAndWeight = FontStyle.Bold; - title.style.whiteSpace = WhiteSpace.Normal; - title.style.unityTextAlign = TextAnchor.MiddleCenter; - title.style.marginBottom = 6; - card.Add(title); - - var iconSprite = option.ResolveIcon(); - if (iconSprite != null) - { - var img = new Image { sprite = iconSprite }; - img.style.width = 48; - img.style.height = 48; - img.style.marginBottom = 6; - card.Add(img); - } - - var desc = new Label(option.Description ?? ""); - desc.style.fontSize = 11; - desc.style.color = new Color(0.82f, 0.82f, 0.82f); - desc.style.whiteSpace = WhiteSpace.Normal; - desc.style.unityTextAlign = TextAnchor.MiddleCenter; - desc.style.marginBottom = 8; - card.Add(desc); - - // Live voter badges — one per player currently voting for this card, in their own - // player color. This row is why the panel rebuilds on every ballot change. - var badgeRow = new VisualElement(); - badgeRow.style.flexDirection = FlexDirection.Row; - badgeRow.style.justifyContent = Justify.Center; - badgeRow.style.minHeight = 24; - badgeRow.style.marginBottom = 6; - - voteVoterScratch.Clear(); - vote.GetVotersFor(optionId, voteVoterScratch); - foreach (var voter in voteVoterScratch) - badgeRow.Add(CreateVoterBadge(voter)); - - card.Add(badgeRow); - - var pick = new Button(() => WaveVote.Instance?.RequestVoteRpc(optionId)) - { - text = isLocalChoice ? "Voted" : "Vote" - }; - card.Add(pick); - - return card; - } - - // Small filled circle carrying the player's slot number, in their canonical player color. - // Same visual vocabulary as the race-selection overlay's picker badges, so players read it - // as "who" without a legend. - private VisualElement CreateVoterBadge(PlayerSlot slot) - { - var badge = new Label(((int)slot).ToString()); - badge.style.width = 20; - badge.style.height = 20; - badge.style.marginLeft = badge.style.marginRight = 2; - badge.style.backgroundColor = PlayerColors.Get(slot); - badge.style.color = Color.black; - badge.style.fontSize = 11; - badge.style.unityFontStyleAndWeight = FontStyle.Bold; - badge.style.unityTextAlign = TextAnchor.MiddleCenter; - badge.style.borderTopLeftRadius = badge.style.borderTopRightRadius = - badge.style.borderBottomLeftRadius = badge.style.borderBottomRightRadius = 10; - return badge; - } - - private void UpdateVoteVisibility() - { - if (votePanel == null) return; - - var vote = WaveVote.Instance; - bool open = vote != null && vote.IsOpen && vote.OptionCount > 0; - votePanel.style.display = open ? DisplayStyle.Flex : DisplayStyle.None; - } - - // ----- Boss bar ----------------------------------------------------- - - // Prominent health bar for the phase boss. Hidden whenever no boss is alive, so it costs - // nothing outside a boss encounter. - private void BuildBossBar(VisualElement root) - { - bossBarPanel = new VisualElement(); - bossBarPanel.style.position = Position.Absolute; - bossBarPanel.style.left = 0; - bossBarPanel.style.right = 0; - bossBarPanel.style.top = 70; - bossBarPanel.style.alignItems = Align.Center; - bossBarPanel.pickingMode = PickingMode.Ignore; - bossBarPanel.style.display = DisplayStyle.None; - - var box = new VisualElement(); - box.style.width = 440; - box.style.alignItems = Align.Center; - box.pickingMode = PickingMode.Ignore; - - bossNameLabel = new Label("BOSS"); - bossNameLabel.style.fontSize = 18; - bossNameLabel.style.color = new Color(0.95f, 0.45f, 0.4f); - bossNameLabel.style.unityFontStyleAndWeight = FontStyle.Bold; - bossNameLabel.style.marginBottom = 3; - box.Add(bossNameLabel); - - var track = new VisualElement(); - track.style.width = 440; - track.style.height = 18; - track.style.backgroundColor = new Color(0.08f, 0.06f, 0.06f, 0.95f); - track.style.borderTopWidth = track.style.borderBottomWidth = - track.style.borderLeftWidth = track.style.borderRightWidth = 2; - var trackBorder = new Color(0.5f, 0.25f, 0.22f); - track.style.borderTopColor = track.style.borderBottomColor = - track.style.borderLeftColor = track.style.borderRightColor = trackBorder; - track.pickingMode = PickingMode.Ignore; - - bossHealthFill = new VisualElement(); - bossHealthFill.style.height = Length.Percent(100); - bossHealthFill.style.width = Length.Percent(100); - bossHealthFill.style.backgroundColor = new Color(0.75f, 0.18f, 0.16f); - bossHealthFill.pickingMode = PickingMode.Ignore; - track.Add(bossHealthFill); - - bossHealthText = new Label(""); - bossHealthText.style.position = Position.Absolute; - bossHealthText.style.left = 0; - bossHealthText.style.right = 0; - bossHealthText.style.top = 0; - bossHealthText.style.bottom = 0; - bossHealthText.style.fontSize = 12; - bossHealthText.style.color = Color.white; - bossHealthText.style.unityTextAlign = TextAnchor.MiddleCenter; - bossHealthText.pickingMode = PickingMode.Ignore; - track.Add(bossHealthText); - - box.Add(track); - bossBarPanel.Add(box); - root.Add(bossBarPanel); - } - - // Polled from the per-frame refresh, like lives and gold. Picks the boss in the local - // player's own zone when there is one — the boss encounter spawns one per zone, and the - // one actually walking through your maze is the one you need to watch. - private void RefreshBossBar() - { - if (bossBarPanel == null) return; - - var boss = ResolveDisplayedBoss(); - if (boss == null) - { - bossBarPanel.style.display = DisplayStyle.None; - return; - } - - bossBarPanel.style.display = DisplayStyle.Flex; - - float max = Mathf.Max(1f, boss.MaxHp); - float pct = Mathf.Clamp01(boss.CurrentHp / max); - bossHealthFill.style.width = Length.Percent(pct * 100f); - bossHealthText.text = $"{Mathf.CeilToInt(boss.CurrentHp)} / {Mathf.CeilToInt(max)}"; - bossNameLabel.text = boss.DisplayName; - } - - private EnemyHealth ResolveDisplayedBoss() - { - var bosses = EnemyHealth.ActiveBosses; - if (bosses.Count == 0) return null; - - var localSlot = PlayerMatchState.Local != null - ? PlayerMatchState.Local.Slot - : PlayerSlot.None; - - EnemyHealth fallback = null; - for (int i = 0; i < bosses.Count; i++) - { - var boss = bosses[i]; - if (boss == null || boss.IsDead) continue; - - fallback ??= boss; - - if (localSlot != PlayerSlot.None) - { - var movement = boss.GetComponent(); - if (movement != null && movement.OriginZone == localSlot) return boss; - } - } - - return fallback; - } - - // ----- Spell hotbar ------------------------------------------------- - - // Rebuilds the hotbar cells for the SELECTED builder's loadout. Called on selection - // change and on OnLoadoutChanged (a new spell granted). Spells are append-only, so - // this is rare, not a per-frame concern. - // - // The hotbar follows selection: it shows the selected builder's spells and is removed - // entirely when no builder is selected (spells belong to the builder). While a builder - // IS selected, the frame keeps its reserved width (visibility toggle, not display) so - // granting a spell mid-selection doesn't reflow/shift the centered command bar. - private void RebuildSpellHotbar() - { - if (spellHotbar == null) return; - spellHotbar.Clear(); - spellSlotUis.Clear(); - - var loadout = GetSelectedBuilderLoadout(); - displayedSpellLoadout = loadout; - - if (spellHotbarFrame != null) - { - if (loadout == null) - { - // No builder selected → remove the slot (the command grid is hidden too). - spellHotbarFrame.style.display = DisplayStyle.None; - return; - } - // Builder selected → keep the reserved slot in layout; toggle only visibility so - // a mid-selection spell grant doesn't jump the command bar. - spellHotbarFrame.style.display = DisplayStyle.Flex; - spellHotbarFrame.style.visibility = - loadout.SlotCount > 0 ? Visibility.Visible : Visibility.Hidden; - } - - if (loadout == null) return; - - int slotCount = loadout.SlotCount; - var layout = SpellHotkeys.Layout; - for (int i = 0; i < slotCount; i++) - { - var kind = loadout.GetKind(i); - if (kind == null) continue; - - var definition = BuilderSpellPool.Instance?.Get(kind.Value); - - var cell = new VisualElement(); - cell.AddToClassList("spell-slot"); - - var icon = new VisualElement(); - icon.AddToClassList("spell-slot-icon"); - icon.pickingMode = PickingMode.Ignore; - if (definition?.Icon != null) - icon.style.backgroundImage = new StyleBackground(definition.Icon); - cell.Add(icon); - - if (i < layout.Length) - { - var hkLabel = new Label(SpellKeyToDisplay(layout[i])); - hkLabel.AddToClassList("spell-slot-hotkey"); - hkLabel.pickingMode = PickingMode.Ignore; - cell.Add(hkLabel); - } - - var cooldownLabel = new Label(""); - cooldownLabel.AddToClassList("spell-slot-cooldown-label"); - cooldownLabel.pickingMode = PickingMode.Ignore; - cell.Add(cooldownLabel); - - cell.RegisterCallback(_ => ShowSpellTooltip(definition)); - cell.RegisterCallback(_ => ClearTooltip()); - - spellHotbar.Add(cell); - spellSlotUis.Add(new SpellSlotUi(cell, cooldownLabel)); - } - } - - // The loadout the spell hotbar should display: the currently-selected builder's - // (resolved via its owner, so it shows whichever builder is selected — normally the - // local player's), or null when the selection isn't a builder → hotbar hidden. - private PlayerSpellLoadout GetSelectedBuilderLoadout() - { - var selected = SelectionState.Instance?.SelectedObject; - if (selected is Builder builder) - return PlayerSpellLoadout.GetForClient(builder.OwnerClientId); - return null; - } - - // Per-frame: dims each slot while on cooldown and shows the remaining whole seconds. - // Cooldown has no change event (it advances continuously with server time), so this - // has to be polled — cheap at hotbar scale (at most MaxSpellSlots cells). - private void UpdateSpellCooldowns() - { - if (spellSlotUis.Count == 0) return; - - var loadout = displayedSpellLoadout; - if (loadout == null) return; - - for (int i = 0; i < spellSlotUis.Count; i++) - { - var ui = spellSlotUis[i]; - bool onCooldown = loadout.IsSlotOnCooldown(i); - ui.Cell.EnableInClassList("on-cooldown", onCooldown); - ui.CooldownLabel.text = onCooldown - ? $"{Mathf.CeilToInt(loadout.GetCooldownRemaining(i))}" - : ""; - } - } - - // Renders a spell hotkey as its display glyph. SpellHotkeys.Layout uses Key.DigitN, - // whose ToString() is "DigitN" — strip the prefix so the badge shows "1", not "Digit1". - private static string SpellKeyToDisplay(Key key) - { - string s = key.ToString(); - return s.StartsWith("Digit") ? s.Substring("Digit".Length) : s; - } - - // Lightweight tooltip for spell slots — reuses the tooltip box (title + desc + cooldown). - private void ShowSpellTooltip(BuilderSpellDefinition def) - { - if (ttTitle == null || def == null) return; - ttTitle.text = def.DisplayName; - ttDesc.text = def.Description ?? ""; - ttStats.text = $"Cooldown: {def.Cooldown:0.#}s"; - ttCost.text = ""; + draftPanel.style.display = (hasDraft || canShowBuy) ? DisplayStyle.Flex : DisplayStyle.None; } private void InitializeUI() @@ -990,7 +460,6 @@ namespace TD.UI nextWaveLabel = Require