mirror of
https://github.com/Earth-Genesis-Games/Ajedrez_Purgatorio.git
synced 2026-09-11 09:47:35 +00:00
feat: La Muerte as speaker with custom art + data-driven quotes
- Portraits/muerte.png (256x256 flat style) wired into SpeakerDatabase.asset via deterministic GUID/fileID; SpeakerDatabaseSetup batch keeps it in sync - PortraitRegistry now fills null portraits of existing speakers (was skip-only) - MuerteQuotes loads pools from Resources Dialogues/muerte_quotes.json with embedded fallback per purgatorio-final.md - Boss art: Resources/Pieces/la_muerte.png (1024px, PPU 100); SpawnBoss swaps the tinted king placeholder for the custom sprite when present - Cleanup: stale TODO in CampaignState.StartChapter, /TestResults/ gitignored, duplicate Assets/Game/Audio removed (broken YAML metas, zero references) Verified in Unity 6000.3.13f1 batch mode: clean import, 200/200 EditMode tests
This commit is contained in:
@@ -105,3 +105,6 @@ TestResults*.xml
|
||||
# Coplay AI assistant (resolved via manifest git URL)
|
||||
/Packages/Coplay/
|
||||
/Packages/com.coplaydev.coplay/
|
||||
|
||||
# Unity test runner output folder
|
||||
/TestResults/
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace AjedrezPurgatorio.EditorTools
|
||||
/// Unity -batchmode -projectPath . -executeMethod
|
||||
/// AjedrezPurgatorio.EditorTools.SpeakerDatabaseSetup.PopulateAndAssign
|
||||
///
|
||||
/// Nota: 'muerte' y 'ricardo' no tienen PNG de retrato todavía; se registran
|
||||
/// con portrait nulo para evitar warnings y facilitar añadir arte después.
|
||||
/// Nota: 'ricardo' no tiene PNG de retrato todavía; se registra con
|
||||
/// portrait nulo para evitar warnings y facilitar añadir arte después.
|
||||
/// </summary>
|
||||
public static class SpeakerDatabaseSetup
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace AjedrezPurgatorio.EditorTools
|
||||
private static readonly (string speaker, string portrait)[] Entries =
|
||||
{
|
||||
("narrator", "narrator"),
|
||||
("muerte", null),
|
||||
("muerte", "muerte"),
|
||||
("ricardo", null),
|
||||
("alfil", "alfil"),
|
||||
("caballo", "caballo"),
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be210525ade96b143bbf7a4b90d5e258
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbee09e29e03488a87056057de3333d3
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39c30d32bdb442ee844d9c2204244d96
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d305733468c4b7199722466abeeace9
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 146caa30b3a549eb8fa8d1fbd296635d
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd7eca68231b48f198532c2a8f8b8ed3
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7347cab1bf24c4a93f0594fab7b84d8
|
||||
AudioImporter:
|
||||
externalObjects: {{}}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
normalizedSampleRate: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
platformSettingOverrides: {{}}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"intro": [
|
||||
"Mate perfecto... para el tablero. Aquí abajo, la partida sigue.",
|
||||
"Llegaste al final del tablero. Bienvenido al principio del mío.",
|
||||
"Todos los caminos del ajedrez terminan frente a mí. Tú llegaste caminando.",
|
||||
"Tu reina no me mateó a mí. Solo despejó la mesa."
|
||||
],
|
||||
"milestone": [
|
||||
"El Purgatorio tiene hambre. Cada turno, una casilla menos.",
|
||||
"El suelo que pisas ya fue. Apúrate.",
|
||||
"No te apresuro. El vacío lo hace por mí.",
|
||||
"Cada casilla que cae fue una partida más. Como la tuya."
|
||||
],
|
||||
"playerWin": [
|
||||
"...Bien jugado. El tablero es tuyo. Por ahora.",
|
||||
"Me capturas hoy. Mañana seré tu siguiente jaque.",
|
||||
"Toma tu victoria. Yo me quedo con el tiempo.",
|
||||
"Nadie me había alcanzado sin perder algo primero. Vuelve pronto."
|
||||
],
|
||||
"playerLost": [
|
||||
"Te dije que nadie gana aquí. Solo algunos posponen.",
|
||||
"Tu pieza descansa. ¿Quieres negociar por ella? Los dados no mienten.",
|
||||
"El vacío también juega. Y siempre va conmigo.",
|
||||
"Otra partida termina. Otra alma aprende."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3b9c74e28d14a6b8e50a1c9d7f26b34
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b071f4614a3499c9929e8f8bbaa0091
|
||||
guid: 8a4d2c91b7e34f6095c1d2e8a6b3f740
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,156 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1167710624d445aa3b7dea5b24b42a5
|
||||
TextureImporter:
|
||||
internalIDToNameTable:
|
||||
- first:
|
||||
213: 6587412096331147520
|
||||
second: la_muerte_0
|
||||
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: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 2
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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:
|
||||
- serializedVersion: 2
|
||||
name: la_muerte_0
|
||||
rect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1024
|
||||
height: 1024
|
||||
alignment: 0
|
||||
pivot: {x: 0, y: 0}
|
||||
border: {x: 0, y: 0, z: 0, w: 0}
|
||||
customData:
|
||||
outline: []
|
||||
physicsShape: []
|
||||
tessellationDetail: -1
|
||||
bones: []
|
||||
spriteID: 009ede666603b6b50800000000000000
|
||||
internalID: 6587412096331147520
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable:
|
||||
la_muerte_0: 6587412096331147520
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,156 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1e6e27e3c8e40129f502081e37ff22d
|
||||
TextureImporter:
|
||||
internalIDToNameTable:
|
||||
- first:
|
||||
213: 7419852336102758402
|
||||
second: muerte_0
|
||||
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: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 2
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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:
|
||||
- serializedVersion: 2
|
||||
name: muerte_0
|
||||
rect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 256
|
||||
height: 256
|
||||
alignment: 0
|
||||
pivot: {x: 0, y: 0}
|
||||
border: {x: 0, y: 0, z: 0, w: 0}
|
||||
customData:
|
||||
outline: []
|
||||
physicsShape: []
|
||||
tessellationDetail: -1
|
||||
bones: []
|
||||
spriteID: c39a1f4d82b60e718000000000000000
|
||||
internalID: 7419852336102758402
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable:
|
||||
muerte_0: 7419852336102758402
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,7 +16,7 @@ MonoBehaviour:
|
||||
- speakerName: narrator
|
||||
portrait: {fileID: 5364273658523971450, guid: 737c4034b70db6d47978d8d288f51f59, type: 3}
|
||||
- speakerName: muerte
|
||||
portrait: {fileID: 0}
|
||||
portrait: {fileID: 7419852336102758402, guid: c1e6e27e3c8e40129f502081e37ff22d, type: 3}
|
||||
- speakerName: ricardo
|
||||
portrait: {fileID: 0}
|
||||
- speakerName: alfil
|
||||
|
||||
@@ -66,8 +66,8 @@ public class CampaignState : ScriptableObject
|
||||
{
|
||||
_currentChapterPiecesLost = 0;
|
||||
|
||||
// Inicializar piezas vivas para el capítulo
|
||||
// TODO: Poblar esto desde el board state de GameManager
|
||||
// Las piezas vivas se sincronizan desde el tablero vía SyncFromBoard(),
|
||||
// llamada por CampaignManager tras SetupBoard().
|
||||
Debug.Log($"[CampaignState] Iniciando capítulo: {chapterId}");
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,27 @@ public class SpeakerDatabase : ScriptableObject
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene el portrait de un speaker sin loguear warning si falta.
|
||||
/// Usado por sistemas runtime (PortraitRegistry) que comprueban existencia.
|
||||
/// </summary>
|
||||
public bool TryGetPortrait(string speakerName, out Sprite portrait)
|
||||
{
|
||||
portrait = null;
|
||||
|
||||
if (_speakerLookup == null)
|
||||
{
|
||||
BuildLookup();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(speakerName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _speakerLookup.TryGetValue(speakerName.ToLower(), out portrait) && portrait != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica si existe un speaker en la base de datos.
|
||||
/// </summary>
|
||||
|
||||
@@ -30,6 +30,7 @@ public class PortraitRegistry : MonoBehaviour
|
||||
|
||||
Sprite[] sprites = Resources.LoadAll<Sprite>(_resourcesPortraitsFolder);
|
||||
int registered = 0;
|
||||
int filled = 0;
|
||||
|
||||
foreach (var sprite in sprites)
|
||||
{
|
||||
@@ -42,9 +43,15 @@ public class PortraitRegistry : MonoBehaviour
|
||||
database.RegisterPortrait(sprite.name, sprite);
|
||||
registered++;
|
||||
}
|
||||
else if (!database.TryGetPortrait(sprite.name, out Sprite current) || current == null)
|
||||
{
|
||||
// Speaker ya registrado en el asset pero sin arte: rellenarlo.
|
||||
database.RegisterPortrait(sprite.name, sprite);
|
||||
filled++;
|
||||
}
|
||||
}
|
||||
|
||||
_registered = true;
|
||||
Debug.Log($"[PortraitRegistry] {registered} retrato(s) registrado(s) desde Resources/{_resourcesPortraitsFolder}.");
|
||||
Debug.Log($"[PortraitRegistry] {registered} retrato(s) registrado(s), {filled} hueco(s) rellenado(s) desde Resources/{_resourcesPortraitsFolder}.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Frases de La Muerte durante el Duelo del Purgatorio.
|
||||
/// Voz solemne según purgatorio-cosmology.md ("la Muerte", máscara formal).
|
||||
/// Los pools se cargan de Resources/Dialogues/muerte_quotes.json (data-driven
|
||||
/// según purgatorio-final.md); las entradas ausentes o un JSON faltante/inválido
|
||||
/// caen a los pools por defecto embebidos.
|
||||
/// </summary>
|
||||
public static class MuerteQuotes
|
||||
{
|
||||
[Serializable]
|
||||
private class QuotePools
|
||||
{
|
||||
public string[] intro = Array.Empty<string>();
|
||||
public string[] milestone = Array.Empty<string>();
|
||||
public string[] playerWin = Array.Empty<string>();
|
||||
public string[] playerLost = Array.Empty<string>();
|
||||
}
|
||||
|
||||
private const string ResourcePath = "Dialogues/muerte_quotes";
|
||||
|
||||
private static readonly string[] Intro =
|
||||
{
|
||||
"Mate perfecto... para el tablero. Aquí abajo, la partida sigue.",
|
||||
@@ -39,15 +53,56 @@ public static class MuerteQuotes
|
||||
"Otra partida termina. Otra alma aprende."
|
||||
};
|
||||
|
||||
public static string GetIntro() => Pick(Intro);
|
||||
public static string GetMilestone() => Pick(Milestone);
|
||||
public static string GetPlayerWin() => Pick(PlayerWin);
|
||||
public static string GetPlayerLost() => Pick(PlayerLost);
|
||||
private static QuotePools _pools;
|
||||
private static bool _loaded;
|
||||
|
||||
public static string GetIntro() => Pick(Resolve(p => p.intro, Intro));
|
||||
public static string GetMilestone() => Pick(Resolve(p => p.milestone, Milestone));
|
||||
public static string GetPlayerWin() => Pick(Resolve(p => p.playerWin, PlayerWin));
|
||||
public static string GetPlayerLost() => Pick(Resolve(p => p.playerLost, PlayerLost));
|
||||
|
||||
/// <summary>
|
||||
/// Descarta la caché del JSON (útil en tests o hot-reload de contenido).
|
||||
/// </summary>
|
||||
public static void Reload()
|
||||
{
|
||||
_loaded = false;
|
||||
}
|
||||
|
||||
private static string[] Resolve(Func<QuotePools, string[]> selector, string[] fallback)
|
||||
{
|
||||
EnsureLoaded();
|
||||
string[] fromJson = selector(_pools);
|
||||
return fromJson != null && fromJson.Length > 0 ? fromJson : fallback;
|
||||
}
|
||||
|
||||
private static void EnsureLoaded()
|
||||
{
|
||||
if (_loaded)
|
||||
return;
|
||||
|
||||
_loaded = true;
|
||||
_pools = new QuotePools();
|
||||
|
||||
TextAsset asset = Resources.Load<TextAsset>(ResourcePath);
|
||||
if (asset == null)
|
||||
return; // Sin JSON: los getters usan los pools embebidos.
|
||||
|
||||
try
|
||||
{
|
||||
JsonUtility.FromJsonOverwrite(asset.text, _pools);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[MuerteQuotes] JSON inválido en {ResourcePath}: {ex.Message}. Usando frases por defecto.");
|
||||
_pools = new QuotePools();
|
||||
}
|
||||
}
|
||||
|
||||
private static string Pick(string[] pool)
|
||||
{
|
||||
if (pool == null || pool.Length == 0)
|
||||
return string.Empty;
|
||||
return pool[Random.Range(0, pool.Length)];
|
||||
return pool[UnityEngine.Random.Range(0, pool.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,12 +175,32 @@ public class PurgatoryDuelManager : MonoBehaviour
|
||||
boss.hasMoved = true;
|
||||
board[spawnPos.x, spawnPos.y] = boss;
|
||||
|
||||
foreach (var spriteRenderer in bossObj.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
spriteRenderer.color = new Color(0.55f, 0.07f, 0.07f);
|
||||
ApplyBossAppearance(bossObj);
|
||||
|
||||
return boss;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arte de La Muerte: usa el sprite propio (Resources/Pieces/la_muerte)
|
||||
/// si existe; si no, tiñe el Rey negro en rojo oscuro como placeholder.
|
||||
/// </summary>
|
||||
private static void ApplyBossAppearance(GameObject bossObj)
|
||||
{
|
||||
SpriteRenderer[] renderers = bossObj.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
|
||||
Sprite muerteSprite = Resources.Load<Sprite>("Pieces/la_muerte");
|
||||
if (muerteSprite != null)
|
||||
{
|
||||
foreach (var spriteRenderer in renderers)
|
||||
spriteRenderer.sprite = muerteSprite;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var spriteRenderer in renderers)
|
||||
spriteRenderer.color = new Color(0.55f, 0.07f, 0.07f);
|
||||
}
|
||||
|
||||
private static Vector2Int PickBossSpawn(Piece[,] board)
|
||||
{
|
||||
foreach (Vector2Int candidate in new[]
|
||||
|
||||
@@ -7717,7 +7717,7 @@ MonoBehaviour:
|
||||
_speakerNameText: {fileID: 1622539956}
|
||||
_speakerPortrait: {fileID: 991001013}
|
||||
_continueIndicator: {fileID: 1699531460}
|
||||
_speakerDatabase: {fileID: 0}
|
||||
_speakerDatabase: {fileID: 11400000, guid: e35f84464de24b4cb0885058c4cdea56, type: 2}
|
||||
_blinkSpeed: 0.5
|
||||
_advanceDialogueAction: {fileID: 0}
|
||||
--- !u!1 &321429398
|
||||
|
||||
@@ -7234,7 +7234,7 @@ MonoBehaviour:
|
||||
_speakerNameText: {fileID: 1622539956}
|
||||
_speakerPortrait: {fileID: 991001013}
|
||||
_continueIndicator: {fileID: 1699531460}
|
||||
_speakerDatabase: {fileID: 0}
|
||||
_speakerDatabase: {fileID: 11400000, guid: e35f84464de24b4cb0885058c4cdea56, type: 2}
|
||||
_blinkSpeed: 0.5
|
||||
_advanceDialogueAction: {fileID: 0}
|
||||
--- !u!1 &321429398
|
||||
|
||||
@@ -107,3 +107,20 @@ Verificación de los 7 bloqueantes listados arriba:
|
||||
|
||||
**Pendiente tras esta auditoría**: correr los menús Tools > Purgatory UI en Unity (Ch1, Ch2, Ch3),
|
||||
guardar escenas, verificar consola sin errores de compilación, y commitear.
|
||||
|
||||
---
|
||||
|
||||
## Actualización 2026-08-24 — Duelo del Purgatorio + La Muerte como personaje
|
||||
|
||||
Commit base: `f7d5606` (Duelo del Purgatorio completo + SFX cableados + menú de opciones + migración
|
||||
de tests). Sobre esa base:
|
||||
|
||||
| Ítem | Estado |
|
||||
|------|--------|
|
||||
| Commit del trabajo pendiente | RESUELTO — `f7d5606` |
|
||||
| La Muerte como speaker | RESUELTO — retrato `Portraits/muerte.png` (256×256, flat) cableado en SpeakerDatabase.asset con GUID/fileID deterministas; `PortraitRegistry` ahora rellena portraits null de speakers existentes; frases data-driven en `Dialogues/muerte_quotes.json` con fallback embebido |
|
||||
| Arte del Jefe (La Muerte) | RESUELTO — sprite propio `Resources/Pieces/la_muerte.png` (1024×1024, PPU 100); `SpawnBoss` lo intercambia con fallback al Rey tintado |
|
||||
| Limpieza menor | RESUELTO — TODO obsoleto en `CampaignState.StartChapter` eliminado (SyncFromBoard ya cubre), `/TestResults/` a .gitignore, duplicado `Assets/Game/Audio/` (metas YAML corruptos, sin referencias) eliminado |
|
||||
|
||||
**Verificación**: Unity 6000.3.13f1 batch mode — assets importados, `SpeakerDatabaseSetup` OK
|
||||
(12 speakers, DialogueUIs actualizados en Ch2/Ch3), EditMode 200/200 pasados.
|
||||
|
||||
Reference in New Issue
Block a user