mirror of
https://github.com/Earth-Genesis-Games/Ajedrez_Purgatorio.git
synced 2026-09-11 09:47:35 +00:00
- 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
137 lines
3.8 KiB
C#
137 lines
3.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Base de datos de speakers con sus portraits.
|
|
/// ScriptableObject que mapea nombres de speakers a sus imágenes de portrait.
|
|
/// </summary>
|
|
[CreateAssetMenu(fileName = "SpeakerDatabase", menuName = "Ajedrez Purgatorio/Narrative/Speaker Database")]
|
|
public class SpeakerDatabase : ScriptableObject
|
|
{
|
|
[Tooltip("Lista de speakers con sus portraits")]
|
|
[SerializeField] private List<SpeakerEntry> _speakers = new List<SpeakerEntry>();
|
|
|
|
private Dictionary<string, Sprite> _speakerLookup;
|
|
|
|
void OnEnable()
|
|
{
|
|
BuildLookup();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Construye el diccionario de búsqueda rápida.
|
|
/// </summary>
|
|
private void BuildLookup()
|
|
{
|
|
_speakerLookup = new Dictionary<string, Sprite>();
|
|
|
|
foreach (var entry in _speakers)
|
|
{
|
|
if (!string.IsNullOrEmpty(entry.speakerName))
|
|
{
|
|
_speakerLookup[entry.speakerName.ToLower()] = entry.portrait;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtiene el portrait de un speaker por nombre.
|
|
/// </summary>
|
|
public Sprite GetPortrait(string speakerName)
|
|
{
|
|
if (_speakerLookup == null)
|
|
{
|
|
BuildLookup();
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(speakerName))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string key = speakerName.ToLower();
|
|
|
|
if (_speakerLookup.TryGetValue(key, out Sprite portrait))
|
|
{
|
|
return portrait;
|
|
}
|
|
|
|
Debug.LogWarning($"[SpeakerDatabase] No se encontró portrait para: {speakerName}");
|
|
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>
|
|
public bool HasSpeaker(string speakerName)
|
|
{
|
|
if (_speakerLookup == null)
|
|
{
|
|
BuildLookup();
|
|
}
|
|
|
|
return !string.IsNullOrEmpty(speakerName) &&
|
|
_speakerLookup.ContainsKey(speakerName.ToLower());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registra (o actualiza) un portrait en runtime.
|
|
/// Usado por PortraitRegistry para speakers de campañas nuevas sin editar el asset.
|
|
/// </summary>
|
|
public void RegisterPortrait(string speakerName, Sprite portrait)
|
|
{
|
|
if (string.IsNullOrEmpty(speakerName) || portrait == null)
|
|
return;
|
|
|
|
string key = speakerName.ToLower();
|
|
|
|
// Mantener la lista serializada sincronizada para el Inspector.
|
|
var existing = _speakers.Find(s => !string.IsNullOrEmpty(s.speakerName) && s.speakerName.ToLower() == key);
|
|
if (existing != null)
|
|
{
|
|
existing.portrait = portrait;
|
|
}
|
|
else
|
|
{
|
|
_speakers.Add(new SpeakerEntry { speakerName = speakerName, portrait = portrait });
|
|
}
|
|
|
|
_speakerLookup[key] = portrait;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Entrada individual de speaker con su portrait.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class SpeakerEntry
|
|
{
|
|
[Tooltip("Nombre del speaker (debe coincidir con el campo 'speaker' en JSON)")]
|
|
public string speakerName;
|
|
|
|
[Tooltip("Imagen del portrait del speaker")]
|
|
public Sprite portrait;
|
|
}
|